> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/harness-platform/use-harness-platform/pipelines/pipeline-identities.md).

# Pipeline identities

Declare identities in pipeline YAML so a pipeline, stage, or step can authenticate to external systems such as AWS and GCP.

{% hint style="success" %}
This feature is in Limited GA[^1] and requires enablement. [View all early access features.](/release-notes/features.md)

{% @harness-feature-flag-access/request-feature-flag-access module="platform" pagePath="platform/use-harness-platform/pipelines/pipeline-identities" featureFlags="%5B%7B%22name%22%3A%22Pipeline%20identities%22%2C%22key%22%3A%22PIPE\_PIPELINE\_IDENTITY%22%2C%22status%22%3A%22LIMITED\_GA%22%2C%22description%22%3A%22Enables%20the%20identities%20map%20in%20pipeline%2C%20stage%2C%20step%2C%20and%20template%20YAML%20so%20a%20pipeline%20can%20authenticate%20to%20external%20systems%20such%20as%20AWS%20and%20GCP.%22%7D%5D" %}
{% endhint %}

When a pipeline interacts with an external system, such as AWS, GCP, Azure, or a secrets manager, the external system requires a **verifiable identity** to authenticate the request.

**Pipeline identities** enable **OIDC-based authentication** in pipelines without relying on long-lived credentials. Harness generates an **OpenID Connect (OIDC) ID token** through **Harness ID** on behalf of the pipeline identity. External systems that support OIDC and trust Harness as an **OIDC identity provider** can verify this token to authenticate the pipeline and authorize access to their resources.

You can use pipeline identities with any external system that supports OIDC and trusts Harness as an OIDC identity provider, such as AWS, GCP, Azure, and HashiCorp Vault.

You define the required identity in the `identities` map in your pipeline YAML. Harness passes the identity details to the module responsible for executing the work, which uses them to authenticate with the external system.

You can define identities at the pipeline, stage, or step level, as well as in templates. Identities are not limited to Shell Script steps. They can be used with any step that supports identities, as well as with OIDC-type connectors.

{% hint style="info" %}
**YAML only feature**

Pipeline identities are available only in YAML. There is no UI for creating or editing them.
{% endhint %}

## What you will learn from this topic

