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

Add docs for using OpenID Connect with the Octopus API #2009

Merged
merged 14 commits into from
Nov 1, 2023
Merged
2 changes: 2 additions & 0 deletions dictionary-octopus.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ WIXUI
workertools
xlarge
xmark
RSASSA
jwks
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 55 additions & 42 deletions src/pages/docs/octopus-rest-api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ navSection: Octopus REST API
description: Octopus integrates with build servers, scripts, external applications and anything else with its REST API.
navOrder: 130
---
import RestApi from 'src/shared-content/concepts/rest-api.include.md';

import RestApi from "src/shared-content/concepts/rest-api.include.md";

<RestApi />

Expand Down Expand Up @@ -40,7 +41,11 @@ https://<your-octopus-url>/api

Replacing `<your-octopus-url>` with the URL that you host your Octopus instance on.

You'll need an API key to access the API. You can get your API key from your profile page on the Octopus Web Portal.
The API supports two methods of authentication.

### API Key

You can get your API key from your profile page on the Octopus Web Portal.

Once you have a key, you can provide it to the API in the following ways:

Expand All @@ -51,6 +56,14 @@ Once you have a key, you can provide it to the API in the following ways:
Learn more about [how to create an API key](/docs/octopus-rest-api/how-to-create-an-api-key).
:::

### OpenID Connect

Octopus supports using OpenID Connect (OIDC) for service accounts to obtain an access token which can then be used to authenticate API requests.

