Tuesday, July 25, 2023

What’s OIDC and why should you use it asap in your GitHub pipeline (keyless)

Table of contents

Hackers Paradise !
                        -- “ 10 million credentials from GitHub were accessible in 2022 alone.” --

This is the shocking truth exposed in a recent
 report published
by secrets-management firm GitGuardian.            

That’s 5.5 out of every 1,000 commits to GitHub spilling secrets, putting applications & businesses at serious risk.
Scattered & hard-coded secrets across environments are one of the biggest threats for users, enterprises, & states.
These incidents that big corporations like Uber, NVIDIA, Lastpass, Samsung,Toyota, Dropbox and even Okta itself serve as a sobering reminder that leaked secrets are a gateway to high-profile breaches.


Infrastructure as Code

Terraform files pushed into GitHub are no exception as it had about 5.57 occurrences of secrets per 1,000 patches


Traditionally, connecting to cloud platforms involved using user or workload principal as shown below. While they served their purpose, they still represent a security risk.

  1. User based Authentication: Interactive login(GCP,Azure) or using access keys (AWS,OCI) => static

  2. Service principals: .i.e GCP (service account key file) , Azure (service principal password) => static

  3. Instance principals/managed identities: Only when Self-hosted runners are located in the cloud =>dynamic

  4. Assumed roles: long-lived secret (i.e AppRole for Hashicorp Vault) =>   semi-dynamic

Why is it wrong?


  • Static credentials never expire which maximise vulnerability surface in case of leaks  

  • Management overhead: secure credential storage and rotation can be daunting for Ops teams

  • Cloud instance principals Self hosted runners, is an overkill especially if you deploy in MultiCloud

  • Even Dynamic secrets like AppRole (Vault) require static credentials to enable the feature(secret eng)    

OAuth `the Underlying Layer of OIDC`

It is impossible to talk about Open ID connect (OIDC) without first introducing OAuth2.0. And the best source for it is OktaDev team. So I’ll be using few illustrations from DevAdvocates Aaron Parecki and David Neal.

Note: The terminology can be super confusing but no worries, I will try my best to share what I learned. 

Back in the Stone AgeZynga Farmville 2 Login - July 15, 2023

Basic Authentication
In the old days, apps like Farmville required your Facebook username/password, in order to play. You not only let them access your account once, but they can keep the credentials forever—that's like giving a shady dude your apartment key, hoping he won't throw a wild party and make copies for all his friends to steal your stuff. So insane.

OAuth 2.0 to the rescue                                                            

      -- “ How to let 3rd party applications access users data without users giving the passwords? ” --
                                                                           Skills-and-Challenges-Icon - LearningWorks for Kids

OAuth global standard answers this by letting apps receive an authorization key to access target data, eliminating the need for password sharing. Access is delegated, and user simply gives consent.

  • See how Google redirects all their apps login URLs into a single OAuth endpoint ‘accounts.google.com.

OAuth 2.0 Terminology

An Introduction to OAuth 2.0. A Quick Guide | by Kayathiri Mahendrakumaran  | DataDrivenInvestor
The OAuth2.0 authorization framework allows a 3rd-party application to access an HTTP service on behalf of a resource owner (via user consent) or by allowing an app to access on its own without knowing the user identity.
End-users provide their username/password at the Authorization server level which in turn replies to the Client with an authorization code allowing for another token exchange to obtain App access to target data.

Let’s review the terminology


                                What is Oauth 2.0 ? A Comprehensive Analysis of OAuth 2.0 Authentication  Vulnerabilities and Prevention - TheHackerStuff

  • Resource Owner: You! or the owner of the identity, data, and actions on the account resources.

  • Client: The application that wants to use the resources on your behalf (i.e GitHub workflow)

    • Client ID: ID used to identify the Client with the Authorization Server (can be visible).

    • Client Secret: Password given by the Authorization Server to a client for private exchange.

    • Client types (by secret retention)

      • Confidential client: Server environments (.NET,java) > can hold secrets

      • Public client: Web, Single Page App, JScript,Mobile aps > too open to keep secrets

  • Authorization Server: Service that manages Resource Owner authorization in target platform(i.e AD).

  • Resource Server: API allowing to use/manage resources belonging to the Resource Owner (i.e AZ API)

