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.
The above diagram depicts a regular flow for our application deployment.
- Our frontend app. inclusive of the environment variables is pushed to the repo
- 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.
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.
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.
Add the environment path to your
.gitignore. this ensures that you do not push your environment files to the repository.
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.
Ensure that our build process has the permission to read from the s3 repository
Modify the buildSpec file to copy the file from the s3 repository to the application root folder during the build process.
s3 folder structure
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:
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,
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.
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
With the above process, you can successfully
Deploy your application to the repo without your environment files
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
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.
Top comments (10)
Why don't you use SSM Paramater store, to store those secrets?
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
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?
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
Is there any critical reason you chose S3 over SSM?
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.
great article! thanks
Thank you Allan
you are welcome