Skip to content

Tutorial: Rotate Keys

Learn how to rotate SSH keys safely and efficiently.

  • Hosts added to SSH-KLM
  • Agent installed on target hosts
  • Keys discovered via scan

Key rotation replaces existing SSH keys with new, cryptographically secure ones while:

  • Maintaining authorized access
  • Updating all trust relationships
  • Keeping audit trail
const { QcClient } = require('@qcecuring/ssh-sdk');
const client = new QcClient({
apiKey: process.env.SSHKLM_API_KEY
});
// Find high-risk keys
const riskyKeys = await client.ssh.listKeys({
filter: {
riskScoreMin: 50,
// Or by algorithm
algorithm: ['dsa', 'rsa-1024', 'rsa-2048'],
// Or by age
ageGreaterThan: '365d'
}
});
console.log(`Found ${riskyKeys.length} keys to rotate`);

Always test first:

const dryRun = await client.ssh.rotateKey({
keyId: 'key_abc123',
algorithm: 'ed25519',
dryRun: true
});
console.log('Dry run results:');
console.log(`- Hosts affected: ${dryRun.hostsAffected}`);
console.log(`- Users affected: ${dryRun.usersAffected}`);
console.log(`- Trust relationships: ${dryRun.trustRelationships}`);
const rotation = await client.ssh.rotateKey({
keyId: 'key_abc123',
algorithm: 'ed25519',
reason: 'Security policy compliance',
notifyUsers: true
});
console.log(`Rotation ID: ${rotation.id}`);
console.log(`Status: ${rotation.status}`);
// Poll for completion
async function waitForRotation(rotationId) {
while (true) {
const status = await client.ssh.getRotationStatus(rotationId);
console.log(`Status: ${status.state} (${status.progress}%)`);
if (status.state === 'completed') {
console.log('Rotation completed successfully!');
return status;
}
if (status.state === 'failed') {
console.error('Rotation failed:', status.error);
throw new Error(status.error);
}
await sleep(5000); // Wait 5 seconds
}
}
await waitForRotation(rotation.id);

Rotate multiple keys matching criteria:

const bulkRotation = await client.ssh.bulkRotate({
filter: {
algorithm: ['dsa', 'rsa-1024'],
labels: { environment: 'staging' }
},
newAlgorithm: 'ed25519',
batchSize: 10, // Keys per batch
delayBetweenBatches: 30000, // 30 seconds
dryRun: false
});
console.log(`Rotating ${bulkRotation.totalKeys} keys`);
console.log(`Batch ID: ${bulkRotation.batchId}`);
// Check key was rotated
const key = await client.ssh.getKey({ keyId: 'key_abc123' });
console.log(`Algorithm: ${key.algorithm}`);
console.log(`Created: ${key.createdAt}`);
console.log(`Fingerprint: ${key.fingerprint}`);

Set up automatic rotation:

const policy = await client.ssh.createPolicy({
name: 'Production 90-day rotation',
type: 'rotation',
enabled: true,
rules: {
interval: '90d',
algorithm: 'ed25519',
hosts: {
labels: { environment: 'production' }
},
excludeUsers: ['root'],
notifyDays: [14, 7, 1] // Notify before rotation
}
});

If rotation causes issues:

// Rollback to previous key
await client.ssh.rollbackRotation({
rotationId: rotation.id,
reason: 'Application compatibility issue'
});
  1. Start with staging - Test on non-production first
  2. Use dry run - Always preview changes
  3. Batch rotations - Don’t rotate all at once
  4. Monitor closely - Watch for connectivity issues
  5. Have rollback plan - Know how to revert