{"slug":"workload-identity-federation","title":"Workload identity federation","tags":["tailscale"],"agent_summary":"Last validated: Jan 30, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Workload identity federation\r\n\r\nLast validated: Jan 30, 2026\r\n\r\nWorkload identity federation lets cloud-hosted infrastructure in providers like Microsoft Azure, Google Cloud Platform, Amazon Web Services, or GitHub Actions authenticate to a tailnet or the Tailscale API using provider-native identity tokens instead of Tailscale auth keys or OAuth clients. By leveraging the provider's federated OpenID Connect (OIDC) identities, tailnet administrators can streamline credential management and infrastructure automation.\r\n\r\n## [How it works](https://tailscale.com/docs/features/workload-identity-federation\\#how-it-works)\r\n\r\n![A process flow diagram for a standard workload identity federation flow, showing how a cloud workload can exchange a signed JWT from its provider with Tailscale to authenticate itself to the Tailscale API.](https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwif-process.0c83a2dc.png&w=3840&q=75)\r\n\r\nWhen a cloud workload (such as a CI job, serverless function, or virtual machine) wants to join your tailnet or call the Tailscale API, it first asks its own platform for an OIDC token.\r\n\r\nThe OIDC token is a signed JSON Web Token (JWT) that conveys three assurances from the cloud platform:\r\n\r\n- It vouches for the workload's identity.\r\n- It specifies exactly which workload the JWT represents.\r\n- It declares who is permitted to consume the token.\r\n\r\nBecause the platform signs the token with its publicly advertised keys, anyone can verify the signature and trust that the claims are genuine.\r\n\r\nBefore any exchange can take place, a tailnet admin establishes trust by specifying the OIDC issuer to trust and defining claim-matching rules that map specific workloads, such as a particular GitHub repository, Google Cloud service account, or Azure workload, onto the tags and API scopes they should receive. Tokens that fail to match these rules are rejected automatically.\r\n\r\nThe workload then sends that OIDC token to Tailscale's token exchange endpoint. Behind the scenes, Tailscale fetches the issuer's public keys, validates the signature, standard claims (issuer, audience, expiry), and claim-matching rules and then returns a short-lived API token with the scopes you configured when configuring identity federation in the Tailscale admin console.\r\n\r\nWith this API token, the workload can join or manage the tailnet with the Tailscale API.\r\n\r\n## [Set up a federated identity](https://tailscale.com/docs/features/workload-identity-federation\\#set-up-a-federated-identity)\r\n\r\nBefore a cloud workload can use its signed OIDC token to authenticate to Tailscale, you must set up a federated identity in Tailscale and assign all necessary [scopes](https://tailscale.com/docs/reference/trust-credentials#scopes).\r\n\r\nFederated identities can be configured using:\r\n\r\n- The [admin console](https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-in-the-admin-console)\r\n- The [Tailscale Terraform provider](https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-the-tailscale-terraform-provider)\r\n- [`tailscale-client-go-v2`](https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-tailscale-client-go-v2)\r\n- The [Tailscale API](https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-the-tailscale-api)\r\n\r\n### [Configure federated identities in the admin console](https://tailscale.com/docs/features/workload-identity-federation\\#configure-federated-identities-in-the-admin-console)\r\n\r\nTo configure federated identities in the Tailscale admin console:\r\n\r\n1. Open the [Trust credentials](https://login.tailscale.com/admin/settings/trust-credentials) page of the admin console.\r\n2. Select the **Credential** button.\r\n3. Select **OpenID Connect**.\r\n4. Select an **Issuer** from the dropdown. Common cloud providers are included in the dropdown, but any infrastructure provider that supports OIDC for workload identity federation can be used if **Custom issuer** is selected.\r\n1. Enter the **Issuer URL** for the cloud provider's OIDC issuer if using a **Custom issuer**.\r\n5. Enter the **Subject**. This value determines the attributes of the workload that must match to successfully receive a Tailscale API token. Find the syntax of the subject (`sub`) claims for common cloud providers in the [common cloud provider token formats](https://tailscale.com/docs/features/workload-identity-federation#common-cloud-provider-token-formats) section.\r\n6. (Optional) Add additional **Custom claims** to further narrow access. Explore token claims for common cloud providers in the [common cloud provider token formats](https://tailscale.com/docs/features/workload-identity-federation#common-cloud-provider-token-formats) section.\r\n7. Select the relevant read and write scopes from the list and select **Generate credential**.\r\n8. Copy the **Client ID** and **Audience (aud claim)**. These are not secrets and will be visible in the admin console.\r\n\r\n#### [Retrieve the Client ID in the admin console](https://tailscale.com/docs/features/workload-identity-federation\\#retrieve-the-client-id-in-the-admin-console)\r\n\r\nIf you need to copy the **Client ID** at a later point in time, you can visit the admin console.\r\n\r\n1. Open the [Trust credentials](https://login.tailscale.com/admin/settings/trust-credentials) page of the admin console.\r\n\r\n2. Use the **Search** and optionally the **Filters** functionality to find the federated identity you are interested in.\r\n   - Searching by `tag` may be useful.\r\n   - Setting the **Filters** value to **Client type** and selecting **OIDC** may also be useful.\r\n3. Either select the arrow toggle to expand the row or select the ![ellipsis icon](https://tailscale.com/files/images/icons/fa-ellipsis-h.svg) menu and select **View** or **Edit**.\r\n\r\n4. Select the clipboard icon to copy the **Client ID**.\r\n\r\n\r\n### [Configure federated identities using the Tailscale Terraform provider](https://tailscale.com/docs/features/workload-identity-federation\\#configure-federated-identities-using-the-tailscale-terraform-provider)\r\n\r\nTo configure federated identities using the Tailscale Terraform provider with the `tailscale_federated_identity` resource:\r\n\r\n```hcl\r\nresource \"tailscale_federated_identity\" \"example_federated_identity\" {\r\n  description = \"Example federated identity\"\r\n  scopes      = [\"auth_keys\", \"devices:core\"]\r\n  tags        = [\"tag:test\"]\r\n  issuer      = \"https://example.com\"\r\n  subject     = \"example-sub-*\"\r\n  custom_claim_rules = {\r\n    repo_name = \"example-repo-name\"\r\n  }\r\n}\r\n```\r\n\r\nFor more information, refer to the [Tailscale Terraform provider documentation](https://registry.terraform.io/providers/tailscale/tailscale/latest/docs/resources/federated_identity).\r\n\r\n### [Configure federated identities using tailscale-client-go-v2](https://tailscale.com/docs/features/workload-identity-federation\\#configure-federated-identities-using-tailscale-client-go-v2)\r\n\r\nTo configure federated identities federated identities using `tailscale-client-go-v2`:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"os\"\r\n\r\n\t\"tailscale.com/client/tailscale/v2\"\r\n)\r\n\r\nfunc main() {\r\n\tclient := &tailscale.Client{\r\n\t\t// Client configuration\r\n\t}\r\n\r\n\treq := tailscale.CreateFederatedIdentityRequest {\r\n\t\tDescription: \"Example federated identity\",\r\n\t\tScopes:  []string{\"auth_keys\", \"devices:core\"},\r\n\t\tTags:    []string{\"tag:test\"},\r\n\t\tSubject: \"example-sub-*\",\r\n\t\tCustomClaimRules: map[string]string{\r\n\t\t\t\"repo_name\": \"example-repo-name\",\r\n\t\t},\r\n\t}\r\n\r\n\tfederatedIdentity, err := client.Keys().CreateFederatedIdentity(context.Background(), req)\r\n}\r\n```\r\n\r\nFor more information, refer to [`tailscale-client-go-v2`](https://github.com/tailscale/tailscale-client-go-v2).\r\n\r\n### [Configure federated identities using the Tailscale API](https://tailscale.com/docs/features/workload-identity-federation\\#configure-federated-identities-using-the-tailscale-api)\r\n\r\nTo configure federated identities using the Tailscale API with the `https://api.tailscale.com/api/v2/tailnet/-/keys` endpoint:\r\n\r\n```shell\r\ncurl -X POST https://api.tailscale.com/api/v2/tailnet/-/keys \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d   '{\r\n  \"keyType\": \"federated\",\r\n  \"description\": \"Example federated identity\",\r\n  \"scopes\": [\\\r\n    \"auth_keys\",\\\r\n    \"devices:core\"\\\r\n  ],\r\n  \"tags\": [\\\r\n    \"tag:test\"\\\r\n  ],\r\n  \"issuer\": \"https://example.com\",\r\n  \"subject\": \"example-sub-*\",\r\n  \"customClaimRules\": {\r\n    \"repo_name\": \"example-repo-name\",\r\n  }'\r\n```\r\n\r\nFor more information, refer to [endpoint API](https://tailscale.com/api#tag/keys/post/tailnet/%7Btailnet%7D/keys).\r\n\r\n## [Exchange workload identity tokens with Tailscale](https://tailscale.com/docs/features/workload-identity-federation\\#exchange-workload-identity-tokens-with-tailscale)\r\n\r\nWorkload identity tokens must be exchanged with Tailscale to authenticate and provide a Tailscale access token.\r\n\r\nUsing workload identity token exchange for authentication is supported natively in:\r\n\r\n- The [Tailscale GitHub Action](https://tailscale.com/docs/features/workload-identity-federation#tailscale-github-action)\r\n- The [Tailscale Terraform provider](https://tailscale.com/docs/features/workload-identity-federation#tailscale-terraform-provider)\r\n- [`tailscale-client-go-v2`](https://tailscale.com/docs/features/workload-identity-federation#tailscale-client-go-v2)\r\n- The [Tailscale API](https://tailscale.com/docs/features/workload-identity-federation#token-exchange-api)\r\n\r\nWorkload identity can also be used for [registering new nodes](https://tailscale.com/docs/features/workload-identity-federation#register-new-nodes-using-workload-identity) in your tailnet.\r\n\r\n### [Tailscale GitHub Action](https://tailscale.com/docs/features/workload-identity-federation\\#tailscale-github-action)\r\n\r\nWorkload identity can be used to authenticate the Tailscale GitHub action by using the `oauth-client-id`, `audience`, and `tags` arguments:\r\n\r\n```yaml\r\n- name: Tailscale\r\n  uses: tailscale/github-action@v4\r\n  with:\r\n    oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}\r\n    audience: ${{ secrets.TS_AUDIENCE }}\r\n    tags: tag:ci\r\n```\r\n\r\nWorkload identity federation requires the `id-token: write` [permission setting](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-cloud-providers#adding-permissions-settings) for the workflow:\r\n\r\n```yaml\r\npermissions:\r\n  id-token: write # This is required for the tailscale action to request a JWT from GitHub\r\n  # Additional required permissions for your workflow\r\n```\r\n\r\nFor more information, refer to [GitHub action](https://github.com/tailscale/github-action).\r\n\r\n### [Tailscale Terraform provider](https://tailscale.com/docs/features/workload-identity-federation\\#tailscale-terraform-provider)\r\n\r\nWorkload identity can be used to authenticate the Tailscale Terraform provider by using the `oauth_client_id` and `id_token` provider arguments:\r\n\r\n```hcl\r\nprovider \"tailscale\" {\r\n  oauth_client_id = \"my_client_id\"\r\n  identity_token  = \"my_identity_token\"\r\n  tailnet         = \"example.com\"\r\n}\r\n```\r\n\r\nFor more information, refer to [Tailscale Terraform provider](https://registry.terraform.io/providers/tailscale/tailscale/latest).\r\n\r\n### [tailscale-client-go-v2](https://tailscale.com/docs/features/workload-identity-federation\\#tailscale-client-go-v2)\r\n\r\nWorkload identity can be used to authenticate `tailscale-client-go-v2` by supplying a `ClientID` and `IDTokenFunc` to `tailscale.Client`:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"os\"\r\n\r\n\t\"tailscale.com/client/tailscale/v2\"\r\n)\r\n\r\nfunc main() {\r\n\tclient := &tailscale.Client{\r\n\t\tTailnet: os.Getenv(\"TAILSCALE_TAILNET\"),\r\n\t\tAuth: &tailscale.IdentityFederation{\r\n\t\t\tClientID: os.Getenv(\"TAILSCALE_OAUTH_CLIENT_ID\"),\r\n\t\t\tIDTokenFunc: func() (string, error) {\r\n\t\t\t\treturn os.Getenv(\"IDENTITY_TOKEN\"), nil\r\n            },\r\n\t\t},\r\n\t}\r\n\r\n\t// Example API call\r\n\tdevices, err := client.Devices().List(context.Background())\r\n}\r\n```\r\n\r\nFor more information, refer to [`tailscale-client-go-v2`](https://github.com/tailscale/tailscale-client-go-v2).\r\n\r\n### [Token exchange API](https://tailscale.com/docs/features/workload-identity-federation\\#token-exchange-api)\r\n\r\nThe Tailscale token exchange endpoint is `https://api.tailscale.com/api/v2/oauth/token-exchange`.\r\n\r\nMake requests to the Tailscale token exchange endpoint when you need a short-lived Tailscale access token:\r\n\r\n```shell\r\ncurl -X POST https://api.tailscale.com/api/v2/oauth/token-exchange \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"client_id=<CLIENT_ID>\" \\\r\n  -d \"jwt=<JWT>\"\r\n```\r\n\r\n- `<CLIENT_ID>`: The client ID generated when you configured a federated identity in the Tailscale admin console.\r\n- `<JWT>`: The signed OIDC JWT provided to the workload by the cloud provider.\r\n\r\nIf the client ID and JWT are valid and match the configured audience, subject, and custom claim rules, Tailscale will return a short-lived API token to use for authenticating the workload to the Tailscale API.\r\n\r\nIf the short-lived API token expires, you can repeat this step to receive a fresh token.\r\n\r\n### [Debugging token exchange errors](https://tailscale.com/docs/features/workload-identity-federation\\#debugging-token-exchange-errors)\r\n\r\nThe latest token exchange error details for a federated identity can be found in the admin console.\r\n\r\n1. Open the [Trust credentials](https://login.tailscale.com/admin/settings/trust-credentials) page of the admin console.\r\n\r\n2. Use the **Search** and optionally the **Filters** functionality to find the federated identity you are interested in.\r\n   - Searching by `tag` may be useful.\r\n   - Setting the **Filters** value to **Client type** and selecting **OIDC** may also be useful.\r\n3. Select the ![ellipsis icon](https://tailscale.com/files/images/icons/fa-ellipsis-h.svg) menu and select **View** or **Edit**.\r\n\r\n\r\nInformation about the error will be present on this page, with specific guidance varying depending on the type of error.\r\n\r\nErrors will only be cleared once a token exchange has succeeded for the federated identity.\r\n\r\n#### [API error responses](https://tailscale.com/docs/features/workload-identity-federation\\#api-error-responses)\r\n\r\nErrors returned from the token exchange API endpoint will not have specific debugging information directly in the error message.\r\n\r\nThis is done to prevent leaking information to potential bad actors as they could otherwise attempt to reverse engineer your federated identity's configuration from error messages if they know its client ID.\r\n\r\nError messages will instead contain a direct link to the federated identity within the admin console in a message of the form:\r\n\r\n```json\r\n{ \"message\": \"Unauthorized. Visit [link to admin console] for details\" }\r\n```\r\n\r\nInformation about the error will be present on this page, with specific guidance varying depending on the type of error.\r\n\r\nErrors will only be cleared once a token exchange has succeeded for the federated identity.\r\n\r\n## [Register new nodes using workload identity](https://tailscale.com/docs/features/workload-identity-federation\\#register-new-nodes-using-workload-identity)\r\n\r\nA device must run Tailscale v1.90.1 or later to have the `--client-id` and `--id-token` flags.\r\n\r\nYou can use a client ID and OIDC token directly in [`tailscale up`](https://tailscale.com/docs/reference/tailscale-cli/up) to register a new node:\r\n\r\n```shell\r\ntailscale up --client-id=${CLIENT_ID} --id-token=${IDENTITY_TOKEN} --advertise-tags=tag:ci\r\n```\r\n\r\nThe `tailscale up` command expects the `client-id` to be the Client ID used to generate auth keys with workload identity federation. Access the admin console to [retrieve the **Client ID**](https://tailscale.com/docs/features/workload-identity-federation#retrieve-the-client-id-in-the-admin-console).\r\n\r\nThe command also expects the `id-token` to be the ID token from the identity provider to exchange with the control server for workload federation. This value is the signed OIDC JWT and not a short-lived API token.\r\n\r\nThe workload identity credential must have the `auth_keys` scope and the [tags](https://tailscale.com/docs/features/tags) passed to `--advertise-tags` must match the tags you selected when you [configured the federated identity](https://tailscale.com/docs/features/workload-identity-federation#set-up-a-federated-identity).\r\n\r\nThe `--client-id` flag can accept additional URL-style parameters:\r\n\r\n```shell\r\ntailscale up --client-id='${CLIENT_ID}?ephemeral=false&preauthorized=true' --id-token=${IDENTITY_TOKEN} --advertise-tags=tag:ci\r\n```\r\n\r\nThe available parameters are:\r\n\r\n- `ephemeral`: register as an [ephemeral node](https://tailscale.com/docs/features/ephemeral-nodes) (defaults to `true`)\r\n- `preauthorized`: skip manual [device approval](https://tailscale.com/docs/features/access-control/device-management/device-approval) (defaults to `false`)\r\n\r\n### [Automatic cloud token discovery and exchange](https://tailscale.com/docs/features/workload-identity-federation\\#automatic-cloud-token-discovery-and-exchange)\r\n\r\nA device must run Tailscale v1.94.0 or later to have the `--audience` flag.\r\n\r\nTailscale can automatically detect certain cloud and CI environments and retrieve a native identity token from the platform it is running on. When enabled, the client uses this token to authenticate the node to your tailnet using **workload identity federation** without requiring you to manually provision or manage credentials.\r\n\r\nThis functionality is intended for **non-interactive workloads**, such as cloud VMs, containerized services, and CI/CD pipelines, where identity should be derived from the execution environment itself.\r\n\r\nNo long-lived credentials, access keys, or secrets are stored on disk or injected at runtime.\r\n\r\nThis behavior is enabled by passing a client ID and audience to [`tailscale up`](https://tailscale.com/docs/reference/tailscale-cli/up):\r\n\r\n```shell\r\ntailscale up --client-id=${CLIENT_ID} --audience=${AUDIENCE} --advertise-tags=tag:ci\r\n```\r\n\r\nThe command expects `audience` to be the audience specified in the trust configuration for the federated identity referred to by `client-id`.\r\n\r\n#### [Supported environments](https://tailscale.com/docs/features/workload-identity-federation\\#supported-environments)\r\n\r\nAutomatic token discovery requires both a native workload identity on the platform and a matching [trust configuration](https://tailscale.com/docs/features/workload-identity-federation#set-up-a-federated-identity) in Tailscale. Once configured, the Tailscale client will obtain a provider token on your behalf on the platforms described below.\r\n\r\n**AWS**\r\n\r\n**Workload environment**\r\n\r\n- The workload runs on an AWS service that supports IAM roles. For example, Elastic Cloud Compute (EC2), Elastic Container Service (ECS), or Elastic Kubernetes Service (EKS).\r\n- An IAM role is attached to the instance, task, or pod.\r\n\r\n**IAM configuration**\r\n\r\n- The IAM role must allow issuance of web identity tokens from AWS Security Token Service (STS).\r\n- The role's trust policy must permit the configured web identity provider.\r\n\r\n```yaml\r\n{\r\n\"Version\": \"2012-10-17\",\r\n  \"Statement\": [\\\r\n  {\\\r\n    \"Sid\": \"AllowGetWebIdentityTokenForTailscale\",\\\r\n    \"Effect\": \"Allow\",\\\r\n    \"Action\": \"sts:GetWebIdentityToken\",\\\r\n    \"Resource\": \"*\",\\\r\n    \"Condition\": {\\\r\n      \"ForAnyValue:StringEquals\": {\\\r\n        \"sts:IdentityTokenAudience\": \"{YOUR_TAILSCALE_AUDIENCE}\"\\\r\n      },\\\r\n      \"NumericLessThanEquals\": {\\\r\n        \"sts:DurationSeconds\": \"300\"\\\r\n      }\\\r\n    }\\\r\n  }\\\r\n  ]\r\n}\r\n```\r\n\r\n**Tailscale configuration**\r\n\r\n- A workload identity federation configuration exists in Tailscale that:\r\n  - Trusts the AWS token issuer.\r\n  - Expects the correct audience (`aud`).\r\n  - Matches any required role or environment-specific claims.\r\n\r\n**Google Cloud**\r\n\r\n**Workload environment**\r\n\r\n- The workload runs on a Google Cloud Platform (GCP) service that exposes the metadata server. For example, Google Compute Engine (GCE) or Google Kubernetes Engine (GKE).\r\n- A **service account** is attached to the VM or workload.\r\n\r\n**IAM configuration**\r\n\r\n- The service account must be allowed to mint identity tokens.\r\n- The workload must be permitted to request identity tokens for the configured audience.\r\n\r\n**Tailscale configuration**\r\n\r\n- A workload identity federation configuration exists in Tailscale that:\r\n  - Trusts the GCP token issuer.\r\n  - Expects the configured audience.\r\n  - Optionally matches service account–specific claims.\r\n\r\n**GitHub Actions**\r\n\r\n**Workflow configuration**\r\n\r\n- The workflow runs on a GitHub-hosted or self-hosted runner that supports OIDC.\r\n- The workflow explicitly enables OIDC token issuance:\r\n\r\n```yaml\r\npermissions:\r\n  id-token: write\r\n```\r\n\r\n**Repository or organization configuration**\r\n\r\n- OIDC token issuance is enabled for the repository or organization.\r\n- Any branch, environment, or repository restrictions align with the expected token claims.\r\n\r\n**Tailscale configuration**\r\n\r\n- A workload identity federation configuration exists in Tailscale that:\r\n  - Trusts the GitHub Actions OIDC issuer.\r\n  - Matches the expected audience, repository, and workflow claims.\r\n\r\n**Unsupported environments**\r\n\r\nIf the client does not detect a supported platform, automatic token discovery is skipped and the client falls back to manual workload identity federation configuration.\r\n\r\n## [Reference](https://tailscale.com/docs/features/workload-identity-federation\\#reference)\r\n\r\nThe following sections provide technical details about claims.\r\n\r\n### [Common cloud provider token formats](https://tailscale.com/docs/features/workload-identity-federation\\#common-cloud-provider-token-formats)\r\n\r\nCloud providers have unique formats for the `sub` claim, and the custom claims, for OIDC tokens that they issue.\r\nBelow are some common cloud providers and the formats of their OIDC tokens.\r\n\r\n[AWS](https://tailscale.com/docs/features/workload-identity-federation?tab=aws) [GitHub Actions](https://tailscale.com/docs/features/workload-identity-federation?tab=github+actions) [Google Cloud](https://tailscale.com/docs/features/workload-identity-federation?tab=google+cloud) [Microsoft Azure](https://tailscale.com/docs/features/workload-identity-federation?tab=microsoft+azure)\r\n\r\n##### [Subject format](https://tailscale.com/docs/features/workload-identity-federation\\#subject-format)\r\n\r\nThe ARN of the IAM principal that requested the token. Refer to [AWS token claims](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound_token_claims.html).\r\n\r\n##### [Token Claims](https://tailscale.com/docs/features/workload-identity-federation\\#token-claims)\r\n\r\nRefer to [AWS token claims](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound_token_claims.html).\r\n\r\n### [Claim value format](https://tailscale.com/docs/features/workload-identity-federation\\#claim-value-format)\r\n\r\nValues specified for the **subject** and **custom claims** are matched against claims values in the OIDC JWT.\r\n\r\nValues can contain an `*` to match against any character. Other characters specified must directly match the value of the claim.\r\n\r\nFor example, specifying `my-example-sub/*` for the subject will successfully match `sub` claims that start with `my-example-sub/`.\r\n\r\n### [Custom claim key format](https://tailscale.com/docs/features/workload-identity-federation\\#custom-claim-key-format)\r\n\r\nKeys for **custom claims** specify the claim in the OIDC JWT to match against.\r\n\r\nFor example, given a token of the form:\r\n\r\n```json\r\n{\r\n\t\"sub\": \"123456-example\",\r\n\t\"iss\": \"https://example.com\",\r\n\t\"aud\": \"api.tailscale.com/12345-67890\",\r\n\t\"user\": \"example\"\r\n}\r\n```\r\n\r\nthe `user` claim can be referenced by specifying `user` for the key.\r\n\r\n#### [Nested claims](https://tailscale.com/docs/features/workload-identity-federation\\#nested-claims)\r\n\r\nKeys can refer to nested claims within a JWT by separating the nested key names with a period.\r\n\r\nFor example, given token of the form:\r\n\r\n```json\r\n{\r\n\t\"sub\": \"123456-example\",\r\n\t\"iss\": \"https://example.com\",\r\n\t\"aud\": \"api.tailscale.com/12345-67890\",\r\n\t\"user\": \"example\",\r\n\t\"user\": {\r\n\t\t\"name\": \"foobar\"\r\n\t}\r\n}\r\n```\r\n\r\nthe nested `name` claim can be referenced by specifying `user.name` for the key.\r\n\r\n#### [Escaping claim names](https://tailscale.com/docs/features/workload-identity-federation\\#escaping-claim-names)\r\n\r\nKeys that contain a period in their name can be escaped by surrounding them in double quotes.\r\n\r\nFor example, given a token of the form:\r\n\r\n```json\r\n{\r\n\t\"sub\": \"123456-example\",\r\n\t\"iss\": \"https://example.com\",\r\n\t\"aud\": \"api.tailscale.com/12345-67890\",\r\n\t\"user\": \"example\",\r\n\t\"open.id\": {\r\n\t\t\"username\": \"foobar\"\r\n\t}\r\n}\r\n```\r\n\r\nthe `open.id` key can be referenced as `\"open.id\"` and the nested `username` key as `\"open.id\".username`.\r\n\r\n### [Generated audience format](https://tailscale.com/docs/features/workload-identity-federation\\#generated-audience-format)\r\n\r\nAudience values generated by Tailscale are of the form: `api.tailscale.com/<client ID>`.\r\n\r\nFor example, a federated identity with the client ID `Tz8TefihCR11EXAMPLE-kZDRvszg8621EXAMPLE` will have a generated audience of `api.tailscale.com/Tz8TefihCR11EXAMPLE-kZDRvszg8621EXAMPLE`\r\n\r\n## [Limitations](https://tailscale.com/docs/features/workload-identity-federation\\#limitations)\r\n\r\n- The issuer that provides signed JSON Web Tokens (JWTs) to your workloads must be publicly accessible.\r\n\r\n![Project Logo](https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed)\r\n\r\nAsk AI\r\n\r\nreCAPTCHA\r\n\r\nRecaptcha requires verification.\r\n\r\nprotected by **reCAPTCHA**\r\n","html":"<h1>Workload identity federation</h1>\n<p>Last validated: Jan 30, 2026</p>\n<p>Workload identity federation lets cloud-hosted infrastructure in providers like Microsoft Azure, Google Cloud Platform, Amazon Web Services, or GitHub Actions authenticate to a tailnet or the Tailscale API using provider-native identity tokens instead of Tailscale auth keys or OAuth clients. By leveraging the provider's federated OpenID Connect (OIDC) identities, tailnet administrators can streamline credential management and infrastructure automation.</p>\n<h2><a href=\"https://tailscale.com/docs/features/workload-identity-federation#how-it-works\">How it works</a></h2>\n<p><img src=\"https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwif-process.0c83a2dc.png&#x26;w=3840&#x26;q=75\" alt=\"A process flow diagram for a standard workload identity federation flow, showing how a cloud workload can exchange a signed JWT from its provider with Tailscale to authenticate itself to the Tailscale API.\"></p>\n<p>When a cloud workload (such as a CI job, serverless function, or virtual machine) wants to join your tailnet or call the Tailscale API, it first asks its own platform for an OIDC token.</p>\n<p>The OIDC token is a signed JSON Web Token (JWT) that conveys three assurances from the cloud platform:</p>\n<ul>\n<li>It vouches for the workload's identity.</li>\n<li>It specifies exactly which workload the JWT represents.</li>\n<li>It declares who is permitted to consume the token.</li>\n</ul>\n<p>Because the platform signs the token with its publicly advertised keys, anyone can verify the signature and trust that the claims are genuine.</p>\n<p>Before any exchange can take place, a tailnet admin establishes trust by specifying the OIDC issuer to trust and defining claim-matching rules that map specific workloads, such as a particular GitHub repository, Google Cloud service account, or Azure workload, onto the tags and API scopes they should receive. Tokens that fail to match these rules are rejected automatically.</p>\n<p>The workload then sends that OIDC token to Tailscale's token exchange endpoint. Behind the scenes, Tailscale fetches the issuer's public keys, validates the signature, standard claims (issuer, audience, expiry), and claim-matching rules and then returns a short-lived API token with the scopes you configured when configuring identity federation in the Tailscale admin console.</p>\n<p>With this API token, the workload can join or manage the tailnet with the Tailscale API.</p>\n<h2><a href=\"https://tailscale.com/docs/features/workload-identity-federation#set-up-a-federated-identity\">Set up a federated identity</a></h2>\n<p>Before a cloud workload can use its signed OIDC token to authenticate to Tailscale, you must set up a federated identity in Tailscale and assign all necessary <a href=\"https://tailscale.com/docs/reference/trust-credentials#scopes\">scopes</a>.</p>\n<p>Federated identities can be configured using:</p>\n<ul>\n<li>The <a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-in-the-admin-console\">admin console</a></li>\n<li>The <a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-the-tailscale-terraform-provider\">Tailscale Terraform provider</a></li>\n<li><a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-tailscale-client-go-v2\"><code>tailscale-client-go-v2</code></a></li>\n<li>The <a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-the-tailscale-api\">Tailscale API</a></li>\n</ul>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-in-the-admin-console\">Configure federated identities in the admin console</a></h3>\n<p>To configure federated identities in the Tailscale admin console:</p>\n<ol>\n<li>Open the <a href=\"https://login.tailscale.com/admin/settings/trust-credentials\">Trust credentials</a> page of the admin console.</li>\n<li>Select the <strong>Credential</strong> button.</li>\n<li>Select <strong>OpenID Connect</strong>.</li>\n<li>Select an <strong>Issuer</strong> from the dropdown. Common cloud providers are included in the dropdown, but any infrastructure provider that supports OIDC for workload identity federation can be used if <strong>Custom issuer</strong> is selected.</li>\n<li>Enter the <strong>Issuer URL</strong> for the cloud provider's OIDC issuer if using a <strong>Custom issuer</strong>.</li>\n<li>Enter the <strong>Subject</strong>. This value determines the attributes of the workload that must match to successfully receive a Tailscale API token. Find the syntax of the subject (<code>sub</code>) claims for common cloud providers in the <a href=\"https://tailscale.com/docs/features/workload-identity-federation#common-cloud-provider-token-formats\">common cloud provider token formats</a> section.</li>\n<li>(Optional) Add additional <strong>Custom claims</strong> to further narrow access. Explore token claims for common cloud providers in the <a href=\"https://tailscale.com/docs/features/workload-identity-federation#common-cloud-provider-token-formats\">common cloud provider token formats</a> section.</li>\n<li>Select the relevant read and write scopes from the list and select <strong>Generate credential</strong>.</li>\n<li>Copy the <strong>Client ID</strong> and <strong>Audience (aud claim)</strong>. These are not secrets and will be visible in the admin console.</li>\n</ol>\n<h4><a href=\"https://tailscale.com/docs/features/workload-identity-federation#retrieve-the-client-id-in-the-admin-console\">Retrieve the Client ID in the admin console</a></h4>\n<p>If you need to copy the <strong>Client ID</strong> at a later point in time, you can visit the admin console.</p>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/settings/trust-credentials\">Trust credentials</a> page of the admin console.</p>\n</li>\n<li>\n<p>Use the <strong>Search</strong> and optionally the <strong>Filters</strong> functionality to find the federated identity you are interested in.</p>\n<ul>\n<li>Searching by <code>tag</code> may be useful.</li>\n<li>Setting the <strong>Filters</strong> value to <strong>Client type</strong> and selecting <strong>OIDC</strong> may also be useful.</li>\n</ul>\n</li>\n<li>\n<p>Either select the arrow toggle to expand the row or select the <img src=\"https://tailscale.com/files/images/icons/fa-ellipsis-h.svg\" alt=\"ellipsis icon\"> menu and select <strong>View</strong> or <strong>Edit</strong>.</p>\n</li>\n<li>\n<p>Select the clipboard icon to copy the <strong>Client ID</strong>.</p>\n</li>\n</ol>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-the-tailscale-terraform-provider\">Configure federated identities using the Tailscale Terraform provider</a></h3>\n<p>To configure federated identities using the Tailscale Terraform provider with the <code>tailscale_federated_identity</code> resource:</p>\n<pre><code class=\"language-hcl\">resource \"tailscale_federated_identity\" \"example_federated_identity\" {\r\n  description = \"Example federated identity\"\r\n  scopes      = [\"auth_keys\", \"devices:core\"]\r\n  tags        = [\"tag:test\"]\r\n  issuer      = \"https://example.com\"\r\n  subject     = \"example-sub-*\"\r\n  custom_claim_rules = {\r\n    repo_name = \"example-repo-name\"\r\n  }\r\n}\n</code></pre>\n<p>For more information, refer to the <a href=\"https://registry.terraform.io/providers/tailscale/tailscale/latest/docs/resources/federated_identity\">Tailscale Terraform provider documentation</a>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-tailscale-client-go-v2\">Configure federated identities using tailscale-client-go-v2</a></h3>\n<p>To configure federated identities federated identities using <code>tailscale-client-go-v2</code>:</p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"os\"\r\n\r\n\t\"tailscale.com/client/tailscale/v2\"\r\n)\r\n\r\nfunc main() {\r\n\tclient := &#x26;tailscale.Client{\r\n\t\t// Client configuration\r\n\t}\r\n\r\n\treq := tailscale.CreateFederatedIdentityRequest {\r\n\t\tDescription: \"Example federated identity\",\r\n\t\tScopes:  []string{\"auth_keys\", \"devices:core\"},\r\n\t\tTags:    []string{\"tag:test\"},\r\n\t\tSubject: \"example-sub-*\",\r\n\t\tCustomClaimRules: map[string]string{\r\n\t\t\t\"repo_name\": \"example-repo-name\",\r\n\t\t},\r\n\t}\r\n\r\n\tfederatedIdentity, err := client.Keys().CreateFederatedIdentity(context.Background(), req)\r\n}\n</code></pre>\n<p>For more information, refer to <a href=\"https://github.com/tailscale/tailscale-client-go-v2\"><code>tailscale-client-go-v2</code></a>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#configure-federated-identities-using-the-tailscale-api\">Configure federated identities using the Tailscale API</a></h3>\n<p>To configure federated identities using the Tailscale API with the <code>https://api.tailscale.com/api/v2/tailnet/-/keys</code> endpoint:</p>\n<pre><code class=\"language-shell\">curl -X POST https://api.tailscale.com/api/v2/tailnet/-/keys \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d   '{\r\n  \"keyType\": \"federated\",\r\n  \"description\": \"Example federated identity\",\r\n  \"scopes\": [\\\r\n    \"auth_keys\",\\\r\n    \"devices:core\"\\\r\n  ],\r\n  \"tags\": [\\\r\n    \"tag:test\"\\\r\n  ],\r\n  \"issuer\": \"https://example.com\",\r\n  \"subject\": \"example-sub-*\",\r\n  \"customClaimRules\": {\r\n    \"repo_name\": \"example-repo-name\",\r\n  }'\n</code></pre>\n<p>For more information, refer to <a href=\"https://tailscale.com/api#tag/keys/post/tailnet/%7Btailnet%7D/keys\">endpoint API</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/workload-identity-federation#exchange-workload-identity-tokens-with-tailscale\">Exchange workload identity tokens with Tailscale</a></h2>\n<p>Workload identity tokens must be exchanged with Tailscale to authenticate and provide a Tailscale access token.</p>\n<p>Using workload identity token exchange for authentication is supported natively in:</p>\n<ul>\n<li>The <a href=\"https://tailscale.com/docs/features/workload-identity-federation#tailscale-github-action\">Tailscale GitHub Action</a></li>\n<li>The <a href=\"https://tailscale.com/docs/features/workload-identity-federation#tailscale-terraform-provider\">Tailscale Terraform provider</a></li>\n<li><a href=\"https://tailscale.com/docs/features/workload-identity-federation#tailscale-client-go-v2\"><code>tailscale-client-go-v2</code></a></li>\n<li>The <a href=\"https://tailscale.com/docs/features/workload-identity-federation#token-exchange-api\">Tailscale API</a></li>\n</ul>\n<p>Workload identity can also be used for <a href=\"https://tailscale.com/docs/features/workload-identity-federation#register-new-nodes-using-workload-identity\">registering new nodes</a> in your tailnet.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#tailscale-github-action\">Tailscale GitHub Action</a></h3>\n<p>Workload identity can be used to authenticate the Tailscale GitHub action by using the <code>oauth-client-id</code>, <code>audience</code>, and <code>tags</code> arguments:</p>\n<pre><code class=\"language-yaml\">- name: Tailscale\r\n  uses: tailscale/github-action@v4\r\n  with:\r\n    oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}\r\n    audience: ${{ secrets.TS_AUDIENCE }}\r\n    tags: tag:ci\n</code></pre>\n<p>Workload identity federation requires the <code>id-token: write</code> <a href=\"https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-cloud-providers#adding-permissions-settings\">permission setting</a> for the workflow:</p>\n<pre><code class=\"language-yaml\">permissions:\r\n  id-token: write # This is required for the tailscale action to request a JWT from GitHub\r\n  # Additional required permissions for your workflow\n</code></pre>\n<p>For more information, refer to <a href=\"https://github.com/tailscale/github-action\">GitHub action</a>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#tailscale-terraform-provider\">Tailscale Terraform provider</a></h3>\n<p>Workload identity can be used to authenticate the Tailscale Terraform provider by using the <code>oauth_client_id</code> and <code>id_token</code> provider arguments:</p>\n<pre><code class=\"language-hcl\">provider \"tailscale\" {\r\n  oauth_client_id = \"my_client_id\"\r\n  identity_token  = \"my_identity_token\"\r\n  tailnet         = \"example.com\"\r\n}\n</code></pre>\n<p>For more information, refer to <a href=\"https://registry.terraform.io/providers/tailscale/tailscale/latest\">Tailscale Terraform provider</a>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#tailscale-client-go-v2\">tailscale-client-go-v2</a></h3>\n<p>Workload identity can be used to authenticate <code>tailscale-client-go-v2</code> by supplying a <code>ClientID</code> and <code>IDTokenFunc</code> to <code>tailscale.Client</code>:</p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"os\"\r\n\r\n\t\"tailscale.com/client/tailscale/v2\"\r\n)\r\n\r\nfunc main() {\r\n\tclient := &#x26;tailscale.Client{\r\n\t\tTailnet: os.Getenv(\"TAILSCALE_TAILNET\"),\r\n\t\tAuth: &#x26;tailscale.IdentityFederation{\r\n\t\t\tClientID: os.Getenv(\"TAILSCALE_OAUTH_CLIENT_ID\"),\r\n\t\t\tIDTokenFunc: func() (string, error) {\r\n\t\t\t\treturn os.Getenv(\"IDENTITY_TOKEN\"), nil\r\n            },\r\n\t\t},\r\n\t}\r\n\r\n\t// Example API call\r\n\tdevices, err := client.Devices().List(context.Background())\r\n}\n</code></pre>\n<p>For more information, refer to <a href=\"https://github.com/tailscale/tailscale-client-go-v2\"><code>tailscale-client-go-v2</code></a>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#token-exchange-api\">Token exchange API</a></h3>\n<p>The Tailscale token exchange endpoint is <code>https://api.tailscale.com/api/v2/oauth/token-exchange</code>.</p>\n<p>Make requests to the Tailscale token exchange endpoint when you need a short-lived Tailscale access token:</p>\n<pre><code class=\"language-shell\">curl -X POST https://api.tailscale.com/api/v2/oauth/token-exchange \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"client_id=&#x3C;CLIENT_ID>\" \\\r\n  -d \"jwt=&#x3C;JWT>\"\n</code></pre>\n<ul>\n<li><code>&#x3C;CLIENT_ID></code>: The client ID generated when you configured a federated identity in the Tailscale admin console.</li>\n<li><code>&#x3C;JWT></code>: The signed OIDC JWT provided to the workload by the cloud provider.</li>\n</ul>\n<p>If the client ID and JWT are valid and match the configured audience, subject, and custom claim rules, Tailscale will return a short-lived API token to use for authenticating the workload to the Tailscale API.</p>\n<p>If the short-lived API token expires, you can repeat this step to receive a fresh token.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#debugging-token-exchange-errors\">Debugging token exchange errors</a></h3>\n<p>The latest token exchange error details for a federated identity can be found in the admin console.</p>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/settings/trust-credentials\">Trust credentials</a> page of the admin console.</p>\n</li>\n<li>\n<p>Use the <strong>Search</strong> and optionally the <strong>Filters</strong> functionality to find the federated identity you are interested in.</p>\n<ul>\n<li>Searching by <code>tag</code> may be useful.</li>\n<li>Setting the <strong>Filters</strong> value to <strong>Client type</strong> and selecting <strong>OIDC</strong> may also be useful.</li>\n</ul>\n</li>\n<li>\n<p>Select the <img src=\"https://tailscale.com/files/images/icons/fa-ellipsis-h.svg\" alt=\"ellipsis icon\"> menu and select <strong>View</strong> or <strong>Edit</strong>.</p>\n</li>\n</ol>\n<p>Information about the error will be present on this page, with specific guidance varying depending on the type of error.</p>\n<p>Errors will only be cleared once a token exchange has succeeded for the federated identity.</p>\n<h4><a href=\"https://tailscale.com/docs/features/workload-identity-federation#api-error-responses\">API error responses</a></h4>\n<p>Errors returned from the token exchange API endpoint will not have specific debugging information directly in the error message.</p>\n<p>This is done to prevent leaking information to potential bad actors as they could otherwise attempt to reverse engineer your federated identity's configuration from error messages if they know its client ID.</p>\n<p>Error messages will instead contain a direct link to the federated identity within the admin console in a message of the form:</p>\n<pre><code class=\"language-json\">{ \"message\": \"Unauthorized. Visit [link to admin console] for details\" }\n</code></pre>\n<p>Information about the error will be present on this page, with specific guidance varying depending on the type of error.</p>\n<p>Errors will only be cleared once a token exchange has succeeded for the federated identity.</p>\n<h2><a href=\"https://tailscale.com/docs/features/workload-identity-federation#register-new-nodes-using-workload-identity\">Register new nodes using workload identity</a></h2>\n<p>A device must run Tailscale v1.90.1 or later to have the <code>--client-id</code> and <code>--id-token</code> flags.</p>\n<p>You can use a client ID and OIDC token directly in <a href=\"https://tailscale.com/docs/reference/tailscale-cli/up\"><code>tailscale up</code></a> to register a new node:</p>\n<pre><code class=\"language-shell\">tailscale up --client-id=${CLIENT_ID} --id-token=${IDENTITY_TOKEN} --advertise-tags=tag:ci\n</code></pre>\n<p>The <code>tailscale up</code> command expects the <code>client-id</code> to be the Client ID used to generate auth keys with workload identity federation. Access the admin console to <a href=\"https://tailscale.com/docs/features/workload-identity-federation#retrieve-the-client-id-in-the-admin-console\">retrieve the <strong>Client ID</strong></a>.</p>\n<p>The command also expects the <code>id-token</code> to be the ID token from the identity provider to exchange with the control server for workload federation. This value is the signed OIDC JWT and not a short-lived API token.</p>\n<p>The workload identity credential must have the <code>auth_keys</code> scope and the <a href=\"https://tailscale.com/docs/features/tags\">tags</a> passed to <code>--advertise-tags</code> must match the tags you selected when you <a href=\"https://tailscale.com/docs/features/workload-identity-federation#set-up-a-federated-identity\">configured the federated identity</a>.</p>\n<p>The <code>--client-id</code> flag can accept additional URL-style parameters:</p>\n<pre><code class=\"language-shell\">tailscale up --client-id='${CLIENT_ID}?ephemeral=false&#x26;preauthorized=true' --id-token=${IDENTITY_TOKEN} --advertise-tags=tag:ci\n</code></pre>\n<p>The available parameters are:</p>\n<ul>\n<li><code>ephemeral</code>: register as an <a href=\"https://tailscale.com/docs/features/ephemeral-nodes\">ephemeral node</a> (defaults to <code>true</code>)</li>\n<li><code>preauthorized</code>: skip manual <a href=\"https://tailscale.com/docs/features/access-control/device-management/device-approval\">device approval</a> (defaults to <code>false</code>)</li>\n</ul>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#automatic-cloud-token-discovery-and-exchange\">Automatic cloud token discovery and exchange</a></h3>\n<p>A device must run Tailscale v1.94.0 or later to have the <code>--audience</code> flag.</p>\n<p>Tailscale can automatically detect certain cloud and CI environments and retrieve a native identity token from the platform it is running on. When enabled, the client uses this token to authenticate the node to your tailnet using <strong>workload identity federation</strong> without requiring you to manually provision or manage credentials.</p>\n<p>This functionality is intended for <strong>non-interactive workloads</strong>, such as cloud VMs, containerized services, and CI/CD pipelines, where identity should be derived from the execution environment itself.</p>\n<p>No long-lived credentials, access keys, or secrets are stored on disk or injected at runtime.</p>\n<p>This behavior is enabled by passing a client ID and audience to <a href=\"https://tailscale.com/docs/reference/tailscale-cli/up\"><code>tailscale up</code></a>:</p>\n<pre><code class=\"language-shell\">tailscale up --client-id=${CLIENT_ID} --audience=${AUDIENCE} --advertise-tags=tag:ci\n</code></pre>\n<p>The command expects <code>audience</code> to be the audience specified in the trust configuration for the federated identity referred to by <code>client-id</code>.</p>\n<h4><a href=\"https://tailscale.com/docs/features/workload-identity-federation#supported-environments\">Supported environments</a></h4>\n<p>Automatic token discovery requires both a native workload identity on the platform and a matching <a href=\"https://tailscale.com/docs/features/workload-identity-federation#set-up-a-federated-identity\">trust configuration</a> in Tailscale. Once configured, the Tailscale client will obtain a provider token on your behalf on the platforms described below.</p>\n<p><strong>AWS</strong></p>\n<p><strong>Workload environment</strong></p>\n<ul>\n<li>The workload runs on an AWS service that supports IAM roles. For example, Elastic Cloud Compute (EC2), Elastic Container Service (ECS), or Elastic Kubernetes Service (EKS).</li>\n<li>An IAM role is attached to the instance, task, or pod.</li>\n</ul>\n<p><strong>IAM configuration</strong></p>\n<ul>\n<li>The IAM role must allow issuance of web identity tokens from AWS Security Token Service (STS).</li>\n<li>The role's trust policy must permit the configured web identity provider.</li>\n</ul>\n<pre><code class=\"language-yaml\">{\r\n\"Version\": \"2012-10-17\",\r\n  \"Statement\": [\\\r\n  {\\\r\n    \"Sid\": \"AllowGetWebIdentityTokenForTailscale\",\\\r\n    \"Effect\": \"Allow\",\\\r\n    \"Action\": \"sts:GetWebIdentityToken\",\\\r\n    \"Resource\": \"*\",\\\r\n    \"Condition\": {\\\r\n      \"ForAnyValue:StringEquals\": {\\\r\n        \"sts:IdentityTokenAudience\": \"{YOUR_TAILSCALE_AUDIENCE}\"\\\r\n      },\\\r\n      \"NumericLessThanEquals\": {\\\r\n        \"sts:DurationSeconds\": \"300\"\\\r\n      }\\\r\n    }\\\r\n  }\\\r\n  ]\r\n}\n</code></pre>\n<p><strong>Tailscale configuration</strong></p>\n<ul>\n<li>A workload identity federation configuration exists in Tailscale that:\n<ul>\n<li>Trusts the AWS token issuer.</li>\n<li>Expects the correct audience (<code>aud</code>).</li>\n<li>Matches any required role or environment-specific claims.</li>\n</ul>\n</li>\n</ul>\n<p><strong>Google Cloud</strong></p>\n<p><strong>Workload environment</strong></p>\n<ul>\n<li>The workload runs on a Google Cloud Platform (GCP) service that exposes the metadata server. For example, Google Compute Engine (GCE) or Google Kubernetes Engine (GKE).</li>\n<li>A <strong>service account</strong> is attached to the VM or workload.</li>\n</ul>\n<p><strong>IAM configuration</strong></p>\n<ul>\n<li>The service account must be allowed to mint identity tokens.</li>\n<li>The workload must be permitted to request identity tokens for the configured audience.</li>\n</ul>\n<p><strong>Tailscale configuration</strong></p>\n<ul>\n<li>A workload identity federation configuration exists in Tailscale that:\n<ul>\n<li>Trusts the GCP token issuer.</li>\n<li>Expects the configured audience.</li>\n<li>Optionally matches service account–specific claims.</li>\n</ul>\n</li>\n</ul>\n<p><strong>GitHub Actions</strong></p>\n<p><strong>Workflow configuration</strong></p>\n<ul>\n<li>The workflow runs on a GitHub-hosted or self-hosted runner that supports OIDC.</li>\n<li>The workflow explicitly enables OIDC token issuance:</li>\n</ul>\n<pre><code class=\"language-yaml\">permissions:\r\n  id-token: write\n</code></pre>\n<p><strong>Repository or organization configuration</strong></p>\n<ul>\n<li>OIDC token issuance is enabled for the repository or organization.</li>\n<li>Any branch, environment, or repository restrictions align with the expected token claims.</li>\n</ul>\n<p><strong>Tailscale configuration</strong></p>\n<ul>\n<li>A workload identity federation configuration exists in Tailscale that:\n<ul>\n<li>Trusts the GitHub Actions OIDC issuer.</li>\n<li>Matches the expected audience, repository, and workflow claims.</li>\n</ul>\n</li>\n</ul>\n<p><strong>Unsupported environments</strong></p>\n<p>If the client does not detect a supported platform, automatic token discovery is skipped and the client falls back to manual workload identity federation configuration.</p>\n<h2><a href=\"https://tailscale.com/docs/features/workload-identity-federation#reference\">Reference</a></h2>\n<p>The following sections provide technical details about claims.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#common-cloud-provider-token-formats\">Common cloud provider token formats</a></h3>\n<p>Cloud providers have unique formats for the <code>sub</code> claim, and the custom claims, for OIDC tokens that they issue.\r\nBelow are some common cloud providers and the formats of their OIDC tokens.</p>\n<p><a href=\"https://tailscale.com/docs/features/workload-identity-federation?tab=aws\">AWS</a> <a href=\"https://tailscale.com/docs/features/workload-identity-federation?tab=github+actions\">GitHub Actions</a> <a href=\"https://tailscale.com/docs/features/workload-identity-federation?tab=google+cloud\">Google Cloud</a> <a href=\"https://tailscale.com/docs/features/workload-identity-federation?tab=microsoft+azure\">Microsoft Azure</a></p>\n<h5><a href=\"https://tailscale.com/docs/features/workload-identity-federation#subject-format\">Subject format</a></h5>\n<p>The ARN of the IAM principal that requested the token. Refer to <a href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound_token_claims.html\">AWS token claims</a>.</p>\n<h5><a href=\"https://tailscale.com/docs/features/workload-identity-federation#token-claims\">Token Claims</a></h5>\n<p>Refer to <a href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound_token_claims.html\">AWS token claims</a>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#claim-value-format\">Claim value format</a></h3>\n<p>Values specified for the <strong>subject</strong> and <strong>custom claims</strong> are matched against claims values in the OIDC JWT.</p>\n<p>Values can contain an <code>*</code> to match against any character. Other characters specified must directly match the value of the claim.</p>\n<p>For example, specifying <code>my-example-sub/*</code> for the subject will successfully match <code>sub</code> claims that start with <code>my-example-sub/</code>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#custom-claim-key-format\">Custom claim key format</a></h3>\n<p>Keys for <strong>custom claims</strong> specify the claim in the OIDC JWT to match against.</p>\n<p>For example, given a token of the form:</p>\n<pre><code class=\"language-json\">{\r\n\t\"sub\": \"123456-example\",\r\n\t\"iss\": \"https://example.com\",\r\n\t\"aud\": \"api.tailscale.com/12345-67890\",\r\n\t\"user\": \"example\"\r\n}\n</code></pre>\n<p>the <code>user</code> claim can be referenced by specifying <code>user</code> for the key.</p>\n<h4><a href=\"https://tailscale.com/docs/features/workload-identity-federation#nested-claims\">Nested claims</a></h4>\n<p>Keys can refer to nested claims within a JWT by separating the nested key names with a period.</p>\n<p>For example, given token of the form:</p>\n<pre><code class=\"language-json\">{\r\n\t\"sub\": \"123456-example\",\r\n\t\"iss\": \"https://example.com\",\r\n\t\"aud\": \"api.tailscale.com/12345-67890\",\r\n\t\"user\": \"example\",\r\n\t\"user\": {\r\n\t\t\"name\": \"foobar\"\r\n\t}\r\n}\n</code></pre>\n<p>the nested <code>name</code> claim can be referenced by specifying <code>user.name</code> for the key.</p>\n<h4><a href=\"https://tailscale.com/docs/features/workload-identity-federation#escaping-claim-names\">Escaping claim names</a></h4>\n<p>Keys that contain a period in their name can be escaped by surrounding them in double quotes.</p>\n<p>For example, given a token of the form:</p>\n<pre><code class=\"language-json\">{\r\n\t\"sub\": \"123456-example\",\r\n\t\"iss\": \"https://example.com\",\r\n\t\"aud\": \"api.tailscale.com/12345-67890\",\r\n\t\"user\": \"example\",\r\n\t\"open.id\": {\r\n\t\t\"username\": \"foobar\"\r\n\t}\r\n}\n</code></pre>\n<p>the <code>open.id</code> key can be referenced as <code>\"open.id\"</code> and the nested <code>username</code> key as <code>\"open.id\".username</code>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/workload-identity-federation#generated-audience-format\">Generated audience format</a></h3>\n<p>Audience values generated by Tailscale are of the form: <code>api.tailscale.com/&#x3C;client ID></code>.</p>\n<p>For example, a federated identity with the client ID <code>Tz8TefihCR11EXAMPLE-kZDRvszg8621EXAMPLE</code> will have a generated audience of <code>api.tailscale.com/Tz8TefihCR11EXAMPLE-kZDRvszg8621EXAMPLE</code></p>\n<h2><a href=\"https://tailscale.com/docs/features/workload-identity-federation#limitations\">Limitations</a></h2>\n<ul>\n<li>The issuer that provides signed JSON Web Tokens (JWTs) to your workloads must be publicly accessible.</li>\n</ul>\n<p><img src=\"https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed\" alt=\"Project Logo\"></p>\n<p>Ask AI</p>\n<p>reCAPTCHA</p>\n<p>Recaptcha requires verification.</p>\n<p>protected by <strong>reCAPTCHA</strong></p>\n"}