# Store Outpost Credentials in a Customer-Managed Secret

An Outpost connection can use the **In Host BYOK** runtime mode. In this mode, the credentials for the connection stay in a secret in the customer environment. Relyance stores only the location of the secret, not the credentials. The scanner reads the secret during the scan with its own identity.

## Secret providers

| Secret provider | Where the secret is | What Relyance stores |
|---|---|---|
| AWS Secrets Manager (default) | A secret in the AWS account of the Outpost deployment | The secret ARN |
| Kubernetes secret (environment variable mount) | A Kubernetes secret that the scanner pods get as an environment variable | No location. The scanner finds the environment variable by its name. |

AWS Secrets Manager is available only for an Outpost deployment on AWS. Relyance rejects a secret ARN for an Outpost deployment on GCP.

## What the secret contains

The secret value is a JSON object. Each key is a credential field of the authentication method. The Authentication step of the connection has a builder that makes this JSON.

Some connection settings are not credentials, for example the data storage location. These settings stay on the Relyance form, and Relyance stores them. All other credential fields go in the secret. This includes the credential fields that are not secret.

For AWS Secrets Manager, a field that is not secret can be left out of the secret when it has a default value on the Relyance form. This also applies to checkbox and dropdown fields. The scanner then uses the default value from the form.

Relyance rejects secret values that are sent for an In Host BYOK connection. When a connection changes to In Host BYOK, Relyance deletes the copy of the credentials that it kept for the connection.

## Set up a connection with AWS Secrets Manager

The Outpost deployment must be on AWS and use the Relyance Terraform module.