App registration (Day1):

At the very beginning the Client (app) needs to register at the Authorization Server to established a working relationship. That’s when a redirect URI is set, and Client ID/Secret are generated by the Authorization server.

Payload Items

  • Scope: Type of permission the Client wants, such as access to data or to perform actions. See Google’s

  • Redirect URI/Callback: URL, Authorization Server redirects a Resource Owner back to after consent.

  • Response/Grant Type: Common type is code, where the Client expects an Authorization Code.

  • Authorization Code: A grant code Client exchanges with the Authorization Server for an Access Token.

  • Consent: Resource Owner agrees to delegate access to a Client and informs Authorization Server.

  • State: Random string generated by the app, which allows to confirm that Auth server reply wasn’t forged.

  • Access Token: A short-lived key the Client obtains to use the Owner’s resources in the target platform.

  • Refresh Token: Sent to the Client by the auth server to refresh a token when the current one expires.

Communication Channels

  • Front channel: Web browser to Server (Auth/API). Can not carry secrets only IDs/scopes [Public client].

  • Back channel: Server(Client) to server (Auth/API). Default channel for secret exchange (token).   

OAuth 2.0 Workflow

Let's break down the OAuth flow ! Assuming we've got our app registered with client ID and secret in place.
This Yelp Auth2 flow comes from Nate Barbettini (see video

  1. Yelp app(Client) sends an API request to the Authorization server containing client info to get access.

  2. Authorization server asks consent from the Resource Owner to delegate access to Yelp. User says yes.

  3. Authorization server then sends back an Authorization code to Yelp app via the callback URL.

  4. Yelp (Client) now sends the code, client secret and client Info to the Auth server in exchange for a token.

  5. The Authorization server validates the code and client info, then sends back the Access Token to Yelp.

  6. Finally, The app(Client) wraps the access token in an API request to the Resource server & gets access to the user’s Gmail contacts.

What is OIDC?

OpenID Connect
is an authentication protocol built on top of OAuth 2.0 by adding an identity layer on top of it.

OAuth 2.0 and OpenID Connect

  • It provides information about the user, as well as enables clients to establish login sessions.

  • OAuth 2.0 provides API security via scoped access tokens, and OpenID Connect provides user authentication and SSO functionality on top of OAuth’s secure Authorization.

OIDC .vs OAuth 2.0 (Permission vs Identity)

Hotel Analogy(OAuth 2.0)

Let’s say you go and check in at a Hotel lobby:

  1. You (or Client on behalf of Resource Owner)Show your ID and credit card. 

  2. Receptionist (Authorization server) gives you back a key card (Access token).

  3. You take that card and go to the room then swipe it on the door (Resource API), door opens.

The door doesn’t need to know who is using the key card(delegated access). Anyone can enter with the card.

  • In Summary

    • OAuth is about accessing APIs (Authorisation), OIDC is about Identifying users (Authentication).

    • OAuth 2.0 is not an authentication flow as opposed to OIDC that verifies the identity of and end-user.

    What OIDC adds

    1. User Info endpoint: For more user information
    2. Standard set of scopes and standardized implementation

    3. ID Token: 

    • Is the core of OIDC as it contains information about the user who signed which is provided to the client.

    • This token is encoded and signed using JWT (Jason Web Token) format, which is readable by the client.

    • In a OIDC flow, the client requests an ID token along with an access token.

    • The data inside the ID Token is called => claims.

    OIDC Authentication flow

    • Same as OAuth’s plus a new open_id scope and the return of a Token ID to Identify the logged-in user.

    • See new user information gathered in step 6 below:

    OIDC in GitHub Actions

    OIDC allows GitHub Actions workflows to access resources in your cloud provider, using ephemeral tokens for each pipeline run directly from your cloud provider.

    • The ID Token, however, is here generated by GitHub’s Identity provider, not by the cloud provider.

    • The Cloud validates ID Token claims based on the mapped cloud identity then provides an access token.


    • Seamless authentication with cloud providers without storing long-lived secrets.

    • Enables Cloud admins to rely on their provider's security mechanisms for minimal access to resources.

    • There is no duplication of secret management in GitHub and the cloud.

    • Using OIDC with Workload Identity Federation is a big win in terms reduced maintenance (rotation).


    • You will first need to configure your cloud provider to trust GitHub's OIDC as a federated identity (set up the OIDC trust), then update your workflow to authenticate using tokens.

    Eliminate Static Keys for Cloud Resources Access Using OpenID Connect | by  Gonzalo Peci | Trade Republic Engineering


    1. Workflow asks GitHub Identity provider for a token

    2. GitHub IdP gives back ID token to the workflow runner

    3. Workflow sends a request with the JWT (ID token) to the Cloud provider Authorization Server (is Az AD)

    4. Cloud provider checks the token & validates the claims against the cloud role definition defined in WIF claim.

    5. Cloud provider then gives back access & refresh tokens to use the resources in the workflow scope

    Note: To control how your cloud provider issues access tokens, you must define at least one condition, so that untrusted repositories can’t request access tokens for your cloud resources.

    How to check my git actions claims?

    The actions-oidc-debugger action, is the perfect tool to print your ID token (JWT) claims.
    Here’s an excerpt of my repo claims:

    Example: OIDC Token claims for “brokedba”s github actions workflow

    { "actor": "brokedba", "aud": "https://github.com/brokedba", "environment": "gcp-labs", "event_name": "push", "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "brokedba/terraform-examples/.github/workflows/..", "ref": "refs/heads/git_actions", "ref_type": "branch", "repository": "brokedba/terraform-examples", "repository_owner": "brokedba", snip ... "sub": "repo:brokedba/terraform-examples:environment:gcp-labs", <<--- "workflow": "Terraform_gcp_vpc", snip ... }

    Note: Standard claims include audience, issuer, and subject. Full description can be found here > Github Doc

    MultiCloud keyless access examples (Azure/AWS/GCP)

    • Azure

    Set up OIDC trust in Azure by creating Workload identity federation for github actions (AD application registration)

    1. The GitHub Actions workflow requests an ID token from the external IdP (GitHub ID provider).

    2. The GitHub ID Provider issues the ID token to the external workload (GitHub actions).

    3. The login action in GitHub actions workflow sends token to Microsoft identity requesting an access token.

    4. Microsoft identity checks the trust relationship on the app registration (or managed Identity) and validates the ID token against the OIDC issuer URL (token.*.githubcontent.com) on the GitHub IdP.

    5. When the checks are satisfied, Microsoft identity platform sends an access token to the GitHub workflow.

    6. The Git Actions workflow accesses Azure resources using the access token to deploy in azure.

    Official OIDC login action
       Owner avatar  Azure/login


    • AWS

    Secretless connections from GitHub Actions to AWS using OIDC

    1. In AWS, set up OIDC trust between aws role and the GitHub ID token used in your GitHub Actions workflow.

    2. Action like configure-aws-credentials, will request a signed JWT with multiple claims during an workflow run.

    3. GitHub OIDC provider issues a signed JWT with multiple claims to the GitHub actions workflow.

    4. The action sends the JWT and the requested role to AWS.

    5. The JWT is validated in AWS and AWS sends a short-lived access token in exchange. With this token, it’s possible to access AWS resources.

    Official OIDC login action
      Owner avatar   aws-actions/configure-aws-credentials

    • GCP

    How does the GCP Workload Identity Federation work with Github Provider? |  by Pradeep Kumar Singh | Google Cloud - Community | Medium

    1. Set up OIDC trust by creating Workload Identity Pool, Workload Identity Provider and IAMs.

    2. A GitHub Action like google-github-actions/auth will request a signed JWT with multiple claims during an action job/workflow run.

    3. The action sends the JWT to GCP security Token Service to get a federated token in return.

    4. The auth action exchanges federated token received in previous step to get IAM access token.

    5. Using the access token received in step 4 workflow makes an API request to GCP for listing instances

    Official OIDC login action
      Owner avatar   google-github-actions/auth


    • We just covered the exciting journey from the birth of OAuth to secretless CI/CD authentication to Cloud.

    • Adopting OIDC will fortify your GitHub pipelines, so you can kiss your leaked credentials good bye.

    • Now, go cleanup all you repos because OIDC is the Mr Clean of Authentication your company hoped for!

    • I hope Oracle Cloud will join the party, and offer support for GitHub OIDC provider.

    • Next, I will write detailed guides about Multicloud deployment pipelines in GitHub actions,
                                                                         (using OIDC of course).

                   Stay tuned      

    Saturday, July 8, 2023

    GitHub Actions Cheat Sheet: What I learned from GitHub CI in 2 weeks


    This year I set a goal to explore and learn most popular CI solutions like GitLab, including all cloud native ones. My first pick had to be GitHub Actions, which I heard a lot of but never used. So I decided to plunge into it to see how rich the solution was. Since I only use CI for terraform deployments, I aimed to cover the features not the dev part. 

    This post is rather a long-mixed pack of titbits & notes out of my 2 weeks immersion, highlighting the particularities and features of GitHub Actions in the CI/CD landscape, with no specific order. This will hopefully get you started with GitHub Actions, whether you're familiar with CI or just a curious newcomer. 

    Table of contents

    GitHub Actions basics

    As most of you know, GitHub Actions is a platform that allows developers to automate workflows and tasks directly within GitHub repositories. Below is a brief description of key components of GitHub Actions:GitHub Actions: Concepts, Features, and a Quick Tutorial

    • Workflows: Configurable, automated process that executes one or more actions and defined by YAML files checked into the repository under .github/workflows.

    • Runner: a GitHub or self-hosted vm used to run your workflow with a list of tools preinstalled.

    • Triggers: Workflows can be triggered by specific events, such as push, pull requests, or scheduled times.

    • Actions: Are prebuilt tasks written in multiple languages that can be called in a workflow.

    • Marketplace: Where developers can discover, and use actions and workflows created by the community.

    • Secrets: Allow Devs to store and use sensitive information (credentials) securely in their workflows.

    • Integration: integrates with a numerous tools and services, to streamline dev & deployment workflows.

    • GitHub plans: Personal (GitHub Free or GitHub Pro), Organizations (GitHub Team, GitHub Enterprise)

    Ok, time to unveil the coffers of valuable git bits, curated from 35+ tabs of doc during my 2 weeks immersion.
    Buckle up!

    down pointing left hand index (brown)" Emoji - Download for free – Iconduck

    1. Default Runners

    GitHub Actions has a variety of default runners with 3 OS allowing you to run your workflows on different platforms

    • Ubuntu: 20, 22.04 LTS
    • MacOS: 11,12,13
    • Windows: 2019,2022

    Runners are vms that come with preinstalled software which allows to run any app or code in your pipeline.

    Language and Runtime

    • Bash, Node.js, Perl, Python,Ruby, Swift, Dash, C++, Julia, kotlin, Mono, MSbuild,…

    Package Management

    • Pip/pip3, Cpan, Helm,Yarn, Homebrew, Miniconda, Npm, NuGet, Pipx, RubyGems, Vcpkg,…


    • Git,SVN, Ansible,Packer, Terraform, Pulumi, Kubectl,Minikube, R, Heroku, Docker, Apt-fast, AzCopy,…

    CLI Tools

    • AWS CLI, Azure CLI, GitHub CLI, Google Cloud SDK, Alibaba Cloud CLI, Hub CLI, OpenShift CLI, ORAS CLI, Vercel CLI


    • JAVA, .NET Tools, Cached tools (Go, Node.js, Python, Pypy, Ruby), Cached Docker Images

    • PHP Tools, Haskell Tools, Rust Tools, PowerShell Tools and modules

    • Browsers: Google Chrome, chromium, Microsoft edge, Mozilla Firefox, Solenium server

    • Databases: sqllite, MySQL, PostreSQL, MSSQL tools (sqlcmd,sqlPackage)

    • Webservers: Nginx, Apache2

    • Mobile OS: Android Command Line Tools, Android Emulator, Android SDK platforms, Google play services, Google repo…

    2. Basic Structure of a Workflow

    The basic structure of a GitHub Actions workflow consists of triggers, jobs, workflow syntax, and commands.

    • Triggers define the events that can trigger a workflow, such as pushes to the repository or pull requests

    • Jobs define the individual tasks or steps that need to be executed as part of the workflow

    ExampleThis image has an empty alt attribute; its file name is image-1.png

      1. Name: Workflow name 

      2. on: Events that trigger a workflow (push on the branch git_actions for any change in paths section)

      3. env: Variables definition (hardcoded or imported from the environment such as secrets, vars)

      4. Permissions: To allow your actions to use the token_id

      5. Jobs section:

        • JobName, runner OS (runs-on) , environment, default shell and working directory

          • Steps section: checkout your code repo + other steps(run tests, build artifacts..)

        • Same for the next job…

    3. How are public Actions used?

    As show below, these prebuilt tasks can be easily called in a workflow and are written in multiple languages. But public actions can’t be referenced from self-hosted runners.They are publicly stored in GitHub Market place.

    # example: setup-node” action that downloads node.js and add it to the PATH

    steps: ... - uses: actions/setup-node@v3 with: node-version: 18

    4. Are public actions safe?

    Public GitHub actions can also be risky to your security and privacy. For instance, malicious actions could steal your secrets, modify your code, or compromise your server. Even if the actions are not malicious, they could have  vulnerabilities, or outdated dependencies that could affect your project.

                                                    Read more in this stackoverflow thread 
    Personally I don’t have time to check random people’s code for backdoors, so I only use actions from trusted sources, like official authentication actions from major cloud platforms and those made by GitHub.

    5. Difference between Public & Private Repositories

    • Beware : GitHub Actions logs of your public repo are visible to anyone as opposed to private ones.

    • Features like Environments, environment secrets, and environment protection rules are available in public repositories for all GitHub plans (Free, Pro, Team, Enterprise).

    • For access to environments, environment secrets, and deployment branches in private or internal. repositories, you must use GitHub Pro,Team, or GitHub Enterprise.

    • Actions and reusable workflows stored in private repositories cannot be used in public repositories.

    • GitHub doesn’t allow individual accounts to use self-hosted runners on public repositories.

    • You can share actions and reusable workflows from your private repo without making them public, by allowing GitHub workflows to access a private repository that contains the action or reusable workflow.

    6. GitHub Environment

    • Environment is an abstraction allowing to differentiate deployments(dev,prod,staging), prevent unauthorized deployments, preserve secrets, track changes and much more.

    • You can use environment protection rules to require a manual approval, delay a job, or restrict the environment to certain branches (i.e dev,staging,dev).

    • It’s Available for all public repositories and private repositories for Pro,Team, and Enterprise accounts 

    • Referencing environment in Git actions has 3 scopes:

      1. The entire workflow, by using env at the top level of the workflow file.

      2. The contents of a job within a workflow, by using jobs.<job_id>.env.

      3. A specific step within a job, by using jobs.<job_id>.steps[*].env.

    7. Environment Files

    • You can share custom environment variable with any subsequent steps in a workflow job by defining or updating the environment variable and writing this to the GITHUB_ENV environment file.

    • echo "{environment_variable_name}={value}" >> "$GITHUB_ENV"

    • For sharing environment between jobs or between workflows you will need GITHUB_OUTPUT

    8. GitHub Actions contexts & Variables

    • You can have repository, environment, as well as intra-workflow (job,step) variable level. 

    • Context is a collection of variables describing workflow runs, runner environments, jobs, steps, secrets & much more.The context reference syntax is ${{ context.variable }}.

    • github reference information about the workflow run & events that triggered the run. i.e github.repository

    • env Reference environment variable defined in the workflow.i.e ${{ env.MY_VARIABLE }}

    • vars context to access configuration variable values ${{ vars.MY_VAR }}

    • There’s a similar collection of variables called default variables within a runner (i.e GITHUB_RUN_ID).

    • If you want to see all the information that GitHub Actions has in a context, use the handy toJson function


      • Runner env variables are always interpolated on the runner vm. However, parts of a workflow are processed by GitHub Actions and are not sent to the runner

    9. GitHub Actions Security (Secrets) 

    • In GitHub Actions, secrets are used to store sensitive information like passwords, API keys, tokens etc.

    • There are organization, repository and environment level secrets.

    • In case of  conflict, organization is overridden by repository and repository is overridden by env values.

      • Secret names can’t contain spaces, not case-sensitive, & must be unique within the same level.

      • Secret names must not begin with the prefix GITHUB_.

      • secrets.GITHUB_TOKEN is a temporary token for each workflow run.

    • Exploitability and impact of untrusted input is real, read more in this excellent GitHub Securitylab post 

    How safe is it on public repos and forks

    • Secrets are safe to use in public repositories as they are automatically masked in build logs & show as *

    • But If in your workflow you create a credential from a secret (e.g. base64 an API key) then you should mask the new value so it doesn't leak in the build log.

    • With the exception of GITHUB_TOKEN, secrets are not passed to the runner when a workflow is triggered from a forked repository.

    • Secrets are not automatically passed to reusable workflows.

    • If you have a public repository, make sure all outside collaborators' PR require approval.

    What is a mask and is it really useful?

    You can mask, or hide, any sensitive data in GitHub Actions logs by adding a new step add-mask in a Workflow.

    ⛔ Unfortunately a variable will still be visible at least once before a mask is applied to it, and from then that value cannot be passed between runners. More examples here

    10.  Job dependency (Needs)

    • needs context: contains outputs from all jobs that are defined as a direct dependency of the current job.

    • By default all your jobs run in parallel in a workflow, but you often need them to run sequentially.


    • Use needs to add dependency between jobs

    • Other needs variables

    • needs.<job_id> : A single job that the current job depends on

    • needs.<job_id>.outputs : outputs of a job that the current job depends on.

    • needs.<job_id>.result: The result of a job that current job depends on. Possible values are success, failure, cancelled, or skipped.

    11. Artifact vs. Caching


    • Allow you to share data between running jobs and save them after the workflow is complete.

    • An artifact is a file or collection of files produced during a workflow run.
        Screenshot of the


    • Artifacts are used to save files after workflow ended. (handy for : Logs, manifest, statefile, config file, Tests Results, Reports, etc)

    • Caching is used to re-use data/files between jobs or workflows (i.e sharing build dependencies files that don't change often between jobs)   

    Beware: Both artifact and Caches are accessible to anyone in public repositories. Artifact can be downloaded, cache can be reused.

    12. Approval Triggers best practice

    • The default behavior of environment protection rules is to set manual approval for first-time contributors.

    • In that case, an attacker could create a simple and innocent pull request (like documentation update).

    • When accepted, his subsequent pull request could be malicious and automatically trigger the workflow.

    • So you need to set “Require approval for all outside collaborators” to ensure a more robust defense.

    • Private Manual approval: use below action if you don’t have an Enterprise/Pro account but still want manual approval without the use of environments.


    13. Random Actions Tips

    • Step ID vs step name:

      • ID is used as a reference, from other jobs or steps (i.e, in jobs. <job_id>. needs ).

      • Name is used for display purposes on GitHub.

    • How to run commands without specifying a step name: run: echo "Run my shell command "

    • Why install custom software via actions vs use local one in the runner (example setup-terraform):

      • terraform_setup action downloads the right version for you to ensure that updates to your infrastructure are safe and predictable (required_version).

      • Local version of Terraform might be too new for the required version, and will fail terraform init 


    • That’s it, a long but very useful cheat sheet that helped me and hopefully helps you explore GH Actions

    • Again if your workflow is in a public repo, remember below safety measures  ⏬  

      • Don't have any workflow with a pull_request trigger and never plan to make one.

      • Have the "Require approval for all outside collaborators" option for GitHub Actions turned on.

      • You must only invite trustworthy outside collaborators.

    • Next, I will write a series about Multicloud terraform deployments in GitHub actions

    Stay tuned