Automating inclusion of build secrets

I am trying to load secrets into the Docker image. These secrets are needed during build time.

  1. How am i supposed to populate the “secrets” and pass it to the Dockerfile.builder?
  2. How do i populate the “secret” here: while read -r secret; do

Followed https://fly.io/docs/apps/build-secrets/#automate-the-inclusion-of-build-secrets-using-an-ephemeral-machine

Docker.builder: Docker.builder · paste.gg
Dockerfile: Dockerfile · paste.gg
Github Action Workflow: Github Workflow · paste.gg

# Extract Fly.io secrets and make them build-time secrets
while read -r secret; do
  echo "export ${secret}=${!secret}" >> /srv/.secrets
  deploy+=(--build-secret "${secret}=${!secret}")
done < <(flyctl secrets list --json | jq -r ".[].Name")

What this code is doing is reading the name of the secret from the output of the flyctl secrets list --json command (after passing the results through jq to extract the Name). So to populate the secret, you just need to run fly secrets set.

            -e NEXT_PUBLIC_PUSHER_KEY="${{ secrets.PUSHER_KEY }}" \
            -e NEXT_PUBLIC_PUSHER_CLUSTER="${{ secrets.PUSHER_CLUSTER }}" \
            -e SENTRY_RELEASE="${{ needs.generate-git-tags.outputs.tag }}" \
            -e FLY_API_TOKEN="${{ secrets.FLY_API_TOKEN }}"

It looks like you are setting Github secrets? That should work too given that you’ve added them yourself:

# Extract all non-sensitive args
deploy+=(
  --build-arg NEXT_PUBLIC_PUSHER_KEY=${NEXT_PUBLIC_PUSHER_KEY}
  --build-arg NEXT_PUBLIC_PUSHER_CLUSTER=${NEXT_PUBLIC_PUSHER_CLUSTER}
  --build-arg SENTRY_RELEASE=${SENTRY_RELEASE}
)

I suspect that your real problem is here:

# Use all secrets from the build context
RUN --mount=type=secret,id=ALL_SECRETS \
    eval "$(base64 -d /run/secrets/ALL_SECRETS)" && \
    echo "Using secrets during build!"
 
# Copy application code
COPY . .
 
# Build application
RUN npx prisma generate
RUN npm run build

The RUN command that mounts your secrets only does it for the duration of that one step. What you will want to do instead is:

# Copy application code
COPY . .

# Build application using all secrets from the build context
RUN --mount=type=secret,id=ALL_SECRETS \
    eval "$(base64 -d /run/secrets/ALL_SECRETS)" && \
    echo "Using secrets during build!" && \
    npx prisma generate && \
    npm run build

Hi, thanks for the quick response!

I already have the list of secrets in fly secrets list but I don’t think the fly console can simply retrieve the values of the fly secrets? (am i wrong?)

There are a bunch of more sensitive secrets that I am not sure where to pass in. (for e.g. NEXT_PUBLIC_S3_ACCESS_ID, NEXT_PUBLIC_S3_ACCESS_KEY…). Do I just create another block like this

Extract all non-sensitive args
deploy+=(
  --build-arg NEXT_PUBLIC_PUSHER_KEY=${NEXT_PUBLIC_PUSHER_KEY}
  --build-arg NEXT_PUBLIC_PUSHER_CLUSTER=${NEXT_PUBLIC_PUSHER_CLUSTER}
  --build-arg SENTRY_RELEASE=${SENTRY_RELEASE}
)

deploy+=(
  --build-secret NEXT_PUBLIC_S3_BUCKET_NAME=${NEXT_PUBLIC_S3_BUCKET_NAME}
  --build-secret NEXT_PUBLIC_S3_ENDPOINT=${NEXT_PUBLIC_S3_ENDPOINT}
  --build-secret NEXT_PUBLIC_S3_ACCESS_ID=${NEXT_PUBLIC_S3_ACCESS_ID}
  --build-secret NEXT_PUBLIC_S3_ACCESS_KEY=${NEXT_PUBLIC_S3_ACCESS_KEY}
)

EDIT: I followed your last suggestion above with my addition above and it worked but I would like to know the best practices still! Thank you.

Would like to know the best practices to pass in secrets, preferably from fly secrets if possible

When you run fly console, the machine that you get has all of your secrets available as environment variables. The while read -r secret will iterate over the names of the secrets and add a --build-secret flag to the deploy command passing in the name and value of the secret. It will also create a script the exports all of the secrets and that script will be base64 encoded and passed as yet another build secret named ALL_SECRETS.

Thank you for the help! I will mark your reply as the solution.