
![aws sm](../pictures/eso-az-kv-aws-sm.png)

## Secrets Manager

A `SecretStore` points to AWS Secrets Manager in a certain account within a
defined region. You should define Roles that define fine-grained access to
individual secrets and pass them to ESO using `spec.provider.aws.role`. This
way users of the `SecretStore` can only access the secrets necessary.

``` yaml
{% include 'aws-sm-store.yaml' %}
```
**NOTE:** In case of a `ClusterSecretStore`, Be sure to provide `namespace` in `accessKeyIDSecretRef` and `secretAccessKeySecretRef`  with the namespaces where the secrets reside.

**NOTE:** `dataFrom` uses the more efficient `BatchGetSecretValue` API when you define a `path`
prefix, or when you filter by `Tags` only (without a `name`). When you search by `name` without a
`path`, the provider falls back to `ListSecrets` and then fetches each matching secret
individually, which is more costly. Define a `path` prefix to reduce the number of API calls.

### IAM Policy

Create a IAM Policy to pin down access to secrets matching `dev-*`.

For Batch permissions read the following post https://aws.amazon.com/about-aws/whats-new/2023/11/aws-secrets-manager-batch-retrieval-secrets/.

``` json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action" : [
        "secretsmanager:ListSecrets",
        "secretsmanager:BatchGetSecretValue"
      ],
      "Effect" : "Allow",
      "Resource" : "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": [
        "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*"
      ]
    }
  ]
}
```

#### Permissions for PushSecret

If you're planning to use `PushSecret`, ensure you also have the following permissions in your IAM policy:

``` json
{
  "Effect": "Allow",
  "Action": [
    "secretsmanager:CreateSecret",
    "secretsmanager:PutSecretValue",
    "secretsmanager:TagResource",
    "secretsmanager:DeleteSecret",
    "secretsmanager:GetResourcePolicy",
    "secretsmanager:PutResourcePolicy",
    "secretsmanager:DeleteResourcePolicy",
    "secretsmanager:ReplicateSecretToRegions",
    "secretsmanager:RemoveRegionsFromReplication"
  ],
  "Resource": [
    "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*"
  ]
}
```

**Note:** The resource policy permissions (`GetResourcePolicy`, `PutResourcePolicy`, `DeleteResourcePolicy`) are only required if you're using the `resourcePolicy` metadata option to manage resource-based policies on secrets.
**Note:** The replication permissions (`ReplicateSecretToRegions`, `RemoveRegionsFromReplication`) are only required if you're using the `replicationLocations` metadata option to manage secret replication across multiple regions.

Here's a more restrictive version of the IAM policy:

``` json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:CreateSecret",
        "secretsmanager:PutSecretValue",
        "secretsmanager:TagResource",
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:PutResourcePolicy",
        "secretsmanager:DeleteResourcePolicy",
        "secretsmanager:ReplicateSecretToRegions",
        "secretsmanager:RemoveRegionsFromReplication"
      ],
      "Resource": [
        "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:DeleteSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*"
      ],
      "Condition": {
        "StringEquals": {
          "secretsmanager:ResourceTag/managed-by": "external-secrets"
        }
      }
    }
  ]
}
```

In this policy, the DeleteSecret action is restricted to secrets that have the specified tag, ensuring that deletion operations are more controlled and in line with the intended management of the secrets.

#### Additional Settings for PushSecret

Additional settings can be set at the `SecretStore` level to control the behavior of `PushSecret` when interacting with AWS Secrets Manager.

```yaml
{% include 'aws-sm-store-secretsmanager-config.yaml' %}
```

#### Additional Metadata for PushSecret

Optionally, it is possible to configure additional options for the parameter. These are as follows:

- kmsKeyID
- secretPushFormat
- description
- tags
- resourcePolicy
- replicationLocations

To control this behavior set the following provider metadata:

```yaml
{% include 'aws-sm-push-secret-with-metadata.yaml' %}
```

- `secretPushFormat` takes two options. `binary` and `string`, where `binary` is the _default_.
- `kmsKeyID` takes a KMS Key `$ID` or `$ARN` (in case a key source is created in another account) as a string, where `alias/aws/secretsmanager` is the _default_.
- `description` Description of the secret.
- `tags` Key-value map of user-defined tags that are attached to the secret.
- `replicationLocations` takes a list of valid AWS region names where the secret should be replicated.

**Note:** ESO treats the PushSecret as the **source of truth** for tags, resource policy, and replication locations. When any of these resources are specified in `metadata`, they will be added or updated, and resources NOT specified but existing will be removed from AWS. This synchronization happens on every reconciliation, even when the secret value hasn't changed.

- `resourcePolicy` Attach a resource-based policy to the secret for cross-account access or advanced access control.
  - `blockPublicPolicy` (optional) - Set to `true` to validate that the policy doesn't grant public access before applying. Defaults to AWS behavior.
  - `policySourceRef` (required) - Reference to a ConfigMap or Secret containing the policy JSON.
    - `kind` - Either `ConfigMap` or `Secret`.
    - `name` - Name of the ConfigMap or Secret.
    - `key` - Key within the ConfigMap/Secret data that contains the policy JSON.


##### KMS Key

The `kmsKeyID` field controls the KMS key used for encrypting/ decrypting the secret.

