Skip to content

Instantly share code, notes, and snippets.

@joariasl
Last active March 28, 2024 02:10
Show Gist options
  • Save joariasl/ed88c2dc556695064dff7d6e89975415 to your computer and use it in GitHub Desktop.
Save joariasl/ed88c2dc556695064dff7d6e89975415 to your computer and use it in GitHub Desktop.
Docker EntryPoint to load environment variables from files to use with file mounted secrets like Secret Store CSI Driver
#!/bin/sh
ENV_PATH_SEPARATOR=${ENV_PATH_SEPARATOR:-':'}
oldIFS=$IFS
IFS=$ENV_PATH_SEPARATOR
for ENV_FILE in $ENV_PATH; do
if [ -f "$ENV_FILE" ]; then
export $(grep -v '^#' "$ENV_FILE" | xargs -0)
else
echo "$ENV_FILE is not a file" >&2
fi
done
IFS=$oldIFS
if [ "$IGNORE_EXEC" != "true" ]; then
# Running params (or CMD) becomes the container’s PID 1
exec "$@"
fi
@joariasl
Copy link
Author

joariasl commented Aug 13, 2021

This is a useful Docker EntryPoint to load environment variables from files to use with file mounted secrets like Secret Store CSI Driver

## Params envs

ENV_PATH # `:` separated list of env files
IGNORE_EXEC=true # To ignore param (or CMD) execution
ENV_PATH_SEPARATOR # Set separator char of files (default `:`)

Usage in Dockerfile

ENTRYPOINT ["/sbin/docker-entrypoint.sh", "/sbin/second-entrypoint.sh"]

or

ENTRYPOINT ["/sbin/docker-entrypoint.sh"]
CMD ["/sbin/second-entrypoint.sh"]

## Example of env file

envs.env

A=ValueA
B=ValueB

Dockerfile example

FROM busybox

COPY load-envs-docker-entrypoint.sh /sbin/docker-entrypoint.sh

RUN chmod 755 /sbin/docker-entrypoint.sh

ENTRYPOINT ["/sbin/docker-entrypoint.sh"]

CMD ["sh"]

Run container with ENVs

docker run --rm -it -v `PWD`:/envs.env --env ENV_PATH='/envs.env' load-envs-docker

Two or more files

docker run --rm -it -v `PWD`:/envs.env --env ENV_PATH='/envs.env:/envs2.env' load-envs-docker

See PID environments inside container

cat /proc/1/environ

Try it in Kubernetes

secret-provider-class.yaml

apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
  name: test-secrets
spec:
  provider: gcp
  # SecretObject defines the desired state of synced K8s secret objects
  secretObjects:
  - secretName: test-secrets
    type: Opaque
    data: 
    - objectName: secrets.env
      key: SECRETS
  parameters:
    secrets: |
      - resourceName: "projects/<your gcp project>/secrets/test-secrets/versions/latest"
        fileName: "secrets.env"

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: envs-from-file
data:
  load-envs-docker-entrypoint.sh: |
    #!/bin/sh

    ENV_PATH_SEPARATOR=${ENV_PATH_SEPARATOR:-':'}

    oldIFS=$IFS
    IFS=$ENV_PATH_SEPARATOR
    for ENV_FILE in $ENV_PATH; do
        if [ -f "$ENV_FILE" ]; then
            export $(grep -v '^#' "$ENV_FILE" | xargs -0)
        else
            echo "$ENV_FILE is not a file" >&2
        fi
    done
    IFS=$oldIFS

    if [ "$IGNORE_EXEC" != "true" ]; then
        # Running params (or CMD) becomes the container’s PID 1
        exec "$@"
    fi

pod.yaml

kind: Pod
apiVersion: v1
metadata:
  name: test-secrets
  labels:
    app.kubernetes.io/name: test-secrets
spec:
  serviceAccountName: test-sa
  containers:
  - name: busybox
    image: k8s.gcr.io/e2e-test-images/busybox:1.29
    command:
    - "/sbin/load-envs-docker-entrypoint.sh"
    - "/bin/sleep"
    - "10000"
    volumeMounts:
    - name: test-secrets
      mountPath: "/mnt/secrets-store"
      readOnly: true
    - name: envs-from-file
      mountPath: /sbin
    env:  
    - name: ENV_PATH
      value: "/mnt/secrets-store/secrets.env"
  volumes:
  - name: test-secrets
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "test-secrets"
  - name: envs-from-file
    configMap:
      name: envs-from-file
      defaultMode: 0555
      items:
      - key: load-envs-docker-entrypoint.sh
        path: load-envs-docker-entrypoint.sh

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