prvng_platform/crates/orchestrator/docs/ssh-key-management.md
2026-01-12 04:53:31 +00:00

12 KiB

SSH Temporal Key Management System

Overview

The SSH Temporal Key Management System provides automated generation, deployment, and cleanup of short-lived SSH keys for secure server access. It eliminates the need for static SSH keys by generating keys on-demand with automatic expiration.

Features

Core Features

  • Short-Lived Keys: Keys expire automatically after a configurable TTL (default: 1 hour)
  • Multiple Key Types:
    • Dynamic Key Pairs (Ed25519)
    • Vault OTP (One-Time Password)
    • Vault CA-Signed Certificates
  • Automatic Cleanup: Background task removes expired keys from servers
  • Audit Trail: All key operations are logged
  • REST API: HTTP endpoints for integration
  • Nushell CLI: User-friendly command-line interface

Security Features

  • Ed25519 keys (modern, secure algorithm)
  • Automatic expiration and cleanup
  • Private keys never stored on disk (only in memory)
  • Vault integration for enterprise scenarios
  • SSH fingerprint tracking
  • Per-key audit logging

Architecture

┌─────────────────────────────────────────────────
────────────┐
│                   SSH Key Manager                           │
├─────────────────────────────────────────────────
────────────┤
│                                                             │
│  ┌──────────────┐  ┌──────────────┐  
┌──────────────┐       │
│  │ Key Generator│  │ Key Deployer │  │   Temporal   │       │
│  │  (Ed25519)   │  │ (SSH Deploy) │  │   Manager    │       │
│  └──────────────┘  └──────────────┘  
└──────────────┘       │
│                                                             │
│  ┌──────────────┐  ┌──────────────┐                         │
│  │    Vault     │  │ Authorized   │                         │
│  │ SSH Engine   │  │ Keys Manager │                         │
│  └──────────────┘  └──────────────┘                         │
│                                                             │
└─────────────────────────────────────────────────
────────────┘
         │                    │                    │
         ▼                    ▼                    ▼
    REST API            Nushell CLI          Background Tasks
```text

## Key Types

### 1. Dynamic Key Pairs (Default)

Generated on-demand Ed25519 keys that are automatically deployed and cleaned up.

**Use Case**: Quick SSH access without Vault infrastructure

**Example**:

```bash
ssh generate-key server.example.com --user root --ttl 30min
```text

### 2. Vault OTP (One-Time Password)

Vault generates a one-time password for SSH authentication.

**Use Case**: Single-use SSH access with centralized authentication

**Requirements**: Vault with SSH secrets engine in OTP mode

**Example**:

```bash
ssh generate-key server.example.com --type otp --ip 192.168.1.100
```text

### 3. Vault CA-Signed Certificates

Vault acts as SSH CA, signing user public keys with short TTL.

**Use Case**: Enterprise scenarios with SSH CA infrastructure

**Requirements**: Vault with SSH secrets engine in CA mode

**Example**:

```bash
ssh generate-key server.example.com --type ca --principal admin --ttl 1hr
```text

## REST API Endpoints

Base URL: `http://localhost:9090`

### Generate SSH Key

```http
POST /api/v1/ssh/generate

{
  "key_type": "dynamickeypair",  // or "otp", "certificate"
  "user": "root",
  "target_server": "server.example.com",
  "ttl_seconds": 3600,
  "allowed_ip": "192.168.1.100",  // optional, for OTP
  "principal": "admin"             // optional, for CA
}

Response:
{
  "success": true,
  "data": {
    "id": "uuid",
    "key_type": "dynamickeypair",
    "public_key": "ssh-ed25519 AAAA...",
    "private_key": "-----BEGIN OPENSSH PRIVATE KEY-----...",
    "fingerprint": "SHA256:...",
    "user": "root",
    "target_server": "server.example.com",
    "created_at": "2024-01-01T00:00:00Z",
    "expires_at": "2024-01-01T01:00:00Z",
    "deployed": false
  }
}
```text

### Deploy SSH Key

