From bda2c0ea236bef58d77d005d7c71db0ab40b0bda Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Thu, 3 Oct 2024 21:41:40 +0200 Subject: [PATCH] feat: enable mtls by default by using smallstep as local pki Signed-off-by: Reuben Miller --- .../child-device-container/child.dockerfile | 8 ++- images/child-device-container/entrypoint.sh | 9 +++ images/child-device-systemd/child.dockerfile | 8 +++ images/common/config/sudoers.d/step-ca | 1 + .../common/utils/configure-device/runner.sh | 3 +- .../configure-device/scripts.d/90_start-agent | 2 +- images/common/utils/enroll/enroll.sh | 68 +++++++++++++++++++ images/common/utils/init-pki/init-pki.sh | 19 ++++++ .../debian-systemd/debian-systemd.dockerfile | 11 +++ images/debian-systemd/docker-compose.yaml | 5 +- 10 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 images/common/config/sudoers.d/step-ca create mode 100755 images/common/utils/enroll/enroll.sh create mode 100755 images/common/utils/init-pki/init-pki.sh diff --git a/images/child-device-container/child.dockerfile b/images/child-device-container/child.dockerfile index 7fcc610..9d0c269 100644 --- a/images/child-device-container/child.dockerfile +++ b/images/child-device-container/child.dockerfile @@ -8,10 +8,16 @@ RUN apk add --no-cache \ && curl -1sLf 'https://dl.cloudsmith.io/public/thinedge/community/config.alpine.txt?distro=alpine&codename=v3.8' >> /etc/apk/repositories \ && apk add --no-cache \ tedge-apk-plugin \ - && echo "tedge ALL = (ALL) NOPASSWD: /usr/bin/tedge, /usr/bin/tedge-write /etc/*, /etc/tedge/sm-plugins/[a-zA-Z0-9]*, /bin/sync, /bin/kill" > /etc/sudoers.d/tedge + tedge-pki-smallstep-client \ + && echo "tedge ALL = (ALL) NOPASSWD: /usr/bin/tedge, /usr/bin/tedge-write /etc/*, /etc/tedge/sm-plugins/[a-zA-Z0-9]*, /bin/sync, /bin/kill" > /etc/sudoers.d/tedge \ + && echo "tedge ALL = (ALL) NOPASSWD: /usr/bin/step-ca-admin.sh, /usr/bin/enroll.sh, /usr/sbin/update-ca-certificates" > /etc/sudoers.d/step-ca \ + # Allow tedge user to control this folder + && mkdir -p /etc/step-ca \ + && chown -R tedge:tedge /etc/step-ca USER tedge COPY child-device-container/config/tedge-configuration-plugin.toml /etc/tedge/plugins/ +COPY common/utils/enroll/enroll.sh /usr/bin/ COPY child-device-container/entrypoint.sh /app/ COPY common/utils/workflows/firmware_update.toml /etc/tedge/operations/ ENV TEDGE_MQTT_CLIENT_HOST=tedge diff --git a/images/child-device-container/entrypoint.sh b/images/child-device-container/entrypoint.sh index aa144cf..157d605 100755 --- a/images/child-device-container/entrypoint.sh +++ b/images/child-device-container/entrypoint.sh @@ -1,5 +1,14 @@ #!/bin/sh set -e +# Enroll device with mtls +PROVISION_PASSWORD_FILE=/tmp/provisioner-password +if [ -n "$PROVISION_PASSWORD" ]; then + printf -- '%s' "$PROVISION_PASSWORD" > "$PROVISION_PASSWORD_FILE" + chmod 600 "$PROVISION_PASSWORD_FILE" +fi +(cd /tmp && sudo /usr/bin/enroll.sh --no-inherit-env --provisioner-password-file "$PROVISION_PASSWORD_FILE") +rm -f "$PROVISION_PASSWORD_FILE" + # start agent exec /usr/bin/tedge-agent diff --git a/images/child-device-systemd/child.dockerfile b/images/child-device-systemd/child.dockerfile index def68dc..d53e3e0 100644 --- a/images/child-device-systemd/child.dockerfile +++ b/images/child-device-systemd/child.dockerfile @@ -42,6 +42,8 @@ RUN echo "running" \ tedge-agent \ tedge-apt-plugin \ tedge-inventory-plugin \ + # Local PKI service for easy child device registration + tedge-pki-smallstep-client \ # Disable mosquitto as it is not needed on a child device && systemctl disable mosquitto.service \ && systemctl mask mosquitto.service \ @@ -61,6 +63,12 @@ COPY common/utils/configure-device/scripts.d/* /usr/share/configure-device/scrip COPY common/utils/configure-device/configure-device.service /lib/systemd/system/ RUN systemctl enable configure-device.service +# add mtls enablement script. Store script under /usr/bin so it can also be manually called +COPY common/utils/enroll/enroll.sh /usr/bin/ +RUN ln -sf /usr/bin/enroll.sh /usr/share/configure-device/scripts.d/70_enable_mtls +# COPY common/utils/enroll/enroll.service /usr/lib/systemd/system/ +# RUN systemctl enable enroll.service + COPY child-device-systemd/config/system.toml /etc/tedge/ COPY child-device-systemd/config/tedge.toml /etc/tedge/ COPY common/utils/workflows/firmware_update.toml /etc/tedge/operations/ diff --git a/images/common/config/sudoers.d/step-ca b/images/common/config/sudoers.d/step-ca new file mode 100644 index 0000000..5425f8f --- /dev/null +++ b/images/common/config/sudoers.d/step-ca @@ -0,0 +1 @@ +tedge ALL = (ALL) NOPASSWD: /usr/bin/step-ca-admin.sh, /usr/bin/step-ca, /usr/sbin/update-ca-certificates diff --git a/images/common/utils/configure-device/runner.sh b/images/common/utils/configure-device/runner.sh index 089a0b3..dbe5fc7 100755 --- a/images/common/utils/configure-device/runner.sh +++ b/images/common/utils/configure-device/runner.sh @@ -13,7 +13,8 @@ if [ $# -ge 2 ]; then fi _NEWLINE=$(printf '\n') -find "$RUN_PARTS" -type f -name "$NAME_FILTER" -perm 755 | while IFS="$_NEWLINE" read -r file +# Use -L to allow scripts to be a symlink, but this requires the results to be sorted afterwards +find -L "$RUN_PARTS" -type f -name "$NAME_FILTER" -perm 755 | sort | while IFS="$_NEWLINE" read -r file do echo "Executing script: $file" >&2 set +e diff --git a/images/common/utils/configure-device/scripts.d/90_start-agent b/images/common/utils/configure-device/scripts.d/90_start-agent index 567f052..55df7c4 100755 --- a/images/common/utils/configure-device/scripts.d/90_start-agent +++ b/images/common/utils/configure-device/scripts.d/90_start-agent @@ -2,4 +2,4 @@ set -ex systemctl enable tedge-agent -systemctl restart tedge-agent +systemctl start tedge-agent diff --git a/images/common/utils/enroll/enroll.sh b/images/common/utils/enroll/enroll.sh new file mode 100755 index 0000000..4e4d782 --- /dev/null +++ b/images/common/utils/enroll/enroll.sh @@ -0,0 +1,68 @@ +#!/bin/sh +set -e + +INHERIT_ENV=${INHERIT_ENV:-1} + +OLD_PWD="$(pwd)" +cd /etc + +while [ $# -gt 0 ]; do + case "$1" in + --inherit-env) + INHERIT_ENV=1 + ;; + --no-inherit-env) + INHERIT_ENV=0 + ;; + --provisioner-password-file) + PROVISION_PASSWORD_FILE="$2" + shift + ;; + esac + shift +done + +if [ "$INHERIT_ENV" = 1 ]; then + # Create env file from PID 1 + # (as this is the old service which inherits the container environment variables) + echo "Loading environment from PID 1" + tr '\0' '\n' "$PROVISION_PASSWORD_FILE" + chmod 600 "$PROVISION_PASSWORD_FILE" +fi + +enroll_device() { + # Enable downloading of root cert (this can be trusted when running in a controlled container env) + if [ -f "$PROVISION_PASSWORD_FILE" ]; then + /usr/bin/step-ca-admin.sh enroll "$(hostname)" \ + --ca-url https://tedge:8443 \ + --allow-insecure-root \ + --provisioner-password-file "$PROVISION_PASSWORD_FILE" + else + /usr/bin/step-ca-admin.sh enroll "$(hostname)" \ + --ca-url https://tedge:8443 \ + --allow-insecure-root + fi +} + +while :; do + if enroll_device; then + echo "Enrollment was successful" + exit 0 + fi + sleep 2 +done + +# restore previous working directory +cd "$OLD_PWD" diff --git a/images/common/utils/init-pki/init-pki.sh b/images/common/utils/init-pki/init-pki.sh new file mode 100755 index 0000000..7b1958e --- /dev/null +++ b/images/common/utils/init-pki/init-pki.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e +# +# Initialize the local pki +# + +# Create env file from PID 1 +# (as this is the old service which inherits the container environment variables) +echo "Loading environment from PID 1" +tr '\0' '\n'