DEV Community

Cover image for Deploy React.js application using AWS S3 & GitLab pipelines for automatic deployment 2024
Nikola Perišić
Nikola Perišić

Posted on • Updated on

Deploy React.js application using AWS S3 & GitLab pipelines for automatic deployment 2024

In this article, we will look at how we can deploy our React.js application to the AWS S3 bucket using GitLab pipelines🚀

We'll look at how to automate our development process as much as possible🔧


1 - Project setup and creating GitLab repository 📁

I'll be using the React.js application I've initialized using the following command:

npm create vite@latest
Enter fullscreen mode Exit fullscreen mode
  1. Login to your GitLab account (Register if you already don't have one)🔐

  2. Create a repository for our project📦

  3. Clone our repository using HTTP or SSH🔗

  4. Commit our code to the repository using the following command💾

git add .
git commit -m "Initial commit"
git push -u origin main
Enter fullscreen mode Exit fullscreen mode

After, when we configure our S3 bucket, we will come back to GitLab to configure our pipeline which will do auto-deployment for us whenever we push new code to the main branch🔄


2 - Login to your AWS account and find the "S3" service🌐

Search for the "S3" service in the search input field which is located at the top of the page.

Choose an option with the green colored icon of a bucket with the description "Scalable Storage in the Cloud"🪣

You will see the following page. Click on the "Create bucket" button
Creating a bucket on AWS


3 - Creating our S3 bucket🛠️

  1. Bucket name: our-react-app-s3-bucket📝

  2. IMPORTANT: Disable the "Block all public access" checkbox input field -> this is important to enable our application to be publicly visible🚫🔓

  3. Click the "Create bucket" button✅

Now, we have successfully created our S3 bucket🎉

AWS S3 bucket

Modify bucket policy📜

Now, you need to edit the Bucket Policy. Click the "Edit" button in the Bucket Policy section. In our case bucket name is our-react-app-s3-bucket so I will use it. Please change it according to your bucket name✏️

Paste the following code into your new policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::our-react-app-s3-bucket/*"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

4 - Create a new Identity Provider🔑

Search for the "Identity Provider" service in the search input field which is located at the top of the page.

AWS Identity Provider

On the left navigation pane, under Access management choose Identity providers and then choose Add provider button➕

For provider type, select OpenID Connect🌐

For Provider URL, enter the address of your GitLab instance, such as https://gitlab.com or https://gitlab.example.com🌍

For Audience, enter something that is generic and specific to your application. In my case, I'm going to enter our-identity-provider🎯

To prevent confused deputy attacks, it's best to make this something that is not easy to guess🚫🕵️‍♂️

Take note of this value because you will use it to set the ID_TOKEN in your .gitlab-ci.yml file📝

Lastly, click on the "Add provider" button to finish up✅

Create the permissions policy📜

After you create the identity provider, you need to create a permissions policy🛡️

From the IAM dashboard, under Access management select Policies and then Create policy

Select the JSON tab and paste the following policy replacing our-react-app-s3-bucket on the Resource line with your bucket name. Click the "Next" button to continue. For a "Policy name" input field type: our-policy. At the end, click the "Create policy" button to finish up📝

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::our-react-app-s3-bucket"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::our-react-app-s3-bucket/*"]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

IAM AWS policy

Note: Don't change anything except the bucket name!🛑


5 - Creating a role🎭

Now it’s time to add the role. From the IAM dashboard, under Access management select Roles and then click Create role button. Select Web identity🆔

In the Web identity section, select the identity provider you created earlier. In our case, it would be gitlab.com🌐

For the Audience, select the audience you created earlier. Select the Next button to continue. In our case, it would be our-identity-provider🎯

Click the "Next" button➡️

If you wanted to limit authorization to a specific group, project, branch, or tag, you could create a Custom trust policy instead of a Web identity. Since I will be deleting these resources after the tutorial, I'm going to keep it simple😊

AWS Roles web identity

Click the "Next button"➡️

During the Add permissions(step number 2), search for the policy you created and click the "Next" button to continue. In our case, it would be our policy🔍

AWS Permissions

In the next step(step number 3), give your role a name and click the "Create role" button. I will call it our-role-name📝

Search for the role you just created. Click on it🔍

In the summary section, find the Amazon Resource Name (ARN) and save it somewhere secure🔒

You will use this in your pipeline🔄

AWS Arn

In our case, it is arn:aws:iam::162340708442:role/our-role-name✏️


6 - Deploy to your Amazon S3 bucket using a GitLab CI/CD pipeline🚀

Inside of your project repository on GitLab, create two CI/CD variables🔧

The first variable should be named ROLE_ARN. For the value, paste the ARN of the role you just created in the last step📝

The second variable should be named S3_BUCKET. For the value, paste the name of the S3 bucket you created earlier. In our case it would be our-react-app-s3-bucket📝

Retrieve your temporary credentials🗝️

Inside of your .gitlab-ci.yml file, paste the following code:

.assume_role: &assume_role
    - >
      STS=($(aws sts assume-role-with-web-identity
      --role-arn ${ROLE_ARN}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token $ID_TOKEN
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
    - export AWS_ACCESS_KEY_ID="${STS[0]}"
    - export AWS_SECRET_ACCESS_KEY="${STS[1]}"
    - export AWS_SESSION_TOKEN="${STS[2]}"
Enter fullscreen mode Exit fullscreen mode

This is going to use the AWS Security Token Service to generate temporary (3,600 seconds) credentials utilizing the OIDC role you created earlier🛡️

Create the deploy job🛠️

Now, let's add a build and deploy job to build your application and deploy it to your S3 bucket📦

First, update the stages in your .gitlab-ci.yml file to include a build and deploy stage as shown below:

stages:
  - build
  - test
  - deploy
Enter fullscreen mode Exit fullscreen mode

Next, let's add a job to build your application. Paste the following code in your .gitlab-ci.yml file:

build artifact:
  stage: build
  image: node:latest
  before_script:
    - npm install
  script:
    - npm run build
  artifacts:
    paths:
      - build/
    when: always
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"'
      when: always
Enter fullscreen mode Exit fullscreen mode

This is going to run npm run build if the change occurs on the main branch and upload the build directory as an artifact to be used during the next step🔄

Next, let's add a job to actually deploy to your S3 bucket. Paste the following code in your .gitlab-ci.yml file:

deploy s3:
  stage: deploy
  image:
    name: amazon/aws-cli:latest
    entrypoint: 
      - '/usr/bin/env'
  id_tokens:
      ID_TOKEN:
        aud: react_s3_gl
  script:
    - *assume_role
    - aws s3 sync build/ s3://$S3_BUCKET
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"'
      when: always
Enter fullscreen mode Exit fullscreen mode

Your complete .gitlab-ci.yml file should look like this:

stages:
  - build
  - test
  - deploy

.assume_role: &assume_role
    - >
      STS=($(aws sts assume-role-with-web-identity
      --role-arn ${ROLE_ARN}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token $ID_TOKEN
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
    - export AWS_ACCESS_KEY_ID="${STS[0]}"
    - export AWS_SECRET_ACCESS_KEY="${STS[1]}"
    - export AWS_SESSION_TOKEN="${STS[2]}"

unit test:
  image: node:latest
  stage: test
  before_script:
    - npm install
  script:
    - npm run test:ci
  coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
  artifacts:
    paths:
      - coverage/
    when: always
    reports:
      junit:
        - junit.xml

build artifact:
  stage: build
  image: node:latest
  before_script:
    - npm install
  script:
    - npm run build
  artifacts:
    paths:
      - build/
    when: always
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"'
      when: always


deploy s3:
  stage: deploy
  image:
    name: amazon/aws-cli:latest
    entrypoint: 
      - '/usr/bin/env'
  id_tokens:
      ID_TOKEN:
        aud: react_s3_gl
  script:
    - *assume_role
    - aws s3 sync build/ s3://$S3_BUCKET
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"'
      when: always
Enter fullscreen mode Exit fullscreen mode

7 - Make a change and test your pipeline🧪

  1. Inside App.js, modify some code✏️
  2. Commit your changes to the main branch. The pipeline should kick off and when it finishes successfully you should see your updated application at the URL of your static website🌐

Voila! 🎉

You now have a CI/CD pipeline built in GitLab that receives temporary credentials from AWS using OIDC and automatically deploys to your Amazon S3 bucket🚀

To take it a step further, you can secure your application with GitLab's built-in security tools🔒

Where to find the URL to visit your website?🔗

Go to the "S3 buckets" page. Click on your bucket. Go to "Properties"🏠
Scroll to the bottom. You will find "Static website hosting". Click the "Edit" button✏️
Select the "Enable" radio checkbox✅

AWS

Click the "Save changes" button💾

In "Index document" fill: index.html📝

You will be redirected back. Again, scroll to the bottom of the page and you will find your website URL in the Static website hosting section🌐

AWS S3 bucket


Thank you for reading. Hope I helped 😊

🚀 Follow me on GitHub

Top comments (0)