```http
POST /api/v1/ssh/{key_id}/deploy

Response:
{
  "success": true,
  "data": {
    "key_id": "uuid",
    "server": "server.example.com",
    "success": true,
    "deployed_at": "2024-01-01T00:00:00Z"
  }
}
```text

### List SSH Keys

```http
GET /api/v1/ssh/keys

Response:
{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "key_type": "dynamickeypair",
      "user": "root",
      "target_server": "server.example.com",
      "expires_at": "2024-01-01T01:00:00Z",
      "deployed": true
    }
  ]
}
```text

### Revoke SSH Key

```http
POST /api/v1/ssh/{key_id}/revoke

Response:
{
  "success": true,
  "data": "Key uuid revoked successfully"
}
```text

### Get SSH Key

```http
GET /api/v1/ssh/{key_id}

Response:
{
  "success": true,
  "data": {
    "id": "uuid",
    "key_type": "dynamickeypair",
    ...
  }
}
```text

### Cleanup Expired Keys

```http
POST /api/v1/ssh/cleanup

Response:
{
  "success": true,
  "data": {
    "cleaned_count": 5,
    "cleaned_key_ids": ["uuid1", "uuid2", ...]
  }
}
```text

### Get Statistics

```http
GET /api/v1/ssh/stats

Response:
{
  "success": true,
  "data": {
    "total_generated": 42,
    "active_keys": 10,
    "expired_keys": 32,
    "keys_by_type": {
      "dynamic": 35,
      "otp": 5,
      "certificate": 2
    },
    "last_cleanup_count": 5,
    "last_cleanup_at": "2024-01-01T00:00:00Z"
  }
}
```text

## Nushell CLI Commands

### Generate Key

```bash
ssh generate-key <server> [options]

Options:
  --user <name>                 SSH user (default: root)
  --ttl <duration>              Key lifetime (default: 1hr)
  --type <ca|otp|dynamic>       Key type (default: dynamic)
  --ip <address>                Allowed IP (OTP mode)
  --principal <name>            Principal (CA mode)

Examples:
  ssh generate-key server.example.com
  ssh generate-key server.example.com --user deploy --ttl 30min
  ssh generate-key server.example.com --type ca --principal admin
```text

### Deploy Key

```bash
ssh deploy-key <key_id>

Example:
  ssh deploy-key abc-123-def-456
```text

### List Keys

```bash
ssh list-keys [--expired]

Example:
  ssh list-keys
  ssh list-keys | where deployed == true
```text

### Revoke Key

```bash
ssh revoke-key <key_id>

Example:
  ssh revoke-key abc-123-def-456
```text

### Connect with Auto-Generated Key

```bash
ssh connect <server> [options]

Options:
  --user <name>                 SSH user (default: root)
  --ttl <duration>              Key lifetime (default: 1hr)
  --type <ca|otp|dynamic>       Key type (default: dynamic)
  --keep                        Keep key after disconnect

Example:
  ssh connect server.example.com --user deploy
```text

This command:

1. Generates a temporal SSH key
2. Deploys it to the server
3. Opens SSH connection
4. Revokes the key after disconnect (unless --keep is used)

### Show Statistics

```bash
ssh stats

Example output:
  SSH Key Statistics:
    Total generated: 42
    Active keys: 10
    Expired keys: 32

  Keys by type:
    dynamic: 35
    otp: 5
    certificate: 2

  Last cleanup: 2024-01-01T00:00:00Z
    Cleaned keys: 5
```text

### Manual Cleanup

```bash
ssh cleanup

Example output:
  ✓ Cleaned up 5 expired keys
  Cleaned key IDs:
    - abc-123
    - def-456
    ...
```text

## Configuration

### Orchestrator Configuration

Add to orchestrator startup:

