Vault SSH Key Management
Overview
Vault SSH Key Management provides secure, centralized storage and automated rotation of SSH credentials for tenant VPS infrastructure. By storing SSH keys in HashiCorp Vault instead of ENV files on VPS instances, PenguinMails enables rapid disaster recovery and eliminates credential exposure risks from VPS compromise.
Problem Statement
Traditional SSH key management approaches create security vulnerabilities:
-
ENV File Exposure: SSH keys stored in ENV files on VPS are exposed if VPS is compromised
-
Manual Rotation: Rotating SSH keys requires manual updates across multiple VPS instances
-
No Audit Trail: Difficult to track who accessed SSH keys and when
-
Disaster Recovery: VPS compromise requires manual credential recovery and rotation
-
Scattered Management: SSH keys managed individually per VPS instead of centrally
Solution
Vault SSH Key Management centralizes SSH credential storage and automates rotation:
-
Centralized Storage: All SSH keys stored in Vault, not on VPS
-
Automated Rotation: SSH keys automatically rotated every 90 days with 24-hour grace period
-
Audit Logging: All SSH key access logged with timestamp, user, and action
-
Rapid Recovery: VPS compromise doesnβt expose secrets; abandon VPS and provision new one
-
Tenant Access: Tenants can download their SSH private key for VPS access
Key Features
1. Dual SSH Key System
Admin SSH Keys (PenguinMails Access):
-
Generated during VPS provisioning
-
Stored in Vault at
/vps/{tenant_id}/admin_ssh -
Used by PenguinMails for infrastructure management
-
Never exposed to tenants
-
Rotated every 90 days automatically
Tenant SSH Keys (Customer Access):
-
Generated during VPS provisioning
-
Stored in Vault at
/vps/{tenant_id}/tenant_ssh -
Downloadable by tenant owner/admin
-
Used for programmatic VPS access
-
Rotated every 90 days automatically
2. Secure Key Download
One-Time Download:
-
Tenant can download private key once from UI
-
Download triggers audit log entry
-
Warning message: βStore this key securely. It will not be shown again.β
-
Key never displayed in UI after initial download
Download Process:
// User clicks "Download Private Key"
POST /api/v1/tenant/infrastructure/ssh-credentials/download
// Backend retrieves key from Vault
const privateKey = await vault.read(`vps/${tenantId}/tenant_ssh/private_key`);
// Log download event
await auditLog.create({
action: 'ssh_key_download',
tenantId,
userId,
timestamp: new Date(),
ipAddress: req.ip
});
// Return key as downloadable file
res.download('tenant-ssh-key.pem', privateKey);
3. Automated Key Rotation
Rotation Schedule:
-
SSH keys rotated every 90 days
-
Cron job checks rotation policy daily
-
Manual rotation trigger available in UI
Rotation Workflow:
Cron job checks last_rotated timestamp
Γ’β β
If rotation due (current_date - last_rotated >= 90 days):
Γ’β β
Generate new RSA 4096-bit key pair
Γ’β β
Store new key in Vault with incremented version
Γ’β β
Add new public key to VPS authorized_keys
Γ’β β
Keep old key active for 24-hour grace period
Γ’β β
Remove old key from authorized_keys after grace period
Γ’β β
Send notification to tenant (email)
Γ’β β
Log rotation event in audit trail
Grace Period:
-
24-hour grace period prevents service disruption
-
Both old and new keys valid during grace period
-
Tenants notified to update their SSH clients
4. Key Revocation and Regeneration
Revoke SSH Access:
-
Tenant can revoke SSH access immediately
-
Removes public key from VPS authorized_keys
-
Marks key as revoked in Vault
-
No grace period (immediate revocation)
Regenerate SSH Key:
-
Tenant can regenerate new SSH key after revocation
-
Generates new RSA 4096-bit key pair
-
Stores new key in Vault
-
Adds new public key to VPS authorized_keys
-
Tenant must download new private key
5. Connection Instructions
UI Display:
# SSH Connection Command
ssh -i /path/to/private-key.pem tenant-{tenant_id}@{vps_ip}
# Example
ssh -i ~/Downloads/tenant-ssh-key.pem tenant-550e8400@192.168.1.100
Troubleshooting Tips:
-
Ensure private key has correct permissions:
chmod 600 private-key.pem -
Verify VPS IP address is correct
-
Check firewall allows SSH connections (port 22)
-
Confirm SSH key hasnβt been rotated (check UI for latest key)
6. Audit Logging
Logged Events:
-
SSH key download (who, when, IP address)
-
SSH key rotation (automated or manual)
-
SSH key revocation
-
SSH key regeneration
-
Failed SSH authentication attempts (from VPS logs)
Audit Log Format:
{
"timestamp": "2025-11-26T10:30:00.000Z",
"action": "ssh_key_download",
"tenantId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0...",
"status": "success"
}
User Workflows
Tenant: Download SSH Key
-
Navigate to Settings β Infrastructure β SSH Access
-
View SSH credentials (VPS IP, username, port)
-
Click βDownload Private Keyβ button
-
Read security warning
-
Confirm download
-
Save private key file securely
-
Follow connection instructions to connect to VPS
Tenant: Rotate SSH Key Manually
-
Navigate to Settings β Infrastructure β SSH Access
-
Click βRotate SSH Keyβ button
-
Read grace period notice (24 hours)
-
Confirm rotation
-
Wait for rotation to complete (30 seconds)
-
Download new private key
-
Update SSH clients with new key
-
Old key remains valid for 24 hours
Tenant: Revoke and Regenerate SSH Key
-
Navigate to Settings β Infrastructure β SSH Access
-
Click βRevoke SSH Accessβ button
-
Confirm revocation (immediate, no grace period)
-
SSH access revoked
-
Click βRegenerate SSH Keyβ button
-
New key generated and stored in Vault
-
Download new private key
-
Connect to VPS with new key
Admin: Monitor SSH Key Health
-
Navigate to Admin Panel β Secrets Management
-
View Vault health dashboard
-
Search for tenant by ID or name
-
View SSH key status (active, expired, revoked)
-
Check last rotation date
-
Review audit logs for suspicious activity
-
Trigger bulk rotation if needed
Technical Architecture
Vault Secret Structure
vault/vps/{tenant_id}/
βββ admin_ssh/
β βββ private_key # RSA 4096-bit private key
β βββ public_key # RSA 4096-bit public key
β βββ created_at # ISO 8601 timestamp
β βββ last_rotated # ISO 8601 timestamp
β βββ rotation_policy # "90_days"
βββ tenant_ssh/
βββ private_key # RSA 4096-bit private key
βββ public_key # RSA 4096-bit public key
βββ created_at # ISO 8601 timestamp
βββ last_rotated # ISO 8601 timestamp
βββ rotation_policy # "90_days"
API Endpoints
Tenant Endpoints:
// Retrieve SSH credentials (public info only)
GET /api/v1/tenant/infrastructure/ssh-credentials
Response: {
vpsIp: string;
sshUsername: string;
sshPort: number;
keyFingerprint: string;
lastRotated: string;
nextRotation: string;
}
// Download private key (one-time)
POST /api/v1/tenant/infrastructure/ssh-credentials/download
Response: File download (tenant-ssh-key.pem)
// Rotate SSH key manually
POST /api/v1/tenant/infrastructure/ssh-credentials/rotate
Response: {
status: 'success';
message: 'SSH key rotated. Old key valid for 24 hours.';
newKeyFingerprint: string;
}
// Revoke SSH access
POST /api/v1/tenant/infrastructure/ssh-credentials/revoke
Response: {
status: 'success';
message: 'SSH access revoked immediately.';
}
// Regenerate SSH key
POST /api/v1/tenant/infrastructure/ssh-credentials/regenerate
Response: {
status: 'success';
message: 'New SSH key generated. Download private key.';
newKeyFingerprint: string;
}
Admin Endpoints:
// Get Vault health status
GET /api/v1/admin/vault/health
Response: {
sealed: boolean;
activeNode: string;
storageStatus: 'healthy' | 'degraded' | 'offline';
lastBackup: string;
}
// List all tenant secrets
GET /api/v1/admin/secrets/tenants
Response: TenantSecretsSummary[]
// Get tenant secret details
GET /api/v1/admin/secrets/tenant/{tenant_id}
Response: {
sshKeys: { admin: KeyStatus; tenant: KeyStatus };
smtpCredentials: CredentialStatus;
apiKeys: ApiKeyStatus[];
}
// Trigger bulk SSH key rotation
POST /api/v1/admin/secrets/rotate-all
Body: { secretType: 'ssh' | 'smtp' | 'dkim' }
Response: {
status: 'success';
rotatedCount: number;
failedCount: number;
}
Access Control
Vault Policies:
# Tenant read-only access to own SSH keys
path "vps//tenant_ssh/*" {
capabilities = ["read"]
}
# Admin full access to all SSH keys
path "vps/*/admin_ssh/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "vps/*/tenant_ssh/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Automation service update access for rotation
path "vps/*/admin_ssh/*" {
capabilities = ["read", "update"]
}
path "vps/*/tenant_ssh/*" {
capabilities = ["read", "update"]
}
Security Considerations
Threat Mitigation
-
VPS Compromise: SSH keys not stored on VPS; can abandon and reprovision
-
Credential Theft: Private key download logged; one-time download only
-
Unauthorized Access: Vault access control enforces tenant isolation
-
Key Exposure: Automated rotation limits exposure window to 90 days
-
Insider Threats: Audit trail tracks all SSH key access
Best Practices
-
Store Private Keys Securely: Use password manager or encrypted storage
-
Rotate Keys Regularly: Donβt disable automated rotation
-
Monitor Audit Logs: Review SSH key access logs monthly
-
Revoke Compromised Keys: Immediately revoke if key is exposed
-
Use Strong Passphrases: Encrypt private key with passphrase (optional)
Compliance
SOC 2 Type II
-
Security: Access control, encryption, audit logging
-
Availability: High availability Vault cluster, disaster recovery
-
Confidentiality: Encryption at rest and in transit
ISO 27001
-
A.9 Access Control: Role-based access control
-
A.10 Cryptography: RSA 4096-bit encryption
-
A.12 Operations Security: Automated rotation, backup
GDPR
-
Article 32 - Security of Processing: Encryption, access control
-
Article 33 - Breach Notification: Audit trail, monitoring
Roadmap
MVP (Q1 2026)
-
Vault integration for SSH key storage
-
Dual SSH key system (admin + tenant)
-
Tenant SSH key download UI
-
Automated 90-day rotation
-
Audit logging for all SSH key operations
-
Connection instructions in UI
Post-MVP (Q2 2026)
-
SSH key passphrase encryption
-
Multi-factor authentication for key download
-
SSH session recording (audit trail)
-
Custom rotation policies per tenant
-
SSH key usage analytics
-
Automated key revocation on suspicious activity
Future (Q3 2026+)
-
SSH certificate authority (short-lived certificates)
-
Just-in-time SSH access (temporary keys)
-
SSH bastion host integration
-
Hardware security module (HSM) integration
-
FIDO2/WebAuthn for SSH authentication
Related Documentation
Route Specifications
-
Infrastructure SSH Access Routes - Complete SSH UI routes
-
Settings Routes - General settings navigation
-
Admin Routes - Admin secrets management panel
Feature Documentation
-
Vault API Keys - Tenant API key system
-
Vault SMTP Credentials - SMTP credentials storage
-
Vault Disaster Recovery - Backup and recovery
-
Email Infrastructure Setup - Infrastructure provisioning
-
Hostwind Management - VPS management
API Documentation
-
Platform API - Platform-level endpoints
-
Hostwinds API - VPS provisioning API
-
API Reference - Complete API documentation
Architecture & Security
-
Vault Integration Architecture - Comprehensive Vault architecture
-
Multi-Tenant Architecture - Tenant isolation
-
Enterprise Security - Security features
-
Security Monitoring - Monitoring and alerting
Planning & Review
-
Integrations Review - Integration completeness review
-
Infrastructure Management Roadmap - Infrastructure features roadmap
-
Technical Roadmap - Overall technical roadmap
Implementation Tasks
-
Task 11.4 - VPS SSH Key Management - SSH key implementation
-
Task 11.3 - Vault Integration Architecture - Architecture documentation
-
Epic 5: Infrastructure Management - Internal task reference for infrastructure tasks
External References
-
HashiCorp Vault Documentation - Official Vault docs
-
SSH Best Practices - SSH security guide
-
OpenSSH Documentation - SSH protocol reference
Last Updated: November 26, 2025 Feature Status: BACKLOG Priority: HIGH (MVP dependency) Estimated Effort: Large (10-15 days)
Vault SSH Key Management is a foundational security feature that enables secure VPS access and rapid disaster recovery. This feature must be implemented before infrastructure provisioning can be considered production-ready.