Zero Trust with OIDC

Abhi
4 min readJan 17, 2025

--

Leaked credentials in CI/CD workflows pose a significant security risk, potentially leading to unauthorized access, data breaches, and system compromises. This can disrupt development pipelines, undermine the integrity of software deployment processes, and ultimately damage an organization’s reputation and bottom line. Protecting sensitive information like API keys, database passwords, and other secrets within the CI/CD pipeline is crucial for maintaining a secure and reliable software delivery process.

Long-lived credentials, such as traditional usernames/passwords and tokens, present significant security risks. Today, we’ll discuss how transitioning to OpenID Connect (OIDC) can mitigate these risks and provide enhanced security and manageability.

These risks of Long-lived credentials:

  • Expiration Management: Enforcing expiration for static credentials is challenging and can lead to workflow disruptions during renewal.
  • Credential Leakage: Long-lived credentials are vulnerable to leaks, potentially remaining undetected for extended periods.
  • Credential Reuse: Reusing credentials across environments significantly increases security risks.

What is OIDC?

OIDC extends OAuth 2.0 by adding an identity layer. While OAuth 2.0 is primarily designed for authorization (granting permissions to access resources), OIDC focuses on authentication — verifying the identity of a user and providing basic profile information.

OIDC introduces a JSON Web Token (JWT) called an ID Token, which contains claims about the authenticated user. This ID Token can be used by applications to verify the user’s identity.

Key Components of OIDC

  1. Relying Party (RP): The application or service requesting authentication.
  2. OpenID Provider (OP): The identity provider (e.g., Google, AWS Cognito) that authenticates users and issues tokens.
  3. ID Token: A signed JWT containing user identity information.
  4. Discovery Document: A JSON document provided by the OP, containing URLs and information about supported OIDC features.

How OIDC Works: Step-by-Step

1. Discover the OpenID Configuration

The relying party fetches the OpenID Provider’s discovery document, typically hosted at a standard URL:
https://<provider-domain>/.well-known/openid-configuration

2. Redirect to Authorization Endpoint

The relying party redirects the user to the OP’s authorization endpoint with the following parameters:

  • client_id: Identifier for the relying party.
  • redirect_uri: URL where the user is redirected after authentication.
  • scope: Permissions requested (e.g., openid, profile, email).
  • response_type: Type of response expected (e.g., code for authorization code flow).
  • state: A random value to prevent CSRF attacks.
    https://<provider-domain>/authorize?response_type=code&client_id=<client-id>&redirect_uri=<redirect-uri>&scope=openid%20profile&state=<random-string>

3. Authenticate User

The OP displays a login page, prompting the user to authenticate (e.g., username/password, biometrics). After successful authentication, the user is redirected back to the relying party.

4. Receive Authorization Code

The relying party receives an authorization code as a query parameter in the redirect URI. This code is short-lived and can be exchanged for tokens.

Example redirect URI:
https://<redirect-uri>?code=<auth-code>&state=<random-string>

5. Exchange Code for Tokens

The relying party sends the authorization code to the OP’s token endpoint using a secure backchannel. This request must include:

  • grant_type: authorization_code
  • code: The received authorization code.
  • redirect_uri: Same as the one used in the authorization request.
  • client_id and client_secret: To authenticate the relying party.

6. Receive Tokens

The OP responds with an access token, ID token, and optionally a refresh token. The ID token contains user identity information (e.g., name, email) and is signed using a JSON Web Key (JWK).

Example token response:

{
"access_token": "eyJhbGciOiJIUzI1...",
"id_token": "eyJhbGciOiJIUzI1...",
"expires_in": 3600,
"token_type": "Bearer"
}

7. Validate ID Token

The relying party validates the ID token by:

  1. Verifying its signature using the OP’s JWKs.
  2. Ensuring the aud (audience) claim matches the client ID.
  3. Checking the exp (expiration) claim to ensure the token is still valid.

8. Authenticate User in the Application

After validating the ID token, the relying party extracts user claims (e.g., sub, email) and uses them to authenticate the user in the application.

9. Optional: Refresh Tokens

If a refresh token is issued, the relying party can request new access tokens without requiring user re-authentication.

Benefits of OIDC

  • Interoperability: Standardized mechanism for authentication across providers.
  • Enhanced Security: Built-in protections like CSRF prevention, token expiration, and secure key handling.
  • User Experience: Simplifies user login with Single Sign-On (SSO).
  • Scalability: Works well with modern, distributed architectures.

Terraform code

provider "aws" {
region = "us-east-1"
}

resource "aws_iam_openid_connect_provider" "github_actions" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

data "aws_iam_policy_document" "github_oidc_assume_role_policy" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]

principals {
type = "Federated"
identifiers = [aws_iam_openid_connect_provider.github_actions.arn]
}

condition {
test = "StringLike"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:abhi-io/test-oidc-cicd:*"]
}
}
}

resource "aws_iam_role" "github_oidc_role" {
name = "github-oidc-role"
assume_role_policy = data.aws_iam_policy_document.github_oidc_assume_role_policy.json
}

data "aws_iam_policy_document" "s3_access_policy" {
statement {
actions = ["s3:*"]
resources = ["arn:aws:s3:::my-test-s3-q98u211u9qw2/*"]
}
}

resource "aws_iam_policy" "github_oidc_s3_policy" {
name = "github-oidc-s3-policy"
policy = data.aws_iam_policy_document.s3_access_policy.json
}

resource "aws_iam_role_policy_attachment" "github_oidc_policy_attachment" {
role = aws_iam_role.github_oidc_role.name
policy_arn = aws_iam_policy.github_oidc_s3_policy.arn
}

reff: https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services

--

--

Abhi
Abhi

Written by Abhi

Hello world, Basically a Linux evangelist, Working as a DevOps engineer — ♥ www.abhinand.in/

No responses yet