Strengthening Security with IAM Roles and OpenID Connect in GitHub Actions Deploy Workflows
Tags: devops, beginners, aws, security
Published: 2024-01-06 22:18:05

To enhance security, we have been minimizing the use of IAM users and instead adopting a method that grants temporary permissions through IAM roles.

However, in our GitHub Actions deploy workflows, we previously thought that credentials of IAM users (Access Key and Secret Access Key) were necessary when assuming roles, as adopted in the following article:
[Enhancing Deployment Security through the Integration of IAM Roles and GitHub Actions](https://dev.to/suzuki0430/enhancing-deployment-security-through-the-integration-of-iam-roles-and-github-actions-4gb6)

Upon further research, we discovered that using OpenID Connect allows us to assume roles within the workflow without needing credentials. This finding has led us to improve our workflows.

This might be common knowledge for engineers with DevOps experience, but it's shared here as a reference for beginners.

## What is OpenID Connect?
OpenID Connect (OIDC) is an open standard protocol for user authentication, built on the OAuth 2.0 protocol. It enables the secure verification of a user's identity.

When used in GitHub Actions workflows, OIDC allows the workflow to request a temporary token from GitHub (acting as an OpenID Connect provider) containing specific workflow-related information (like repository name, workflow ID, etc.). GitHub generates this token in response to the request, which remains valid only during the execution of the workflow. This enhances security and simplifies management compared to using IAM user access keys.

The OIDC token generated is then sent from the GitHub Actions workflow to AWS. On AWS, a pre-configured IAM role is set to accept tokens from the OIDC provider (GitHub). This IAM role is associated with specific policies (set of permissions), allowing the GitHub Actions workflow access to certain AWS resources based on the OIDC token.

The GitHub Actions workflow invokes AWS's 'AssumeRoleWithWebIdentity' API, using the provided OIDC token to obtain permissions associated with the specified IAM role. During this step, AWS verifies the OIDC token and grants access only if the token information matches the configured IAM role.

In simple terms, using OIDC allows GitHub Actions to receive a "temporary certificate" to perform necessary operations, eliminating the need to store IAM user credentials within the workflow and significantly reducing security risks.

## Implementation
Here's a step-by-step explanation.

### Adding an ID Provider (AWS)
Setting up an ID provider ensures that AWS can verify requests from GitHub Actions as legitimate. The configuration of the OIDC ID provider allows for the authentication tokens generated by GitHub Actions workflows to be validated, permitting access to specific AWS resources based on the token.

In the AWS Management Console, go to 'IAM > Identity Providers > Create Provider' and add an ID provider with the following settings:
- Provider Type: OpenID Connect
- Provider URL: `https://token.actions.githubusercontent.com`
- Audience: `sts.amazonaws.com`

Obtaining the thumbprint of GitHub's OIDC provider (token.actions.githubusercontent.com) and adding it to the AWS OIDC ID provider settings ensures that GitHub Actions can securely access AWS services.

![Screenshot 2024-01-06 22.12.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/4259fea1-0041-27be-c8fe-ac66fc9db1bd.png)

### Creating an IAM Role
Create an IAM role to assume. Grant it the necessary IAM policies for deployment (like access permissions to ECS and ECR), and set up the trusted entities using the following JSON in the trust relationship tab:

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<account-id>:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub": "repo:<organization-name>/<repository-name>:*"
                }
            }
        }
    ]
}
```

This JSON defines conditions to allow authentication requests from GitHub Actions:
- Principal: Specifies the OIDC provider of GitHub Actions (`token.actions.githubusercontent.com`).
- Action: `sts:AssumeRoleWithWebIdentity` refers to the action of assuming an IAM role using a Web Identity (OIDC token).
- Condition: Specifies requests from a particular GitHub repository (`<organization-name>/<repository-name>`).

This setup of the IAM role and trust relationship enables specific GitHub Actions workflows to access designated services on AWS.

### Modifying the Deployment Workflow
Modify the workflow as follows:

Before modification:
```yml
name: Lambda Deploy
on:
  push:
    branches:
      - develop
    paths:
      - "**"
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: install dependencies
        run: yarn install
        working-directory: ./

      - name: configure aws
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME }}
          role-duration-seconds: 3600
```

After modification:
```yml
name: Lambda Deploy
on:
  push:
    branches:
      - develop
    paths:
      - "**"
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: install dependencies
        run: yarn install
        working-directory: ./

      - name: configure aws
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME }}
          aws-region: ${{ secrets.AWS_REGION }}
          role-session-name: GitHubActions
          role-duration-seconds: 3600
```

Key modifications include:
1. Addition of `permissions`: The modified workflow includes a new `permissions` section, required for GitHub Actions to request and use the OIDC token. `id-token: write` grants permission to obtain the OIDC token from GitHub, and `contents: read` allows reading the repository contents.
2. Removal of credentials: In the modified workflow, `aws-access-key-id` and `aws-secret-access-key` are removed, enhancing security by eliminating the exposure of IAM user credentials.
3. Change in `configure-aws-credentials` action: The use of the `aws-actions/configure-aws-credentials` action is modified to authenticate with AWS using the OIDC token. `role-to-assume` continues to be used, enabling the OIDC-authorized GitHub Actions workflow to assume the specified IAM role.

## Conclusion
The adoption of OpenID Connect (OIDC) in GitHub Actions workflows represents a significant advancement in securing automated deployment processes. By transitioning from the traditional use of IAM user credentials to a more secure, token-based authentication system, we have significantly mitigated potential security risks. This approach not only enhances the security posture of our deployments but also simplifies the management and maintenance of our AWS access strategy.

The implementation of OIDC, combined with the setup of an appropriate IAM role and the modification of the deployment workflow, demonstrates a proactive approach to embracing modern security practices. It aligns with the best practices recommended by AWS and GitHub, ensuring that our deployments are both efficient and secure.

This article not only serves as a guide for integrating OIDC with GitHub Actions and AWS but also highlights the importance of continually reassessing and improving our security practices. As technology evolves, so do the threats, and our methodologies must adapt accordingly. By sharing our experience and the steps taken to enhance our security, we hope to inspire others to review and improve their own deployment workflows, contributing to a more secure and reliable software development ecosystem.