Skip to content
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

Allow creating a trust relationship with Github Actions OIDC provider to retrieve an uaa access token using a Github id_token #2838

Open
vchrisb opened this issue Apr 18, 2024 · 8 comments

Comments

@vchrisb
Copy link

vchrisb commented Apr 18, 2024

What version of UAA are you running?

  • 76.26.0
  • 77.1.0

How are you deploying the UAA?

I am deploying the UAA

  • as part of a commercial Cloud Foundry distribution

What did you do?

JWT Bearer Token Grant by adding the Github OIDC Provider:

I added the Github OIDC provider using non existing credentials and used the repository_owner claim as the user_name:

uaa curl /identity-providers -X POST -H "Content-Type: application/json" -d '{"type": "oidc1.0", "name": "Github", "originKey": "github", "config": {"discoveryUrl": "https://token.actions.githubusercontent.com/.well-known/openid-configuration", "scopes": ["read:user", "user:email"], "linkText": "Login with Github", "showLinkText": false, "addShadowUserOnLogin": true, "clientAuthInBody": true, "relyingPartyId": "uaa", "relyingPartySecret": "uaa", "addShadowUserOnLogin": true, "attributeMappings" : {"given_name": "repository_owner", "family_name": "repository_owner_id", "user_name": "repository_owner"}}}'

The sub can't be used for the user_name, as it includes unsupported characters like / and :. I used the repository_owner claim for the user_name.

UAA client required for authentication:

uaa curl /oauth/clients -X POST -H "Content-Type: application/json" -d '{"client_id" : "jwt-bearer-client", "client_secret" : "secret", "access_token_validity": 1800,  "authorities" : [ "uaa.resource" ], "authorized_grant_types" : [ "urn:ietf:params:oauth:grant-type:jwt-bearer" ], "scope": ["openid", "cloud_controller.read"], "allowedproviders" : [ "github" ], "name" : "JWT Bearer Client"}'

Finally the request to get an access_token (uaa has to be used for requesting the id_token)

curl -u 'jwt-bearer-client:secret' -d 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<github id token>' https://uaa.sys.domain.com/oauth/token

The resulting access_token:

{
  "jti": "a6bfcbc1e851444196ce76779567cbed",
  "sub": "c8068c6a-8e21-408f-9532-0f3a413f988e",
  "scope": [
    "openid",
    "cloud_controller.read"
  ],
  "client_id": "jwt-bearer-client",
  "cid": "jwt-bearer-client",
  "azp": "jwt-bearer-client",
  "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
  "user_id": "c8068c6a-8e21-408f-9532-0f3a413f988e",
  "origin": "github",
  "user_name": "vchrisb",
  "email": "[email protected]",
  "rev_sig": "7ec0c4f2",
  "iat": 1713450185,
  "exp": 1713493385,
  "iss": "https://uaa.sys.domain.com/oauth/token",
  "zid": "uaa",
  "aud": [
    "cloud_controller",
    "openid",
    "jwt-bearer-client"
  ]
}

Example Github workflow to retrieve the id_token using a custom github action vchrisb/setup-cf:

name: CI
permissions:
  id-token: write # This is required for requesting the JWT
  contents: read  # This is required for actions/checkout

on:
  push:

jobs:
  deploy:
    name: password
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: setup cf cli
      uses: vchrisb/[email protected]
      with:
        api: ${{ secrets.CF_API }}
        client_id: ${{ secrets.CF_CLIENT_ID }}
        client_secret: ${{ secrets.CF_CLIENT_SECRET }}
        grant_type: jwt-bearer
        org: test
        space: dev
    - name: access cloud foundry api
      run: cf push --strategy rolling

It is possible to get an uaa access_token using the JWT Bearer Token Grant, but this has limitations:

  • adding the identity provider requires fake credentials
  • the sub, or combination of claims, can't be used for the user_name
  • a client_secret is required

client_credentials Grant:

I also tried using the client_credentials Grant with private_key_jwt to retrieve an UAA access_token by providing a Github id_token.
For that I created a UAA client, which name matched the sub claim of the id_token. I configured the client's jwks_uri with the one of Github. An authentication does fail, because the iss claim does not include the client_id, which is required by the specs for this flow.

Conversation on that in UAA Slack.

What did you expect to see? What goal are you trying to achieve with the UAA?

I would like to be able to access the cloud foundry api from a Github workflow using temporary credentials.

Background

From Github Security hardening with OpenID Connect:

GitHub Actions workflows are often designed to access a cloud provider (such as AWS, Azure, GCP, or HashiCorp Vault) in order to deploy software or use the cloud's services. Before the workflow can access these resources, it will supply credentials, such as a password or token, to the cloud provider. These credentials are usually stored as a secret in GitHub, and the workflow presents this secret to the cloud provider every time it runs.

However, using hardcoded secrets requires you to create credentials in the cloud provider and then duplicate them in GitHub as a secret.

