SSH Temporal Keys - User Guide
Quick Start
Generate and Connect with Temporary Key
The fastest way to use temporal SSH keys:
# Auto-generate, deploy, and connect (key auto-revoked after disconnect)
ssh connect server.example.com
# Connect with custom user and TTL
ssh connect server.example.com --user deploy --ttl 30min
# Keep key active after disconnect
ssh connect server.example.com --keep
Manual Key Management
For more control over the key lifecycle:
# 1. Generate key
ssh generate-key server.example.com --user root --ttl 1hr
# Output:
# ✓ SSH key generated successfully
# Key ID: abc-123-def-456
# Type: dynamickeypair
# User: root
# Server: server.example.com
# Expires: 2024-01-01T13:00:00Z
# Fingerprint: SHA256:...
#
# Private Key (save securely):
# -----BEGIN OPENSSH PRIVATE KEY-----
# ...
# -----END OPENSSH PRIVATE KEY-----
# 2. Deploy key to server
ssh deploy-key abc-123-def-456
# 3. Use the private key to connect
ssh -i /path/to/private/key root@server.example.com
# 4. Revoke when done
ssh revoke-key abc-123-def-456
Key Features
Automatic Expiration
All keys expire automatically after their TTL:
- Default TTL: 1 hour
- Configurable: From 5 minutes to 24 hours
- Background Cleanup: Automatic removal from servers every 5 minutes
Multiple Key Types
Choose the right key type for your use case:
| Type | Description | Use Case |
|---|---|---|
| dynamic (default) | Generated Ed25519 keys | Quick SSH access |
| ca | Vault CA-signed certificate | Enterprise with SSH CA |
| otp | Vault one-time password | Single-use access |
Security Benefits
✅ No static SSH keys to manage ✅ Short-lived credentials (1 hour default) ✅ Automatic cleanup on expiration ✅ Audit trail for all operations ✅ Private keys never stored on disk
Common Usage Patterns
Development Workflow
# Quick SSH for debugging
ssh connect dev-server.local --ttl 30min
# Execute commands
ssh root@dev-server.local "systemctl status nginx"
# Connection closes, key auto-revokes
Production Deployment
# Generate key with longer TTL for deployment
ssh generate-key prod-server.example.com --ttl 2hr
# Deploy to server
ssh deploy-key <key-id>
# Run deployment script
ssh -i /tmp/deploy-key root@prod-server.example.com < deploy.sh
# Manual revoke when done
ssh revoke-key <key-id>
Multi-Server Access
# Generate one key
ssh generate-key server01.example.com --ttl 1hr
# Use the same private key for multiple servers (if you have provisioning access)
# Note: Currently each key is server-specific, multi-server support coming soon
Command Reference
ssh generate-key
Generate a new temporal SSH key.
Syntax:
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 only)--principal <name>: Principal (CA mode only)
Examples:
# Basic usage
ssh generate-key server.example.com
# Custom user and TTL
ssh generate-key server.example.com --user deploy --ttl 30min
# Vault CA mode
ssh generate-key server.example.com --type ca --principal admin
ssh deploy-key
Deploy a generated key to the target server.
Syntax:
ssh deploy-key <key-id>
Example:
ssh deploy-key abc-123-def-456
ssh list-keys
List all active SSH keys.
Syntax:
ssh list-keys [--expired]
Examples:
# List active keys
ssh list-keys
# Show only deployed keys
ssh list-keys | where deployed == true
# Include expired keys
ssh list-keys --expired
ssh get-key
Get detailed information about a specific key.
Syntax:
ssh get-key <key-id>
Example:
ssh get-key abc-123-def-456
ssh revoke-key
Immediately revoke a key (removes from server and tracking).
Syntax:
ssh revoke-key <key-id>
Example:
ssh revoke-key abc-123-def-456
ssh connect
Auto-generate, deploy, connect, and revoke (all-in-one).
Syntax:
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: Don’t revoke after disconnect
Examples:
# Quick connection
ssh connect server.example.com
# Custom user
ssh connect server.example.com --user deploy
# Keep key active after disconnect
ssh connect server.example.com --keep
ssh stats
Show SSH key statistics.
Syntax:
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-01T12:00:00Z
Cleaned keys: 5
ssh cleanup
Manually trigger cleanup of expired keys.
Syntax:
ssh cleanup
ssh test
Run a quick test of the SSH key system.
Syntax:
ssh test <server> [--user <name>]
Example:
ssh test server.example.com --user root
ssh help
Show help information.
Syntax:
ssh help
Duration Formats
The --ttl option accepts various duration formats:
| Format | Example | Meaning |
|---|---|---|
| Minutes | 30min | 30 minutes |
| Hours | 2hr | 2 hours |
| Mixed | 1hr 30min | 1.5 hours |
| Seconds | 3600sec | 1 hour |
Working with Private Keys
Saving Private Keys
When you generate a key, save the private key immediately:
# Generate and save to file
ssh generate-key server.example.com | get private_key | save -f ~/.ssh/temp_key
chmod 600 ~/.ssh/temp_key
# Use the key
ssh -i ~/.ssh/temp_key root@server.example.com
# Cleanup
rm ~/.ssh/temp_key
Using SSH Agent
Add the temporary key to your SSH agent:
# Generate key and extract private key
ssh generate-key server.example.com | get private_key | save -f /tmp/temp_key
chmod 600 /tmp/temp_key
# Add to agent
ssh-add /tmp/temp_key
# Connect (agent provides the key automatically)
ssh root@server.example.com
# Remove from agent
ssh-add -d /tmp/temp_key
rm /tmp/temp_key
Troubleshooting
Key Deployment Fails
Problem: ssh deploy-key returns error
Solutions:
-
Check SSH connectivity to server:
ssh root@server.example.com -
Verify provisioning key is configured:
echo $PROVISIONING_SSH_KEY -
Check server SSH daemon:
ssh root@server.example.com "systemctl status sshd"
Private Key Not Working
Problem: SSH connection fails with “Permission denied (publickey)”
Solutions:
-
Verify key was deployed:
ssh list-keys | where id == "<key-id>" -
Check key hasn’t expired:
ssh get-key <key-id> | get expires_at -
Verify private key permissions:
chmod 600 /path/to/private/key
Cleanup Not Running
Problem: Expired keys not being removed
Solutions:
-
Check orchestrator is running:
curl http://localhost:9090/health -
Trigger manual cleanup:
ssh cleanup -
Check orchestrator logs:
tail -f ./data/orchestrator.log | grep SSH
Best Practices
Security
-
Short TTLs: Use the shortest TTL that works for your task
ssh connect server.example.com --ttl 30min -
Immediate Revocation: Revoke keys when you’re done
ssh revoke-key <key-id> -
Private Key Handling: Never share or commit private keys
# Save to temp location, delete after use ssh generate-key server.example.com | get private_key | save -f /tmp/key # ... use key ... rm /tmp/key
Workflow Integration
-
Automated Deployments: Generate key in CI/CD
#!/bin/bash KEY_ID=$(ssh generate-key prod.example.com --ttl 1hr | get id) ssh deploy-key $KEY_ID # Run deployment ansible-playbook deploy.yml ssh revoke-key $KEY_ID -
Interactive Use: Use
ssh connectfor quick accessssh connect dev.example.com -
Monitoring: Check statistics regularly
ssh stats
Advanced Usage
Vault Integration
If your organization uses HashiCorp Vault:
CA Mode (Recommended)
# Generate CA-signed certificate
ssh generate-key server.example.com --type ca --principal admin --ttl 1hr
# Vault signs your public key
# Server must trust Vault CA certificate
Setup (one-time):
# On servers, add to /etc/ssh/sshd_config:
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
# Get Vault CA public key:
vault read -field=public_key ssh/config/ca | \
sudo tee /etc/ssh/trusted-user-ca-keys.pem
# Restart SSH:
sudo systemctl restart sshd
OTP Mode
# Generate one-time password
ssh generate-key server.example.com --type otp --ip 192.168.1.100
# Use the OTP to connect (single use only)
Scripting
Use in scripts for automated operations:
# deploy.nu
def deploy [target: string] {
let key = (ssh generate-key $target --ttl 1hr)
ssh deploy-key $key.id
# Run deployment
try {
ssh $"root@($target)" "bash /path/to/deploy.sh"
} catch {
print "Deployment failed"
}
# Always cleanup
ssh revoke-key $key.id
}
API Integration
For programmatic access, use the REST API:
# Generate key
curl -X POST http://localhost:9090/api/v1/ssh/generate \
-H "Content-Type: application/json" \
-d '{
"key_type": "dynamickeypair",
"user": "root",
"target_server": "server.example.com",
"ttl_seconds": 3600
}'
# Deploy key
curl -X POST http://localhost:9090/api/v1/ssh/{key_id}/deploy
# List keys
curl http://localhost:9090/api/v1/ssh/keys
# Get stats
curl http://localhost:9090/api/v1/ssh/stats
FAQ
Q: Can I use the same key for multiple servers? A: Currently, each key is tied to a specific server. Multi-server support is planned.
Q: What happens if the orchestrator crashes? A: Keys in memory are lost, but keys already deployed to servers remain until their expiration time.
Q: Can I extend the TTL of an existing key? A: No, you must generate a new key. This is by design for security.
Q: What’s the maximum TTL? A: Configurable by admin, default maximum is 24 hours.
Q: Are private keys stored anywhere? A: Private keys exist only in memory during generation and are shown once to the user. They are never written to disk by the system.
Q: What happens if cleanup fails?
A: The key remains in authorized_keys until the next cleanup run. You can trigger manual cleanup with ssh cleanup.
Q: Can I use this with non-root users?
A: Yes, use --user <username> when generating the key.
Q: How do I know when my key will expire?
A: Use ssh get-key <key-id> to see the exact expiration timestamp.
Support
For issues or questions:
- Check orchestrator logs:
tail -f ./data/orchestrator.log - Run diagnostics:
ssh stats - Test connectivity:
ssh test server.example.com - Review documentation:
SSH_KEY_MANAGEMENT.md
See Also
- Architecture:
SSH_KEY_MANAGEMENT.md - Implementation:
SSH_IMPLEMENTATION_SUMMARY.md - Configuration:
config/ssh-config.toml.example