# Secrets Management System - Configuration Guide

**Status**: Production Ready
**Date**: 2025-11-19
**Version**: 1.0.0

## Overview

The provisioning system supports secure SSH key retrieval from multiple secret sources, eliminating hardcoded filesystem dependencies and enabling enterprise-grade security. SSH keys are retrieved from configured secret sources (SOPS, KMS, RustyVault) with automatic fallback to local-dev mode for development environments.

## Secret Sources

### 1. SOPS (Secrets Operations)

Age-based encrypted secrets file with YAML structure.

**Pros**:

- ✅ Age encryption (modern, performant)
- ✅ Easy to version in Git (encrypted)
- ✅ No external services required
- ✅ Simple YAML structure

**Cons**:

- ❌ Requires Age key management
- ❌ No key rotation automation

**Environment Variables**:

```bash
PROVISIONING_SECRET_SOURCE=sops
PROVISIONING_SOPS_ENABLED=true
PROVISIONING_SOPS_SECRETS_FILE=/path/to/secrets.enc.yaml
PROVISIONING_SOPS_AGE_KEY_FILE=$HOME/.age/provisioning
```plaintext

**Secrets File Structure** (provisioning/secrets.enc.yaml):

```yaml
# Encrypted with sops
ssh:
  web-01:
    ubuntu: /path/to/id_rsa
    root: /path/to/root_id_rsa
  db-01:
    postgres: /path/to/postgres_id_rsa
```plaintext

**Setup Instructions**:

```bash
# 1. Install sops and age
brew install sops age

# 2. Generate Age key (store securely!)
age-keygen -o $HOME/.age/provisioning

# 3. Create encrypted secrets file
cat > secrets.yaml << 'EOF'
ssh:
  web-01:
    ubuntu: ~/.ssh/provisioning_web01
  db-01:
    postgres: ~/.ssh/provisioning_db01
EOF

# 4. Encrypt with sops
sops -e -i secrets.yaml

# 5. Rename to enc version
mv secrets.yaml provisioning/secrets.enc.yaml

# 6. Configure environment
export PROVISIONING_SECRET_SOURCE=sops
export PROVISIONING_SOPS_SECRETS_FILE=$(pwd)/provisioning/secrets.enc.yaml
export PROVISIONING_SOPS_AGE_KEY_FILE=$HOME/.age/provisioning
```plaintext

### 2. KMS (Key Management Service)

AWS KMS or compatible key management service.

**Pros**:

- ✅ Cloud-native security
- ✅ Automatic key rotation
- ✅ Audit logging built-in
- ✅ High availability

**Cons**:

- ❌ Requires AWS account/credentials
- ❌ API calls add latency (~50 ms)
- ❌ Cost per API call

**Environment Variables**:

```bash
PROVISIONING_SECRET_SOURCE=kms
PROVISIONING_KMS_ENABLED=true
PROVISIONING_KMS_REGION=us-east-1
```plaintext

**Secret Storage Pattern**:

```plaintext
provisioning/ssh-keys/{hostname}/{username}
```plaintext

**Setup Instructions**:

```bash
# 1. Create KMS key (one-time)
aws kms create-key \
    --description "Provisioning SSH Keys" \
    --region us-east-1

# 2. Store SSH keys in Secrets Manager
aws secretsmanager create-secret \
    --name provisioning/ssh-keys/web-01/ubuntu \
    --secret-string "$(cat ~/.ssh/provisioning_web01)" \
    --region us-east-1

# 3. Configure environment
export PROVISIONING_SECRET_SOURCE=kms
export PROVISIONING_KMS_REGION=us-east-1

# 4. Ensure AWS credentials available
export AWS_PROFILE=provisioning
# or
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
```plaintext

### 3. RustyVault (Hashicorp Vault-Compatible)

Self-hosted or managed Vault instance for secrets.

**Pros**:

- ✅ Self-hosted option
- ✅ Fine-grained access control
- ✅ Multiple authentication methods
- ✅ Easy key rotation

**Cons**:

- ❌ Requires Vault instance
- ❌ More operational overhead
- ❌ Network latency

**Environment Variables**:

```bash
PROVISIONING_SECRET_SOURCE=vault
PROVISIONING_VAULT_ENABLED=true
PROVISIONING_VAULT_ADDRESS=http://localhost:8200
PROVISIONING_VAULT_TOKEN=hvs.CAESIAoICQ...
```plaintext

**Secret Storage Pattern**:

```plaintext
GET /v1/secret/ssh-keys/{hostname}/{username}
# Returns: {"key_content": "-----BEGIN OPENSSH PRIVATE KEY-----..."}
```plaintext

**Setup Instructions**:

```bash
# 1. Start Vault (if not already running)
docker run -p 8200:8200 \
    -e VAULT_DEV_ROOT_TOKEN_ID=provisioning \
    vault server -dev

# 2. Create KV v2 mount (if not exists)
vault secrets enable -version=2 -path=secret kv

# 3. Store SSH key
vault kv put secret/ssh-keys/web-01/ubuntu \
    key_content=@~/.ssh/provisioning_web01

# 4. Configure environment
export PROVISIONING_SECRET_SOURCE=vault
export PROVISIONING_VAULT_ADDRESS=http://localhost:8200
export PROVISIONING_VAULT_TOKEN=provisioning

# 5. Create AppRole for production
vault auth enable approle
vault write auth/approle/role/provisioning \
    token_ttl=1h \
    token_max_ttl=4h
vault read auth/approle/role/provisioning/role-id
vault write -f auth/approle/role/provisioning/secret-id
```plaintext

### 4. Local-Dev (Fallback)

Local filesystem SSH keys (development only).

**Pros**:

- ✅ No setup required
- ✅ Fast (local filesystem)
- ✅ Works offline

**Cons**:

- ❌ NOT for production
- ❌ Hardcoded filesystem dependency
- ❌ No key rotation

**Environment Variables**:

```bash
PROVISIONING_ENVIRONMENT=local-dev
```plaintext

**Behavior**:

Standard paths checked (in order):

1. `$HOME/.ssh/id_rsa`
2. `$HOME/.ssh/id_ed25519`
3. `$HOME/.ssh/provisioning`
4. `$HOME/.ssh/provisioning_rsa`

## Auto-Detection Logic

When `PROVISIONING_SECRET_SOURCE` is not explicitly set, the system auto-detects in this order:

```plaintext
1. PROVISIONING_SOPS_ENABLED=true or PROVISIONING_SOPS_SECRETS_FILE set?
   → Use SOPS
2. PROVISIONING_KMS_ENABLED=true or PROVISIONING_KMS_REGION set?
   → Use KMS
3. PROVISIONING_VAULT_ENABLED=true or both VAULT_ADDRESS and VAULT_TOKEN set?
   → Use Vault
4. Otherwise
   → Use local-dev (with warnings in production environments)
```plaintext

## Configuration Matrix

| Secret Source | Env Variables | Enabled in |
|---|---|---|
| **SOPS** | `PROVISIONING_SOPS_*` | Development, Staging, Production |
| **KMS** | `PROVISIONING_KMS_*` | Staging, Production (with AWS) |
| **Vault** | `PROVISIONING_VAULT_*` | Development, Staging, Production |
| **Local-dev** | `PROVISIONING_ENVIRONMENT=local-dev` | Development only |

## Production Recommended Setup

### Minimal Setup (Single Source)

```bash
# Using Vault (recommended for self-hosted)
export PROVISIONING_SECRET_SOURCE=vault
export PROVISIONING_VAULT_ADDRESS=https://vault.example.com:8200
export PROVISIONING_VAULT_TOKEN=hvs.CAESIAoICQ...
export PROVISIONING_ENVIRONMENT=production
```plaintext

### Enhanced Setup (Fallback Chain)

```bash
# Primary: Vault
export PROVISIONING_VAULT_ADDRESS=https://vault.primary.com:8200
export PROVISIONING_VAULT_TOKEN=hvs.CAESIAoICQ...

# Fallback: SOPS
export PROVISIONING_SOPS_SECRETS_FILE=/etc/provisioning/secrets.enc.yaml
export PROVISIONING_SOPS_AGE_KEY_FILE=/etc/provisioning/.age/key

# Environment
export PROVISIONING_ENVIRONMENT=production
export PROVISIONING_SECRET_SOURCE=vault  # Explicit: use Vault first
```plaintext

### High-Availability Setup

```bash
# Use KMS (managed service)
export PROVISIONING_SECRET_SOURCE=kms
export PROVISIONING_KMS_REGION=us-east-1
export AWS_PROFILE=provisioning-admin

# Or use Vault with HA
export PROVISIONING_VAULT_ADDRESS=https://vault-ha.example.com:8200
export PROVISIONING_VAULT_NAMESPACE=provisioning
export PROVISIONING_ENVIRONMENT=production
```plaintext

## Validation & Testing

### Check Configuration

```bash
# Nushell
provisioning secrets status

# Show secret source and configuration
provisioning secrets validate

# Detailed diagnostics
provisioning secrets diagnose
```plaintext

### Test SSH Key Retrieval

```bash
# Test specific host/user
provisioning secrets get-key web-01 ubuntu

# Test all configured hosts
provisioning secrets validate-all

# Dry-run SSH with retrieved key
provisioning ssh --test-key web-01 ubuntu
```plaintext

## Migration Path

### From Local-Dev to SOPS

```bash
# 1. Create SOPS secrets file with existing keys
cat > secrets.yaml << 'EOF'
ssh:
  web-01:
    ubuntu: ~/.ssh/provisioning_web01
  db-01:
    postgres: ~/.ssh/provisioning_db01
EOF

# 2. Encrypt with Age
sops -e -i secrets.yaml

# 3. Move to repo
mv secrets.yaml provisioning/secrets.enc.yaml

# 4. Update environment
export PROVISIONING_SECRET_SOURCE=sops
export PROVISIONING_SOPS_SECRETS_FILE=$(pwd)/provisioning/secrets.enc.yaml
export PROVISIONING_SOPS_AGE_KEY_FILE=$HOME/.age/provisioning
```plaintext

### From SOPS to Vault

```bash
# 1. Decrypt SOPS file
sops -d provisioning/secrets.enc.yaml > /tmp/secrets.yaml

# 2. Import to Vault
vault kv put secret/ssh-keys/web-01/ubuntu key_content=@~/.ssh/provisioning_web01

# 3. Update environment
export PROVISIONING_SECRET_SOURCE=vault
export PROVISIONING_VAULT_ADDRESS=http://vault.example.com:8200
export PROVISIONING_VAULT_TOKEN=hvs.CAESIAoICQ...

# 4. Validate retrieval works
provisioning secrets validate-all
```plaintext

## Security Best Practices

### 1. Never Commit Secrets

```bash
# Add to .gitignore
echo "provisioning/secrets.enc.yaml" >> .gitignore
echo ".age/provisioning" >> .gitignore
echo ".vault-token" >> .gitignore
```plaintext

### 2. Rotate Keys Regularly

```bash
# SOPS: Rotate Age key
age-keygen -o ~/.age/provisioning.new
# Update all secrets with new key

# KMS: Enable automatic rotation
aws kms enable-key-rotation --key-id alias/provisioning

# Vault: Set TTL on secrets
vault write -f secret/metadata/ssh-keys/web-01/ubuntu \
    delete_version_after=2160h  # 90 days
```plaintext

### 3. Restrict Access

```bash
# SOPS: Protect Age key
chmod 600 ~/.age/provisioning

# KMS: Restrict IAM permissions
aws iam put-user-policy --user-name provisioning \
    --policy-name ProvisioningSecretsAccess \
    --policy-document file://kms-policy.json

# Vault: Use AppRole for applications
vault write auth/approle/role/provisioning \
    token_ttl=1h \
    secret_id_ttl=30m
```plaintext

### 4. Audit Logging

```bash
# KMS: Enable CloudTrail
aws cloudtrail put-event-selectors \
    --trail-name provisioning-trail \
    --event-selectors ReadWriteType=All

# Vault: Check audit logs
vault audit list

# SOPS: Version control (encrypted)
git log -p provisioning/secrets.enc.yaml
```plaintext

## Troubleshooting

### SOPS Issues

```bash
# Test Age decryption
sops -d provisioning/secrets.enc.yaml

# Verify Age key
age-keygen -l ~/.age/provisioning

# Regenerate if needed
rm ~/.age/provisioning
age-keygen -o ~/.age/provisioning
```plaintext

### KMS Issues

```bash
# Test AWS credentials
aws sts get-caller-identity

# Check KMS key permissions
aws kms describe-key --key-id alias/provisioning

# List secrets
aws secretsmanager list-secrets --filters Name=name,Values=provisioning
```plaintext

### Vault Issues

```bash
# Check Vault status
vault status

# Test authentication
vault token lookup

# List secrets
vault kv list secret/ssh-keys/

# Check audit logs
vault audit list
vault read sys/audit
```plaintext

## FAQ

**Q: Can I use multiple secret sources simultaneously?**
A: Yes, configure multiple sources and set `PROVISIONING_SECRET_SOURCE` to specify primary. If primary fails, manual fallback to secondary is supported.

**Q: What happens if secret retrieval fails?**
A: System logs the error and fails fast. No automatic fallback to local filesystem (for security).

**Q: Can I cache SSH keys?**
A: Currently not, keys are retrieved fresh for each operation. Use local caching at OS level (ssh-agent) if needed.

**Q: How do I rotate keys?**
A: Update the secret in your configured source (SOPS/KMS/Vault) and retrieve fresh on next operation.

**Q: Is local-dev mode secure?**
A: No - it's development only. Production requires SOPS/KMS/Vault.

## Architecture

```plaintext
SSH Operation
    ↓
SecretsManager (Nushell/Rust)
    ↓
[Detect Source]
    ↓
┌─────────────────────────────────────┐
│ SOPS          KMS      Vault   LocalDev
│ (Encrypted    (AWS KMS (Self-  (Filesystem
│  Secrets)     Service)  Hosted) Dev Only)
│
└─────────────────────────────────────┘
    ↓
Return SSH Key Path/Content
    ↓
SSH Operation Completes
```plaintext

## Integration with SSH Utilities

SSH operations automatically use secrets manager:

```nushell
# Automatic secret retrieval
ssh-cmd-smart $settings $server false "command" $ip
# Internally:
#   1. Determine secret source
#   2. Retrieve SSH key for server.installer_user@ip
#   3. Execute SSH with retrieved key
#   4. Cleanup sensitive data

# Batch operations also integrate
ssh-batch-execute $servers $settings "command"
# Per-host: Retrieves key → executes → cleans up
```plaintext

---

**For Support**: See `docs/user/TROUBLESHOOTING_GUIDE.md`
**For Integration**: See `provisioning/core/nulib/lib_provisioning/platform/secrets.nu`
