Technology Blog Posts by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
SebastianRies
Advisor
Advisor
6,600

Abstract

When building CI/CD pipelines, developers are responsible for managing the credentials used by these pipelines for authentication to external systems. This traditionally requires developers to take care of the lifecycle of the credentials, including secure storage and regular rotation of the credentials, which comes with repeated efforts and might be error-prone.

This blog post demonstrates how to authenticate to the SAP BTP, Cloud Foundry environment from a GitHub Actions workflow using GitHub-issued short-lived JSON Web Tokens (JWTs), thereby eliminating the need for manual secret management and enabling secure, efficient CI/CD workflows. In particular, it provides a step-by-step guide to configuring the SAP Cloud Identity Services and the SAP BTP, Cloud Foundry environment, along with a practical example showing how to deploy an application to the Cloud Foundry environment using a GitHub Actions workflow.

While the blog post gives an example in the context of GitHub and GitHub Actions, the concepts can be applied to other environments providing environment-issued JWTs to their workloads or pipelines as well.

 

Overview

In modern computing environments, workloads running in those environments can retrieve short-lived credentials representing the workload's identity (and conveying workload-related attributes) via means built into the environment without the need for a developer-managed secret. In the context of GitHub, this pattern enables GitHub Actions workflows to retrieve short-lived JWTs from GitHub’s OpenID Connect Provider containing information about the context in which the workflow is running (e.g., GitHub organization and repository).

With the recent enhancements of the SAP BTP, Cloud Foundry environment and the SAP Cloud Identity Services, the GitHub-issued JWTs can be used to authenticate workflows when deploying to Cloud Foundry, eliminating the need for providing (and managing) a password.

The setup of the main components and their interactions is as follows (see also diagram below):

  • SAP Cloud Identity Services:
    • Federation with GitHub's OpenID Connect Provider as Corporate Identity Provider
    • User account representing GitHub Actions workflows (e.g., for all workflows running in a certain GitHub organization and repository)
    • 'SAP Business Technology Platform' Application configured for token-based login with GitHub-issued JWTs
  • SAP BTP, Cloud Foundry environment:
    • SAP Cloud Identity Services configured as 'custom identity provider for platform users' on the global account
    • User representing the GitHub Actions workflows added with role 'Space Developer' in the space that is targeted by the deployment
  • GitHub/GitHub Actions:
    • GitHub acts as OpenID Connect Provider issuing JWTs available to GitHub Actions workflows.
    • GitHub Actions workflows use CF CLI (>= v8.12.0) for authenticating and deploying to the SAP BTP, Cloud Foundry environment.

workload-cf-access.png

 

Note: In this blog post, github.example.com refers to a fictional GitHub Enterprise server. Please adjust these references to match your own GitHub server or CI/CD environment.

 

Prerequisites

To follow the steps provided in this blog post, you need to have access to the SAP BTP, Cloud Foundry environment (see: Getting Started in the Cloud Foundry Environment | SAP Help Portal) and administrative access to a tenant in SAP Cloud Identity Services (see: Get Your Tenant | SAP Help Portal). Furthermore, you need to be able to set up a GitHub repository that can run GitHub Actions workflows.

 

Configuration Steps

Step 1: Configure SAP Cloud Identity Services

Open the admin console of your SAP Cloud Identity Services tenant in the browser.

Step 1.1: Create a (Helper) User for GitHub Actions Workflows

When defining the attributes of the (helper) user for GitHub Actions workflows, consider this proposal:

  • Use the first name and last name to give a human-readable hint on the environment in which the GitHub Actions workflows represented by this user are running.
  • Use the 'email' attribute as a unique identifier. The email attribute will serve two purposes:
    • It serves as a unique identifier for the (helper) user in the SAP Cloud Foundry Identity Services and in the SAP BTP, Cloud Foundry environment.
    • It is used as part of the mapping of the GitHub-issued JWT to the user.

Following this proposal, create a user that represents the GitHub Actions workflows running in a given GitHub organization and repository as described below:

