Skip to content

Instantly share code, notes, and snippets.

@ahgraber
Last active June 12, 2024 12:37
Show Gist options
  • Save ahgraber/6068e56cf9310175c234f89f26c05a38 to your computer and use it in GitHub Desktop.
Save ahgraber/6068e56cf9310175c234f89f26c05a38 to your computer and use it in GitHub Desktop.
Docker-secrets

GOAL: Keep secrets out of plaintext (esp when syncing dockerfile and docker-compose.yaml to repo)

  1. Each secret needs to be a single text file with a clear name
  2. Edit docker-entrypoint.sh to run per environmental variable
  3. (Re)Build docker image with docker-entrypoint.sh as entrypoint
  4. Create secrets in docker-compose
  5. Call secrets with "_FILE" appended to the name when specifying environmental variable

secret-init.sh:

use if secrets are passed as environmental variables

#!/bin/sh

# logic cribbed from linuxserver.io: 
# https://github.com/linuxserver/docker-baseimage-ubuntu/blob/bionic/root/etc/cont-init.d/01-envfile

# iterate over environmental variables
# if variable ends in "__FILE"
for FULLVAR in $(env | grep "^.*__FILE="); do
    # trim "=..." from variable name
    VARNAME=$(echo $FULLVAR | sed "s/=.*//g")
    echo "[secret-init] Evaluating ${VARNAME}"

    # set SECRETFILE to the contents of the variable
    # Use 'eval hack' for indirect expansion in sh: https://unix.stackexchange.com/questions/111618/indirect-variable-expansion-in-posix-as-done-in-bash
    # WARNING: It's not foolproof is an arbitrary command injection vulnerability 
    eval SECRETFILE="\$${VARNAME}"

    echo "[secret-init] Setting SECRETFILE to ${SECRETFILE} ..."  # DEBUG - rm for prod!
    
    # if SECRETFILE exists
    if [[ -f ${SECRETFILE} ]]; then
        # strip the appended "__FILE" from environmental variable name
        STRIPVAR=$(echo $VARNAME | sed "s/__FILE//g")
        echo "[secret-init] Set STRIPVAR to ${STRIPVAR}"  # DEBUG - rm for prod!

        # set value to contents of secretfile
        eval ${STRIPVAR}=$(cat "${SECRETFILE}")
        echo "[secret_init] Set ${STRIPVAR} to $(eval echo \$${STRIPVAR})"  # DEBUG - rm for prod!
        
        export "${STRIPVAR}"
        echo "[secret-init] Success! ${STRIPFILE} set from ${VARNAME}"
        
    else
        echo "[secret-init] ERROR: Cannot find secret in ${VARNAME}"
    fi
done

Add to dockerfile

COPY secret-init.sh /usr/local/bin/
ENTRYPOINT [ "docker-entrypoint.sh" ]

Build secrets into docker-compose

version: '3.3'
secrets:
  NAMED_SECRET_ONE:
    file: ../.secrets/secret_one.txt
  NAMED_SECRET_TWO:
    file: ../.secrets/secret_two.txt
services:
  db:
    image: mysql:5.7
    secrets:
      - NAMED_SECRET_ONE
      - NAMED_SECRET_TWO
    environment:
      SECRET_ONE_ENV__FILE: /run/secrets/NAMED_SECRET_ONE
      SECRET_TWO_ENV__FILE: /run/secrets/NAMED_SECRET_TWO

01_envfile.sh

use if container uses s6 initiation

#! /bin/bash
# ref: https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/cont-init.d/01-envfile

# in s6, environmental variables are written as text files for s6 to monitor
for FILENAME in $(find /var/run/s6/container_environment/ | grep "^.*__FILE"); do
    echo "[secret-init] Evaluating ${FILENAME}"

    # set SECRETFILE to the contents of the variable
    SECRETFILE=$(cat ${FILENAME})
    # SECRETFILE=${FILENAME}
    echo "[secret-init] Setting SECRETFILE to ${SECRETFILE}..."  # DEBUG - rm for prod!

    # if SECRETFILE exists / is not null
    if [[ -f ${SECRETFILE} ]]; then
        # strip the appended "__FILE" from environmental variable name ...
        STRIPFILE=$(echo $FILENAME | sed "s/__FILE//g")   
        echo "[secret-init] Set STRIPFILE to ${STRIPFILE}"  # DEBUG - rm for prod!

        # ... and set value to contents of secretfile
        # since s6 uses text files, this is effectively "export ..."
        cat ${SECRETFILE} > ${STRIPFILE}
        echo "[secret-init] Set ${STRIPFILE} to $(cat ${STRIPFILE})"  # DEBUG - rm for prod!"
        echo "[secret-init] Success! ${STRIPFILE##*/} set from ${FILENAME##*/}"

    else
        echo "[secret-init] cannot find secret in ${FILENAME##*/}"
    fi
done

Add to dockerfile

COPY 01_envfile.sh /etc/cont-init.d/

Ref:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment