Allowing GitHub Actions to SSH into Your Server

In this article, we will discuss how to configure your AWS environment to allow GitHub Actions to SSH into your server. This setup is essential for automating deployments and other tasks that require server access.

Overview

To enable GitHub Actions to connect to your AWS EC2 instance via SSH, you need to configure IAM roles, Security Groups, and set up a GitHub Actions workflow. This ensures that your server remains secure while allowing automated processes to run smoothly.

Steps to Configure AWS

1. Setting up GitHub OIDC Provider

  1. Go to the IAM console in AWS
  2. Navigate to Identity providers
  3. Click “Add provider”
  4. Select “OpenID Connect”
  5. Provider URL: https://token.actions.githubusercontent.com
  6. Audience: sts.amazonaws.com
  7. Click “Add provider”

2. Security Group

Create a security group named github-actions-ec2-ssh with no rules configured. Attach this to your EC2 instance.

To create the security group:

  1. Go to the EC2 console
  2. Navigate to Security Groups
  3. Click “Create security group”
  4. Name it github-actions-ec2-ssh
  5. Attach it to your EC2 instance

3. IAM Role

Create an IAM role called Github-Action-Assume-Role with the following trust relationship:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::AWS_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:GITHUB_ORG/*"
                }
            }
        }
    ]
}

4. Policy

Create a policy named manage-security-group-ingress and attach it to your IAM Role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:RevokeSecurityGroupIngress",
                "ec2:AuthorizeSecurityGroupIngress"
            ],
            "Resource": "arn:aws:ec2:AWS_REGION:AWS_ACCOUNT_ID:security-group/SECURITY_GROUP_ID"
        }
    ]
}

Steps to Configure GitHub Actions

1. Update Security Group Rules

To allow GitHub Actions to connect to your EC2 instance via SSH, you need to add rules to your github-actions-ec2-ssh security group. You can do this through the AWS Management Console or by using the AWS CLI.

Example CLI Command

You can use the following command to authorize SSH access from GitHub Actions:

aws ec2 authorize-security-group-ingress \
--group-id SECURITY_GROUP_ID \
--protocol tcp \
--port 22 \
--cidr GITHUB_ACTIONS_IP/32

Replace GITHUB_ACTIONS_IP with the IP address or CIDR range from GitHub’s published list of Action runner IPs.

2. GitHub Actions Workflow Setup

Now that your IAM role and Security Group are configured, you can set up your GitHub Actions workflow.

Ensure you have configured the following secrets in your GitHub repository settings: AWS_ASSUME_ROLE (ARN of the IAM Role), AWS_REGION, AWS_SECURITY_GROUP (ID of the github-actions-ec2-ssh group), DEPLOY_USER, HOSTNAME, and SSH_PRIVATE_KEY.”

Below is an example of a job in a workflow that allows GitHub Actions to SSH into your server:

  deploy:
    name: Deploy
    runs-on: ubuntu-24.04
    outputs:
      ipv4: ${{ steps.ip.outputs.ipv4 }}
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
          role-session-name: github-runner-${{ env.APP_ENV }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Public IP
        id: ip
        run: |
          ipv4=$(dig +short -4 txt ch whoami.cloudflare @1.0.0.1)
          echo "ipv4=$ipv4" >> $GITHUB_OUTPUT

      - name: Add Github Actions IP to Security group
        run: |
          aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SECURITY_GROUP }} \
          --ip-permissions IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges="[{CidrIp=${{ steps.ip.outputs.ipv4 }}/32,Description='Github Action'}]"

      - name: Prepare SSH configuration.
        run: |
          mkdir -p ~/.ssh
          chmod 700 ~/.ssh
          touch ~/.ssh/known_hosts
        shell: bash

      - name: Add SSH key.
        run: |
          ssh-agent -a $SSH_AUTH_SOCK > /dev/null
          echo "$SSH_KEY" | ssh-add -
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock
          SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
        shell: bash

      - name: Verify SSH Connection
        run: |
          attempt_ssh_connection() {
            local ssh_options="$1"
            timeout 10s ssh $ssh_options -p 22 ${{ secrets.DEPLOY_USER }}@${{ secrets.HOSTNAME }} exit 2>/dev/null
          }

          connection_successful=false

          if attempt_ssh_connection "-o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=no"; then
            echo "SSH connection successful"
            connection_successful=true
          fi

          if $connection_successful; then
            exit 0
          fi

          echo "CONNECTION FAILED"
          ssh -vvv -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p 22 ${{ secrets.DEPLOY_USER }}@${{ secrets.HOSTNAME }}
          exit 1
        shell: bash
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock

      - name: ssh-keyscan to get the public key of the remote server.
        run: |
          ssh-keyscan -p 22 -H ${{ secrets.HOSTNAME }} >> ~/.ssh/known_hosts
          chmod 644 ~/.ssh/known_hosts
        shell: bash
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock

      # Additional steps for deployment can be added here...

  revokeSecurityGroup:
    name: Revoke Security Group Ingress
    runs-on: ubuntu-24.04
    needs: deploy
    if: always()
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
          role-session-name: github-runner-${{ env.APP_ENV }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Remove Github Actions IP from Security group
        run: |
          aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_SECURITY_GROUP }} --protocol tcp --port 22 --cidr ${{ needs.deploy.outputs.ipv4 }}/32

Best Practices

  1. Security

    • Regularly rotate SSH keys
    • Use the principle of least privilege for IAM roles
    • Monitor security group changes
    • Consider using AWS CloudTrail to audit changes
    • Consider using AWS Systems Manager Session Manager for alternative access methods
  2. Maintenance

    • Keep track of GitHub Actions IP ranges
    • Regularly review IAM permissions
    • Monitor failed deployment attempts

Conclusion

By following the steps outlined in this article, you can successfully configure your AWS environment to allow GitHub Actions to SSH into your server. This setup enhances your deployment automation while maintaining security.

In future articles, we will explore how we are using Github Actions with PHP Deployer or Docker Swarm to handle deployments.