1. Open the connection.
2. In **Connection Settings**, set **Runtime Mode** to **In Host BYOK**.
3. Save the connection settings.
4. Go to the **Authentication** step.
5. Select the authentication method.
6. In **Credentials Secret**, set **Secret provider** to **AWS Secrets Manager**.
7. Enter the credential values in the builder fields. The JSON shows in **Secret value (JSON)**.
8. Click **Copy**.
9. In AWS Secrets Manager, create a secret. Use the copied JSON as the secret value.
10. Give the scanner role access to the secret. Refer to [Give the scanner access](#give-the-scanner-access).
11. Copy the full secret ARN from the secret details page in AWS Secrets Manager.
12. Enter the ARN in **Secret ARN**.
13. Save the connection.

:::info
The builder uses the values only in the browser to make the JSON. The values are not sent to Relyance. The builder clears them when the connection, the authentication method or the secret provider changes.
:::

Use one secret for each connection. A common name prefix, for example `relyance/inhost/`, lets one access pattern cover all connections. This example creates the secret from a file that contains the copied JSON:

```bash
aws secretsmanager create-secret \
  --name relyance/inhost/example-vendor/example-connection \
  --secret-string file://secret.json
```

Delete the local file after AWS creates the secret. To encrypt the secret with a customer-managed KMS key, add `--kms-key-id` with the key ARN.

## Give the scanner access

The scanner reads the secret with the scanner IAM role of the Outpost deployment. The default name of this role is `Relyance_Sierra`. Set these variables in the Relyance Terraform module, then apply the module:

```hcl
module "outpost" {
  # ...
  byok_secret_arn_patterns = [
    "arn:aws:secretsmanager:us-west-2:123456789012:secret:relyance/inhost/*",
  ]

  # Only for secrets that a customer-managed KMS key encrypts.
  byok_secret_kms_key_arns = [
    "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
  ]

  # The default is true.
  byok_secret_write_back = true
}
```

| Variable | Permissions that the module gives to the scanner role |
|---|---|
| `byok_secret_arn_patterns` | `secretsmanager:GetSecretValue` on the matching secrets. An empty list gives no permissions. |
| `byok_secret_write_back` | When `true`: `secretsmanager:PutSecretValue` on the matching secrets. The scanner uses it to store OAuth tokens that change. |
| `byok_secret_kms_key_arns` | `kms:Decrypt` on the keys. When `byok_secret_write_back` is `true`, also `kms:GenerateDataKey`. The role can use the keys only through AWS Secrets Manager. |

- A secret ARN ends with a random suffix of six characters. End each pattern with `*`.
- The AWS managed key `aws/secretsmanager` needs no entry in `byok_secret_kms_key_arns`.
- A key policy that does not delegate to IAM policies must also allow the scanner role.
- A secret resource policy must not deny access to the scanner role.

## How the scanner uses the secret

**Read.** The scanner reads the secret when a scan starts. Relyance does not test access to the secret when the connection is saved. The next scan shows access problems.

**Rotation.** The scanner keeps the secret value in memory for up to 5 minutes. After a change to the secret, scans use the new value within 5 minutes. A pod restart is not necessary.

**Region.** The scanner calls AWS Secrets Manager in the region of the secret ARN.

**Default values.** Some fields that are not secret have a default value on the Relyance form. Checkbox and dropdown fields can also have a default value. If the secret does not contain such a field, the scanner uses the default value. This applies only to AWS Secrets Manager.

**Required fields.** Each required credential field must be in the secret with a value. If a required field is missing or empty, the scan fails.

**Token write-back.** The scanner writes to the secret only when it refreshes an OAuth token and the token changes. It writes only the keys that changed, and merges them into the current secret value. The other keys do not change. The scanner does not write to the secret at other times, for example when it only reads the secret.

If a write-back fails, the scan does not fail. The scanner continues the scan with the new token in memory. The scan shows a warning that starts with "Token refresh could not be saved to the credential secret". The warning gives a reason code and does not contain the secret ARN. The scanner logs also record the failure. For a vendor that rotates refresh tokens, correct the cause before the next scan. The secret still contains the old refresh token.

**Automatic rotation.** Do not turn on automatic rotation in AWS Secrets Manager for a secret of an OAuth connection with a refresh token. A rotation function can write over a token that the scanner saved. The next scan then uses a token that is not valid, and authentication fails.

**Write-back setting.** The Terraform module and the deployment each have a write-back setting. Set the deployment setting to the same value as the Terraform variable. A Helm deployment uses `byokSecretWriteBack`. A kustomize deployment uses `SECRET_REF_WRITE_BACK`.

| Setting | Where | Default |
|---|---|---|
| `byok_secret_write_back` | Relyance Terraform module. Gives the scanner role the write permissions. The module output `byok_secret_write_back` gives the value. | `true` |
| `byokSecretWriteBack` | Relyance Helm chart value. The chart sets the environment variable `SECRET_REF_WRITE_BACK` from it. | `true` |
| `SECRET_REF_WRITE_BACK` | Environment variable of the scanner pods, in the `common-env` ConfigMap. Set it directly in a kustomize deployment. Use `"true"` or `"false"`. | `"true"` |

When the value is `false`, the scanner does not write to the secret. Vendors with static credentials are not affected. A vendor that rotates refresh tokens fails after the first token refresh, because the secret keeps the old refresh token.

**Runtime mode change.** When the runtime mode changes from In Host BYOK to a different mode, Relyance removes the stored secret ARN and disconnects the connection. The connection does not scan until its credentials are saved and it is connected again.

## Authentication methods that cannot use AWS Secrets Manager

| Authentication method | Why | What the connection uses |
|---|---|---|
| Oauth2 / App Token | The sign-in goes through Relyance. Relyance completes the token exchange, so Relyance would get the tokens. | Kubernetes secret |
| JWT | The scanner reads the client secret, the private key and the password of a JWT method only from a Kubernetes secret. | Kubernetes secret |
| A method with no credential fields for the secret | There is nothing to keep in a secret. | No secret |

## Use a Kubernetes secret

1. In **Credentials Secret**, set **Secret provider** to **Kubernetes secret (environment variable mount)**.
2. Enter the credential values in the builder fields.
3. Click **Copy**.
4. Create a Kubernetes secret with the copied JSON as the value.
5. Give the secret to the scanner pods as the environment variable `RELYANCE_INTEGRATION_<vendor-key>_<connection-id>`.
6. Save the connection.

A Kubernetes secret is different from AWS Secrets Manager in these ways:

- The scanner does not fill default values for missing fields. It checks only the required secret fields.
- The scanner does not write refreshed tokens back to the secret.
- A connection that was connected with a Kubernetes secret before continues to use it. To change to AWS Secrets Manager, set **Secret provider** and enter the secret ARN.

## Limits

- **Provider.** Relyance accepts only AWS Secrets Manager ARNs, in the format `arn:aws:secretsmanager:<region>:<account-id>:secret:<name>`.
- **Cloud.** Secret ARNs are available only for an Outpost deployment on AWS.
- **Account.** The secret must be in the AWS account of the Outpost deployment. Relyance must know that account. If Relyance does not know the account, it rejects the secret ARN.
- **Value.** The secret value must be a JSON object in the secret text. A binary secret value does not work.

## Troubleshooting

When the scanner cannot read the secret, the scan fails with an authentication error. The message starts with "Authentication failed. The scanner cannot read the credential secret:". The rest of the message gives the reason. The message never contains the secret value or the secret ARN.

| Message ends with | What to check |
|---|---|
| access denied. Allow the scanner's AWS role secretsmanager:GetSecretValue on the secret. | Make sure that `byok_secret_arn_patterns` matches the full secret ARN, including the six-character suffix. Make sure that the module change is applied. Make sure that no secret resource policy denies the scanner role. If the scanner pods run in a namespace other than `sierra`, add that namespace to `additional_service_account_namespaces`. |
| the secret was not found. Check the secret reference on the connection. | Compare the ARN on the connection with the ARN in AWS Secrets Manager. Make sure that the secret exists in that region. |
| decryption denied. Allow the scanner's AWS role kms:Decrypt on the key that encrypts the secret. | Make sure that `byok_secret_kms_key_arns` contains the key. Make sure that the key policy allows the scanner role. Make sure that the key is enabled. |
| the secret value is not a valid JSON object. | Make sure that the secret text is one JSON object, as the builder makes it. Make sure that the secret does not have a binary value. |
| the secret is missing one or more required fields. | Compare the keys in the secret with the keys in the builder JSON. Make sure that each required field has a value. |
| the secret reference is not an AWS Secrets Manager ARN. | Enter an AWS Secrets Manager secret ARN on the connection. |
| an unexpected error occurred while reading it. | Examine the scanner logs in the customer environment. The logs give the reason. They do not contain the secret value. |

:::info
A failed token write-back does not fail the scan. It shows as a warning on the scan: "Token refresh could not be saved to the credential secret (…). The next scan may fail authentication." The reason code is in the parentheses. The scanner logs in the customer environment also record the failure. Usually the scanner role does not have `secretsmanager:PutSecretValue`, or `kms:GenerateDataKey` for a customer-managed KMS key.
:::

Relyance can also reject the connection when it is saved:

| Message | What to do |
|---|---|
| Enter an AWS Secrets Manager secret ARN, for example arn:aws:secretsmanager:us-east-1:123456789012:secret:relyance/example. | Enter the full ARN from the secret details page. |
| Only AWS Secrets Manager ARNs are supported. Expected arn:aws:secretsmanager:\<region\>:\<account-id\>:secret:\<name\>. | Enter the full ARN from the secret details page. Do not enter a secret name, a partial ARN or a reference to a different secret manager. |
| The region … is not in the AWS partition …. | Make sure that the region in the ARN is a region of the ARN partition: `aws` for a commercial region, `aws-cn` for a China region, `aws-us-gov` for an AWS GovCloud (US) region. Enter the full ARN from the secret details page. |
| The secret reference is longer than 2048 characters. | Enter only the ARN from the secret details page, with no other text. |
| Secret references are available only for Outpost on AWS. | Use a Kubernetes secret. AWS Secrets Manager is available only for an Outpost deployment on AWS. |
| A secret reference can only be set on an InHost BYOK connection. Set the runtime mode to IN_HOST_BYOK first. | Set **Runtime Mode** to **In Host BYOK** and save the connection settings. Then enter the secret ARN. |
| The AWS account of your InHost deployment is not known, so the secret reference cannot be checked. Contact Relyance support. | Contact Relyance support. Relyance must record the AWS account of the Outpost deployment before it accepts a secret ARN. |
| Relyance could not read your InHost deployment to check the secret reference. Try again. | Save the connection again. If the message shows again, contact Relyance support. |
| Secret values cannot be sent to Relyance for InHost BYOK connections; store them in your own secret manager instead. Remove the value(s) for: … | Remove the values of the listed fields from the Relyance form. Put the values in the secret. |
| The secret must be in the AWS account of your InHost deployment (…); this ARN is in account … | Create the secret in the AWS account of the Outpost deployment. |
| Invalid value for: …. | Enter a value for each listed field on the Relyance form. These fields are not secret, for example the data storage location. Relyance keeps them on the connection. |
| This authentication method needs a browser sign-in that Relyance completes, so it cannot be used with a secret reference. … | Use a Kubernetes secret, or select a different authentication method. |
| This authentication method (JWT) cannot be used with a secret reference. Put its client secret, private key and password in the Kubernetes secret for this connection, or choose another authentication method. | Use a Kubernetes secret, or select a different authentication method. |

:::warning
Do not send secret values to Relyance support. The messages and the logs give the reason without the secret value.
:::

## Related

- [How Outpost Works](/docs/introduction-to-relyance-ai/how-outpost-works/)
