Skip to content

AWS Secrets Manager

The AWS Secrets Manager key store persists encryption keys as SecretString values in AWS Secrets Manager, encrypted at rest with AWS KMS. Use it when policy mandates Secrets Manager (rotation, replication, resource-based policies) or when you are using a per-tenant key model where the secret count is small.

What SecretString actually means

SecretString is the JSON field name in Secrets Manager's CreateSecret and GetSecretValue API payloads - it is the UTF-8 text payload of the secret. Secrets Manager always encrypts every secret value at rest with KMS; there is no plaintext option. The companion field SecretBinary exists for non-text payloads, but Tayra always uses SecretString because it stores a Base64-encoded representation of the AES-256 key bytes.

In other words: SecretString is not a security mode you opt into - it is just "here is my secret value, as text." The encryption is implicit and unavoidable, controlled by the KMS key set on the secret (the AWS-managed alias/aws/secretsmanager by default, or your own CMK via KmsKeyId).

Cost - read this first

AWS Secrets Manager bills $0.40 per secret per month + $0.05 per 10,000 API calls. With Tayra's default per-data-subject key model, every customer gets their own encryption key - and therefore their own secret. At 100,000 subjects that is $40,000 per month just for storage, before API calls.

For per-data-subject keys at scale, prefer:

Use Secrets Manager when:

  • You have a per-tenant or per-organization key model (tens or hundreds of secrets, not millions).
  • Internal policy requires Secrets Manager over Parameter Store.
  • You need built-in automatic rotation, cross-region replication, or resource-based policies that Parameter Store does not provide.

Installation

shell
dotnet add package Tayra.KeyStore.AwsSecretsManager
powershell
Install-Package Tayra.KeyStore.AwsSecretsManager

Basic Setup

The simplest registration uses the default AWS credentials chain (environment, profile, instance profile, IAM role, etc.):

cs
var services = new ServiceCollection();

// Use AWS Secrets Manager with the default AWS credentials chain
services.AddTayra(opts => opts.LicenseKey = licenseKey)
    .UseAwsSecretsManagerKeyStore();
anchor

Configuration Options

cs
var services = new ServiceCollection();

services.AddTayra(opts => opts.LicenseKey = licenseKey)
    .UseAwsSecretsManagerKeyStore(options =>
    {
        // Name prefix for secrets (default: "tayra/"). Trailing '/' added automatically.
        options.NamePrefix = "myapp/encryption/keys/";

        // Optional custom KMS CMK for encrypting the secret value
        // (defaults to alias/aws/secretsmanager when null)
        options.KmsKeyId = "alias/my-cmk";

        // Optional AWS region override
        options.Region = "us-west-2";

        // Crypto-shredding: 0 = ForceDeleteWithoutRecovery (recommended for GDPR erasure).
        // 7-30 = soft delete with recovery window.
        options.RecoveryWindowInDays = 0;

        // Optional cross-region replication for HA/DR
        options.ReplicaRegions = ["eu-west-1"];

        // Retry tuning
        options.MaxRetries = 5;
        options.RetryBaseDelay = TimeSpan.FromMilliseconds(200);
    });
anchor

Options Reference

PropertyTypeDefaultDescription
NamePrefixstring"tayra/"Name prefix for secrets in Secrets Manager. Trailing / is added automatically if missing.
KmsKeyIdstring?nullOptional custom KMS key ID, ARN, or alias for encrypting the secret value. When null, the AWS-managed key (alias/aws/secretsmanager) is used.
Regionstring?nullOptional AWS region override. When null, the region from the default credentials chain is used.
RecoveryWindowInDaysint7Recovery window for soft-deleted secrets (7-30). Set to 0 for ForceDeleteWithoutRecovery - recommended for crypto-shredding.
ReplicaRegionsIReadOnlyList<string>[]AWS regions to replicate each secret to on creation. Empty by default.
MaxRetriesint3Maximum retries for transient errors.
RetryBaseDelayTimeSpan100msBase delay for exponential backoff on retries.

Pre-configured Client

If you already have an IAmazonSecretsManager (e.g., with assumed-role credentials), pass it directly:

cs
var services = new ServiceCollection();

var smClient = new Amazon.SecretsManager.AmazonSecretsManagerClient(
    Amazon.RegionEndpoint.USWest2);

services.AddTayra(opts => opts.LicenseKey = licenseKey)
    .UseAwsSecretsManagerKeyStore(smClient, options =>
    {
        options.NamePrefix = "myapp/encryption/keys/";
    });