* What an [identity](#identity-configuration-and-execution) is and how Harness passes it to an external system.
* How to [declare an identity](#declare-an-identity) at the pipeline, stage, and step levels in YAML.
* How to set each [identity field](#identity-fields).
* How to choose a [token mode](#token-mode) for each identity.
* How to control where an identity is available using [scope and inheritance](#scope-and-inheritance), [overrides](#override-an-identity-at-a-lower-level), and the [disabled field](#disable-an-identity-for-selected-stages).
* How to [use identities in templates](#use-identities-in-templates).

## Before you begin

* **Feature flag**: Enable `PIPE_PIPELINE_IDENTITY` for your account. Contact [Harness Support](mailto:support@harness.io) to enable it.
* **Harness ID**: Pipeline identities build on Harness ID. This topic covers only what the pipeline supports. For more information on how Harness generates the token, see [Harness ID tokens for the Shell Script step](https://developer.harness.io/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/utilities/shell-script-step#harness-id-tokens-for-the-shell-script-step).
* **Permissions**: You need the **View** and **Edit** pipeline permissions to add or change identities in an existing pipeline, and **Create** to add them to a new pipeline. Identities are part of the pipeline definition, so they are subject to pipeline-level access control. For more information, see [Permissions reference](/harness-platform/use-harness-platform/platform-access-control/permissions-reference.md#pipelines).

## Identity configuration and execution

An identity is the information that Harness presents to an external system to say who is making the request.

The `identities` field is a map, so a single pipeline can declare several identities. For example, you can declare one identity for AWS and another for GCP, each with its own audience. The key for each entry is the identity's name.

Harness does not interpret how the external system uses the identity. Harness resolves the fields you define and hands them to the module that performs the work, such as a step that supports identities or an OIDC connector. That module sends them to the external system.

The Shell Script step is one example of a step that uses identities. In a Shell Script step, the identity name is the name of the environment variable that holds the generated token. For example, `TOKEN` is available as an environment variable in the step, and you access it as `$TOKEN`.

***

## Declare an identity

Add an `identities` map at the level where you want the identity to be available. The placement of the map follows the level.

| Level    | Where to add `identities`                                       |
| -------- | --------------------------------------------------------------- |
| Pipeline | Under `pipeline`, alongside `name`, `identifier`, and `stages`. |
| Stage    | Under `stage`, alongside `name`, `identifier`, and `spec`.      |
| Step     | Under `step`, alongside `type`, `name`, and `spec`.             |

Perform the following steps to declare an identity:

1. Open the pipeline and select the **YAML** tab. To edit a template, open the template and select its **YAML** tab.
2. Add an `identities` map at the level where you want the identity to be available.
3. Add an entry for each identity. The key to the entry is the identity name.
4. Set the [identity fields](#identity-fields) for the entry.
5. Save the pipeline.

### Pipeline-level identity

The following example declares an identity named `TOKEN` at the pipeline level. Every stage and step in the pipeline can use it. The example uses a Shell Script step to decode the token so you can inspect its claims.

<details>

<summary>Pipeline-level identity</summary>

```yaml
pipeline:
  name: Identity demo
  identifier: identity_demo
  projectIdentifier: my_project
  orgIdentifier: default
  identities:
    TOKEN:
      audience: https://external-system.example.com  # Replace with the URL of your external system
      subjectTemplate: account/{account_id}:project/{project_id}:pipeline/{pipeline_id}
      customClaims:
        tier: gold  # Replace with your own key-value pairs
      cloudProvider: AWS  # For example, AWS or GCP
  stages:
    - stage:
        name: Inspect token
        identifier: inspect_token
        type: Custom
        spec:
          execution:
            steps:
              - step:
                  type: ShellScript
                  name: Decode token
                  identifier: decode_token
                  spec:
                    shell: Bash
                    executionTarget: {}
                    source:
                      type: Inline
                      spec:
                        script: |-
                          # Decode the JWT payload with jq (handles base64url and padding)
                          jq -Rr 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | . + "=" * (3 - (length-1) % 4) | @base64d | fromjson' <<< "$TOKEN"
                    environmentVariables: []
                    outputVariables: []
                  timeout: 10m
        tags: {}
```

</details>

### Step-level identity

The following example declares an identity at the step level. It is available only in that step.

<details>

<summary>Step-level identity with a subject template and custom claims</summary>

```yaml
- step:
    type: ShellScript
    name: Authenticate with Harness ID
    identifier: harness_id_step
    identities:
      AWS_ID_TOKEN:
        cloudProvider: AWS
        audience: sts.amazonaws.com
        subjectTemplate: account/{account_id}:project/{project_id}:pipeline/{pipeline_id}
        customClaims:
          environment: production
    spec:
      shell: Bash
      onDelegate: true
      source:
        type: Inline
        spec:
          script: |-
            echo "Token acquired for AWS: ${AWS_ID_TOKEN}"
    timeout: 10m
```

</details>

Go to [Shell Script step](https://developer.harness.io/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/utilities/shell-script-step) to see how one step that supports identities injects a generated token into a script.

***

## Identity fields

Each entry in the `identities` map supports the following fields.

| Field             | Description                                                                                                                                                                                                                                                                                            |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cloudProvider`   | The cloud provider that the identity is used with. This field is optional. Supported values include `AWS` and `GCP`. For other external systems, such as Azure or HashiCorp Vault, omit `cloudProvider` and specify the expected value in `audience`. You cannot override this field at a lower level. |
| `audience`        | The URL of the external system that the identity is created for. The external system checks this value to confirm that the identity is meant for it.                                                                                                                                                   |
| `subjectTemplate` | Identifies the pipeline to the external system, based on the pipeline identifier. Set it so the subject the external system receives matches the pipeline. The template uses the `account/{account_id}:project/{project_id}:pipeline/{pipeline_id}` format.                                            |
| `customClaims`    | Key-value pairs that you define for your own use case. Harness does not interpret them. Harness passes them to the module and the external system.                                                                                                                                                     |
| `tokenMode`       | Controls how Harness uses the identity token. Supported values are `STANDARD` and `CLIENT_ASSERTION`. The default is `STANDARD`. Go to [Token mode](#token-mode) for details.                                                                                                                          |
| `workloadUri`     | Required when `tokenMode` is `CLIENT_ASSERTION`. Specifies the URI that identifies the workload to the identity provider.                                                                                                                                                                              |
| `adfsEndpoint`    | Required when `tokenMode` is `CLIENT_ASSERTION`. Specifies the identity provider endpoint (for example, an AD FS endpoint) that receives the client assertion and exchanges it for an access token.                                                                                                    |
| `disabled`        | Set to `true` to make the identity unavailable. Set to `false` to make it available. A disabled identity is not resolved, and referencing it returns no value.                                                                                                                                         |

***

## Token mode

Token mode controls how Harness uses the identity token it creates for your pipeline, stage, or step. You set it per identity with the `tokenMode` field.

| Token mode           | What it does                                                                                                                                                                            | When to use it                                                                                                                     |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `STANDARD` (default) | Harness issues a signed OIDC ID token for the identity. Your step receives the token, and you present it directly to the service you want to access, such as AWS, GCP, Azure, or Vault. | Most cases, where the service trusts Harness as an OIDC provider and accepts the token as is.                                      |
| `CLIENT_ASSERTION`   | The ID token is used as a client assertion. It proves the identity of your workload to your own identity provider, such as AD FS, which then issues the access token.                   | Your organization requires its own identity provider to issue the final credentials, rather than trusting Harness tokens directly. |

The following example declares one identity in each mode.

<details>

<summary>Identities with different token modes</summary>

```yaml
identities:
  AWS_ID_TOKEN:
    audience: https://sts.amazonaws.com
    tokenMode: STANDARD

  CORP_ID_TOKEN:
    tokenMode: CLIENT_ASSERTION
    workloadUri: <your workload URI>
    adfsEndpoint: <your AD FS endpoint>
```

</details>

{% hint style="info" %}
**Token mode defaults and requirements**

If you do not set `tokenMode`, Harness uses `STANDARD`. The `CLIENT_ASSERTION` mode requires the `workloadUri` and `adfsEndpoint` fields, which identify your workload and the endpoint of your identity provider. Go to [Identity fields](#identity-fields) for details.
{% endhint %}

***

## Scope and inheritance

Where you declare an identity decides where it is available.

* An identity declared at the pipeline level is available in every stage and step of the pipeline.
* An identity declared at the stage level is available in that stage and in the steps inside it. It is not available in other stages.
* An identity declared at the step level is available only in that step.

For example, if you declare `AWS_ID_TOKEN` in one stage, you cannot use it in another stage. Declare it at the pipeline level if all stages need it.

### Override an identity at a lower level

You can declare an identity with the same name at a lower level to change part of it. The lower-level definition is merged with the upper-level definition, and the lower-level values take precedence. You only need to list the fields you want to change. Every other field remains as defined at the upper level.

{% hint style="warning" %}
**The cloudProvider field cannot be overridden**

You cannot change `cloudProvider` at a lower level. An override can change the other fields, but the cloud provider always comes from the level where you first declared the identity.
{% endhint %}

The override applies only to the stage or step where you make it. Other stages and steps continue to use the upper-level definition.

In the following example, the pipeline declares `AWS_ID_TOKEN` with an audience. One stage overrides only the audience. The cloud provider and custom claims still come from the pipeline-level definition.

<details>

<summary>Stage-level override of a pipeline-level identity</summary>

```yaml
pipeline:
  identities:
    AWS_ID_TOKEN:
      cloudProvider: AWS
      audience: sts.amazonaws.com
      customClaims:
        team: platform
  stages:
    - stage:
        name: Regional access
        identifier: regional_access
        type: Custom
        identities:
          AWS_ID_TOKEN:
            audience: sts.eu-west-1.amazonaws.com
```

</details>

### Disable an identity for selected stages

Use `disabled` to declare an identity once and use it only where you need it. Set `disabled: true` at the pipeline level so the identity is not available by default. Then set `disabled: false` in the stages where you want it.

In the following example, the identity is available in the `Publish` stage. In all other stages, referencing it returns no value.

<details>

<summary>Enable a disabled pipeline-level identity in one stage</summary>

```yaml
pipeline:
  identities:
    GCP_ID_TOKEN:
      cloudProvider: GCP
      audience: https://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/providers/<PROVIDER_ID>  # Replace with your workload identity provider
      disabled: true
  stages:
    - stage:
        name: Publish
        identifier: publish
        type: Custom
        identities:
          GCP_ID_TOKEN:
            disabled: false
```

</details>

***

## Use identities in templates

Pipeline, stage, and step templates support the `identities` map in the same way as pipeline YAML. Declare the identities in the template definition, and they apply wherever the template is used.

***

## Important notes

The following limitations apply to pipeline identities.

* **YAML only**: Pipeline identities are configured in YAML. There is no UI for creating or editing them.
* **Expressions**: Expressions are not supported in pipeline-level identities.
* **Cloud provider**: The `cloudProvider` field cannot be overridden at the stage or step level.

***

## Next steps

* [Shell Script step](https://developer.harness.io/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/utilities/shell-script-step): An example of a step that injects a generated identity token into a script.

[^1]: On by default, ready for production use and rolling out to every Harness environment incrementally. If you want it before it reaches your environment, request access and Harness will turn it on for your account. Rollout happens in stages, so a feature can reach some environments a week or two before others. Harness can also turn it off via the same **Request access** process for your account if you need it off.