Go to 'Users & Authorizations' -> 'User Management' -> Click '+ Add', and configure the required parameters as:

  • First name: <orgName>/<repositoryName> (e.g., myOrg/myRepo, where myOrg/myRepo refers to the GitHub organization and repository running the GitHub Actions workflow which you want to deploy to CF)
  • Last name: <githubServerDomain> (e.g., github.example.com)
  • Email: repo/<orgName>/<repoName>@<emailDomain> (e.g., repo/myOrg/myRepo@github.example.com, make sure to choose an appropriate email domain)
  • Login Name: <leave empty - no value required>
  • User Type: Public
  • Account Activation: select Set status active

Step 1.2: Create a Group for GitHub CI/CD Users and Add the User

Go to 'Users & Authorizations' → 'Groups'

  • Create a group with 'Name' and 'Display Name': GitHub CI/CD
  • Note: No application-specific setting required.

On the newly created group, under 'user members' click '+ Add' and add the previously created user to this group.

Step 1.3: Add GitHub as Corporate Identity Provider

Add Identity Provider for GitHub

Go to 'Identity Providers' → 'Corporate Identity Providers' → Click '+ Create'

Create a new Identity Provider with Display Name <githubServerDomain> (e.g., github.example.com) and type 'OpenID Connect Compliant'.

Do the following steps on the 'list items' belonging to the newly created corporate identity provider.

Configure the Discovery URL (OpenID Connect Configuration Endpoint)

Go to the list item 'Trust' → 'OpenID Connect Configuration' and provide the discovery URL of the OpenID Connect Provider of the GitHub environment. The discovery URL is specific to your GitHub environment:

After providing the discovery URL, click 'Load' and 'Save'.

Configure Token to User Mapping via 'Enriched Token Claims'

Go to the list item 'Trust' → 'Enriched Token Claims' and add the following claim-value pair:

  • Claim: NameID
  • Value: repo/${repository}@<emailDomain> (e.g., repo/${repository}@github.example.com)

This enables the mapping of the incoming GitHub-issued JWT using the repository claim provided in the token to a user with an email address with the pattern repo/<orgName>/<repoName>@<emailDomain>.

For additional information see:

Configure 'Identity Federation' to Restrict the GitHub IdP to GitHub CI/CD Users Only

Go to the list item 'Single Sign On' → 'Identity Federation'.

  • Enable 'Use Identity Authentication user store'
  • Enable 'Allow Identity Authentication users only'
  • Add restriction based on group membership by clicking 'Add' next to 'Assigned User Groups' and selecting the previously created user group GitHub CI/CD.

 

Step 1.4: Configure 'SAP Business Technology Platform' Application

Go to the tile 'Applications & Resources' → 'Applications'.

Select the application named 'SAP Business Technology Platform' (representing the SAP BTP, Cloud Foundry environment in your tenant). Note: If the application 'SAP Business Technology Platform' does not show up in the list of applications, you need to establish trust between the BTP Global Account and your SAP Cloud Identity Services tenant first (see step 2 below) and then complete this step.

Go to the list item 'Trust' → 'Conditional Authentication' and click 'Add Rule', and add a new rule with:

  • Identity Provider: github.example.com
  • Email domain: <emailDomain> e.g., github.example.com
  • Group: GitHub CI/CD

Finally, click 'OK' on the new rule, and click 'Save' on 'Conditional Authentication' (top right corner).

 

Step 2: Configure SAP BTP, Cloud Foundry environment

Open the SAP BTP cockpit in the browser.

In the following it is assumed that you already have a global account and subaccount on SAP Business Technology Platform (SAP BTP), as well as access to the SAP BTP, Cloud Foundry environment, such that an authorized user can successfully deploy an application. If this is not the case, please see the documentation at: SAP Business Technology Platform (SAP BTP) | SAP Help Portal and Getting Started with an Enterprise Account in the Cloud Foundry Environment | SAP Help Portal.

Step 2.1: Establish Trust for Platform Users (Global Account)