anchor

Per-Subject vs Per-Tenant Decision

Tayra's default crypto-shredding model uses one key per data subject. Secrets Manager makes this expensive - pick the model deliberately.

ModelHowSecret countErasure granularityCost (monthly storage)
Per-data-subject (default)[DataSubjectId] on a per-user identifier1 per userPer-user GDPR Article 17$0.40 × N users
Per-tenant / per-organization[DataSubjectId] on OrgId (with Prefix = "org-")1 per tenantPer-tenant offboarding only$0.40 × N tenants
Tenant-namespaced per-subjectTenantAwareKeyStore decorator wrapping this provider1 per tenant × usersBoth$0.40 × N tenants × users

Recommendation:

  • If you need per-user GDPR right-to-be-forgotten → use Parameter Store, HashiCorp Vault, or PostgreSQL, not Secrets Manager.
  • If you only need tenant-level isolation (offboard whole orgs) → set [DataSubjectId] to the org ID. Secrets Manager cost stays trivial.
  • If you need both → wrap with TenantAwareKeyStore from the Compliance edition; understand the multiplicative cost.
  • At consumer scale, the cleanest answer is envelope encryption: one master key per org in Secrets Manager + N wrapped DEKs in a cheap data keystore. 15M subjects ≈ $1/mo total.

Crypto-Shredding and the Recovery Window

By default, AWS schedules deleted secrets for permanent removal after a 7-day recovery window. Tayra's default RecoveryWindowInDays = 7 matches this behavior, but it means a "shredded" key can technically be restored within 7 days - which is inconsistent with GDPR Article 17 erasure semantics.

For irreversible crypto-shredding, set RecoveryWindowInDays = 0:

csharp
options.RecoveryWindowInDays = 0; // ForceDeleteWithoutRecovery

This calls DeleteSecret with ForceDeleteWithoutRecovery = true, which permanently destroys the secret immediately. There is no undo. This is the right setting for production crypto-shredding.

TIP

Keep the recovery window for development/staging where accidental deletions are recoverable. Set RecoveryWindowInDays = 0 only in production (or any environment where erasure must be auditable as immediate).

Cross-Region Replication

Secrets Manager can automatically replicate each secret to other AWS regions for high availability or disaster recovery:

csharp
options.ReplicaRegions = ["us-west-2", "eu-west-1"];

When configured, replicas are created at secret-creation time using the same KMS key (or the AWS-managed key) in each region. There is no replication cost beyond the per-region per-secret storage charge ($0.40/secret/region/month).

Crypto-shredding affects all replicas

Deleting a primary secret automatically deletes all replicas. This is the desired behavior for GDPR - erasure must be global, not local.

NamePrefix Convention

Tayra builds the full secret name as:

{name_prefix}{sanitized_key_id}
ComponentValueSource
name_prefixtayra/NamePrefix option (trailing / added automatically).
sanitized_key_iduser-123/personal/nameTayra key identifier with colons (:) converted to slashes (/).

For a key ID of user-123:personal:name and the default prefix, the secret name is:

tayra/user-123/personal/name

This naming enables IAM policies scoped to a path-like prefix and ListSecrets filter queries for prefix-based operations.

IAM Policy Requirements

The IAM role or user must have the following permissions:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:CreateSecret",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:DeleteSecret",
        "secretsmanager:ListSecrets"
      ],
      "Resource": "arn:aws:secretsmanager:*:*:secret:tayra/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "arn:aws:kms:*:*:key/*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "secretsmanager.*.amazonaws.com"
        }
      }
    }
  ]
}

If you set ReplicaRegions, also grant secretsmanager:ReplicateSecretToRegions and secretsmanager:RemoveRegionsFromReplication.

Least Privilege

Scope the Resource ARN to match your NamePrefix. The example above matches the default tayra/ prefix.

Retry Logic

The Secrets Manager key store includes built-in exponential-backoff retries for transient errors. Defaults: 3 retries, base delay 100ms, doubling each attempt (100ms → 200ms → 400ms). Tune with MaxRetries and RetryBaseDelay.

Service Limits

LimitValueNotes
Max secrets per region500,000Soft limit, raisable via AWS Support.
Max secret value size64 KBAES-256 keys are 32 bytes - well within.
API request rateRegion-specific (DescribeSecret 50 TPS, GetSecretValue 10,000 TPS)Tayra's in-process key cache means steady-state requests are minimal.
Soft delete recovery window7-30 daysOr ForceDeleteWithoutRecovery. See above.

See Also