I am trying to find some guidance on what's the best method to add secrets to a vault container (running in dev mode) at startup. I came up with one way of doing it, albeit not very clean. So, I'm looking for some suggestions on better ways to implement this.
I took the Vault parent image, and created a shell script to call the parent image's entrypoint first, then add a loop to wait for vault to come up, initialize it, add secrets to it. If I leave the script at this point, the container simply stops and exits, so I also added a loop to keep a timer going as long as vault is up and running.
FROM vault
# Install Curl
RUN apk add --no-cache curl
# Instal jq
ADD https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 /usr/bin/jq
RUN chmod 755 /usr/bin/jq
ENV MYSQL_URL default
ENV MYSQL_USERNAME default
ENV MYSQL_PASSWORD default
ENV VAULT_DEV_ROOT_TOKEN_ID 0000
EXPOSE 8200
ADD vault-init.sh /
RUN chmod 755 vault-init.sh
ENTRYPOINT exec "./vault-init.sh"
Here's the vault-init.sh referenced above.
echo "Staring Vault..."
docker-entrypoint.sh server -dev &
echo "Sleeping 10..."
sleep 10
echo "Vault Started."
echo "Exporting address"
export VAULT_ADDR="http://localhost:8200"
echo "Authenticate into Vault"
# Authenticate to Vault
vault login $VAULT_DEV_ROOT_TOKEN_ID
echo "Adding secrets to Vault..."
vault kv put secret/fruit-basket mysql.username=$MYSQL_USERNAME mysql.password=$MYSQL_PASSWORD mysql.url=$MYSQL_URL
while [ "$(curl -XGET --insecure --silent -H "X-Vault-Token: $VAULT_DEV_ROOT_TOKEN_ID" http://localhost:8200/v1/sys/health | jq '.initialized')" == "true" ]
do
sleep 2
done
Thanks @David for your input. What I ended up doing was a little different. I think this was a much more elegant solution. I created two different vault container images, one that is the actual vault image running to do its job as vault, and the second that loads the secret (called vault-secret
). In the vault-secret
image, I rewrote the above unix script to wait for vault to come up, and then load the secrets in. Since I overrided the parent image's (vault
in this case) ENTRYPOINT in my script, vault only comes up on the image thats called vault
and the vault-secret
container stops and exits since it has no process running after loading the secrets (much like a Kubernetes Job). Here's my new Dockerfile and the unix script.
FROM vault
# Install Curl
RUN apk add --no-cache curl
# Instal jq
ADD https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 /usr/bin/jq
RUN chmod 755 /usr/bin/jq
ENV MYSQL_URL default
ENV MYSQL_USERNAME default
ENV MYSQL_PASSWORD default
ENV VAULT_DEV_ROOT_TOKEN_ID 0000
EXPOSE 8200
ADD vault-init.sh /
RUN chmod 755 vault-init.sh
ENTRYPOINT exec "./vault-init.sh"
vault-init.sh from above
echo "Waiting for Vault..."
while [ "$(curl -XGET --insecure --silent -H "X-Vault-Token: $VAULT_TOKEN" $VAULT_ADDR/v1/sys/health | jq '.initialized')" != "true" ]
do
echo 'Vault is Initializing...'
sleep 2
done
echo "Vault Started."
echo "Authenticate into Vault"
# Authenticate to Vault
vault login $VAULT_TOKEN
echo "Adding secrets to Vault..."
vault kv put secret/fruit-basket mysql.username=$MYSQL_USERNAME mysql.password=$MYSQL_PASSWORD mysql.url=$MYSQL_URL
In the above solution I use the vault
base image to run the "load secrets" job. Thats just so I can use the vault command line tool to load the secrets. If you were to replace that with curl, you could move to using alpine or even busybox reducing the container footprint.
Thanks for reading!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With