top of page
  • Writer's pictureArjav Dave

Deploy Angular to AWS S3 with GitHub Actions


Introduction


Continuous Deployment needs no introduction. It has multiple advantages over deploying things manually. Firstly, one can deploy things confidently without breaking things. Secondly, running automated tests guarantees the quality of work. Lastly, it provides security by storing the environment variables in the CD pipelines instead of storing them on local machines or worse in the source code (Don't do that!).


This tutorial will help create a Continuous Deployment pipeline using GitHub Actions. This pipeline will build and deploy an Angular application to the AWS S3 bucket.



Prerequisites


Before we move forward, set up an Angular GitHub repository with GitHub Actions enabled.


To enable GitHub Actions visit the Settings -> Actions -> General in your GitHub repository. Select the Allow all actions and reusable workflows and click the Save button.

Enable Actions Tab

The Actions tab should now be visible at the top.


Actions Tab



Overview


Here is a brief overview of the article we'll be going through:



Create AWS S3 Bucket


Let's create an S3 bucket to which the angular dist files will be pushed by the GitHub Actions.


To do so, visit this link, enter the name of the bucket, and click the "Create Bucket" button at the bottom. The other values are kept default. For tutorial purposes, I have added it as daveops.co.in.


Create Bucket with Configuration


Add IAM User


An IAM (Identity and Access Management) user allows access to GitHub Actions to upload objects to the bucket. You can learn more about IAM here.


Firstly, a policy with relevant permissions needs to be created. A policy is a set of rules and permissions which can be attached to an IAM user. You can read more about it here.


To create a policy visit this link and follow these steps:

  • Click on the "Create Policy" button on the top right.

  • Switch to the "JSON" tab instead of the "Visual" tab.

  • Replace the existing JSON with the below JSON content. The list of permissions is mentioned as needed by the user to upload objects to the bucket. The permissions also allow the ACL to be set for the objects.

Make sure to change the ARN to your bucket name.


{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::daveops.co.in/*"
    }
  ]
}

Policy for Uploading Objects


  • Click "Next" and give a nice name and description of the policy.


Add policy details

  • Once done, click on the "Create Policy" button to create the policy.


After creating the policy, visit this link to start the process of creating an IAM user.

  • Firstly, enter a username of your choice and click "Next".


Specify username

  • Secondly, in the permission checkbox select "Attach policies directly". Next, search for the name of the policy you just created. Select that policy and click "Next".


Attach policy to a user

Search for a policy to be attached

  • Finally, click "Create User" to create a new user.


Generate Security Credentials


The IAM User in itself is not very helpful. For GitHub Actions to be able to upload objects to the bucket, an Access Key and a Secret need to be generated.


To generate the security credentials follow the below steps:

  • Go to the list of users by opening the link.

  • Click on the newly created user to view its details.

  • Select the "Security Credentials" tab and scroll to the "Access Keys" section. Click on the "Create access keys" button which will open a use case page.

Create access key

  • "Application running outside AWS" seems the most relevant use case. Select it and click "Next".

Select use case for the access key

  • Enter a description tag and click "Create".

This will create the Access Key and Access Key Secret needed for the IAM user to upload objects to the AWS S3 Bucket. Store them temporarily in a safe place. In the next section, they will be stored securely in the GitHub Secrets after which you can discard them.



Add Secrets to GitHub


The credentials generated above are very important. Since they provide access to upload objects to the bucket we'll be storing them in the GitHub Secrets. Once stored they cannot be recovered/ viewed easily.


To begin, go to your GitHub repository and open Settings -> Security -> Actions

Adding action secrets

Here we will be storing 3 secrets.

  • Access Key

  • Access Key Secret

  • AWS Region

Next, click on "New repository secret" to add the first item i.e. Access Key.

Enter the Name as "AWS_ACCESS_KEY" and in the Secret paste in the value of your Access Key retrieved in the above step.

Add AWS Access Key as a GitHub Secret

Similarly, add the AWS Secret Access Key with the name "AWS_SECRET_ACCESS_KEY" and the value from the previous section.



Add AWS Secret Access Key as a GitHub Secret

Lastly, add the region to which the user was added. This can be viewed by visiting the URL https://console.aws.amazon.com/iamv2/home#/users/. This URL will automatically redirect to the default region URL. For me, it was "https://us-east-1.console.aws.amazon.com/iamv2/home#/users/". Hence the AWS_REGION value will be us-east-1.

Add AWS Region as a GitHub Secret


After adding all 3 secrets the Action Secrets will look like below. As mentioned above, it is now not possible to view the values of these secrets. But, it can be easily accessed in the continuous deployment pipeline as we will see in the next section.

AWS credentials added to GitHub Secrets

Create a GitHub Action Pipeline


To create a continuous deployment pipeline visit the Actions tab in your GitHub repository. If you haven't enabled the Actions for the repository yet, check the Prerequisites section above.


There will be a lot of options to create a new workflow. But, we will be creating our workflow. To do so click the Select a workflow yourself link.

Setup a new workflow


In the main.yaml file copy and paste the below code.

# Workflow name
name: Continuous Deployment

# This allows manual start of the pipeline as needed.
on: workflow_dispatch

# The list of jobs to run 
jobs:
  build_and_deploy_job:
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:

      # 1. Configure AWS credentials      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}
          
      # 2. Checkout Repository
      - name: Checkout Repository
        uses: actions/checkout@v3
        with:
          ref: main
      
      # 3. Setup Node
      - name: Setup Node 
        uses: actions/setup-node@v3
        with:
          node-version: '18.12.0'
          
      # 4. Setup Cache
      - name: Setup Cache
        uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      # 5. Build Angular
      - name: Build Angular Application
        run: |
          ls
          npm install -g @angular/cli
          npm install
          ng build
          
      # 6. Copy to S3 bucket.
      - name: Copy to S3 Bucket
        run: |
          aws s3 cp ./dist/* s3://daveops.co.in
          
      # 7. (Optional) Invalidate CloudFront
      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation --distribution-id <CLOUDFRONT DISTRIBUTION ID> --paths "/*"


Here are the 7 steps in the build and deploy job mentioned above:

  1. AWS Credentials: Fetch the AWS credentials from the GitHub Secrets and configure the pipeline to use these credentials.

  2. Checkout Repository: Pull the main branch of the repository into the pipeline. The Angular build will be created from this branch, so replace the branch name as needed.

  3. Setup Node: Set up the node version for the pipeline. At the time of writing this article version 18.12.0 was the latest LTS version.

  4. Setup Cache: To avoid downloading all dependencies every time npm install is run, store the node_modules and other project files in a cache. Due to this, subsequent runs will be much faster.

  5. Build Angular: This step essentially installs the Angular CLI, installs the dependencies, and finally creates a distribution folder for the Angular project.

  6. Copy to S3 Bucket: Once the dist folder is created, copy it to the S3 bucket. Don’t forget to change the name of the bucket as required. Secondly, make sure the dist folder contains the index.html file. If not, alter the path of ‘./dist’ accordingly.

  7. Invalidate CloudFront (Optional): If you have a CloudFront distribution, invalidate it with the below command. Replace the <CLOUDFRONT_DISTRIBUTION_ID> with your own CloudFront distribution id.


Run the pipeline!

It's time for your hard work to pay off.


Go to the GitHub Actions tab in the repository. A pipeline with the name Continuous Deployment will be visible under the All Workflows section.

The newly created pipeline

Click on the Run workflow dropdown on the right and click the green Run workflow button.

Run the workflow

Once the workflow starts it will take around 3 minutes to complete the build and deploy the Angular application to the S3 bucket.

Successful Completion of a Workflow Pipeline

Conclusion


Setting up the GitHub Actions & AWS might seem a daunting task at first. But, once set up, it transfers the responsibility of deployment from a human to a machine. This reduces human errors with faulty deployments and gives the confidence to deploy with less stress!



Hope you have enjoyed the tutorial. Please subscribe to the newsletter for many such articles to follow.








555 views1 comment

Recent Posts

See All
bottom of page