diff --git a/dictionary-octopus.txt b/dictionary-octopus.txt index dc641e2973..d96764e609 100644 --- a/dictionary-octopus.txt +++ b/dictionary-octopus.txt @@ -51,3 +51,5 @@ WIXUI workertools xlarge xmark +RSASSA +jwks diff --git a/public/docs/octopus-rest-api/images/oidc-github-actions-details.png b/public/docs/octopus-rest-api/images/oidc-github-actions-details.png new file mode 100644 index 0000000000..51c10e1fea Binary files /dev/null and b/public/docs/octopus-rest-api/images/oidc-github-actions-details.png differ diff --git a/public/docs/octopus-rest-api/images/oidc-identity-github-actions-custom-subject.png b/public/docs/octopus-rest-api/images/oidc-identity-github-actions-custom-subject.png new file mode 100644 index 0000000000..fc47e71355 Binary files /dev/null and b/public/docs/octopus-rest-api/images/oidc-identity-github-actions-custom-subject.png differ diff --git a/public/docs/octopus-rest-api/images/oidc-identity-github-actions-enterprise.png b/public/docs/octopus-rest-api/images/oidc-identity-github-actions-enterprise.png new file mode 100644 index 0000000000..bbebd3b8a2 Binary files /dev/null and b/public/docs/octopus-rest-api/images/oidc-identity-github-actions-enterprise.png differ diff --git a/public/docs/octopus-rest-api/images/oidc-identity-github-actions.png b/public/docs/octopus-rest-api/images/oidc-identity-github-actions.png new file mode 100644 index 0000000000..7a21f5f1c6 Binary files /dev/null and b/public/docs/octopus-rest-api/images/oidc-identity-github-actions.png differ diff --git a/public/docs/octopus-rest-api/images/oidc-identity-other-issuer.png b/public/docs/octopus-rest-api/images/oidc-identity-other-issuer.png new file mode 100644 index 0000000000..9d2245ca0b Binary files /dev/null and b/public/docs/octopus-rest-api/images/oidc-identity-other-issuer.png differ diff --git a/public/docs/octopus-rest-api/images/oidc-other-issuer-details.png b/public/docs/octopus-rest-api/images/oidc-other-issuer-details.png new file mode 100644 index 0000000000..374474f879 Binary files /dev/null and b/public/docs/octopus-rest-api/images/oidc-other-issuer-details.png differ diff --git a/src/pages/docs/octopus-rest-api/index.mdx b/src/pages/docs/octopus-rest-api/index.mdx index 4d06c1fac1..f962752778 100644 --- a/src/pages/docs/octopus-rest-api/index.mdx +++ b/src/pages/docs/octopus-rest-api/index.mdx @@ -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"; @@ -40,7 +41,11 @@ https:///api Replacing `` 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: @@ -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:///swaggerui/`. The original Non-Swagger API page is still available and can always be accessed via `https:///api/`. @@ -63,31 +76,31 @@ 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" + } } ``` @@ -95,9 +108,9 @@ For example, a `GET` request to `/api` returns a resource that looks like: 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 @@ -105,29 +118,29 @@ Some links (mainly to collections) use URI templates as defined in [RFC 6570](ht ### 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} diff --git a/src/pages/docs/octopus-rest-api/openid-connect/github-actions.md b/src/pages/docs/octopus-rest-api/openid-connect/github-actions.md new file mode 100644 index 0000000000..b12c89b099 --- /dev/null +++ b/src/pages/docs/octopus-rest-api/openid-connect/github-actions.md @@ -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 + +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. diff --git a/src/pages/docs/octopus-rest-api/openid-connect/index.md b/src/pages/docs/octopus-rest-api/openid-connect/index.md new file mode 100644 index 0000000000..a7aa4dc3da --- /dev/null +++ b/src/pages/docs/octopus-rest-api/openid-connect/index.md @@ -0,0 +1,175 @@ +--- +layout: src/layouts/Default.astro +pubDate: 2023-09-27 +modDate: 2023-09-27 +title: Using OpenID Connect with the Octopus API +description: External systems can use OpenID Connect with service accounts to access the Octopus API without needing to provision API keys +navOrder: 30 +hideInThisSection: true +--- + +Octopus supports using [OpenID Connect (OIDC)](https://openid.net/) to access the Octopus API without needing to provision API keys. + +## What is OpenID Connect and how is it used in Octopus? + +OpenID Connect is a set of identity specifications that build on OAuth 2.0 to allow software systems to connect to each other in a way that promotes security best practices. + +When using OIDC, Octopus will validate an identity token coming from a trusted external system using [public key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) and issue a short-lived access token which can then be used to interact with the Octopus API. + +Some of the benefits of using OIDC in Octopus include: + +- API keys do not need to be provisioned and stored in external systems, reducing the risk of unauthorized access to the Octopus API from exposed keys. +- API keys do not need to be rotated manually by administrators, reducing the risk of disruption when updating to newer keys in external systems. +- Access tokens issued by Octopus are short-lived, reducing the risk of unauthorized access to the Octopus API. +- Access tokens are only issued for requests from trusted external systems, allowing for controlled access to service accounts and promoting using the principle of least access. + +:::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). +::: + +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. + +## Getting started with GitHub Actions + +To get started using OIDC with GitHub Actions use the below instructions. For more information see [Using OpenID Connect with Octopus and GitHub Actions](/docs/octopus-rest-api/openid-connect/github-actions). + +### Create an OIDC identity for a service account + +The first step is to create an OIDC identity for your GitHub repository to allow workflow runs to access the Octopus API. + +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. +::: + +:::figure +![OIDC Identity for GitHub Actions](/docs/octopus-rest-api/images/oidc-identity-github-actions.png "width=500") +::: + +### Add the `OctopusDeploy/login` action to your workflow + +After the OIDC identity for GitHub Actions has been created a snippet of the `OctopusDeploy/login` step will be provided which you can use in your workflow to configure the workflow run job to use OIDC authentication. + +:::figure +!['OctopusDeploy/login' snippet](/docs/octopus-rest-api/images/oidc-github-actions-details.png "width=500") +::: + +1. Click the Copy to clipboard to copy the `OctopusDeploy/login` step. +2. Paste the `OctopusDeploy/login` step into your workflow job. +3. Add `id-token: write` to the `permissions` on the workflow job. This is required to allow the `OctopusDeploy/login` action to request an OIDC token from GitHub to use. + +:::div{.hint} +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/). +::: + +4. Add any additional Octopus provided GitHub Actions that you require e.g. [`OctopusDeploy/create-release-action`](https://github.com/OctopusDeploy/create-release-action). These actions will automatically work with OIDC. Any script steps that use the `octopus` cli will also automatically work with OIDC. + +When the workflow runs the `OctopusDeploy/login` action will authenticate with Octopus using OIDC and configure the remainder of the workflow job to work without needing to provide the `server` or `api_key` values. + +```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 +``` + +## Getting started with other issuers + +To get started using OIDC with other issuers use the below instructions. For more information see [Using OpenID Connect with Other Issuers](/docs/octopus-rest-api/openid-connect/other-issuers). + +### Create an OIDC identity for a service account + +The first step is to create an OIDC identity for your issuer to access the Octopus API. + +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 Other Issuer as the issuer type. +5. Enter the URL of the identity. Octopus uses OpenID Configuration Discovery to validate the OIDC token provided by the issuer. + 1. The issuer URL must be HTTPS. + 2. The URL should be the base where the OIDC Discovery endpoint (`/.well-known/openid-configuration`) endpoint can be found. For example if the discovery endpoint is `https://my-oidc-issuer.com/.well-known/openid-configuration` then the issuer should be set to `https://my-oidc-issuer.com`. +6. Enter the subject of the identity. This must match exactly the subject that is provided in the OIDC token and is _case-sensitive_. The format of the subject will differ by issuer, please consult your OIDC issuers documentation. +7. Click Save. + +:::div{.hint} +Multiple OIDC identities can be added for a service account. +::: + +:::figure +![OIDC Identity for other issuer](/docs/octopus-rest-api/images/oidc-identity-other-issuer.png "width=500") +::: + +### Exchange an OIDC token for an Octopus access token + +After the OIDC identity has been created it can be used as part of exchanging an OIDC token for an Octopus access token. + +A Service Account Id will be shown, this will be a GUID which must be supplied as the `aud` of the ID token, as well as in the token exchange request. + +:::figure +![Other issuer audience details](/docs/octopus-rest-api/images/oidc-other-issuer-details.png "width=500") +::: + +1. Obtain an OIDC token from the issuer, the `aud` claim must be the Service Account Id. The process for obtaining the OIDC token from the issuer will differ by issuer, please consult your OIDC issuers documentation. +2. Get the token exchange endpoint for your Octopus server from the `token_endpoint` property of the OpenID Connect Discovery endpoint `https://my-octopus-server.com/.well-known/openid-configuration`. +3. Exchange the OIDC token for an Octopus access token, setting `audience` property to the Service Account Id from above. See [Exchanging an OIDC token for an Octopus access token](/docs/octopus-rest-api/openid-connect/other-issuers#OidcOtherIssuers-TokenExchange) for more details on the token exchange request. +4. Get the `access_token` from the token exchange response. + +### Using the access token to access the Octopus API + +The access token obtained from the token exchange must be supplied in the `Authorization` header of API requests, using the `Bearer` scheme, for example `Authorization: Bearer {the-access-token}`. + +## Validation of OIDC tokens + +## Access tokens + +When an OIDC token from a trusted external system is validated, Octopus will issue an access token. This token is a Json Web Token (JWT) which is cryptographically signed by the Octopus server, allowing it to be validated to ensure it is a legitimate token that was issued from the correct system and hasn't been tampered with. The token is short-lived (1 hour) and cannot be used after it has expired, reducing the impact that stolen credentials could have. + +### How tokens are signed + +Access tokens are signed using [public key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography). Octopus securely maintains a private and public key pair, and signs the token using the private key, which only the Octopus Server can use. The token can then be validated using the public key to ensure that it is legitimate. + +Access tokens are signed with [RSA keys]() with a key length of 2048 bits, using the [RSASSA-PSS (PS256) algorithm](https://www.rfc-editor.org/rfc/rfc8017#section-8.1). + +The keys used to sign access tokens are automatically rotated every 90 days, and a new key is used to sign tokens. Once a key has been rotated it is no longer used to sign new tokens, however continues to be used to validate existing tokens, in order to minimize disruption to the use of existing tokens. Keys will be removed after another 90 days and no longer used for validation. + +### Validating tokens + +Octopus Server exposes well-known endpoints from the [OpenID discovery specification](https://openid.net/specs/openid-connect-discovery-1_0.html) to make available the public keys that are used to sign access tokens, which can then be used to validate access tokens that the Octopus Server issues. + +The discovery endpoint can be found at `{OctopusServerUrl}/.well-known/openid-configuration` e.g. `https://my.octopus.app/.well-known/openid-configuration`. The response from this endpoint will contain a `jwks_uri` property which contains the URL at which the public keys can be found. The jwks endpoint uses the [JWK specification](https://datatracker.ietf.org/doc/html/rfc7517). + +:::div{.hint} +Public sites such as [jwt.io](https://jwt.io/) can be used to inspect and validate access tokens. + +IMPORTANT: Access tokens are credentials to your Octopus Server in the same way that API keys are, be careful where you paste them! +::: diff --git a/src/pages/docs/octopus-rest-api/openid-connect/other-issuers.md b/src/pages/docs/octopus-rest-api/openid-connect/other-issuers.md new file mode 100644 index 0000000000..d149568505 --- /dev/null +++ b/src/pages/docs/octopus-rest-api/openid-connect/other-issuers.md @@ -0,0 +1,106 @@ +--- +layout: src/layouts/Default.astro +pubDate: 2023-09-27 +modDate: 2023-09-27 +title: Using OpenID Connect in Octopus with other issuers +description: How to use OpenID Connect to interact with Octopus using other issuers +navOrder: 30 +hideInThisSection: true +--- + +Octopus supports using OpenID Connect for any external system that can issue a signed OIDC token which can be validated anonymously via an HTTPS endpoint. + +:::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). +::: + +## Configuring an OIDC identity + +The first step is to create an OIDC identity for your issuer to access the Octopus API. + +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 Other Issuer as the issuer type. +5. Enter the URL of the identity. Octopus uses OpenID Configuration Discovery to validate the OIDC token provided by the issuer. + 1. The issuer URL must be HTTPS. + 2. The URL should be the base where the OIDC Discovery endpoint (`/.well-known/openid-configuration`) endpoint can be found. For example if the discovery endpoint is `https://my-oidc-issuer.com/.well-known/openid-configuration` then the issuer should be set to `https://my-oidc-issuer.com`. +6. Enter the subject of the identity. This must match exactly the subject that is provided in the OIDC token and is _case-sensitive_. The format of the subject will differ by issuer, please consult your OIDC issuers documentation. +7. Click Save. + +:::div{.hint} +Multiple OIDC identities can be added for a service account. +::: + +:::figure +![OIDC Identity for other issuer](/docs/octopus-rest-api/images/oidc-identity-other-issuer.png "width=500") +::: + +## OpenID discovery endpoints + +Octopus uses [OpenID Configuration Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) to validate the OIDC token provided by the issuer. + +The issuer must provide an anonymously accessible endpoint `/well-known/openid-configuration` which meets the following specifications: + +- The URL must be secure i.e. it must use HTTPS. +- The response must contain the `jwks_uri` property, which must be a URL. + +The `jwks_uri` endpoint must be an anonymously accessible endpoint which meets the following specifications: + +- The URL must be secure i.e. it must use HTTPS. +- The response must contain a set of signing keys in the [JWK specification](https://datatracker.ietf.org/doc/html/rfc7517) which can be used to validate the OIDC token from the issuer. + +## Exchanging an OIDC token for an Octopus access token {#OidcOtherIssuers-TokenExchange} + +To exchange the issuers OIDC token for an Octopus access token, a request can be made to a anonymously accessible endpoint in the Octopus Server. + +Octopus Server exposes a [OpenID Configuration Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) at `/.well-known/openid-configuration`. The response from this endpoint will contain a `token_endpoint` which can be used to perform the exchange. + +The token exchange endpoint uses the [OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693) specification: + +| Property | Value | +| -------------- | --------------------------------------------------------- | +| HTTP Method | POST | +| Authentication | N | +| Content-Type | `application/x-www-form-urlencoded` or `application/json` | + +A request to the endpoint requires the following properties: + +| Property | Value | +| -------------------- | ----------------------------------------------------------------- | +| `grant_type` | Must be set to `urn:ietf:params:oauth:grant-type:token-exchange`. | +| `audience` | The id of the service account to exchange the OIDC token for. | +| `subject_token_type` | Must be set to `urn:ietf:params:oauth:token-type:jwt`. | +| `subject_token` | The signed OIDC token from the issuer. | + +If the request is successful, the response will contain the following properties: + +| Property | Value | +| ------------------- | ----------------------------------------------------------------------------------------------------------- | +| `access_token` | The Octopus access token which can be used to authenticate API requests. | +| `token_type` | A string representing how the token should be passed to API request. This will always be set to `Bearer`. | +| `issued_token_type` | The type of token being issued. This will always be set to `urn:ietf:params:oauth:token-type:access_token`. | +| `expires_in` | The number of seconds until the token expires. | + +TODO: If the request is not successful, the response will contain the following properties: + +### `subject_token` + +The OIDC token must conform to the [JSON Web Token](https://datatracker.ietf.org/doc/html/rfc7519) standard and contain the following claims: + +| Claim | Value | Example | +| ----- | ----------------------------------------------------------------------------------- | ------------------------------------ | +| `iss` | The issuer of the token. This must match exactly the issuer on the OIDC identity. | https://my-oidc.issuer.com | +| `sub` | The subject of the token. This must match exactly the subject on the OIDC identity. | scope:a-scope-to-restrict-the-usage | +| `aud` | The id of the service account to exchange the OIDC token for. | 863b4b7d-6308-456e-8375-8d9270e9be44 | +| `exp` | The expiration time of the token. The token must not be expired. | 1632493567 | + +The OIDC token must be signed by the issuer, with the signature included as part of the token payload. + +## Using the access token in API requests + +To use the access token as authentication for a request to the Octopus API, it must be included in the `Authorization` header using the `Bearer scheme`: + +``` +Authorization: Bearer {the-access-token-obtained-from-octopus} +``` diff --git a/src/pages/docs/security/users-and-teams/service-accounts.md b/src/pages/docs/security/users-and-teams/service-accounts.md index 946e7c059b..835d023e88 100644 --- a/src/pages/docs/security/users-and-teams/service-accounts.md +++ b/src/pages/docs/security/users-and-teams/service-accounts.md @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2023-01-01 -modDate: 2023-01-01 +modDate: 2023-10-27 title: Service accounts description: Creating Service Accounts to provide individual services with the least privileges required for the tasks they will perform. navOrder: 2 @@ -18,10 +18,10 @@ It is best to create **Service accounts** for this purpose to provide each servi :::div{.hint} **Service accounts** are **API-only accounts** that can be assigned permissions in the same way you do for normal user accounts, but are prevented from using the Octopus Web Portal. -Service accounts authenticate with the Octopus API using their [Octopus API Key](/docs/octopus-rest-api/how-to-create-an-api-key). +Service accounts authenticate with the Octopus API using [OpenID Connect](/docs/octopus-rest-api/openid-connect) or an [Octopus API Key](/docs/octopus-rest-api/how-to-create-an-api-key). ::: -## Creating a service account {#ServiceAccounts-Creatingaserviceaccount} +## Creating a service account {#ServiceAccounts-CreatingAServiceAccount} [Getting Started - Service Accounts](https://www.youtube.com/watch?v=SMsZMpUwCZc) @@ -37,9 +37,15 @@ Creating a new Service account is very similar to creating a new User account: ::: :::div{.hint} -This Service account is not very useful until it [belongs to one or more teams](/docs/security/users-and-teams/), and has one or more [Octopus API keys](/docs/octopus-rest-api/how-to-create-an-api-key) associated with it +This Service account is not very useful until it [belongs to one or more teams](/docs/security/users-and-teams/), and has one or more [OpenID Connect Identities](/docs/octopus-rest-api/openid-connect) or [Octopus API keys](/docs/octopus-rest-api/how-to-create-an-api-key) associated with it. ::: +## OpenID Connect (OIDC) + +You can use [OpenID Connect (OIDC)](/docs/octopus-rest-api/openid-connect) to automate Octopus with another service without needing to provision or manage API Keys. To do this you configure a specific *OIDC Identity* for the service which allows it to connect to Octopus securely. The service then exchanges an ID token with Octopus for a short-lived access token which it can then use for API requests. + +## API Keys + :::figure ![Service account API Key](/docs/security/users-and-teams/images/service-account-apikey.png) :::