Table of Contents

Secrets (KMS / Secrets Manager)

Wire an AWS KMS-backed secret protector and a Secrets Manager store, then envelope-encrypt and store values.

What you'll build

A host that registers ISecretProtector (KMS envelope encryption) and ISecretStore (AWS Secrets Manager) from SquidStd.Secrets.Aws, then exercises protect/unprotect and set/get/list.

Prerequisites

  • .NET 10 SDK
  • dotnet add package SquidStd.Secrets.Aws
  • The live calls (steps 2–3) need a KMS + Secrets Manager endpoint. The sample is compile-and-wire focused: it resolves the services without AWS and only runs the live calls when SQUIDSTD_RUN_AWS=1 is set with LocalStack (or real AWS) reachable at the configured endpoint.

Steps

1. Register the KMS protector and Secrets Manager store

RegisterKmsSecretProtector and RegisterAwsSecretsManagerStore take the KMS key alias, the secret name prefix, and the AWS endpoint - pointed here at a LocalStack ServiceUrl.


// Wire the KMS-backed protector and the Secrets Manager store against a LocalStack endpoint.
bootstrap.ConfigureServices(
    container =>
    {
        // Core services are registered one by one here: RegisterCoreServices() would also add
        // the default AES-GCM protector and file secret store, which must not compete with the
        // KMS protector and AWS Secrets Manager store registered below.
        container.RegisterDataSerializer();
        container.RegisterEventBusService();
        container.RegisterJobSystemService();
        container.RegisterMainThreadDispatcherService();
        container.RegisterTimerWheelService();
        container.RegisterMetricsCollectionService();

        container.RegisterKmsSecretProtector(
            options =>
            {
                options.KeyId = "alias/app";
                options.Aws = new()
                {
                    Region = "us-east-1",
                    ServiceUrl = "http://localhost:4566"
                };
            }
        );

        container.RegisterAwsSecretsManagerStore(
            options =>
            {
                options.NamePrefix = "myapp/";
                options.Aws = new()
                {
                    Region = "us-east-1",
                    ServiceUrl = "http://localhost:4566"
                };
            }
        );

        return container;
    }
);

2. Envelope-encrypt a value

Protect requests a KMS data key, encrypts the payload with it, and wraps the encrypted data key alongside the ciphertext; Unprotect reverses it.


// Envelope-encrypt a value with a KMS data key, then decrypt it back.
var protectedBytes = protector.Protect(Encoding.UTF8.GetBytes("api-token"));
var plaintext = protector.Unprotect(protectedBytes);

Console.WriteLine($"Unprotected: {Encoding.UTF8.GetString(plaintext)}");

3. Store, fetch and list secrets

ISecretStore reads and writes named secrets through Secrets Manager; ListNamesAsync streams the names under the configured prefix.


// Store, fetch, and list secrets through the Secrets Manager store.
await store.SetAsync("db-password", "s3cr3t");
var password = await store.GetAsync("db-password");
Console.WriteLine($"db-password: {password}");

await foreach (var name in store.ListNamesAsync())
{
    Console.WriteLine($"secret: {name}");
}

Run it

dotnet run --project samples/SquidStd.Samples.Secrets
# with the live calls:
SQUIDSTD_RUN_AWS=1 dotnet run --project samples/SquidStd.Samples.Secrets

Next steps