Try it free

Workload identity federation

  • Latest Dynatrace
  • Reference
  • 1-min read
  • Preview

Workload identity federation is an Early Access feature. To request access, see Workload identity federation in the Preview program.

Workload identity federation (WIF) lets an external workload call the Dynatrace API with a token issued by its own identity provider. Dynatrace resolves that token to a service user, so you never store a Dynatrace client secret or platform token alongside your workload.

This suits any workload that already has a machine identity—an Azure virtual machine with a managed identity, a GitHub Actions job, a Google Cloud service, or a Kubernetes pod with a projected service account token.

You configure workload identity federation through the Account Management API.

How it works

  1. The workload obtains a short-lived OpenID Connect token from its own identity provider.
  2. The workload calls the Dynatrace API, passing that token in the Authorization header as a bearer token.
  3. Dynatrace looks for a trust policy matching the token's iss and aud claims, then verifies the token signature against the issuer's JSON Web Key Set.
  4. Dynatrace compares the token's claims against the service user mappings on that trust policy.
  5. On a match, Dynatrace runs the request as the mapped service user, limited to the scopes allowed by the mapping.

Steps 3 to 5 happen inside the platform on every request. Your workload only ever handles its own identity provider token.

Because that token is short-lived and issued on demand, no Dynatrace credential is ever written to disk, baked into an image, or stored in a CI secret.

Concepts

ObjectDescription

Trust policy

Declares an external identity provider that Dynatrace trusts, identified by an issuer URL and an audience. A trust policy is unique per issuer URL, and audience combination. One Dynatrace account can have many such trust policies.

Service user mapping

Binds tokens that satisfy a trust policy to one service user, one environment, and a set of scopes. A trust policy can hold many mappings. Same service user can be assigned to mappings from different trust policies, as long as they do not overlap with each other.

Claim mapping

A condition on a single claim in the external token. A mapping needs at least one claim mapping, and all of them must match for the mapping to apply.

Each claim mapping uses a matchType:

  • EXACT—the claim value must match the configured value exactly.
  • GLOB—the claim value is matched against a wildcard pattern, which is useful for matching a group of repositories, branches, or namespaces.

Prerequisites

  • An OAuth client with the account-idm-read and account-idm-write scopes. See OAuth clients.
  • An active service user to receive the federated identity.
  • An identity provider that issues tokens signed with ES256 or RS256. The provider must either publish an OpenID Connect discovery document over HTTPS (URL mode), or you must paste its JSON Web Key Set directly when you create the trust policy (manual mode—no outbound calls are made).

External tokens must carry the iss, aud, exp, iat, and sub claims.

Manage trust policies

All requests below authenticate with an OAuth bearer token, as described in OAuth clients.

OperationEndpointRequired scope

Create

POST /iam/v1/accounts/{accountUuid}/wif/trust-policies

account-idm-write

List

GET /iam/v1/accounts/{accountUuid}/wif/trust-policies

account-idm-read

Retrieve

GET /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}

account-idm-read

Update

PUT /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}

account-idm-write

Change status

PATCH /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}

account-idm-write

Delete

DELETE /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}

account-idm-write

Create a trust policy

OperationEndpoint

POST

https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies

Content type

application/json

Provide the following parameters in the request body.

ParameterValue

name

Required A name for the trust policy, unique within the account.

issuerUrl

Required The issuer URL of the external identity provider, matched against the iss claim of the external token.

In URL mode (default): must use HTTPS, no query string or fragment, and Dynatrace rejects addresses that resolve to private or loopback ranges. Dynatrace discovers the JSON Web Key Set from {issuerUrl}/.well-known/openid-configuration.

In manual mode (jwksSource: MANUAL): URL-format validation is relaxed because Dynatrace makes no outbound fetch—the value is only matched against the iss claim of the external token.

audience

Required The expected value of the aud claim of the external token. Matched exactly, with no wildcards and no normalization.

description

Optional A free-text description of the trust policy.

jwksSource

Optional The registration mode. Accepted values: URL (default) or MANUAL.

URL—Dynatrace resolves the JWKS URI from the issuer's OpenID Connect discovery document and refreshes signing keys automatically. Use this when the identity provider's OIDC endpoint is publicly reachable.