Establish trust between your global account and your SAP Cloud Identity Services tenant as 'Custom Identity Provider for Platform Users' (see Establish Trust and Federation of Custom Identity Providers for Platform Users).

Note: Remember to complete step 1.4, if not yet done.

Step 2.2: Add (Helper) User to Space

Select a subaccount and navigate to 'Cloud Foundry->Spaces'. Then, select the space that the GitHub Actions workflow should have access to (create a new space first, if required).

Add the (helper) user as member to the space with role 'Space Developer':

  • Go to 'Space Members' and click 'Add Members'
  • Add a new user with the parameters:
    • email: <email-address-of-helper-user>, .e.g, repo/myOrg/myRepo@github.example.com
    • origin: <origin of the custom platform IdP from the trust configuration above> - e.g., myTenant-platform
    • role: Space Developer

Note: The role 'Space Developer' enables the user to push to this space.

 

Push an Application using a GitHub Actions Workflow

Step 3: Create a GitHub Repository and Push an Application

For pushing an application using a GitHub Actions workflow, you need a repository (e.g., myOrg/myRepo) on a GitHub server (e.g. github.example.com) which contains a GitHub Actions workflow that fetches a short-lived JWT from GitHub and uses this token for authentication in the login to the SAP BTP, Cloud Foundry environment.

Step 3.1: Create a GitHub Repository with a Hello World Sample

A GitHub repository with a simple 'Hello World Sample' may look as described below. Note: Make sure that the GitHub repository has GitHub Actions enabled and make sure that the configuration of GitHub, SAP Cloud Identity Services, and SAP BTP, Cloud Foundry environment fit together.

The 'Hello World Sample' GitHub repository may have the following structure and contain the following files:

<repository-root-directory>/
├── manifest.yml
├── .github/
│   └── workflows/
│       └── deploy.yml
└── resources/
    └── hello.json

The manifest.yml defines an application manifest for deploying to the Cloud Foundry environment. The manifest given below, will deploy a staticfile_buildbpack serving the hello.json file.

manifest.yml

applications:
- name: github-cf-access
  disk_quota: 1G
  instances: 1
  memory: 256M
  random-route: true
  path:
    ./resources
  buildpacks:
    - staticfile_buildpack

The resources/hello.json file contains some sample content to deploy.

resources/hello.json

{
    "hello": "from GitHub Actions"
}

 

Finally, the deploy.yml contains the definition of the GitHub Actions workflow that pushes the application to the SAP BTP, Cloud Foundry environment.

Notes:

  • When requesting the JWT from GitHub, make sure to request a token where the audience claim equals the 'issuer' of the SAP Cloud Identity Services tenant which is configured as 'custom identity provider for platform users'.
  • Authentication to the SAP BTP, Cloud Foundry environment with a JWT requires at least Cloud Foundry CLI version v8.12.0.

Before running the script below, review it, and adjust the GitHub Actions runner, if needed. Note: There is no need to adjust the inputs, as they actual values can be provided when running the workflow via the UI.

