Skip to content

Commit

Permalink
Merge pull request #2 from OpenCHAMI/alovelltroy/quickstart
Browse files Browse the repository at this point in the history
Replace the entrypoint with an upstream version and instrument it for use with the Dockerfile with appropriate README descriptions
  • Loading branch information
alexlovelltroy authored Apr 17, 2024
2 parents 721af64 + 6b67a0d commit 12b5d5a
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 14 deletions.
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,60 @@
# local-ca
# Local ACME Certificate authority

This repo builds a container that can be used in a docker-compose environment to create a disposable CA and issue/update certificates using certbot.

It is heavily informed by the smallstep authors via https://github.com/smallstep/certificates/blob/master/docker/entrypoint.sh

## Accessing the root cert

The easiest way to obtain the cert for use validating other certs within the environment is to download the pem from the smallstep ca at the well known url: `https://step-ca:9000/roots.pem`.

The next easiest way to obtain the cert is through mounting a docker volume which contains the certificate. See the docker-compose example below or follow the OpenCHAMI quickstart.


## Docker Compose Usage

This container can be used with docker compose following this example:

```
step-ca:
container_name: step-ca
hostname: step-ca
image: ghcr.io/openchami/local-ca:v0.1.0
ports:
- "9000:9000"
networks:
- openchami-certs
volumes:
- ./configs/step-ca/:/home/step
# Keeping the database in a volume improves performance. I don't understand why.
- step-ca-db:/home/step/db
# Keeping the root CA in a volume allows us to back it up and restore it.
- step-root-ca:/root-ca/
environment:
# To initialize your CA, modify these environment variables
- STEPPATH=/home/step
- DOCKER_STEPCA_INIT_NAME=OpenCHAMI
- DOCKER_STEPCA_INIT_DNS_NAMES=localhost,step-ca
- DOCKER_STEPCA_INIT_ACME=true
healthcheck:
test: ["CMD", "step", "ca", "health", "--ca-url", "https://step-ca:9000", "--root", "/root-ca/root_ca.crt"]
interval: 10s
timeout: 10s
retries: 5
certbot-issue-cert:
container_name: certbot
hostname: certbot
image: certbot/certbot:v2.10.0
depends_on:
step-ca:
condition: service_healthy
environment:
- REQUESTS_CA_BUNDLE=/root-ca/root_ca.crt # This is the root CA certificate that we use to verify the local CA.
command: [ "certonly", "--webroot", "--server", "https://step-ca:9000/acme/acme/directory", "--webroot-path", "/var/www/html", "--agree-tos", "--email", "[email protected]", "-d", "openchami.bikeshack.dev", "-n" ]
networks:
- openchami-certs
volumes:
- local-certs:/etc/letsencrypt
- certbot-challenges:/var/www/html/
- step-root-ca:/root-ca:ro
```
25 changes: 20 additions & 5 deletions local-ca/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
FROM cgr.dev/chainguard/wolfi-base
#install step dependencies
RUN apk add wget step step-ca
#need a mountpoint on /mnt, with files password1 and password2 within the base dir
ENV STEPPATH=/mnt/
COPY --chmod=555 init.sh /bin/init.sh
ENTRYPOINT init.sh
RUN apk add --no-cache wget step step-ca bash

ENV CONFIGPATH="/home/step/config/ca.json"
ENV PWDPATH="/home/step/secrets/password"
ENV STEPPATH="/home/step"

RUN mkdir /root-ca

VOLUME ["/home/step", "/root-ca"]

# The entrypoint script will generate the certificate and export the root cert to the /root-ca volume

STOPSIGNAL SIGTERM
HEALTHCHECK CMD step ca health 2>/dev/null | grep "^ok" >/dev/null

COPY entrypoint.sh /entrypoint.sh

EXPOSE 9000/TCP

ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
CMD exec /usr/bin/step-ca --password-file $PWDPATH $CONFIGPATH
105 changes: 105 additions & 0 deletions local-ca/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash
set -eo pipefail

# Adapted from the smallstep example entrypoint at: https://github.com/smallstep/certificates/blob/master/docker/entrypoint.sh

# Paraphrased from:
# https://github.com/influxdata/influxdata-docker/blob/0d341f18067c4652dfa8df7dcb24d69bf707363d/influxdb/2.0/entrypoint.sh
# (a repo with no LICENSE.md)

export STEPPATH=$(step path)

# List of env vars required for step ca init
declare -ra REQUIRED_INIT_VARS=(DOCKER_STEPCA_INIT_NAME DOCKER_STEPCA_INIT_DNS_NAMES)