MANUAL—Dynatrace uses the JWKS document supplied in the jwks field and makes no outbound HTTP calls. Use this for identity providers whose endpoints are not publicly reachable, such as private Kubernetes clusters or VPC-internal issuers. Key rotation in this mode is the account admin's responsibility via the update endpoint.

jwks

Required Required when jwksSource is MANUAL. The identity provider's JSON Web Key Set as a raw JSON object. The keys array must be non-empty and each key must include the required JWK fields (kty, kid, and algorithm-appropriate parameters). Omit in URL mode.

curl --request POST \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"name": "Azure production tenant",
"issuerUrl": "https://sts.windows.net/{tenantId}/",
"audience": "api://dynatrace-wif",
"description": "Workloads running in the production Azure subscription"
}'

A successful request returns 201 and the created trust policy.

{
"uuid": "3f1c9a2e-5d47-4b8a-9c31-7e0b2d6f8a15",
"name": "Azure production tenant",
"issuerUrl": "https://sts.windows.net/{tenantId}/",
"issuerUrlHash": "9b74c9897bac770ffc029102a200c5de",
"jwksUri": "https://sts.windows.net/{tenantId}/.well-known/openid-configuration",
"description": "Workloads running in the production Azure subscription",
"audience": "api://dynatrace-wif",
"status": "ACTIVE",
"createdAt": "2026-08-06T09:14:22Z",
"updatedAt": "2026-08-06T09:14:22Z",
"serviceUserMappings": []
}

Dynatrace creates new trust policies with status ACTIVE. In URL mode, the jwksUri field in the response is read-only and populated automatically from the issuer's OpenID Connect discovery document. In manual mode, the response reflects the jwks document you supplied; update it at any time via PUT to rotate keys.

To create a trust policy in manual mode, include jwksSource: MANUAL and the raw JWKS document. Dynatrace makes no outbound calls to resolve the issuer.

curl --request POST \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"name": "On-premises Kubernetes cluster",
"issuerUrl": "https://kubernetes.default.svc.cluster.local",
"audience": "api://dynatrace-wif",
"description": "Private cluster with no public OIDC endpoint",
"jwksSource": "MANUAL",
"jwks": {
"keys": [
{
"kty": "RSA",
"kid": "key-id-1",
"use": "sig",
"alg": "RS256",
"n": "{base64url-modulus}",
"e": "AQAB"
}
]
}
}'

In manual mode, Dynatrace does not refresh signing keys automatically. When your identity provider rotates its keys, send a PUT request with the updated jwks document to keep token validation working.

List trust policies

curl --request GET \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies?pageSize=50&pageNumber=1' \
--header 'Authorization: Bearer {your-access-token}'

The response is paginated. Use the pageNumber and pageSize query parameters to page through results.

{
"pageSize": 50,
"pageNumber": 1,
"total": 1,
"results": [
{
"uuid": "3f1c9a2e-5d47-4b8a-9c31-7e0b2d6f8a15",
"name": "Azure production tenant",
"issuerUrl": "https://sts.windows.net/{tenantId}/",
"audience": "api://dynatrace-wif",
"status": "ACTIVE",
"createdAt": "2026-08-06T09:14:22Z",
"updatedAt": "2026-08-06T09:14:22Z"
}
]
}

Retrieve a trust policy

Retrieving a single trust policy also returns its service user mappings.

curl --request GET \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}' \
--header 'Authorization: Bearer {your-access-token}'

Update a trust policy

Send the complete object. Fields you omit are cleared.

curl --request PUT \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"name": "Azure production tenant",
"issuerUrl": "https://sts.windows.net/{tenantId}/",
"audience": "api://dynatrace-wif",
"description": "Updated description"
}'

Enable or disable a trust policy

Disabling a trust policy immediately stops all workloads that rely on it from authenticating, without deleting its mappings. Disabling is the quickest way to cut off access from a compromised identity provider. Note that there still might be a short delay due to caching until this takes effect.

curl --request PATCH \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{ "status": "INACTIVE" }'

Set status to ACTIVE to re-enable the trust policy.

Delete a trust policy