.github/workflows/deploy.yml

 

  name: Deploy

  on:
    workflow_dispatch:
      inputs:
        cfApiEndpointUrl:
          description: 'Cloud Foundry environment API endpoint'
          default: '<e.g., https://api.cf.eu10.hana.ondemand.com>'
          required: true
          type: string
        cfOrg:
          description: 'CF org name'
          default: '<e.g., myCfOrg>'
          required: true
        cfSpace:
          description: 'CF space name'
          default: '<e.g., myCfSpace>'
          required: true
        userOrigin:
          description: 'The "origin-identifier" of your custom platform IdP (see origin of the space user)'
          default: '<e.g., myTenant-platform>'
          required: true
          type: string
        tenantIssuerUri:
          description: 'Issuer URI of your SAP Cloud Identity Services tenant'
          default: '<e.g., https://myTenant.accounts.ondemand.com>'
          required: true
  
  jobs:
    deploy:
      runs-on: [ ubuntu-latest ]
      permissions:
        id-token: write # This is required for requesting the JWT
        contents: read  # This is required for actions/checkout
      steps:
        - name: Show provided parameters
          run: |
            echo "Provided parameters:"
            echo '${{ toJson(inputs) }}' | jq -r 'to_entries | .[] | "- \(.key): \(.value)"'

        - name: Check out repository code
          uses: actions/checkout@v4
  
        - name: Download CF CLI
          run: |
            cf_version="8.12.0"
            mkdir .cfcli
            curl -L "https://github.com/cloudfoundry/cli/releases/download/v${cf_version}/cf8-cli_${cf_version}_linux_x86-64.tgz" | tar -zvx -C .cfcli
            echo "$(pwd)/.cfcli" >> "$GITHUB_PATH"

        - name: Get short-lived GitHub-issued JWT
          id: get-github-jwt
          run: |
            githubJwt=$(curl -s -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" -H "Content-Type: application/json" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{inputs.tenantIssuerUri}}" | jq -r '.value')
            echo $githubJwt | jq -R 'split(".") | .[0],.[1] | @base64d | fromjson'
            echo "githubJwt=$githubJwt" >> $GITHUB_OUTPUT

        - name: Set Cloud Foundry API
          run: |
            cf api ${{inputs.cfApiEndpointUrl}}
            
        - name: Login to Cloud Foundry environment
          run: |
            cf auth --assertion ${{steps.get-github-jwt.outputs.githubJwt}} --origin ${{inputs.userOrigin}}

        - name: Target Cloud Foundry org and space
          run: |
            cf target -o '${{inputs.cfOrg}}' -s '${{inputs.cfSpace}}'
  
        - name: Deploy to Cloud Foundry environment
          run: |          
            cf push --strategy rolling
  
        - name: Logout from Cloud Foundry environment
          if: always()
          run: |
            cf logout

 

Step 3.2: Deploy to SAP BTP, Cloud Foundry environment using GitHub Actions

In order to run the GitHub Actions workflow go to 'Actions' -> 'Deploy' and click 'Run workflow' and override the provided default values in the 'run workflow UI' with your specific parameters. Finally, click the green 'Run workflow' button.

Once the workflow has been successfully executed:

  • Check the logs of the GitHub Actions workflow
  • Access the deployed application at: https://<app-domain>/hello.json (the domain under which the application is available can be found in the workflow's logs at the end of the step 'Deploy to Cloud Foundry environment').

 

Additional Notes

  • As now GitHub Actions workflows can deploy to the SAP BTP, Cloud Foundry environment, make sure to control access to your GitHub repository and execution of GitHub Actions workflows accordingly.
  • You might consider adjusting the configuration given above according to your needs, e.g., adjust the email address pattern or email domain of the (helper) user and/or adjust the mapping of the GitHub-issued JWT to the user account in SAP Cloud Identity Services. Note: The character set supported in email addresses is limited.
  • While this blog post demonstrates how to authenticate to the SAP BTP, Cloud Foundry environment with a GitHub-issued JWT from a GitHub Actions workflow, you can adopt the approach to authenticate to the SAP BTP, Cloud Foundry environment also with JWTs issued by other environments after establishing trust to your SAP Cloud Identity Services tenant and managing the user’s authorizations in the Cloud Foundry environment.
  • If you have other use cases in which you like to authenticate workloads to SAP Cloud Identity Services, but you actually need an SAP Cloud Identity Services-issued access token to authenticate to a protected API (instead of login to the Cloud Foundry environment), then have a look at SAP Cloud Identity Services' functionality to authenticate applications with JWTs as described at Configure JWT for OAuth Client Authentication | SAP Help Portal.

 

Conclusion

By using GitHub-issued, short-lived JWTs and integrating GitHub Actions workflows with SAP Cloud Identity Services and the SAP BTP, Cloud Foundry environment, developers can enhance security, simplify automation, and streamline CI/CD workflows. Especially, this approach eliminates the need for managing long-lived credentials and reduces operational overhead.

 

Additional links

SAP Cloud Identity Services

GitHub

6 Comments