Skip to content

OIDC diagrams #2657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 24, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions docs/2.0/docs/pipelines/concepts/cloud-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,60 @@ The AWS IAM Role in the Management Account must have permissions to provision ne
Each child account (e.g., `dev`, `stage`, `prod`, etc.) contains an AWS IAM role that Pipelines can assume from GitHub Actions or GitLab CI using OIDC. This role is automatically provisioned during the [account baseline process](/2.0/docs/accountfactory/guides/vend-aws-account). Once the role is established in the child account, users can submit pull requests/merge requests to add, modify, or delete resources in that account.

When a pull request/merge request is created or synchronized, or when changes are pushed to the `main` branch, Pipelines detects the changes, maps them to the appropriate account, assumes the role in the child account, and executes a `terragrunt plan` (for pull requests/merge requests) or `terragrunt apply` (for pushes to `main`).

### Fundamentals of OIDC for Publicly Available and Private CI/CD platforms

### JWT Token Issuers
A JWT token is a base64-encoded JSON object that contains three parts: a header, a payload, and a signature. The header typically contains metadata about the token, such as the algorithm used to sign it. The payload contains the claims or assertions made by the issuer, such as the subject (user), audience (intended recipient), and expiration time. The signature is used to verify that the token was issued by a trusted authority and has not been tampered with.

Critically, the issuer is a URL that is both specified inside the token, and is used by consumers of the token to fetch the public key used to validate the signature of that same token. Assuming the public key is fetched via HTTPS, there is a valid trust chain that the token was in fact issued by the expected issuer and you have typical cryptographic guarantees it wasn't substituted or tampered with.

Typically the issuer is the hostname of the CI/CD platform, such as `https://gitlab.com`, and thus oidc configuration (and public keys) can be fetched from the publicly available route, `https://gitlab.com/.well-known/openid-configuration` etc.

If, however, your CI/CD platform is hosted privately, you will need to host the public key and OIDC configuration in a publicly accessible location, such as an S3 bucket, and update the issuer in your CI/CD configuration to point to that location. The diagrams below illustrate both approaches - fetching the keys directly from your CI/CD platform via a public route, or fetching the keys from a public S3 bucket.


#### Publicly Available CI/CD Platforms
```mermaid
sequenceDiagram
participant SCM as SCM (GitLab/GitHub etc.)
participant SCMPublicRoute as SCM Hostname e.g. gitlab.com
participant AWSIdP as AWS IdP & STS

SCM->>SCM: Generate a public/private key pair
SCM->>SCM: Generate a JWT and sign with the private key
SCM->AWSIdP: Send JWT to AWS requesting a role
AWSIdP->>SCMPublicRoute: Fetch public key via HTTPS <br>(which validates that the SCM is who it says it is)
SCMPublicRoute->>AWSIdP: Return the public key
AWSIdP->>AWSIdP: Validate signature on JWT using public key to validate that it was generated by the Issuer
AWSIdP->>AWSIdP: Inspect JWT Content and ensure it passes trust policies
AWSIdP->>SCM: Return temporary tokens for the role requested

```

#### Non-Publicly Available CI/CD Platforms

This diagram follows the [recommended approach](https://docs.gitlab.com/ci/cloud_services/aws/#configure-a-non-public-gitlab-instance) from GitLab for private CI/CD platform instances. The guidance is to host the public key in a publicly accessible S3 bucket and update the issuer in the CI/CD configuration.

A common alternative approach to re-hosting the public key and OIDC configuration is to update the application firewalls to specifically allow requests to the `.well-known/openid-configuration` endpoint and the JWKS endpoint from the AWS IdP.

```mermaid
sequenceDiagram
participant SCM as SCM (GitLab/GitHub etc.)
participant SCMPublicRoute as Public S3 Bucket (e.g. acme-public.s3.com)
participant AWSIdP as AWS IdP & STS


SCM->>SCM: Generate a public/private key pair
SCM->>SCMPublicRoute: Publish public key to S3
SCM->>AwsIdP: Update provider URL in AWS IdP to S3 bucket public URL
SCM->>SCM: Update issuer to hostname of S3 bucket public URL
SCM->>SCM: Generate a JWT with updated issuer and sign with the private key
SCM->>AWSIdP: Send JWT to AWS requesting a role
AWSIdP->>SCMPublicRoute: Fetch public key via HTTPS <br>(HTTPS is important as it validates that the host is in fact the issuer)
SCMPublicRoute->>AWSIdP: Return the public key
AWSIdP->>AWSIdP: Validate signature on JWT using public key to validate that it was generated by the Issuer
AWSIdP->>AWSIdP: Inspect JWT Content and ensure it passes trust policies
AWSIdP->>SCM: Return temporary tokens for the role requested

```