What Is OIDC and Why Do We Need It?

What Is OIDC and Why Do We Need It?

In the rapidly evolving landscape of cloud computing and application security, managing user identities and ensuring secure authentication are critical for business success. The era of AWS static credentials being exposed in GitHub and filesystems should be behind us, thanks to better alternatives.

OpenID Connect (OIDC) is emerging as a crucial protocol in this field, bridging the gap between robust security and user convenience by enabling auto-generated, short-lived, and non-persistent credentials.

But what exactly is OIDC, and how does it work? Let's delve deeper into this four-letter acronym and explore why it is an essential tool for modern cloud applications.

Understanding OIDC

To understand OIDC, we must first describe all the components involved and their role.

OpenID Provider - The service that authenticates the request and issues identity tokens. There are many of these such as GitHub, Vercel, Google, AWS Cognito & Microsoft.

Relying Party - The application or service that requires authentication. This could be any web or mobile app or a service like a GitHub Actions needing to access AWS resources.

JSON Web Token - A JSON Web Token (JWT) issued by the OpenID Provider, containing information about the authenticated user, service or app.

UserInfo Endpoint - An API endpoint provided by the OpenID Provider to fetch additional user details after authentication.

So how do these components fit together to provide access to resources. The key is the contents of the claims defined within the JWT.

What is a JWT?

A JSON Web Token (JWT) is a compact, URL-safe token that can be used to securely transmit information between parties. Typically represented as a string with three parts separated by dots (.), like this:

Encrypted JWT Token

It is made up of three parts: the header, the payload, and the signature.

A simple diagram illustrating the structure of a JSON Web Token (JWT), divided into three sections: Header, Payload, and Signature.

  • Header: Encodes information about the type of token and the algorithm used for signing.

  • Payload: Contains the claims.

  • Signature: Ensures that the token has not been altered.

Claims

Claims are statements about an entity (typically, the user) and additional data. These details are used to validate the source of the request.

There are three types of claims:

  • Registered claims: Predefined claims that are recommended to provide a set of useful, interoperable claims.

  • Public claims: Claims that are defined by those using JWTs. They must be collision-resistant.

  • Private claims: Custom claims are created to share information between parties that agree on using them.

The following shows an example of a JWT that would be sent to AWS IAM, via a GitHub Actions workflow.

{
  "sub": "repo:sjramblings/aws-repo:ref:refs/heads/main",
  "aud": "sts.amazonaws.com",
  "iss": "https://token.actions.githubusercontent.com",
  "iat": 1625724353,
  "exp": 1625727953
}
  • sub: Identifies the subject of the token, which is the GitHub Organisation/Repository in this case, sjramblings/aws-repo.

  • aud: The audience for the token, in this case, sts.amazonaws.com.

  • iss: The issuer of the token, which is https://token.actions.githubusercontent.com.

  • iat: The timestamp when the token was issued.

  • exp: The timestamp when the token expires.

Signature

The signature is created by taking the encoded header, the encoded payload, a secret, and the algorithm specified in the header, then signing them.

In the above example, the signature would be generated using the RSA private key corresponding to the public key hosted by GitHub -https://token.actions.githubusercontent.com.

OIDC Authentication Flow

A sequence diagram demonstrating the OpenID Connect authentication flow. It involves the End User, Relying Party, and OIDC Provider. The End User requests a protected resource from the Relying Party, which then requests authentication from the OIDC Provider. The OIDC Provider prompts the End User for login and, upon receiving the credentials, returns an ID token and access token back to the Relying Party. The Relying Party then provides the End User with the protected resource.

OIDC relies on establishing trust with an OpenID Provider. Once established, the OIDC authentication process typically follows these steps:

  1. The End User requests a protected resource from the Relying Party.

  2. The Relying Party requests authentication from the OIDC Provider.

  3. The OIDC Provider prompts the End User to log in.

  4. The End User submits their credentials to the OIDC Provider.

  5. The OIDC Provider sends an ID token and access token to the Relying Party.

  6. The Relying Party provides the protected resource to the End User.

That’s the high-level flow when there is an end user, what does it look like when we want to authenticate a GitHub Actions workflow to access resources in AWS.

In the following example the components required for OIDC map to:-

  • GitHub acts as the OpenID Provider and Endpoint. When a workflow runs, GitHub can issue an OIDC token for the job.

  • AWS IAM is the resource that validates the OIDC token issued by GitHub to grant temporary credentials.

  • The GitHub Actions workflow acts as the relying party, which uses the OIDC token to request temporary AWS credentials.

A sequence diagram illustrating the interaction between a user, GitHub Actions, OIDC Provider, IAM, and IAM Role to establish trust and obtain temporary credentials. The steps include pushing code to the repository, starting the workflow, triggering an authentication request, generating and sending an ID token, requesting temporary credentials with the ID token, establishing trust, validating the trust policy, and returning the access key and ID.

Let's walk through each step:

  1. Firstly trust is established with GitHub and AWS IAM, this allows an IAM Role to be assumed by GitHub Actions with the correct claims.

  2. A user pushes some code or a repo or creates a Pull Request triggering a GitHub Actions Workflow

  3. The GitHub OIDC Provider issues an OIDC JWT token for the job.

  4. The JWT token is used to request temporary credentials from AWS IAM.

  5. AWS IAM validates the claims in the JWT and if they match the requested IAM Role returns a temporary access key and ID.

  6. The GitHub Actions workflow can now use those credentials to perform actions on AWS resources as per the permissions assigned in the IAM Role.

AWS IAM Role Trust Policy

The IAM role specified in the workflow must have a trust policy that allows it to be assumed by entities presenting a valid OIDC token from GitHub.

Here’s an example:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:sub": "repo:sjramblings/aws-repo:ref:refs/heads/main"
        }
      }
    }
  ]
}

Let’s break down the components.

  • Principal.Federated: Specifies the OIDC provider (GitHub) that can assume the role.

  • Action: Allows the sts:AssumeRoleWithWebIdentity action, which is necessary for assuming roles with OIDC tokens.

  • Condition: Adds a condition to ensure that only tokens i.e. the claims for a specific repository and branch (in this case, main) can assume the role.

💡
With great power comes great responsibility, if we were to not have a condition we risk any repo on GitHub being able to assume our role via GitHub Actions so bear this in mind.

Summary

This article covered the components of OIDC and how it can be used to grant access to AWS Cloud resources. By understanding and implementing OIDC you can ensure secure access to your resources for your apps, users, or DevOps workflows.

Hope this helps someone.

Cheers! 👋

If you found the introduction to OIDC insightful, you might also be interested in exploring other AWS services and IAM policies. These articles will help you understand the differences between AWS messaging services, master IAM roles, and get practical with IAM policies: