In this tutorial we will see how to add GitHub actions IP dynamically to AWS security group. Whenever a workflow runs, Github actions IP will be added to the security group and removed when the jobs are done.

If you use AWS security group to protect your infrastructure from any external access and you also use Github Action for CI/CD, you might need to allow Github Actions IP in AWS security group so that the workflow can execute the tasks in your instance. However, finding Github actions IP ranges and adding them to security groups is not a dynamic solution. Moreover, those IPs change very often.

So, to solve this issue dynamically, we will:

  • Grab github action IP from running job
  • Add it to the security groups via aws-cli
  • SSH and deploy the code to the instance
  • Remove the action IP from security group for cleanup
  • Profit!
  • Prerequisite:

    First, create an IAM user and make sure to tick “Programmatic access”

    <img class="size-full wp-image-723 alignnone" src="/uploads/2021/04/githubaws1.png" alt="" width="1019" height="490" srcset="/uploads/2021/04/githubaws1.png 1019w, /uploads/2021/04/githubaws1-768x369.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" />

    Attach the following inline policy to the user. This policy will allow the user to modify AWS security group. At line 11, make sure to replace your-account-idyour-security-group-id

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "UpdateIngress",
                "Effect": "Allow",
                "Action": [
                    "ec2:RevokeSecurityGroupIngress",
                    "ec2:AuthorizeSecurityGroupIngress"
                ],
                "Resource": "arn:aws:ec2:your-region:your-account-id:security-group/your-security-group-id"
            },
            {
                "Sid": "DescribeGroups",
                "Effect": "Allow",
                "Action": "ec2:DescribeSecurityGroups",
                "Resource": "*"
            }
        ]
    }
    

    Finally note the aws secret id and access key of the user and add them to your project’s secret.

    <img class="size-full wp-image-723 alignnone" src="/uploads/2021/04/githubaws2.png" alt="" width="1019" height="490" srcset="/uploads/2021/04/githubaws2.png 1019w, /uploads/2021/04/githubaws2-768x369.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" />

    Create the workflow

    Now, in your project, create a workflow. Lets name it prod.yaml and paste the following codeblocks:

    name: Deploy to prod
    
    # on:
    #   workflow_dispatch:
    on:
      push:
        branches: [ master ]
    jobs:
      deploy:
        runs-on: ubuntu-18.04
        steps:
        - name: Get Github action IP
          id: ip
          uses: haythem/[email protected]
    
        - name: Setting environment variables..
          run: |
            echo "AWS_DEFAULT_REGION=ap-southeast-1" &gt;&gt; $GITHUB_ENV
            echo "AWS_SG_NAME=default" &gt;&gt; $GITHUB_ENV
            
        - name: Add Github Actions IP to Security group
          run: |
            aws ec2 authorize-security-group-ingress --group-name ${{ env.AWS_SG_NAME }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32    
          env:
            AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
            AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
            AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION }}
            
        - name: Deploy to prod server
          uses: appleboy/ssh-action@master
          with:
            host: 11.22.33.44
            username: ubuntu
            key: ${{ secrets.SSH_KEY }}
            script: |
              cd /var/www/html/my-awesome-project
              git stash
              git pull origin master
                  
        - name: Remove Github Actions IP from security group
          run: |
            aws ec2 revoke-security-group-ingress --group-name ${{ env.AWS_SG_NAME }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
          env:
            AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
            AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
            AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION }}
          if: always()
    

    This workflow will run only when there is a push in the master branch. If you want to run this workflow manually, uncomment line 3-4 and comment line 5-7

    At line 12-14, we grab the GitHub action IP. From 16-19, two environment variables are set globally. Put your region and security group at line 18-19 I am using default security group and ap-southeast-1 as the region.

    From 21-27, we are adding the GitHub action IP to AWS security group.

    From line 29-38 we login to the instance and pull the code. Please make sure that the host IP address is correct and SSH_KEY (for accessing the server) in the project’s secret is valid.

    After successfully deploying the code, at line 40-46, we remove the Github actions IP from the security group.

    Let’s run the workflow and see the result:
    <img class="aligncenter size-full wp-image-730" src="/uploads/2021/04/githubaws3.png" alt="" width="1116" height="660" srcset="/uploads/2021/04/githubaws3.png 1116w, /uploads/2021/04/githubaws3-768x454.png 768w" sizes="(max-width: 1116px) 100vw, 1116px" /> Profit!