Search code examples
dockerazure-devopsazure-pipelines

Docker build using secrets


I am trying to inject a azure variable into a docker file env but I am getting an error indicating that the token is not valid. When I hardcode the token, it works fine.

# 1. Install dependencies only when needed
FROM node:20-alpine AS base

RUN --mount=type=secret,id=SENTRY_AUTH_TOKEN \
    SENTRY_AUTH_TOKEN=$(cat /run/secrets/SENTRY_AUTH_TOKEN)


# 2. Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY . .
RUN yarn install --frozen-lockfile

ENV NODE_ENV=production
ENV NEXT_PUBLIC_SENTRY_DSN="{{NEXT_PUBLIC_SENTRY_DSN}}"
ENV NEXT_PUBLIC_SENTRY_LOGGING_ENABLED="{{NEXT_PUBLIC_SENTRY_LOGGING_ENABLED}}"
ENV SENTRY_LOG_LEVEL=debug
ENV SENTRY_AUTH_TOKEN="{{SENTRY_AUTH_TOKEN}}"

RUN yarn build

# 3. Production image, copy all the files and run next
FROM base AS runner

WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV USE_HTTPS=true

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/entrypoint.sh ./entrypoint.sh
COPY --from=builder --chown=nextjs:nodejs /app/next.config.js ./next.config.js
COPY --from=builder --chown=nextjs:nodejs /app/next-i18next.config.js ./next-i18next.config.js

RUN ["chmod", "755", "/app/entrypoint.sh"]

USER nextjs

EXPOSE 3000

ENV PORT 3000

ENTRYPOINT ["/app/entrypoint.sh"]

CMD ["node", "server.js"]

The token is stored as a azure secret variable. Here is the build pipeline command to inject.

 - script: 
   SENTRY_AUTH_TOKEN=SENTRY_AUTH_TOKEN docker buildx build -f
   dockerfile.prod --secret id=SENTRY_AUTH_TOKEN -t $(IMAGE_ID)
   --progress plain .

   displayName: 'docker build'
   env:
     SENTRY_AUTH_TOKEN: $(SENTRY_AUTH_TOKEN)

It feels like the token is not encrypted at all. Anyone got an answer?


Solution

  • It looks like you're only using the secret value in the RUN yarn build step. If that's the case, you need the --mount=type=secret option in that specific RUN line, and nowhere else. You do not need to set the variable as an ENV.

    FROM node:20-alpine AS base
    # empty
    
    FROM base AS builder
    ...
    RUN --mount=type=secret,id=SENTRY_AUTH_TOKEN \
      SENTRY_AUTH_TOKEN=$(cat /run/secrets/SENTRY_AUTH_TOKEN) \
      yarn build
    

    Remember that anything built into your image is fairly easily extracted. If the token is being built into your browser-based application, it may be there in plain text in the final application, and it may be served on the public Internet that way. This also may be required for your front-end application to interact with the external service.

    If that's accepable (or required) then it may be more straightforward to just pass the variable as a ARG. This will automatically be visible in the environment to RUN instructions, and if it's present in the final image then it will be accessible there.

    ARG SENTRY_AUTH_TOKEN
    RUN yarn build
    
    docker buildx build \
      -f dockerfile.prod \
      --build-arg SENTRY_AUTH_TOKEN=... \
      -t $(IMAGE_ID) \
      --progress plain \
      .