mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
change(docker): use step-ca for CA + cert generation
Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
e558e979ff
commit
b98159d5b9
10 changed files with 160 additions and 69 deletions
|
@ -13,7 +13,8 @@ RUN /install-deps.sh
|
||||||
|
|
||||||
# Copy Docker scripts
|
# Copy Docker scripts
|
||||||
COPY ./docker /docker
|
COPY ./docker /docker
|
||||||
COPY ./docker/scripts/*.sh /usr/local/bin/
|
COPY ./docker/scripts/* /usr/local/bin/
|
||||||
|
|
||||||
|
|
||||||
# Copy over all aurweb files.
|
# Copy over all aurweb files.
|
||||||
COPY . /aurweb
|
COPY . /aurweb
|
||||||
|
|
|
@ -70,9 +70,8 @@ services:
|
||||||
nginx:
|
nginx:
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ${GIT_DATA_DIR}:/aurweb/aur.git
|
|
||||||
- data:/data
|
- data:/data
|
||||||
- logs:/var/log/nginx
|
- archives:/var/lib/aurweb/archives
|
||||||
- smartgit_run:/var/run/smartgit
|
- smartgit_run:/var/run/smartgit
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -6,10 +6,6 @@ services:
|
||||||
mariadb:
|
mariadb:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
ca:
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
|
|
||||||
git:
|
git:
|
||||||
volumes:
|
volumes:
|
||||||
- git_data:/aurweb/aur.git
|
- git_data:/aurweb/aur.git
|
||||||
|
@ -45,13 +41,3 @@ services:
|
||||||
- ./web/template:/aurweb/web/template
|
- ./web/template:/aurweb/web/template
|
||||||
- ./web/lib:/aurweb/web/lib
|
- ./web/lib:/aurweb/web/lib
|
||||||
- ./templates:/aurweb/templates
|
- ./templates:/aurweb/templates
|
||||||
|
|
||||||
nginx:
|
|
||||||
volumes:
|
|
||||||
- git_data:/aurweb/aur.git
|
|
||||||
- ./data:/data
|
|
||||||
- ./logs:/var/log/nginx
|
|
||||||
- ./web/html:/aurweb/web/html
|
|
||||||
- ./web/template:/aurweb/web/template
|
|
||||||
- ./web/lib:/aurweb/web/lib
|
|
||||||
- smartgit_run:/var/run/smartgit
|
|
||||||
|
|
|
@ -29,7 +29,16 @@ services:
|
||||||
image: aurweb:latest
|
image: aurweb:latest
|
||||||
init: true
|
init: true
|
||||||
entrypoint: /docker/ca-entrypoint.sh
|
entrypoint: /docker/ca-entrypoint.sh
|
||||||
command: echo
|
command: /docker/scripts/run-ca.sh
|
||||||
|
healthcheck:
|
||||||
|
test: "bash /docker/health/run-ca.sh"
|
||||||
|
interval: 3s
|
||||||
|
tmpfs:
|
||||||
|
- /tmp
|
||||||
|
volumes:
|
||||||
|
- ./docker:/docker
|
||||||
|
- ./data:/data
|
||||||
|
- step:/root/.step
|
||||||
|
|
||||||
memcached:
|
memcached:
|
||||||
image: aurweb:latest
|
image: aurweb:latest
|
||||||
|
@ -261,7 +270,9 @@ services:
|
||||||
php-fpm:
|
php-fpm:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
- archives:/var/lib/aurweb/archives
|
- archives:/var/lib/aurweb/archives
|
||||||
|
- smartgit_run:/var/run/smartgit
|
||||||
|
|
||||||
sharness:
|
sharness:
|
||||||
image: aurweb:latest
|
image: aurweb:latest
|
||||||
|
@ -347,3 +358,4 @@ volumes:
|
||||||
git_data: {} # Share aurweb/aur.git
|
git_data: {} # Share aurweb/aur.git
|
||||||
smartgit_run: {}
|
smartgit_run: {}
|
||||||
archives: {}
|
archives: {}
|
||||||
|
step: {}
|
||||||
|
|
|
@ -1,58 +1,123 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# Initialize step-ca and request certificates from it.
|
||||||
|
#
|
||||||
|
# Certificates created by this service are meant to be used in
|
||||||
|
# aurweb Docker's nginx service.
|
||||||
|
#
|
||||||
|
# If ./data/root_ca.crt is present, CA generation is skipped.
|
||||||
|
# If ./data/${host}.{cert,key}.pem is available, host certificate
|
||||||
|
# generation is skipped.
|
||||||
|
#
|
||||||
set -eou pipefail
|
set -eou pipefail
|
||||||
|
|
||||||
if [ -f /data/ca.root.pem ]; then
|
# /data-based variables.
|
||||||
echo "Already have certs, skipping."
|
DATA_DIR="/data"
|
||||||
exit 0
|
DATA_ROOT_CA="$DATA_DIR/root_ca.crt"
|
||||||
|
DATA_CERT="$DATA_DIR/localhost.cert.pem"
|
||||||
|
DATA_CERT_KEY="$DATA_DIR/localhost.key.pem"
|
||||||
|
|
||||||
|
# Host certificates requested from the CA (separated by spaces).
|
||||||
|
DATA_CERT_HOSTS='localhost'
|
||||||
|
|
||||||
|
# Local step paths and CA configuration values.
|
||||||
|
STEP_DIR="$(step-cli path)"
|
||||||
|
STEP_CA_CONFIG="$STEP_DIR/config/ca.json"
|
||||||
|
STEP_CA_ADDR='127.0.0.1:8443'
|
||||||
|
STEP_CA_URL='https://localhost:8443'
|
||||||
|
STEP_CA_PROVISIONER='admin@localhost'
|
||||||
|
|
||||||
|
# Password file used for both --password-file and --provisioner-password-file.
|
||||||
|
STEP_PASSWD_FILE="$STEP_DIR/password.txt"
|
||||||
|
|
||||||
|
# Hostnames supported by the CA.
|
||||||
|
STEP_CA_NAME='aurweb'
|
||||||
|
STEP_CA_DNS='localhost'
|
||||||
|
|
||||||
|
make_password() {
|
||||||
|
# Create a random 20-length password and write it to $1.
|
||||||
|
openssl rand -hex 20 > $1
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_step_ca() {
|
||||||
|
# Cleanup and setup step ca configuration.
|
||||||
|
rm -rf $STEP_DIR/*
|
||||||
|
|
||||||
|
# Initialize `step`
|
||||||
|
make_password "$STEP_PASSWD_FILE"
|
||||||
|
step-cli ca init \
|
||||||
|
--name="$STEP_CA_NAME" \
|
||||||
|
--dns="$STEP_CA_DNS" \
|
||||||
|
--address="$STEP_CA_ADDR" \
|
||||||
|
--password-file="$STEP_PASSWD_FILE" \
|
||||||
|
--provisioner="$STEP_CA_PROVISIONER" \
|
||||||
|
--provisioner-password-file="$STEP_PASSWD_FILE" \
|
||||||
|
--with-ca-url="$STEP_CA_URL"
|
||||||
|
|
||||||
|
# Update ca.json max TLS certificate duration to a year.
|
||||||
|
update-step-config "$STEP_CA_CONFIG"
|
||||||
|
|
||||||
|
# Install root_ca.crt as read/writable to /data/root_ca.crt.
|
||||||
|
install -m666 "$STEP_DIR/certs/root_ca.crt" "$DATA_ROOT_CA"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_step_ca() {
|
||||||
|
# Start the step-ca web server.
|
||||||
|
step-ca "$STEP_CA_CONFIG" \
|
||||||
|
--password-file="$STEP_PASSWD_FILE" &
|
||||||
|
until printf "" 2>>/dev/null >>/dev/tcp/127.0.0.1/8443; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
kill_step_ca() {
|
||||||
|
# Stop the step-ca web server.
|
||||||
|
killall step-ca >/dev/null 2>&1 || /bin/true
|
||||||
|
}
|
||||||
|
|
||||||
|
install_step_ca() {
|
||||||
|
# Install step-ca certificate authority to the system.
|
||||||
|
step-cli certificate install "$STEP_DIR/certs/root_ca.crt"
|
||||||
|
}
|
||||||
|
|
||||||
|
step_cert_request() {
|
||||||
|
# Request a certificate from the step ca.
|
||||||
|
step-cli ca certificate \
|
||||||
|
--not-after=8800h \
|
||||||
|
--provisioner="$STEP_CA_PROVISIONER" \
|
||||||
|
--provisioner-password-file="$STEP_PASSWD_FILE" \
|
||||||
|
$1 $2 $3
|
||||||
|
chmod 666 /data/${1}.*.pem
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -f $DATA_ROOT_CA ]; then
|
||||||
|
setup_step_ca
|
||||||
|
install_step_ca
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate a new 2048-bit RSA key for the Root CA.
|
# For all hosts separated by spaces in $DATA_CERT_HOSTS, perform a check
|
||||||
openssl genrsa -des3 -out /data/ca.key -passout pass:devca 2048
|
# for their existence in /data and react accordingly.
|
||||||
|
for host in $DATA_CERT_HOSTS; do
|
||||||
|
if [ -f /data/${host}.cert.pem ] && [ -f /data/${host}.key.pem ]; then
|
||||||
|
# Found an override. Move on to running the service after
|
||||||
|
# printing a notification to the user.
|
||||||
|
echo "Found '${host}.{cert,key}.pem' override, skipping..."
|
||||||
|
echo -n "Note: If you need to regenerate certificates, run "
|
||||||
|
echo '`rm -f data/*.{cert,key}.pem` before starting this service.'
|
||||||
|
exec "$@"
|
||||||
|
else
|
||||||
|
# Otherwise, we had a missing cert or key, so remove both.
|
||||||
|
rm -f /data/${host}.cert.pem
|
||||||
|
rm -f /data/${host}.key.pem
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Request and self-sign a new Root CA certificate, using
|
start_step_ca
|
||||||
# the RSA key. Output Root CA PEM-format certificate and key:
|
for host in $DATA_CERT_HOSTS; do
|
||||||
# /data/ca.root.pem and /data/ca.key.pem
|
step_cert_request $host /data/${host}.cert.pem /data/${host}.key.pem
|
||||||
openssl req -x509 -new -nodes -sha256 -days 1825 \
|
done
|
||||||
-passin pass:devca \
|
kill_step_ca
|
||||||
-subj "/C=US/ST=California/L=Authority/O=aurweb/CN=localhost" \
|
|
||||||
-in /data/ca.key -out /data/ca.root.pem -keyout /data/ca.key.pem
|
|
||||||
|
|
||||||
# Generate a new 2048-bit RSA key for a localhost server.
|
# Set permissions to /data to rwx for everybody.
|
||||||
openssl genrsa -out /data/localhost.key 2048
|
chmod 777 /data
|
||||||
|
|
||||||
# Generate a Certificate Signing Request (CSR) for the localhost server
|
|
||||||
# using the RSA key we generated above.
|
|
||||||
openssl req -new -key /data/localhost.key -passout pass:devca \
|
|
||||||
-subj "/C=US/ST=California/L=Server/O=aurweb/CN=localhost" \
|
|
||||||
-out /data/localhost.csr
|
|
||||||
|
|
||||||
# Get our CSR signed by our Root CA PEM-formatted certificate and key
|
|
||||||
# to produce a fresh /data/localhost.cert.pem PEM-formatted certificate.
|
|
||||||
openssl x509 -req -in /data/localhost.csr \
|
|
||||||
-CA /data/ca.root.pem -CAkey /data/ca.key.pem \
|
|
||||||
-CAcreateserial \
|
|
||||||
-out /data/localhost.cert.pem \
|
|
||||||
-days 825 -sha256 \
|
|
||||||
-passin pass:devca \
|
|
||||||
-extfile /docker/localhost.ext
|
|
||||||
|
|
||||||
# Convert RSA key to a PEM-formatted key: /data/localhost.key.pem
|
|
||||||
openssl rsa -in /data/localhost.key -text > /data/localhost.key.pem
|
|
||||||
|
|
||||||
# At the end here, our notable certificates and keys are:
|
|
||||||
# - /data/ca.root.pem
|
|
||||||
# - /data/ca.key.pem
|
|
||||||
# - /data/localhost.key.pem
|
|
||||||
# - /data/localhost.cert.pem
|
|
||||||
#
|
|
||||||
# When running a server which uses the localhost certificate, a chain
|
|
||||||
# should be used, starting with localhost.cert.pem:
|
|
||||||
# - cat /data/localhost.cert.pem /data/ca.root.pem > localhost.chain.pem
|
|
||||||
#
|
|
||||||
# The Root CA (ca.root.pem) should be imported into browsers or
|
|
||||||
# ca-certificates on machines wishing to verify localhost.
|
|
||||||
#
|
|
||||||
|
|
||||||
chmod 666 /data/*
|
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|
2
docker/health/ca.sh
Executable file
2
docker/health/ca.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
exec printf "" 2>>/dev/null >>/dev/tcp/127.0.0.1/8443
|
|
@ -15,7 +15,7 @@ if [ -f "$CERT" ]; then
|
||||||
cp -vf "$CERT" "$DEST_CERT"
|
cp -vf "$CERT" "$DEST_CERT"
|
||||||
cp -vf "$KEY" "$DEST_KEY"
|
cp -vf "$KEY" "$DEST_KEY"
|
||||||
else
|
else
|
||||||
cat /data/localhost.cert.pem /data/ca.root.pem > "$DEST_CERT"
|
cat /data/localhost.cert.pem /data/root_ca.crt > "$DEST_CERT"
|
||||||
cp -vf /data/localhost.key.pem "$DEST_KEY"
|
cp -vf /data/localhost.key.pem "$DEST_KEY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,6 @@ pacman -Syu --noconfirm --noprogressbar \
|
||||||
mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \
|
mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \
|
||||||
php php-fpm memcached php-memcached python-pip pyalpm \
|
php php-fpm memcached php-memcached python-pip pyalpm \
|
||||||
python-srcinfo curl libeatmydata cronie python-poetry \
|
python-srcinfo curl libeatmydata cronie python-poetry \
|
||||||
python-poetry-core
|
python-poetry-core step-cli step-ca
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|
7
docker/scripts/run-ca.sh
Executable file
7
docker/scripts/run-ca.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
STEP_DIR="$(step-cli path)"
|
||||||
|
STEP_PASSWD_FILE="$STEP_DIR/password.txt"
|
||||||
|
STEP_CA_CONFIG="$STEP_DIR/config/ca.json"
|
||||||
|
|
||||||
|
# Start the step-ca https server.
|
||||||
|
exec step-ca "$STEP_CA_CONFIG" --password-file="$STEP_PASSWD_FILE"
|
19
docker/scripts/update-step-config
Executable file
19
docker/scripts/update-step-config
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
CA_CONFIG = sys.argv[1]
|
||||||
|
|
||||||
|
with open(CA_CONFIG) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
if "authority" not in data:
|
||||||
|
data["authority"] = dict()
|
||||||
|
if "claims" not in data["authority"]:
|
||||||
|
data["authority"]["claims"] = dict()
|
||||||
|
|
||||||
|
# One year of certificate duration.
|
||||||
|
data["authority"]["claims"] = {"maxTLSCertDuration": "8800h"}
|
||||||
|
|
||||||
|
with open(CA_CONFIG, "w") as f:
|
||||||
|
json.dump(data, f)
|
Loading…
Add table
Add a link
Reference in a new issue