```rust
use provisioning_orchestrator::{SshKeyManager, SshConfig};

// Create SSH configuration
let ssh_config = SshConfig {
    vault_enabled: false,           // Enable Vault integration
    vault_addr: None,               // Vault address
    vault_token: None,              // Vault token
    vault_mount_point: "ssh".to_string(),
    vault_mode: "ca".to_string(),   // "ca" or "otp"
    default_ttl: Duration::hours(1),
    cleanup_interval: Duration::minutes(5),
    provisioning_key_path: Some("/path/to/provisioning/key".to_string()),
};

// Create SSH key manager
let ssh_manager = Arc::new(SshKeyManager::new(ssh_config).await?);

// Start background cleanup task
Arc::clone(&ssh_manager).start_cleanup_task().await;
```text

### Vault SSH Configuration

#### OTP Mode

```bash
# Enable SSH secrets engine
vault secrets enable ssh

# Configure OTP role
vault write ssh/roles/otp_key_role \
    key_type=otp \
    default_user=root \
    cidr_list=0.0.0.0/0
```text

#### CA Mode

```bash
# Enable SSH secrets engine
vault secrets enable ssh

# Generate SSH CA
vault write ssh/config/ca generate_signing_key=true

# Configure CA role
vault write ssh/roles/default \
    key_type=ca \
    ttl=1h \
    max_ttl=24h \
    allow_user_certificates=true \
    allowed_users="*" \
    default_extensions="permit-pty,permit-port-forwarding"

# Get CA public key (add to servers' /etc/ssh/trusted-user-ca-keys.pem)
vault read -field=public_key ssh/config/ca
```text

Server configuration (`/etc/ssh/sshd_config`):

```plaintext
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
```text

## Deployment

### Prerequisites

1. **Orchestrator**: Running on port 8080
2. **SSH Access**: Provisioning key for deploying to servers
3. **Vault** (optional): For OTP or CA modes

### Environment Variables

```bash
# Vault integration (optional)
export VAULT_ADDR=https://vault.example.com:8200
export VAULT_TOKEN=your-vault-token

# Provisioning SSH key path
export PROVISIONING_SSH_KEY=/path/to/provisioning/key
```text

### Integration with Workflows

The SSH key manager integrates with existing workflows:

```nushell
# In server creation workflow
let ssh_key = (ssh generate-key $server --ttl 30min)
ssh deploy-key $ssh_key.id

# Execute remote commands
ssh root@$server "install-kubernetes.sh"

# Auto-revoke after workflow
ssh revoke-key $ssh_key.id
```text

## Security Considerations

1. **Private Key Exposure**: Private keys are only shown once during generation
2. **Key Storage**: Keys stored in memory only, not on disk
3. **Cleanup**: Automatic cleanup removes expired keys from servers
4. **Audit Logging**: All operations logged for security audit
5. **Vault Integration**: Optional Vault integration for enterprise security
6. **TTL Limits**: Enforce maximum TTL to prevent long-lived keys

## Troubleshooting

### Key Deployment Fails

Check SSH connectivity:

```bash
ssh -i /path/to/provisioning/key root@server.example.com
```text

Verify SSH daemon is running:

```bash
systemctl status sshd
```text

### Cleanup Not Working

Check orchestrator logs:

```bash
tail -f ./data/orchestrator.log | grep SSH
```text

Manual cleanup:

```bash
ssh cleanup
```text

### Vault Integration Issues

Test Vault connectivity:

```bash
vault status
vault token lookup
```text

Check SSH secrets engine:

```bash
vault secrets list
vault read ssh/config/ca
```text

## Performance

- **Key Generation**: <100ms (Ed25519)
- **Key Deployment**: ~1s (depends on SSH latency)
- **Cleanup Task**: Every 5 minutes (configurable)
- **Concurrent Keys**: Unlimited (memory bound)

## Future Enhancements

- [ ] SSH certificate rotation
- [ ] Integration with KMS for key encryption
- [ ] WebSocket notifications for key expiration
- [ ] Prometheus metrics export
- [ ] SSH session recording
- [ ] Role-based key generation policies

## References

- RFC 8709: Ed25519 and Ed448 Public Key Algorithms for SSH
- Vault SSH Secrets Engine: <https://www.vaultproject.io/docs/secrets/ssh>
- OpenSSH Certificate Authentication: <https://man.openbsd.org/ssh-keygen>