Skip to content
Merged
Show file tree
Hide file tree
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
267 changes: 175 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
# setup-cf

This action provides the following functionality for GitHub Actions users:
## Overview

- Installing a version of [Cloud Foundry CLI](https://github.com/cloudfoundry/cli) and adding it to the PATH
- Authenticating to the Cloud Foundry API using different grant types:
The `setup-cf` GitHub Action enables seamless integration with Cloud Foundry in your CI/CD pipelines. It simplifies the process of installing the Cloud Foundry CLI (cf cli), authenticating with Cloud Foundry services, and targeting specific organizations and spaces.

This action is particularly useful for teams who deploy applications to Cloud Foundry platforms and want to automate their deployment workflows.

## Features

- **Installation**: Automatically installs a specified version of [Cloud Foundry CLI](https://github.com/cloudfoundry/cli) and adds it to the PATH
- **Authentication**: Supports multiple authentication grant types:
- Password
- Client Credentials
- Client Credentials with JWT
- JWT Bearer Token Grant
- Target Org and Space
- **Targeting**: Automatically targets specified organization and space
- **GitHub OIDC Integration**: Works with GitHub's OpenID Connect (OIDC) for secure authentication

## Basic usage
## Basic Usage

See [action.yml](action.yml)
See [action.yml](action.yml) for complete action definition.

```yaml
steps:
Expand All @@ -28,113 +35,69 @@ steps:
run: cf apps
```

## Parameter
* `api`
* Url of the cloud controller api
* required
* `audience`
* audience for requesting the GitHub `id_token`
* `client_id`
* client id for `client_credentals` or `jwt-bearer`
* `client_secret`
* client secret for `client_credentals` or `jwt-bearer`
* `grant_type`
* grant type for access
* required
* default: `password`
* valid values:
* `password`
* `client_credentals`
* `jwt-bearer`
* `jwt`
* jwt for usage with `client_credentals` or `jwt-bearer`. If omitted, a GitHub `id_token` will be requested
* `username`
* username for `password` grant
* `password`
* password for `password` grant
* `org`
* Cloud Foundry organization name
* `skip_ssl_validation`
* Skip verification of the API endpoint
* default: `false`
* `space`
* Cloud Foundry space name
* `version`
* cf cli version
* required
* default: `8.12.0`

## Advanced

Requires at least UAA `77.20.4`.

### GitHub id_token

https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect

To allow a workflow to request an `id_token`, the workflow needs to have the correct permissions:
## Parameters

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

> The `sub` may not be used for the `user_name` attribute mapping, as it can include unsupported characters like `/` and `:`.
| Parameter | Description | Required | Default |
|-----------|-------------|:--------:|:-------:|
| `api` | URL of the Cloud Foundry API endpoint | Yes | - |
| `audience` | Audience for requesting the GitHub `id_token` | No | - |
| `client_id` | Client ID for `client_credentials` or `jwt-bearer` grant types | No | - |
| `client_secret` | Client secret for `client_credentials` or `jwt-bearer` grant types | No | - |
| `grant_type` | Authentication grant type (`password`, `client_credentials`, or `jwt-bearer`) | Yes | `password` |
| `jwt` | JWT token for use with `client_credentials` or `jwt-bearer`. If omitted with these grant types, a GitHub `id_token` will be requested automatically | No | - |
| `org` | Cloud Foundry organization name to target | No | - |
| `origin` | Identity provider origin to use for authentication with `jwt-bearer` or `password` | No | - |
| `username` | Username for `password` grant type | No | - |
| `password` | Password for `password` grant type | No | - |
| `skip_ssl_validation` | Skip verification of the API endpoint (not recommended for production) | No | `false` |
| `space` | Cloud Foundry space name to target | No | - |
| `version` | Cloud Foundry CLI version to install | Yes | `8.12.0` |

The sub can be customized https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-subject-claims-for-an-organization-or-repository
## Authentication Methods

### setup UAA for JWT Bearer Token Grant with GitHub
### Password Authentication

Add the GitHub OIDC provider and use e.g. the `repository_owner` claim as the `user_name`:
The simplest authentication method using username and password:

```
uaac 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", "addShadowUserOnLogin": true, "attributeMappings" : {"given_name": "repository_owner", "family_name": "repository_owner_id", "user_name": "repository_owner"}}}'
```yaml
- uses: vchrisb/setup-cf@v2
with:
api: ${{ secrets.CF_API }}
grant_type: password
username: ${{ secrets.CF_USERNAME }}
password: ${{ secrets.CF_PASSWORD }}
org: myorg
space: myspace
```

The UAA client used does need to include `urn:ietf:params:oauth:grant-type:jwt-bearer` in the `authorized_grant_types`.
This can be the default `cf` client, but also a dedicated one:
### JWT Bearer Token Grant with GitHub OIDC

```
uaac curl /oauth/clients -X POST -H "Content-Type: application/json" -d '{"client_id" : "jwt-bearer-client", "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"}'
```
This method leverages GitHub's OIDC provider for secure, token-based authentication:

```yaml
name: Jwt Bearer Flow using GitHub id_token
name: JWT Bearer Flow using GitHub id_token
on: [push]
permissions:
id-token: write
contents: read
id-token: write # Required for requesting the JWT
contents: read # Required for actions/checkout
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vchrisb/setup-cf@v2
with:
with:
api: ${{ secrets.CF_API }}
grant_type: jwt-bearer
org: test
space: dev
- name: run cf command
run: cf apps
run: cf apps
```

The cf cli will be authenticated as an user, which username is defined by the `attributeMappings`.
### Client Credentials with JWT

### setup UAA for JWT client credentials

The UAA client used does need to include `client_credentials` in the `authorized_grant_types`.

```
uaac client add setup-cf --scope uaa.none --authorities cloud_controller.read --authorized_grant_type "client_credentials"
```

Add the jwt configuration to the client.
The following example is for GitHub. You can also pass a different token using `jwt` parameter, but will need to adapt the configuration to your idp.
```
uaac client jwt add setup-cf --issuer https://token.actions.githubusercontent.com --subject repo:vchrisb/setup-cf:environment:Production --aud https://github.com/vchrisb
```
This method uses client credentials with JWT verification:

```yaml
name: Client Credentials using GitHub id_token
Expand All @@ -148,24 +111,144 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: vchrisb/setup-cf@v2
with:
with:
api: ${{ secrets.CF_API }}
client_id: setup-cf
grant_type: client_credentials
org: test
space: dev
- name: run cf command
run: cf apps
run: cf apps
```

## Advanced Configuration

### Setting up UAA for GitHub Authentication

#### Prerequisites
- UAA version 77.20.4 or higher
- Administrative access to UAA

#### Configuring UAA for JWT Bearer Token Grant with GitHub

1. Add the GitHub OIDC provider to UAA:

```
uaac 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": false,
"clientAuthInBody": true,
"relyingPartyId": "uaa",
"addShadowUserOnLogin": true,
"attributeMappings": {
"given_name": "repository_owner",
"family_name": "repository_owner_id",
"user_name": "repository_owner"
}
}
}'
```

2. Ensure your UAA client includes the JWT bearer grant type:

Either create a dedicated client to be used for JWT bearer grant:

```
uaac curl /oauth/clients -X POST -H "Content-Type: application/json" -d '{
"client_id": "jwt-bearer-client",
"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"
}'
```

Or add the grant type to the default `cf` client:

```
uaac client update cf \
--authorized_grant_types refresh_token,password,urn:ietf:params:oauth:grant-type:jwt-bearer
```

#### Configuring UAA for JWT Client Credentials

1. Create a client with client credentials grant type:

```
uaac client add setup-cf \
--scope uaa.none \
--authorities cloud_controller.read,cloud_controller.write,clients.read \
--authorized_grant_type "client_credentials"
```

The cf cli will be authenticated as the client `setup-cf`.
2. Add JWT configuration to the client:

## Developmet
```
uaac client jwt add setup-cf \
--issuer https://token.actions.githubusercontent.com \
--subject repo:vchrisb/setup-cf:environment:Production \
--aud https://github.com/vchrisb
```

### update action
Subject and Audience need to adapted to your repo and workflow.

### GitHub OIDC Configuration

To use GitHub's OIDC provider, your workflow must have the appropriate permissions:

```yaml
permissions:
id-token: write # Required for requesting the JWT
contents: read # Required for actions/checkout
```

Note: The `sub` claim from GitHub may contain characters like `/` and `:` which are not supported for the `user_name` attribute. Consider using alternative claims or customizing the subject as described in [GitHub's documentation](https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-subject-claims-for-an-organization-or-repository).

## Troubleshooting

### Common Issues

1. **Authentication Failures**
- Verify your credentials are correct
- Check that your client has the necessary authorities and grant types
- Ensure the UAA version is 77.20.4 or higher for JWT-based auth

2. **Permission Issues**
- For GitHub OIDC, make sure the workflow has `id-token: write` permission
- Verify the client or user has appropriate Cloud Foundry permissions

3. **Targeting Issues**
- Confirm the organization and space exist
- Check that the authenticated user/client has access to the specified org/space

### Debugging

Add the following to your workflow to see more detailed output:

```yaml
env:
CF_LOG_LEVEL: DEBUG
```

## Development

To update the action:

```
npm i -g @vercel/ncc
npm run format
npm run build
```

## License

This project is licensed under the MIT License - see the LICENSE file for details.
9 changes: 6 additions & 3 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ inputs:
jwt:
description: "jwt for usage with `client_credentials` or `jwt-bearer`."
required: false
org:
description: "org"
required: false
origin:
description: "origin"
required: false
username:
description: "username"
required: false
password:
description: "password"
required: false
org:
description: "org"
required: false
skip_ssl_validation:
description: "skip_ssl_validation"
required: false
Expand Down
Loading