Skip to content

feat: add external ID output for service accounts#176

Merged
bec-callow-oct merged 4 commits intomainfrom
fnm/add-external-id
Mar 5, 2026
Merged

feat: add external ID output for service accounts#176
bec-callow-oct merged 4 commits intomainfrom
fnm/add-external-id

Conversation

@bec-callow-oct
Copy link
Copy Markdown
Contributor

@bec-callow-oct bec-callow-oct commented Feb 25, 2026

[SC-136951]
Requires the changes in this client PR OctopusDeploy/go-octopusdeploy#402

This PR adds a new ExternalId output field that can be used in the GitHub actions Login step to authenticate via OIDC.

Outputs:

service_account_external_id = "2b9d3792-3995-4149-b2af-703985d704ff"
image

I've named the output External ID because this is the name of the field in the response to this server endpoint /api/serviceaccounts/Users-83/oidcidentities/v1?skip=0&take=1. We refer to the same value as Service Account ID in the Login step, and also use the value as the Audience during OIDC authentication

Sample terraform for testing

# Create a service account with OIDC identity to test External ID output
resource "octopusdeploy_user" "oidc_service_account" {
  display_name = "OIDC Service Account Test"
  username     = "oidc-service-account-test"
  is_service   = true
  is_active    = true
}

# 2. Create OIDC identity for that service account
resource "octopusdeploy_service_account_oidc_identity" "oidc_identity" {
  name               = "OIDC Identity"
  service_account_id = octopusdeploy_user.oidc_service_account.id  # This will be a GUID
  issuer             = "https://token.actions.githubusercontent.com"
  subject            = "repo:myorg/myrepo:ref:refs/heads/main"
}

# Output the External ID to verify it's being populated correctly
output "service_account_external_id" {
  description = "The External ID (GUID) for the OIDC service account"
  value       = octopusdeploy_user.oidc_service_account.external_id
}

Testing

When a new service account is created

terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # octopusdeploy_user.oidc_service_account will be created
  + resource "octopusdeploy_user" "oidc_service_account" {
      + can_password_be_edited = (known after apply)
      + display_name           = "OIDC Service Account Test"
      + external_id            = (known after apply)
      + id                     = (known after apply)
      + is_active              = true
      + is_requestor           = (known after apply)
      + is_service             = true
      + username               = (sensitive value)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + service_account_external_id = "2b9d3792-3995-4149-b2af-703985d704ff"

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

octopusdeploy_user.oidc_service_account: Creating...
octopusdeploy_user.oidc_service_account: Creation complete after 0s [id=Users-101]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

service_account_external_id = "2b9d3792-3995-4149-b2af-703985d704ff"

 terraform output -raw service_account_external_id
2b9d3792-3995-4149-b2af-703985d704ff

When the service account is deleted

terraform apply
octopusdeploy_user.oidc_service_account: Refreshing state... [id=Users-83]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # octopusdeploy_user.oidc_service_account will be destroyed
  # (because octopusdeploy_user.oidc_service_account is not in configuration)
  - resource "octopusdeploy_user" "oidc_service_account" {
      - can_password_be_edited = false -> null
      - display_name           = "OIDC Service Account Test" -> null
      - external_id            = "6b453c3a-0e28-4a69-8bf6-91f58c9ea0a3" -> null
      - id                     = "Users-83" -> null
      - is_active              = true -> null
      - is_requestor           = false -> null
      - is_service             = true -> null
      - username               = (sensitive value) -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Changes to Outputs:
  - service_account_external_id = (sensitive value) -> null

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

octopusdeploy_user.oidc_service_account: Destroying... [id=Users-83]
octopusdeploy_user.oidc_service_account: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.

terraform output -raw service_account_external_id
╷
│ Warning: No outputs found
│
│ The state file either has no outputs defined, or all the defined outputs are empty. Please define an output in your configuration with the `output` keyword and
│ run `terraform refresh` for it to become available. If you are using interpolation, please verify the interpolated value is not empty. You can use the
│ `terraform console` command to assist.

Apply with no changes

terraform apply
octopusdeploy_user.oidc_service_account: Refreshing state... [id=Users-101]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

service_account_external_id = "2b9d3792-3995-4149-b2af-703985d704ff"

terraform output -raw service_account_external_id
2b9d3792-3995-4149-b2af-703985d704ff

Copy link
Copy Markdown
Contributor

@benPearce1 benPearce1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally. 👍

@bec-callow-oct bec-callow-oct merged commit 3034217 into main Mar 5, 2026
18 checks passed
@bec-callow-oct bec-callow-oct deleted the fnm/add-external-id branch March 5, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants