Claude
Skills
Sign in
Back

secrets-management

Included with Lifetime
$97 forever

Comprehensive guidance for secure secrets management including storage solutions (Vault, AWS Secrets Manager, Azure Key Vault), environment variables, secret rotation, scanning tools, and CI/CD pipeline security. Use when implementing secrets storage, configuring secret rotation, preventing secret leaks, or reviewing credentials handling.

Cloud & DevOps

What this skill does


# Secrets Management

Comprehensive guidance for securely storing, accessing, rotating, and protecting secrets.

## When to Use This Skill

Use this skill when:

- Choosing a secrets management solution
- Implementing secret rotation
- Preventing secrets in source code
- Configuring CI/CD pipeline secrets
- Setting up secrets scanning
- Reviewing credentials handling
- Migrating from insecure secret storage

## Secrets Management Solutions

### Comparison Matrix

| Solution | Self-Hosted | Cloud | Dynamic Secrets | Rotation | Cost |
|----------|-------------|-------|-----------------|----------|------|
| HashiCorp Vault | ✅ | ✅ | ✅ | ✅ | Free (OSS) / $$ |
| AWS Secrets Manager | ❌ | ✅ | ❌ | ✅ | $ |
| Azure Key Vault | ❌ | ✅ | ❌ | ✅ | $ |
| Google Secret Manager | ❌ | ✅ | ❌ | ✅ | $ |
| Doppler | ❌ | ✅ | ❌ | ❌ | $$ |
| Environment Variables | ✅ | ✅ | ❌ | Manual | Free |

### When to Use What

| Use Case | Recommended Solution |
|----------|---------------------|
| Enterprise, multi-cloud | HashiCorp Vault |
| AWS-native applications | AWS Secrets Manager |
| Azure-native applications | Azure Key Vault |
| GCP-native applications | Google Secret Manager |
| Simple applications | Environment variables |
| Development | .env files (never commit!) |

## HashiCorp Vault

### Basic Usage

```bash
# Enable secrets engine
vault secrets enable -path=secret kv-v2

# Store a secret
vault kv put secret/myapp/database \
    username="dbuser" \
    password="supersecret"

# Read a secret
vault kv get secret/myapp/database

# Get specific field
vault kv get -field=password secret/myapp/database
```

### Application Integration (C#)

```csharp
using System.Text.Json;
using VaultSharp;
using VaultSharp.V1.AuthMethods.Token;

/// <summary>
/// HashiCorp Vault client for secrets retrieval.
/// </summary>
public sealed class VaultClient
{
    private readonly IVaultClient _client;

    public VaultClient(string url, string token)
    {
        var authMethod = new TokenAuthMethodInfo(token);
        var settings = new VaultClientSettings(url, authMethod);
        _client = new VaultSharp.VaultClient(settings);
    }

    /// <summary>
    /// Get a secret from Vault KV v2.
    /// </summary>
    public async Task<string> GetSecretAsync(string path, string key, CancellationToken cancellationToken = default)
    {
        var secret = await _client.V1.Secrets.KeyValue.V2.ReadSecretAsync(path: path);
        return secret.Data.Data[key].ToString()!;
    }

    /// <summary>
    /// Get database credentials.
    /// </summary>
    public async Task<DatabaseCredentials> GetDatabaseCredentialsAsync(CancellationToken cancellationToken = default)
    {
        return new DatabaseCredentials(
            Username: await GetSecretAsync("myapp/database", "username", cancellationToken),
            Password: await GetSecretAsync("myapp/database", "password", cancellationToken)
        );
    }
}

public sealed record DatabaseCredentials(string Username, string Password);

// Usage
var vault = new VaultClient(
    url: Environment.GetEnvironmentVariable("VAULT_ADDR")!,
    token: Environment.GetEnvironmentVariable("VAULT_TOKEN")!
);
var dbCreds = await vault.GetDatabaseCredentialsAsync();
```

### Dynamic Database Credentials

```bash
# Enable database secrets engine
vault secrets enable database

# Configure PostgreSQL connection
vault write database/config/mydb \
    plugin_name=postgresql-database-plugin \
    connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb" \
    allowed_roles="readonly,readwrite" \
    username="vault" \
    password="vault-password"

# Create a role
vault write database/roles/readonly \
    db_name=mydb \
    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="1h" \
    max_ttl="24h"

# Get dynamic credentials
vault read database/creds/readonly
# Returns: username=v-token-readonly-xxx, password=xxx, lease_id=xxx
```

**For detailed Vault patterns:** See [Vault Patterns Reference](references/vault-patterns.md)

## AWS Secrets Manager

### Store and Retrieve Secrets

```csharp
using Amazon.SecretsManager;
using Amazon.SecretsManager.Model;
using System.Text.Json;

/// <summary>
/// AWS Secrets Manager client.
/// </summary>
public sealed class AwsSecretsClient(IAmazonSecretsManager client)
{
    /// <summary>
    /// Retrieve secret from AWS Secrets Manager.
    /// </summary>
    public async Task<T> GetSecretAsync<T>(string secretName, CancellationToken cancellationToken = default)
    {
        var response = await client.GetSecretValueAsync(
            new GetSecretValueRequest { SecretId = secretName },
            cancellationToken
        );

        return JsonSerializer.Deserialize<T>(response.SecretString)!;
    }
}

// Usage with DI
public sealed record DbCredentials(string Username, string Password);

// In Startup/Program.cs
services.AddAWSService<IAmazonSecretsManager>();
services.AddSingleton<AwsSecretsClient>();

// In application code
var dbCreds = await secretsClient.GetSecretAsync<DbCredentials>("prod/myapp/database");
// Returns: DbCredentials { Username = "dbuser", Password = "secret" }
```

### Automatic Rotation

```csharp
using Amazon.SecretsManager;
using Amazon.SecretsManager.Model;
using System.Text.Json;

/// <summary>
/// Create secret with automatic rotation enabled.
/// </summary>
public static async Task CreateSecretWithRotationAsync(
    IAmazonSecretsManager client,
    string secretName,
    object secretValue,
    string rotationLambdaArn,
    int rotationDays = 30,
    CancellationToken cancellationToken = default)
{
    // Create the secret
    await client.CreateSecretAsync(new CreateSecretRequest
    {
        Name = secretName,
        SecretString = JsonSerializer.Serialize(secretValue)
    }, cancellationToken);

    // Enable rotation (requires Lambda function)
    await client.RotateSecretAsync(new RotateSecretRequest
    {
        SecretId = secretName,
        RotationLambdaARN = rotationLambdaArn,
        RotationRules = new RotationRulesType
        {
            AutomaticallyAfterDays = rotationDays
        }
    }, cancellationToken);
}
```

## Environment Variables

### Best Practices

```bash
# Set environment variables (not in code!)
export DATABASE_URL="postgresql://user:pass@localhost/db"
export API_KEY="sk_live_xxx"

# In systemd service file
[Service]
Environment="DATABASE_URL=postgresql://user:pass@localhost/db"
EnvironmentFile=/etc/myapp/secrets.env

# In Docker
docker run -e DATABASE_URL="postgresql://..." myapp
# Or from file
docker run --env-file ./secrets.env myapp

# In Kubernetes
kubectl create secret generic myapp-secrets \
    --from-literal=DATABASE_URL="postgresql://..." \
    --from-literal=API_KEY="sk_live_xxx"
```

### Loading in Application

```csharp
using Microsoft.Extensions.Configuration;

/// <summary>
/// Application configuration loaded from environment variables.
/// </summary>
public sealed class AppConfig
{
    public required string DatabaseUrl { get; init; }
    public required string ApiKey { get; init; }
    public bool Debug { get; init; }
}

// In Program.cs or Startup.cs
var configuration = new ConfigurationBuilder()
    .AddEnvironmentVariables()
    .AddUserSecrets<Program>(optional: true)  // For development
    .Build();

// Bind to strongly-typed config
services.Configure<AppConfig>(options =>
{
    options.DatabaseUrl = configuration["DATABASE_URL"]
        ?? throw new InvalidOperationException("DATABASE_URL is required");
    options.ApiKey = configuration["API_KEY"]
        ?? throw new InvalidOperationException("API_KEY is required");
    options.Debug = bool.TryParse(configuration["DEBUG"], out var debug) && debug;
});

// Or use options pattern
services.AddOptions<AppConfig>()
    .Bind(configuration.GetSection("App"))
    .ValidateDataAnnotations()
    .ValidateOnStart();

// In application cod

Related in Cloud & DevOps