1

I have a multicontainer docker environment running on AWS Elastic Beanstalk (ECS under the hood). Each instance in the cluster is running all of the containers (proxy, auth, api, client, notifications). I am using Codepipeline and Codebuild as a CICD linked to Github push to master branch.

The flow to build the prod environment for any one of the services currently looks like:

PR into master -> push to Github -> triggers Codepipeline -> triggers Codebuild (here I build, tag, and push a docker image created from a Dockerfile in the source code to Elastic Container Registrary [ECR]).

Once the image is pushed to ECR I can update the Elastic Beanstalk environment to start using the new image for that service.

I do not understand how I can get environment variables into each of the services. I have used the environment section of elastic beanstalk before but how can this work when I have a multicontainer environment? For instance one service might have DB_CONNECTION_STRING=foo and another might have DB_CONNECTION_STRING=bar. So using the centralised environment properties section of elastic beanstalk will not work.

I also can't push the env file to source code as it contains passwords/secrets so I cannot add it as part of the build phase. Unless I can add all of the environment variables in Codepipeline? Or should I use a Secrets manager?

What is the best practices on this?

Also important to note that the build phase is the same for all of the services.

Thanks

cjd
  • 43
  • 5

1 Answers1

1

I use Github workflow and not Codebuild but the idea is the same. I'm assuming that you can store your secrets in AWS and access them during build (as in github workflow)

What we do:

In Github workflow yml file:

jobs:
  deploy:
    name: some job name
    runs-on: ubuntu-latest
    env:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      ACCESS_TOKEN_SECRET: ${{ secrets.ACCESS_TOKEN_SECRET }}
      REFRESH_TOKEN_SECRET: ${{ secrets.REFRESH_TOKEN_SECRET }}

Then, later on job:

- name: Build dockers
        id: build-dockers
        run: |
          docker build --build-arg NPM_TOKEN=$NPM_TOKEN --build-arg dockerAccessTokenSecretDefault=$ACCESS_TOKEN_SECRET -t your_registry/name

Docker file:

FROM node:latest

ARG NPM_TOKEN
ARG dockerAccessTokenSecretDefault
ARG dockerRefreshTokenSecretDefault
ENV ACCESS_TOKEN_SECRET=$dockerAccessTokenSecretDefault
ENV REFRESH_TOKEN_SECRET=$dockerRefreshTokenSecretDefault


COPY some_folder some_docker_folder

WORKDIR some_docker_folder

RUN npm install --production


EXPOSE 3000

ENTRYPOINT [ "npm", "start" ]

You can see in docker file that I have ARG and ENV, ARG is there only during build time, but ENV stay there for runtime.

Aviad
  • 521
  • 2
  • 5
  • Great, thank you for this! by the look of the Github workflow yml file is similar to a buildspec yml file so this may work on codebuild. Any service could have ~15 environment variables so this could get out of hand. For that would you recommend using a secret manager and only passing env variables needed to connect to the secret manager? – cjd Feb 24 '21 at 12:02
  • NP. Yes, build file and docker file are not code, but declaration files, and if you have 15 environment variables you should pass them somewhere. In Github workflow you can split jobs and pass data between them if you want (1 for any service maybe?), but long file not necessarily means that it is hard to read. I think that if I needed to update this kind of file in the future and I see 35 environment variable somewhere it not out of hand, you can skip the section and jump to relevant one real quick. Anyway we store all our secrets in Github secrets. – Aviad Feb 24 '21 at 12:12
  • This solution has one security issue is that the docker image contains sensitive information such as access token and secret. It is recommended to avoid any sensitive information in docker image, as `docker image inspect` command can revel the environment variables here. Thus, the right solution is to not contains sensitive information in docker image(basically always runtime, and never build time), while only pass the values from secret manager to the Elastic Beanstalk. Read details here: https://stackoverflow.com/questions/22651647/docker-and-securing-passwords – Yang Liu Jan 14 '23 at 03:11