DEV Community

Cover image for Injecting Angular Environment Variables at Build Time
Valentine Awe
Valentine Awe

Posted on

Injecting Angular Environment Variables at Build Time

In this article, I assume that you are containerizing your Angular application and also have a CI/CD process in place. While the example in the article is also AWS specific, you can use the same principle across other cloud services.

By default, Angular injects the environment variable at the application build time.

deployment image

The above diagram depicts a regular flow for our application deployment.

  1. Our frontend app. inclusive of the environment variables is pushed to the repo
  2. Our build process picks it up, builds and deploy to our server.

While the above works very well, there are very unique cases where you would be required not to push your environment files to your application repository. If this happens, knowing that angular injects the environment variables at build time, we would need to find a way to inject the environment files during the build process.

Below are unique reasons why you might be required not to deploy your environment files to your repository

1.Extra level of security:
Some companies have policies which prevent them from pushing applications environment variables to their repository whether private repos or not. Although it is worthy to note that the safest way to keep your secret is not to put them in your frontend applications. So, on no account should you place any secret on your Frontend application whether as an environment variable or inside the application.

2.DevOps flow:
There are situations where the parameters of your applications can vary based on different environments, while you may know the specifics for an environment file. e.g the dev environment, the production credentials may be required to be added to your application by your devOps team or your client. In order to avoid them making changes to your application or going through a PR flow (which could be necessary depending on your policies). You would want to isolate the environment file from your application.

3.Multiple instances with dynamic variables:
There are scenarios where you would have a single repository for your application but multiple deployment instances that require different configuration files (environment variable). These types of variables could be styles, images, currency type, app settings, base url and many other variables that differ based on each instance. Below is a depiction.

deployment image

In the Image above, we have a single application repository that is deployed to multiple instances.

If we follow the flow of having our environment variables in the repository, there would be no way to set different configurations for each of the various instances except we implement the logic of setting variables in the application level based on users, which wouldn't be a 100% perfect solution if we need some configuration on application startup.

In my experience, I was faced with the three (3) situations above.

My Solution

  1. Add the environment path to your .gitignore. this ensures that you do not push your environment files to the repository.

  2. Create a private repo on AWS S3.
    a. you can call it (Frontend Env. Variables)
    b. Create sub folders for each of your application
    c. upload the different environment files. eg (dev, staging and prod)
    (In the case of multiple instances with dynamic variables, this should be replicated in each of the environments.

  3. Ensure that our build process has the permission to read from the s3 repository

  4. Modify the buildSpec file to copy the file from the s3 repository to the application root folder during the build process.

s3 folder structure

deployment image

Buildspec file

 build:
    commands:
      - echo Build started on `date`
      - printenv
      - aws s3 cp s3://frontend-env-variable/payment- application/ src/ --recursive
      - docker build -t payment-app --build-arg IMAGE_TAG=$IMAGE_TAG .
      - docker images -a
      - echo Building the Docker image...
      - docker tag $APP_NAME:latest $AWS_ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - docker images -a
      # - command
  post_build:
Enter fullscreen mode Exit fullscreen mode

Before the docker file is invoked, We already have the environment file copied from the s3 folder to the app folder as seen above in our buildspec file.

For the multi instance scenario with different environment variables in different cloud instances,

  1. Create separate buildspec files for each environment in your application root. eg. (instance1.buildspec.yml, instance2.buildspec.yml) and each of them will have the reference to the corresponding s3 path.

  2. In your AWS CDK or codebuild (or whichever build process you have in place, specify the name of the buildspec file for the specific environment

deployment image

With the above process, you can successfully

  1. Deploy your application to the repo without your environment files

  2. Have your devOps, client or anyone for each of your business instances that needs to update the environment variables do so.

Just an extra info on what the docker file look file

#building angular App
FROM node:14.0.0 as node

WORKDIR /app
COPY package.json /app/
RUN npm install
COPY ./ /app/
ARG IMAGE_TAG=dev
RUN npm run build -- --prod --configuration $IMAGE_TAG

# building nginx
FROM public.ecr.aws/nginx/nginx:1.20-alpine

# FROM nginx:1.12.2-alpine
COPY --from=node /app/dist/payment-app /usr/share/nginx/html
COPY ./nginx-custom.conf /etc/nginx/conf.d/default.conf
Enter fullscreen mode Exit fullscreen mode

Conclusion

I believe that there are other fun ways to inject your environment variables at build time. While the above works perfectly for me, I am open to know if you have a differ approach in solving this.

Remember that this solution is not cloud environment dependent.

Do not add any secret to your frontend application

Discussion (10)

Collapse
talr98 profile image
TalR98

Why don't you use SSM Paramater store, to store those secrets?

Collapse
valoni01 profile image
Valentine Awe Author

Thanks for asking. like I said in the article, secrets should not be stored in the frontend application. There are other environment variables that you need to and Angular expect these variables to be injected to your application at build time

Collapse
talr98 profile image
TalR98

Yes but those are really not secrets. It's a front-end application. Whatever env variable you would eventually use, it would be plaintext for the client-browser anyway.

So what I'm asking is basically - why wouldn't you store these variables (which are not secrets tho) in the SSM Parameter store? Why did you choose S3?

Thread Thread
valoni01 profile image
Valentine Awe Author

Great.. I thought you suggested SSM because of security. It is absolutely fine to store the variables anywhere. As long as you can extract the variables at build time from your build process and inject to the code

Thread Thread
talr98 profile image
TalR98

Is there any critical reason you chose S3 over SSM?

Thread Thread
valoni01 profile image
Valentine Awe Author

For me, it was simplicity. I can easily manage the the folders and environment files in S3. I guess with the SSM param store you will have to write the logic of reading the parameters from a path in your store and then create your environment files on the fly and also write the parameters to the created file.
with the s3, we just have to copy.

Collapse
allanshady profile image
Allan Camilo

great article! thanks

Collapse
valoni01 profile image
Valentine Awe Author

Thank you Allan

Collapse
talr98 profile image
TalR98

Thanks

Collapse
valoni01 profile image
Valentine Awe Author

you are welcome