Any issuer that can generate signed OIDC tokens which can be validated anonymously is supported, however first-class support for GitHub Actions is provided with the [`OctopusDeploy/login`](https://github.com/OctopusDeploy/login) action.

For more information see [Using OpenId Connect with the Octopus API](/docs/octopus-rest-api/openid-connect).

## REST API Swagger documentation \{#api-swagger-docs}

Octopus includes the default Swagger UI for displaying the API documentation in a nice human readable way. To browse that UI just open your browser and go to `https://<your-octopus-url>/swaggerui/`. The original Non-Swagger API page is still available and can always be accessed via `https://<your-octopus-url>/api/`.
Expand All @@ -63,71 +76,71 @@ You can view the API through the Octopus Demo server at [demo.octopus.app/swagge

## REST API links \{#api-links}

All resources returned by the REST API contain links to other resources. The idea is that instead of memorizing or hard-coding URL's when using the API, you should start with the root API resource and use links to navigate.
All resources returned by the REST API contain links to other resources. The idea is that instead of memorizing or hard-coding URL's when using the API, you should start with the root API resource and use links to navigate.

For example, a `GET` request to `/api` returns a resource that looks like:

```json
```json
{
"Application": "Octopus Deploy",
"Version": "2022.1.2386",
"ApiVersion": "3.0.0",
"InstallationId": "9f155416-5d9e-4e19-ba58-b710d4edf336",
"Links": {
"Self": "/api",
"Accounts": "/api/Spaces-1/accounts{/id}{?skip,take,ids,partialName,accountType}",
"Environments": "/api/Spaces-1/environments{/id}{?name,skip,ids,take,partialName}",
"Machines": "/api/Spaces-1/machines{/id}{?skip,take,name,ids,partialName,roles,isDisabled,healthStatuses,commStyles,tenantIds,tenantTags,environmentIds,thumbprint,deploymentId,shellNames,deploymentTargetTypes}",
"Projects": "/api/Spaces-1/projects{/id}{?name,skip,ids,clone,take,partialName,clonedFromProjectId}",
"RunbookProcesses": "/api/Spaces-1/runbookProcesses{/id}{?skip,take,ids}",
"RunbookRuns": "/api/Spaces-1/runbookRuns{/id}{?skip,take,ids,projects,environments,tenants,runbooks,taskState,partialName}",
"Runbooks": "/api/Spaces-1/runbooks{/id}{?skip,take,ids,partialName,clone,projectIds}",
"RunbookSnapshots": "/api/Spaces-1/runbookSnapshots{/id}{?skip,take,ids,publish}",
"Feeds": "/api/feeds{/id}{?skip,take,ids,partialName,feedType,name}",
"Tasks": "/api/tasks{/id}{?skip,active,environment,tenant,runbook,project,name,node,running,states,hasPendingInterruptions,hasWarningsOrErrors,take,ids,partialName,spaces,includeSystem,description,fromCompletedDate,toCompletedDate,fromQueueDate,toQueueDate,fromStartDate,toStartDate}",
"Variables": "/api/Spaces-1/variables{/id}{?ids}",
"Web": "/app"
}
"Application": "Octopus Deploy",
"Version": "2022.1.2386",
"ApiVersion": "3.0.0",
"InstallationId": "9f155416-5d9e-4e19-ba58-b710d4edf336",
"Links": {
"Self": "/api",
"Accounts": "/api/Spaces-1/accounts{/id}{?skip,take,ids,partialName,accountType}",
"Environments": "/api/Spaces-1/environments{/id}{?name,skip,ids,take,partialName}",
"Machines": "/api/Spaces-1/machines{/id}{?skip,take,name,ids,partialName,roles,isDisabled,healthStatuses,commStyles,tenantIds,tenantTags,environmentIds,thumbprint,deploymentId,shellNames,deploymentTargetTypes}",
"Projects": "/api/Spaces-1/projects{/id}{?name,skip,ids,clone,take,partialName,clonedFromProjectId}",
"RunbookProcesses": "/api/Spaces-1/runbookProcesses{/id}{?skip,take,ids}",
"RunbookRuns": "/api/Spaces-1/runbookRuns{/id}{?skip,take,ids,projects,environments,tenants,runbooks,taskState,partialName}",
"Runbooks": "/api/Spaces-1/runbooks{/id}{?skip,take,ids,partialName,clone,projectIds}",
"RunbookSnapshots": "/api/Spaces-1/runbookSnapshots{/id}{?skip,take,ids,publish}",
"Feeds": "/api/feeds{/id}{?skip,take,ids,partialName,feedType,name}",
"Tasks": "/api/tasks{/id}{?skip,active,environment,tenant,runbook,project,name,node,running,states,hasPendingInterruptions,hasWarningsOrErrors,take,ids,partialName,spaces,includeSystem,description,fromCompletedDate,toCompletedDate,fromQueueDate,toQueueDate,fromStartDate,toStartDate}",
"Variables": "/api/Spaces-1/variables{/id}{?ids}",
"Web": "/app"
}
}
```

:::div{.hint}
Note: the `Links` collection example above has been significantly reduced in size for demonstration purposes.
:::

You can follow the links in the result to navigate around the API; for example, by following the `Projects` link, you'll find a list of the projects on your Octopus server.
You can follow the links in the result to navigate around the API; for example, by following the `Projects` link, you'll find a list of the projects on your Octopus server.

Since the format and structure of links may change, it's essential that clients avoid hardcoding URL's to resources, and instead rely on starting at `/api` and navigating from there.
Since the format and structure of links may change, it's essential that clients avoid hardcoding URL's to resources, and instead rely on starting at `/api` and navigating from there.

### URI templates

Some links (mainly to collections) use URI templates as defined in [RFC 6570](http://tools.ietf.org/html/rfc6570). If in doubt, a client should assume that any link is a URI template.

### Collections

Collections of resources also include links. For example, following the `Environments` link above will give you a list of environments.
Collections of resources also include links. For example, following the `Environments` link above will give you a list of environments.

```json
{
"ItemType": "Environment",
"TotalResults": 20,
"ItemsPerPage": 10,
"NumberOfPages": 2,
"LastPageNumber": 1,
"Items": [
// ... a list of environments ...
],
"Links": {
"Self": "/api/Spaces-1/environments?skip=0&take=10",
"Template": "/api/Spaces-1/environments{?skip,ids,take,partialName}",
"Page.All": "/api/Spaces-1/environments?skip=0&take=2147483647",
"Page.Next": "/api/Spaces-1/environments?skip=10&take=10",
"Page.Current": "/api/Spaces-1/environments?skip=0&take=10"
}
"ItemType": "Environment",
"TotalResults": 20,
"ItemsPerPage": 10,
"NumberOfPages": 2,
"LastPageNumber": 1,
"Items": [
// ... a list of environments ...
],
"Links": {
"Self": "/api/Spaces-1/environments?skip=0&take=10",
"Template": "/api/Spaces-1/environments{?skip,ids,take,partialName}",
"Page.All": "/api/Spaces-1/environments?skip=0&take=2147483647",
"Page.Next": "/api/Spaces-1/environments?skip=10&take=10",
"Page.Current": "/api/Spaces-1/environments?skip=0&take=10"
}
}
```

The links at the bottom of the resource allow you to traverse the pages of results. Again, instead of hard-coding query string parameters, you can look for a `Page.Next` link and follow that instead.
The links at the bottom of the resource allow you to traverse the pages of results. Again, instead of hard-coding query string parameters, you can look for a `Page.Next` link and follow that instead.

## REST API and Spaces \{#api-and-spaces}

Expand Down
168 changes: 168 additions & 0 deletions src/pages/docs/octopus-rest-api/openid-connect/github-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
layout: src/layouts/Default.astro
pubDate: 2023-09-27
modDate: 2023-09-27
title: Using OpenID Connect with Octopus and GitHub Actions
description: How to use OpenID Connect to interact with Octopus in GitHub Actions
navOrder: 30
hideInThisSection: true
---

Octopus has first-class support for using OpenID Connect (OIDC) within GitHub Actions when using the [`OctopusDeploy/login`](https://github.com/OctopusDeploy/login) action.

:::div{.hint}
Using OIDC to access the Octopus API is only supported for service accounts, to access the API for a user account please use [an API key](/docs/octopus-rest-api/how-to-create-an-api-key).
:::

For more information on OIDC in GitHub Actions see [Security hardening with OpenID Connect](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect).

## Configuring an OIDC identity for GitHub Actions
geofflamrock marked this conversation as resolved.
Show resolved Hide resolved

To configure an OIDC identity for a GitHub Actions workflow:

1. Go to Configuration -> Users and either create a new service account or locate an existing one.
2. Open the OpenID Connect section.
3. Click the New OIDC Identity button.
4. Select GitHub Actions as the issuer type.
5. Enter the details of your repository and how you want to filter the workflow runs that can authenticate using OIDC.
6. Click Save.

:::div{.hint}
Multiple OIDC identities can be added for a service account, these could be for workflow runs from the same repository, or separate repositories depending on your needs.
:::

### Filtering workflow runs

The [`OctopusDeploy/login`](https://github.com/OctopusDeploy/login) action obtains an ID token from GitHub and then exchanges it for an Octopus access token.

The ID token that GitHub generates contains a subject (the `sub` property in the ID token), which is generated based on the details of the workflow that is being run. The subject of the OIDC identity in Octopus needs to match this subject exactly in order for the access token to be issued, the Octopus Portal will help you to generate this subject correctly.

The details of the subject that GitHub Actions will generate follow specific rules including:

- Whether a GitHub `environment` is being used within the workflow
- The trigger for the workflow run e.g. `pull_request` vs `push`
- Whether the GitHub workflow is running for a branch or a tag

For more information on the generation of subject claims see [Example subject claims](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#example-subject-claims).

When configuring an OIDC identity for GitHub Actions you need to choose a filter that will match the workflow you want to be able to use OIDC with, the following options are available that match the subject claims above that GitHub uses:

- Branch: Workflow runs for the specific branch will be allowed to connect using the OIDC identity. The prefix for the git ref does not need to be supplied e.g. Use `main` instead of `refs/heads/main`.
- Environment: Workflow runs for the specific GitHub environment will be allowed to connect using the OIDC identity.
- Pull Requests: Workflow runs triggered from pull requests will be allowed to connect using the OIDC identity.
- Tag: Workflow runs for the specific tag will be allowed to connect using the OIDC identity. The prefix for the git ref does not need to be supplied e.g. Use `v1` instead of `refs/tags/v1`.

:::div{.hint}
The subject in an OIDC identity is case-sensitive and must match exactly, wildcards are currently not supported.
:::

### Customized subject claims

GitHub supports [customizing the subject claims for an organization or repository](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-subject-claims-for-an-organization-or-repository), allowing other properties to be used in the generated subject of the ID token instead of the standard properties above. When configuring an OIDC identity for GitHub Actions you can click the Edit icon next to the subject to enter a custom subject matching the generated one from GitHub.

:::figure
![Configuring a custom subject for GitHub Actions](/docs/octopus-rest-api/images/oidc-identity-github-actions-custom-subject.png "width=500")
:::

### GitHub Enterprise (self-hosted)

When configuring an OIDC identity for GitHub Actions, by default the issuer URL will be set to the well-known issuer for GitHub Cloud: `https://token.actions.githubusercontent.com`. If you are using GitHub Actions from self-hosted GitHub Enterprise you can configure the Issuer URL by clicking the Edit icon and entering the URL. The URL must be HTTPS.

:::figure
![Configuring an OIDC identity for self-hosted GitHub Enterprise](/docs/octopus-rest-api/images/oidc-identity-github-actions-enterprise.png "width=500")
:::

## Using `OctopusDeploy/login` in GitHub Actions workflows

The [`OctopusDeploy/login`](https://github.com/OctopusDeploy/login) action provides a first-class way to use OIDC with Octopus in GitHub Actions, exchanging the GitHub ID token for an Octopus access token. Other Octopus actions (e.g. [`OctopusDeploy/create-release-action`](https://github.com/OctopusDeploy/create-release-action)) within the same workflow job will be pre-configured to use this access token, including any use of the [`octopus` cli](https://github.com/OctopusDeploy/cli) in scripts.

See the [readme](https://github.com/OctopusDeploy/login) for more information on how to use the action.

If you are using multiple jobs within a workflow that interact with Octopus the login action needs to be added to each job.

### Workflow job permissions

To use the [`OctopusDeploy/login`](https://github.com/OctopusDeploy/login) action within a workflow job, a specific permission `id-token: write` needs to be granted to the job in to obtain the ID token from GitHub, for example:

```yaml
jobs:
octopus:
permissions:
id-token: write
steps: ...
```

When `permissions` are specified on a workflow job, any built-in permissions for the job are reset. This means that some existing steps in your workflow may now require setting explicit permissions in order to work correctly.

For example to checkout source code using the `actions/checkout` action you will need to add `contents: read` to the permissions.

For more information see [Assigning permissions to jobs](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs/).

## Converting existing Octopus GitHub Actions workflows to use OIDC

To convert existing Octopus GitHub Actions that are using API keys to instead use OIDC:

- Create an OIDC identity on a service account for the GitHub Action as outlined above.
- Copy the `OctopusDeploy/login` snippet that is generated for the service account and add it to the workflow job.
- Add `id-token: write` permissions to the workflow job as outlined above.
- Remove any existing usage of `server` and `api_key` from other Octopus actions.

### Example

The following is an example of a simple GitHub Actions workflow using API keys.

```yaml
name: Create a release in Octopus
on:
push:
branches:
- main

jobs:
create_release:
runs-on: ubuntu-latest
name: Create a release in Octopus
steps:
- name: Create Octopus release
uses: OctopusDeploy/create-release-action@v3
with:
server: https://my.octopus.app
space: Default
project: MyOctopusProject
api_key: ${{ secrets.OCTOPUS_API_KEY }}
```

After conversion to use OIDC the workflow looks like:

```yaml
name: Create a release in Octopus
on:
push:
branches:
- main

jobs:
create_release:
runs-on: ubuntu-latest
name: Create a release in Octopus
permissions:
id-token: write # This is required to obtain the ID token from GitHub Actions
steps:
- name: Login to Octopus
uses: OctopusDeploy/login@v1
with:
server: https://my.octopus.app
service_account_id: 5be4ac10-2679-4041-a8b0-7b05b445e19e

- name: Create Octopus release
uses: OctopusDeploy/create-release-action@v3
with:
space: Default
project: MyOctopusProject
```

## API keys

It is recommended to use OIDC over API keys due to the benefits it provides, however the [`OctopusDeploy/login`](https://github.com/OctopusDeploy/login) action also supports using an API key, for scenarios where using OIDC is not available. When using an API key the remainder of the workflow job will be configured to use the Server URL and API key automatically via environment variables, eliminating the need to supply these to any other Octopus actions or to the `octopus` cli.

See the [readme](https://github.com/OctopusDeploy/login?tab=readme-ov-file#api-key) for more information.
Loading
Loading