Deleting a trust policy also removes its service user mappings.

curl --request DELETE \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}' \
--header 'Authorization: Bearer {your-access-token}'

Manage service user mappings

A trust policy establishes who Dynatrace trusts. A service user mapping decides what a trusted workload can do.

OperationEndpointRequired scope

Create

POST /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings

account-idm-write

List

GET /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings

account-idm-read

Retrieve

GET /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}

account-idm-read

Update

PUT /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}

account-idm-write

Change status

PATCH /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}

account-idm-write

Delete

DELETE /iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}

account-idm-write

Create a service user mapping

OperationEndpoint

POST

https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings

Content type

application/json

ParameterValue

serviceUserUuid

Required The UUID of an active service user. Requests that match this mapping run as this user.

environmentId

Required The environment this mapping grants access to.

scopes

Required The service user scope subset that will be assigned to the access token issued for the matching workload.

claimMappings

Required One or more conditions on the claims of the external token. Each entry takes a claimName, a claimValue, and a matchType of either EXACT or GLOB.

All claim mappings must match. Each claimName can appear only once per mapping.

curl --request POST \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"serviceUserUuid": "be820735-3114-4d40-9c44-dfa18fa62be9",
"environmentId": "{environmentId}",
"scopes": ["storage:logs:read", "storage:events:read"],
"claimMappings": [
{
"claimName": "sub",
"claimValue": "11111111-2222-3333-4444-555555555555",
"matchType": "EXACT"
}
]
}'

A successful request returns 201 and the created mapping.

{
"uuid": "7a2b4c6d-8e10-4f32-b5a7-9c1d3e5f7089",
"serviceUserUuid": "be820735-3114-4d40-9c44-dfa18fa62be9",
"environmentId": "{environmentId}",
"scopes": ["storage:logs:read", "storage:events:read"],
"status": "ACTIVE",
"claimMappings": [
{
"claimName": "sub",
"claimValue": "11111111-2222-3333-4444-555555555555",
"matchType": "EXACT"
}
],
"createdAt": "2026-08-06T09:22:41Z",
"updatedAt": "2026-08-06T09:22:41Z"
}

An external token must match exactly one mapping. If it matches none, or more than one, the request fails with an HTTP 401. Keep claim mappings specific enough to stay unambiguous.

To grant a group of workloads the same access, use a GLOB match instead of listing each identity.

{
"claimName": "sub",
"claimValue": "repo:my-org/my-service:ref:refs/heads/*",
"matchType": "GLOB"
}

List service user mappings

curl --request GET \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings?pageSize=50&pageNumber=1' \
--header 'Authorization: Bearer {your-access-token}'

Retrieve a service user mapping

curl --request GET \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}' \
--header 'Authorization: Bearer {your-access-token}'

Update a service user mapping

Send the complete object, including all claim mappings you want to keep.

curl --request PUT \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"serviceUserUuid": "be820735-3114-4d40-9c44-dfa18fa62be9",
"environmentId": "{environmentId}",
"scopes": ["storage:logs:read"],
"claimMappings": [
{
"claimName": "sub",
"claimValue": "11111111-2222-3333-4444-555555555555",
"matchType": "EXACT"
}
]
}'

Enable or disable a service user mapping

curl --request PATCH \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{ "status": "INACTIVE" }'

Delete a service user mapping

curl --request DELETE \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings/{mappingUuid}' \
--header 'Authorization: Bearer {your-access-token}'

Authenticate a workload

Once a trust policy and a matching service user mapping exist, the workload authenticates by attaching its own identity provider token to the Authorization header, preceded by the Bearer realm. Note that some workloads, like the OTel Collector, already implement libraries that handle the authorization header with every http request, as well as refreshing the OIDC token.

--header 'Authorization: Bearer {your-oidc-token}'

There is nothing to exchange and no Dynatrace token to manage. Dynatrace resolves the token to the mapped service user on each request.

curl --request POST \
--url 'https://{environmentId}.apps.dynatrace.com/platform/storage/query/v1/query:execute' \
--header 'Authorization: Bearer {your-oidc-token}' \
--header 'Content-Type: application/json' \
--data '{ "query": "fetch logs | limit 10" }'