With OpenID Connect (OIDC), you can take a different approach by configuring your workflow to request a short-lived access token directly from the cloud provider. Your cloud provider also needs to support OIDC on their end, and you must configure a trust relationship that controls which workflows are able to request the access tokens. Providers that currently support OIDC include Amazon Web Services, Azure, Google Cloud Platform, and HashiCorp Vault, among others.

Github Actions does provide an id_token to workflows with following relevant claims from Understanding the OIDC token:

  • sub, e.g. repo:octo-org/octo-repo:environment:prod, the template used to generate the sub value can be configured
  • iss is always https://token.actions.githubusercontent.com
  • aud can be configured when requesting the id_token in the workflow

Example Job to retrieve the id_token:

  job:
    environment: Production
    runs-on: ubuntu-latest
    steps:
    - name: Install OIDC Client from Core Package
      run: npm install @actions/[email protected] @actions/http-client
    - name: Get Id Token
      uses: actions/github-script@v7
      id: idtoken
      with:
        script: |
          const coredemo = require('@actions/core')
          let id_token = await coredemo.getIDToken('https://uaa.sys.domain.com/oauth/token')
          coredemo.setOutput('id_token', id_token)

The Github OIDC provider is solely exposing the JSON web key (JWK) endpoint: https://token.actions.githubusercontent.com/.well-known/jwks to be used to validate the Github id_token.

Github OIDC openid-configuration

The Github documentation does have examples how to create a trust relation with AWS, Azure, GCP and Vault.

(The Github actions OIDC provider is not the same as the Oauth2 provider for Github Oauth2 Apps.)

Ask

I want to use a short live token to interact with the cloud foundry api.
For that, I would like to be able to create a trust relation from UAA to Github, (and other CI systems like GitLab) to use the id_token provided in the workflow to retrieve an UAA client access_token.
The UAA client might be created using the sub claim of the id_token or a pre created client might be pattern matched against the sub.
The client will be used to assign a cloud foundry space role to it.

@cf-gitbot
Copy link

We have created an issue in Pivotal Tracker to manage this:

https://www.pivotaltracker.com/story/show/187454040

The labels on this github issue will be updated when the story is started.

@vchrisb vchrisb changed the title Allow creating a trust relationship with Github OIDC provider to retrieve an uaa access token using a Github id_token Allow creating a trust relationship with Github Actions OIDC provider to retrieve an uaa access token using a Github id_token Apr 18, 2024
@strehle
Copy link
Member

strehle commented Apr 18, 2024

Ok, thank you. I know understand what you want and I have a plan in my mind howto solve it... the Prio is currently so that I want solve PR 2813 and then I can start to create some PRs for this fix. I think I will solve this issue with more than one PR, because the issue now exists in some parts, but finally the client credential flow should work and JWT bearer as well

@strehle
Copy link
Member

strehle commented Apr 18, 2024

@peterhaochen47 , FYI

@vchrisb
Copy link
Author

vchrisb commented Apr 18, 2024

thank you @strehle
I did some more testing and had success with jwt bearer grant.

I updated the initial issue with the findings

@peterhaochen47
Copy link
Member

peterhaochen47 commented Apr 19, 2024

Ok cool, seems like there's at least a workaround / a hack.

We'll keep the issue open and in mind but likely won't pursue a fix immediately, because being compatible with a non-standard OIDC is not on our current roadmap. Nevertheless, your issue will help others & help us gather data point about the demand for this.

@vchrisb
Copy link
Author

vchrisb commented Apr 19, 2024

My last comment might have been misleading.

For the jwt bearer token grant that is probably right, but the original ask is to support a trust relation.
To use the jwt bearer token grant for this problem, is already a workaround by itself.

AWS, Azure, GCP and Vault do support a trust with amongst others GitHub and Gitlab.
From a bit more research, I think they actually use OIDC Token Exchange RFC 8693?

Here is the original github roadmap issue: github/roadmap#376

@damzog
Copy link

damzog commented Jun 6, 2024

Hi @vchrisb great stuff! I did not fully get it yet but it seems this requirement matches very much with one of our own: We have Azure Entra as Identity provider and would like to enable API developers to take an Azure Entra Bearer token from there clients and then use this token to execute API calls to a Cloudfoundry instance using UAA (knowing the same identities) on behalf the identy from the Azure token.

@damzog
Copy link

damzog commented Jun 14, 2024

Hi @vchrisb , I have been able to use this pattern to create a web app offering SSO with Microsoft Entra which exchanges the Azure id-token to a UAA issued access-token and uses it to call the CF Api with it.

In this scenario it is actually ok to have a uaa client that is used be the server side part of the app to do the token exchange. It is a security gain in any case.

Now in your case I was wondering: Wouldn't it make sense to put a reverse proxy between your github runner and the cf api that actually does the token exchange using a uaa client?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

5 participants