# Ensure all env vars required to run step ca init are set.
function init_if_possible () {
local missing_vars=0
for var in "${REQUIRED_INIT_VARS[@]}"; do
if [ -z "${!var}" ]; then
missing_vars=1
fi
done
if [ ${missing_vars} = 1 ]; then
>&2 echo "there is no ca.json config file; please run step ca init, or provide config parameters via DOCKER_STEPCA_INIT_ vars"
else
step_ca_init "${@}"
fi
}

function generate_password () {
set +o pipefail
< /dev/urandom tr -dc A-Za-z0-9 | head -c40
echo
set -o pipefail
}

# Initialize a CA if not already initialized
function step_ca_init () {
DOCKER_STEPCA_INIT_PROVISIONER_NAME="${DOCKER_STEPCA_INIT_PROVISIONER_NAME:-admin}"
DOCKER_STEPCA_INIT_ADMIN_SUBJECT="${DOCKER_STEPCA_INIT_ADMIN_SUBJECT:-step}"
DOCKER_STEPCA_INIT_ADDRESS="${DOCKER_STEPCA_INIT_ADDRESS:-:9000}"

local -a setup_args=(
--name "${DOCKER_STEPCA_INIT_NAME}"
--dns "${DOCKER_STEPCA_INIT_DNS_NAMES}"
--provisioner "${DOCKER_STEPCA_INIT_PROVISIONER_NAME}"
--password-file "${STEPPATH}/password"
--provisioner-password-file "${STEPPATH}/provisioner_password"
--address "${DOCKER_STEPCA_INIT_ADDRESS}"
)
if [ -n "${DOCKER_STEPCA_INIT_PASSWORD_FILE}" ]; then
cat < "${DOCKER_STEPCA_INIT_PASSWORD_FILE}" > "${STEPPATH}/password"
cat < "${DOCKER_STEPCA_INIT_PASSWORD_FILE}" > "${STEPPATH}/provisioner_password"
elif [ -n "${DOCKER_STEPCA_INIT_PASSWORD}" ]; then
echo "${DOCKER_STEPCA_INIT_PASSWORD}" > "${STEPPATH}/password"
echo "${DOCKER_STEPCA_INIT_PASSWORD}" > "${STEPPATH}/provisioner_password"
else
generate_password > "${STEPPATH}/password"
generate_password > "${STEPPATH}/provisioner_password"
fi
if [ "${DOCKER_STEPCA_INIT_SSH}" == "true" ]; then
setup_args=("${setup_args[@]}" --ssh)
fi
if [ "${DOCKER_STEPCA_INIT_ACME}" == "true" ]; then
setup_args=("${setup_args[@]}" --acme)
fi
if [ "${DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT}" == "true" ]; then
setup_args=("${setup_args[@]}" --remote-management
--admin-subject "${DOCKER_STEPCA_INIT_ADMIN_SUBJECT}"
)
fi
step ca init "${setup_args[@]}"
echo ""
if [ "${DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT}" == "true" ]; then
echo "👉 Your CA administrative username is: ${DOCKER_STEPCA_INIT_ADMIN_SUBJECT}"
fi
echo "👉 Your CA administrative password is: $(< $STEPPATH/provisioner_password )"
echo "🤫 This will only be displayed once."
shred -u $STEPPATH/provisioner_password
mv $STEPPATH/password $PWDPATH

# Copy the CA certificates to a volume that can be shared for future interaction with the CA
# First we put the root ca cert and intermediate cert in the easiest place to find it in the volume
cp /home/step/certs/root_ca.crt /root-ca/root_ca.crt
cp /home/step/certs/intermediate_ca.crt /root-ca/intermediate_ca.crt
# Then we set up the files in the right place for the step client to find them
mkdir -p /root-ca/step/certs
cp /home/step/certs/root_ca.crt /root-ca/step/certs/root_ca.crt
cp /home/step/certs/intermediate_ca.crt /root-ca/step/certs/intermediate_ca.crt
# Finally, we copy the step config files to the volume without exposing any secrets
mkdir -p /root-ca/step/config
cp /home/step/config/ca.json /root-ca/step/config/ca.json
cp /home/step/config/defaults.json /root-ca/step/config/defaults.json
echo "🔒 Your CA is ready to go!"
}

if [ -f /usr/sbin/pcscd ]; then
/usr/sbin/pcscd
fi

if [ ! -f "${STEPPATH}/config/ca.json" ]; then
init_if_possible
fi

exec "${@}"
8 changes: 0 additions & 8 deletions local-ca/init.sh

This file was deleted.

0 comments on commit 12b5d5a

Please sign in to comment.