Request a fresh token from your identity provider whenever the current one expires. These tokens are short-lived by design.

Any problem with the token results in an HTTP 401 response. Dynatrace doesn't distinguish between an unknown issuer, an invalid signature, an expired token, an inactive trust policy, and a claim set that matches no mapping or more than one. If you get a 401, check the validation rules and confirm your trust policy and service user mapping against the claims your identity provider actually issues.

Example — Azure Entra managed identity

This example gives an Azure virtual machine read access to logs in a Dynatrace environment. The virtual machine uses a managed identity, so no secret is stored anywhere.

Step 1—Expose an audience in Microsoft Entra

Register an application in Microsoft Entra ID and set its Application ID URI, for example api://dynatrace-wif. This value becomes the aud claim of the tokens your workloads request, and the audience of the Dynatrace trust policy. You don't need a client secret.

Note your Entra tenant ID and the object ID of the managed identity assigned to the virtual machine.

Step 2—Create the trust policy

The issuer URL for Microsoft Entra tokens is https://sts.windows.net/{tenantId}/, including the trailing slash.

curl --request POST \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"name": "Azure production tenant",
"issuerUrl": "https://sts.windows.net/{tenantId}/",
"audience": "api://dynatrace-wif"
}'

Note the uuid from the response.

Step 3—Map the managed identity to a service user

Match on the sub claim, which for a managed identity is the object ID of its service principal.

curl --request POST \
--url 'https://api.dynatrace.com/iam/v1/accounts/{accountUuid}/wif/trust-policies/{trustPolicyUuid}/mappings' \
--header 'Authorization: Bearer {your-access-token}' \
--header 'Content-Type: application/json' \
--data '{
"serviceUserUuid": "be820735-3114-4d40-9c44-dfa18fa62be9",
"environmentId": "{environmentId}",
"scopes": ["storage:logs:read"],
"claimMappings": [
{
"claimName": "sub",
"claimValue": "{managed-identity-object-id}",
"matchType": "EXACT"
}
]
}'

Step 4—Get an Entra token on the workload

From inside the virtual machine, request a token from the Azure Instance Metadata Service for the audience you exposed in Step 1.

AZURE_TOKEN=$(curl -s \
--header 'Metadata: true' \
--url 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api://dynatrace-wif' \
| jq -r '.access_token')

Step 5—Call the Dynatrace API

Pass the Entra token straight to Dynatrace. The request runs as the mapped service user.

curl --request POST \
--url 'https://{environmentId}.apps.dynatrace.com/platform/storage/query/v1/query:execute' \
--header "Authorization: Bearer $AZURE_TOKEN" \
--header 'Content-Type: application/json' \
--data '{ "query": "fetch logs | limit 10" }'

Repeat Step 4 whenever the Entra token expires.

Validation rules

For the maximum number of trust policies per account and service user mappings per trust policy, see Identity and Access Management limits.

RuleDetail

Trust policy uniqueness

One trust policy per combination of account, issuer URL, and audience.

Issuer URL

HTTPS only, up to 2048 characters, and no query string or fragment. Dynatrace rejects URLs that resolve to private or loopback addresses.

Audience

Non-empty, up to 512 characters. Compared exactly: the trust policy audience must equal one value in the external token's aud claim. There is no wildcard matching and no normalization.

jwksSource

Optional. Accepted values: URL (default) or MANUAL. URL mode requires the issuer to expose a public OIDC discovery endpoint. Manual mode requires a jwks document and makes no outbound HTTP calls—HTTPS-URL validation of issuerUrl does not apply.

JWKS document (jwks)

Required when jwksSource is MANUAL. Must be a valid JSON object with a non-empty keys array. Each key must include kty, kid, and the algorithm-appropriate key parameters. Omit in URL mode.

Signature algorithms

ES256 and RS256.

Required token claims

iss, aud, exp, iat, and sub.

Claim mappings

At least one per service user mapping. Each claimName may appear only once, and all must match.

Related topics

  • Tokens and oauth client concepts
  • Service users
  • Platform tokens
  • OAuth clients
  • Workload identity federation with the OTel Collector
Related tags
Dynatrace Platform