- If `kmsKeyID` is provided, ESO always uses that value for the primary secret.
- If `kmsKeyID` is not provided, ESO falls back to AWS’s default Secrets Manager key: `alias/aws/secretsmanager`.
- ESO does not currently support specifying different `kmsKeyID` values per replica region. A single `kmsKeyID` value is applied uniformly across the primary secret and all configured replication regions.

##### Resource Policy Example

To attach a resource policy to a secret for cross-account access:

```yaml
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: pushsecret-example
  namespace: default
spec:
  refreshInterval: 10s
  secretStoreRefs:
    - name: aws-secretsmanager
      kind: SecretStore
  selector:
    secret:
      name: pokedex-credentials
  data:
    - match:
        secretKey: my-secret-key
        remoteRef:
          remoteKey: my-remote-secret
          property: password
      metadata:
        resourcePolicy:
          blockPublicPolicy: true
          policySourceRef:
            kind: ConfigMap
            name: my-secret-resource-policy
            key: policy.json
        kmsKeyID: bb123123-b2b0-4f60-ac3a-44a13f0e6b6c
        secretPushFormat: string
        description: "Cross-account accessible secret"
        tags:
          team: platform-engineering
```

The ConfigMap should contain the policy JSON:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-secret-resource-policy
  namespace: default
data:
  policy.json: |
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "AWS": "arn:aws:iam::123456789012:root"
          },
          "Action": "secretsmanager:GetSecretValue",
          "Resource": "*"
        }
      ]
    }
```

**Note:** The resource policy is synchronized on every reconciliation, even when the secret value hasn't changed. If the `resourcePolicy` field is removed from metadata, the existing policy will be deleted from the secret.

##### Location Replication

When this field is set, _ESO_ manages replication as part of the PushSecret reconciliation loop and treats the list as the desired state:

- Regions present in `replicationLocations` but not yet configured in AWS will be added.
- Regions already configured in AWS but not listed in `replicationLocations` will be removed.
- If `replicationLocations` is omitted entirely, ESO does not manage replication for that secret.
- Invalid/unsupported region values or missing permissions will cause the AWS replication call to fail.

**Note**: Replicas do not support per-region KMS key selection. If you configure replication, all replica regions will use the same `kmsKeyID` value defined in the main metadata block, or `alias/aws/secretsmanager` when no key is specified.

**Note**: The KMS key **must be available** in the replication region, usually via KMS key replication.

###### Location Replication Example

You can specify a list of locations for your secrets to be replicated by setting the `replicationLocations` field.

``` yaml
{% include 'aws-sm-push-secret-with-replication.yaml' %}
```

### JSON Secret Values

SecretsManager supports *simple* key/value pairs that are stored as json. If you use the API you can store more complex JSON objects. You can access nested values or arrays using [gjson syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md):

Consider the following JSON object that is stored in the SecretsManager key `friendslist`:
``` json
{
  "name": {"first": "Tom", "last": "Anderson"},
  "friends": [
    {"first": "Dale", "last": "Murphy"},
    {"first": "Roger", "last": "Craig"},
    {"first": "Jane", "last": "Murphy"}
  ]
}
```

This is an example on how you would look up nested keys in the above json object:

``` yaml
{% include 'aws-sm-external-secret.yaml' %}
```

### Secret Versions

SecretsManager creates a new version of a secret every time it is updated. The secret version can be reference in two ways, the `VersionStage` and the `VersionId`. The `VersionId` is a unique uuid which is generated every time the secret changes. This id is immutable and will always refer to the same secret data. The `VersionStage` is an alias to a `VersionId`, and can refer to different secret data as the secret is updated. By default, SecretsManager will add the version stages `AWSCURRENT` and `AWSPREVIOUS` to every secret, but other stages can be created via the [update-secret-version-stage](https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/update-secret-version-stage.html) api.

The `version` field on the `remoteRef` of the ExternalSecret will normally consider the version to be a `VersionStage`, but if the field is prefixed with `uuid/`, then the version will be considered a `VersionId`.

So in this example, the operator will request the same secret with different versions: `AWSCURRENT` and `AWSPREVIOUS`:

``` yaml
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: versioned-api-key
spec:
  refreshInterval: 1h0m0s
  secretStoreRef:
    name: aws-secretsmanager
    kind: SecretStore
  target:
    name: versioned-api-key
    creationPolicy: Owner
  data:
  - secretKey: previous-api-key
    remoteRef:
      key: "production/api-key"
      version: "AWSPREVIOUS"
  - secretKey: current-api-key
    remoteRef:
      key: "production/api-key"
      version: "AWSCURRENT"
```

While in this example, the operator will request the secret with `VersionId` as `abcd-1234`

``` yaml
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: versioned-api-key
spec:
  refreshInterval: 1h0m0s
  secretStoreRef:
    name: aws-secretsmanager
    kind: SecretStore
  target:
    name: versioned-api-key
    creationPolicy: Owner
  data:
  - secretKey: api-key
    remoteRef:
      key: "production/api-key"
      version: "uuid/123e4567-e89b-12d3-a456-426614174000"
```

## Authentication

See [AWS Authentication](aws-access.md) for all supported methods: controller pod identity, IRSA, static credentials, session tokens, assuming roles, session tags, and remote key prefixes.
