Tutorial: Setup Bastion
Tutorial: Setup Bastion Integration
Section titled “Tutorial: Setup Bastion Integration”Learn how to integrate SSH-KLM with bastion hosts for secure jump-server access.
Prerequisites
Section titled “Prerequisites”- SSH-KLM instance running
- Bastion host accessible
- Admin access to both systems
Architecture Overview
Section titled “Architecture Overview”┌──────────┐ ┌─────────┐ ┌─────────────┐│ User │──────│ Bastion │──────│ Target Host │└──────────┘ └─────────┘ └─────────────┘ │ │ │ └────────────┬────┴──────────────────┘ │ ┌──────┴──────┐ │ SSH-KLM │ └─────────────┘Step 1: Add Bastion Host to SSH-KLM
Section titled “Step 1: Add Bastion Host to SSH-KLM”const { QcClient } = require('@qcecuring/ssh-sdk');
const client = new QcClient({ apiKey: process.env.SSHKLM_API_KEY});
// Add bastion as managed hostconst bastion = await client.ssh.addHost({ hostname: 'bastion.example.com', port: 22, labels: { type: 'bastion', environment: 'production' }});
console.log(`Bastion added: ${bastion.id}`);Step 2: Install Agent on Bastion
Section titled “Step 2: Install Agent on Bastion”# On the bastion hostcurl -fsSL https://get.qcecuring.com/ssh-agent | sudo bash -s -- \ --server https://ssh-klm.example.com \ --token YOUR_REGISTRATION_TOKEN
# Enable bastion modesudo ssh-klm-agent configure --mode bastionStep 3: Configure Bastion Integration
Section titled “Step 3: Configure Bastion Integration”In SSH-KLM UI or via API:
const integration = await client.ssh.createBastionIntegration({ name: 'Production Bastion', bastionHostId: bastion.id, targetHosts: { labels: { environment: 'production' } }, settings: { sessionRecording: true, sessionTimeout: 3600, // 1 hour allowedUsers: ['admin', 'deploy'], requireApproval: false }});Step 4: Configure SSH ProxyJump
Section titled “Step 4: Configure SSH ProxyJump”Update user SSH config for automatic bastion routing:
Host bastion HostName bastion.example.com User admin IdentityFile ~/.ssh/id_ed25519
Host *.internal.example.com ProxyJump bastion User adminStep 5: Enable Certificate-Based Auth
Section titled “Step 5: Enable Certificate-Based Auth”For enhanced security, use SSH certificates:
// Configure CA for bastionawait client.ssh.configureBastionCA({ bastionId: bastion.id, caSettings: { enabled: true, maxCertTTL: 3600, // 1 hour max defaultTTL: 300, // 5 minutes default allowedPrincipals: ['admin', 'deploy', 'readonly'] }});Step 6: Request Access via Bastion
Section titled “Step 6: Request Access via Bastion”Users request short-lived certificates:
// Request access through bastionconst access = await client.ssh.requestBastionAccess({ bastionId: bastion.id, targetHost: 'server01.internal.example.com', username: 'deploy', ttl: 300, reason: 'Deploy v2.0.0'});
// Save certificatefs.writeFileSync('~/.ssh/bastion-cert', access.certificate);fs.writeFileSync('~/.ssh/bastion-key', access.privateKey);
console.log(`Access granted until: ${access.expiresAt}`);Step 7: Connect Through Bastion
Section titled “Step 7: Connect Through Bastion”# SSH with certificate (auto-routed through bastion)ssh -i ~/.ssh/bastion-key \ -o CertificateFile=~/.ssh/bastion-cert \ deploy@server01.internal.example.comSession Recording
Section titled “Session Recording”View recorded sessions:
const sessions = await client.ssh.listBastionSessions({ bastionId: bastion.id, startDate: '2026-01-01', endDate: '2026-01-07'});
for (const session of sessions) { console.log(`${session.user} → ${session.targetHost}`); console.log(` Duration: ${session.duration}s`); console.log(` Commands: ${session.commandCount}`);}Approval Workflows
Section titled “Approval Workflows”Enable approval for sensitive hosts:
await client.ssh.updateBastionIntegration({ integrationId: integration.id, settings: { requireApproval: true, approvers: ['security-team@example.com'], approvalTimeout: 3600 // 1 hour to approve }});Monitoring Bastion Access
Section titled “Monitoring Bastion Access”// Real-time connection monitoringconst connections = await client.ssh.listActiveConnections({ bastionId: bastion.id});
for (const conn of connections) { console.log(`${conn.user} connected to ${conn.targetHost}`); console.log(` Started: ${conn.startedAt}`); console.log(` Source IP: ${conn.sourceIp}`);}