Automatically synchronize SSH keys from Azure Key Vault to your VMs, eliminating manual key management and connection failures.
Auto-sync keys is an azlin feature that automatically ensures your VM has the correct SSH public key from Key Vault before every connection attempt. When you run azlin connect, azlin:
- Retrieves the VM-specific SSH key from Azure Key Vault (the source of truth)
- Checks if the public key exists in the VM's
~/.ssh/authorized_keysfile - Appends the key to the VM if missing
- Proceeds with the SSH connection
This eliminates the common problem where Key Vault has the correct key, but the VM has a different or outdated key, causing connection failures.
Auto-sync keys solves several real-world problems:
You store your SSH keys in Key Vault, but somehow the VM has a different key in its authorized_keys file. Your connection fails with "Permission denied (publickey)".
Without auto-sync: You manually SSH into the VM (if you can) and append the Key Vault key to authorized_keys.
With auto-sync: azlin automatically appends the Key Vault key before connecting. Connection succeeds.
You create a new VM with one key, then store a different key in Key Vault. Now the keys don't match.
Without auto-sync: Connection fails. You debug for 30 minutes before realizing the key mismatch.
With auto-sync: azlin syncs the Key Vault key automatically. Connection works on first try.
Your security team rotates SSH keys regularly. You update Key Vault, but forget to update the VM.
Without auto-sync: All connections fail until you manually update each VM.
With auto-sync: azlin keeps VMs synchronized automatically.
When you run azlin connect my-vm, here's what happens behind the scenes:
1. Fetch SSH key from Key Vault
└─▶ Query: az keyvault secret show --name azlin-my-vm-key
2. Check if key exists on VM
└─▶ Run: grep -Fq "<public-key>" ~/.ssh/authorized_keys
3. If key missing: Append it
└─▶ Run: echo "<public-key>" >> ~/.ssh/authorized_keys
4. Connect via SSH
└─▶ ssh -i ~/.ssh/azlin_key azureuser@my-vm
azlin uses two methods to sync keys, automatically choosing the best one:
The default method uses Azure's az vm run-command API to append the key:
az vm run-command invoke \
--name my-vm \
--resource-group my-rg \
--command-id RunShellScript \
--scripts "echo '<public-key>' >> ~/.ssh/authorized_keys"Advantages:
- Works without an existing SSH connection
- Reliable across network configurations
- Handles first-boot scenarios
Requirements:
- VM Agent must be running (enabled by default on Azure VMs)
- You need VM Contributor permissions
Performance: Adds 2-3 seconds to first connection only
If VM Agent is unavailable, azlin falls back to SSH:
ssh azureuser@my-vm "echo '<public-key>' >> ~/.ssh/authorized_keys"When used:
- VM Agent not responding
- VM run-command permissions denied
- SSH connection already established
Performance: Less than 1 second
Auto-sync keys is designed with security first:
-
Append-Only: Keys are always appended (
>>operator), never replaced (>operator). This preserves any existing keys on the VM. -
No Private Key Exposure: Only the public key is transmitted to the VM. Your private key never leaves your local machine.
-
Audit Logging: Every sync operation is logged to
~/.azlin/logs/key_sync_audit.logwith timestamp, VM name, and user. -
Idempotent: Running the sync multiple times is safe. If the key already exists, no changes are made.
-
Fail-Safe: If sync fails (VM not running, timeout, permissions), azlin logs a warning but continues with the connection attempt. The feature never blocks your work.
Connect to a VM with auto-sync enabled (default):
azlin connect my-vmOutput:
Fetching SSH key from Key Vault... ✓
Auto-syncing key to VM... ✓
SSH key synchronized to VM
Connecting to my-vm...
Connected!
If the key was already present:
azlin connect my-vmOutput:
Fetching SSH key from Key Vault... ✓
Checking key on VM... ✓
SSH key already present on VM
Connecting to my-vm...
Connected!
Enable debug logging to see detailed sync information:
azlin --debug connect my-vmOutput:
DEBUG: Loading configuration from ~/.azlin/config.toml
DEBUG: Feature auto_sync_keys=true
INFO: Fetching SSH key from Key Vault...
DEBUG: Retrieved key from vault: azlin-my-vm-key
INFO: Auto-syncing SSH key to VM...
DEBUG: Using sync method: run-command
DEBUG: Checking if key exists on VM...
DEBUG: Key not found in authorized_keys
INFO: Appending key to VM's authorized_keys...
DEBUG: Running az vm run-command invoke --name my-vm ...
INFO: SSH key synchronized to VM (2.4 seconds)
INFO: Connecting to my-vm via SSH...
Connected!
You updated the Key Vault key and now connect:
azlin connect my-vmOutput:
Fetching SSH key from Key Vault... ✓
Auto-syncing key to VM... ✓
SSH key synchronized to VM
Connecting to my-vm...
Connected!
Check the audit log to verify:
cat ~/.azlin/logs/key_sync_audit.log | tail -1Output:
{
"timestamp": "2025-11-26T14:32:10Z",
"vm_name": "my-vm",
"resource_group": "my-rg",
"synced": true,
"method": "run-command",
"user": "username"
}If you need to disable auto-sync for a specific connection:
azlin connect my-vm --no-auto-sync-keysOutput:
Fetching SSH key from Key Vault... ✓
Skipping auto-sync (disabled via --no-auto-sync-keys)
Connecting to my-vm...
Connected!
Force the SSH fallback method instead of VM run-command:
azlin connect my-vm --sync-method=sshOutput:
Fetching SSH key from Key Vault... ✓
Auto-syncing key via SSH... ✓
SSH key synchronized to VM
Connecting to my-vm...
Connected!
Enable auto-sync (default):
azlin config set ssh.auto_sync_keys trueDisable auto-sync globally:
azlin config set ssh.auto_sync_keys falseView current setting:
azlin config get ssh.auto_sync_keysChange the sync operation timeout (default: 30 seconds):
azlin config set ssh.sync_timeout 60Choose the sync method explicitly:
# Automatic (default - tries run-command, falls back to SSH)
azlin config set ssh.sync_method auto
# Always use run-command (fail if unavailable)
azlin config set ssh.sync_method run-command
# Always use SSH
azlin config set ssh.sync_method ssh
# Skip sync entirely
azlin config set ssh.sync_method skipEdit ~/.azlin/config.toml directly:
[ssh]
auto_sync_keys = true # Enable auto-sync
sync_timeout = 30 # Timeout in seconds
sync_method = "auto" # auto, run-command, ssh, skip| Flag | Description | Example |
|---|---|---|
--no-auto-sync-keys |
Disable auto-sync for this connection | azlin connect vm --no-auto-sync-keys |
--sync-method=METHOD |
Force specific sync method | azlin connect vm --sync-method=ssh |
--sync-timeout=SEC |
Override sync timeout | azlin connect vm --sync-timeout=60 |
--dry-run |
Check only, make no changes | azlin connect vm --dry-run |
Error:
Warning: Failed to sync SSH key to VM (VM Agent not responding)
Connection may fail if VM has different key.
Attempting connection...
Cause: The Azure VM Agent is not running or not responding.
Solutions:
-
Check VM Agent status:
az vm get-instance-view \ --name my-vm \ --resource-group my-rg \ --query "instanceView.vmAgent.statuses" -
Wait for VM to finish booting (VM Agent starts automatically):
# Wait 2 minutes for first boot, then retry sleep 120 azlin connect my-vm -
Force SSH sync method:
azlin connect my-vm --sync-method=ssh
-
Disable auto-sync and manually add key:
azlin connect my-vm --no-auto-sync-keys # Then manually append key on VM: echo "<public-key>" >> ~/.ssh/authorized_keys
Error:
Error: Failed to sync SSH key to VM (Permission denied)
You need 'Virtual Machine Contributor' role for VM run-command.
Cause: Your Azure account lacks permissions to run commands on the VM.
Solutions:
-
Request VM Contributor role:
# Ask your Azure admin to grant this role: az role assignment create \ --assignee your-email@company.com \ --role "Virtual Machine Contributor" \ --scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Compute/virtualMachines/<vm>"
-
Use SSH fallback (requires existing SSH access):
azlin connect my-vm --sync-method=ssh
-
Disable auto-sync:
azlin config set ssh.auto_sync_keys false
Error:
Warning: SSH key sync operation timed out (30 seconds)
Connection may fail if VM has different key.
Attempting connection...
Cause: Azure VM run-command took longer than expected (network latency, VM under load).
Solutions:
-
Increase timeout:
azlin connect my-vm --sync-timeout=60
-
Retry the connection:
azlin connect my-vm # Sync is idempotent - safe to retry -
Check Azure service health:
az monitor service-health list-events
Error:
SSH key synchronized to VM ✓
Connecting to my-vm...
Permission denied (publickey)
Cause: The sync succeeded, but there's a different issue (wrong username, VM firewall, SSH daemon config).
Solutions:
-
Verify the key was actually added:
az vm run-command invoke \ --name my-vm \ --resource-group my-rg \ --command-id RunShellScript \ --scripts "cat ~/.ssh/authorized_keys" -
Check SSH username:
# Default is 'azureuser' azlin connect my-vm --user azureuser -
Check VM firewall rules:
az vm show \ --name my-vm \ --resource-group my-rg \ --query "networkProfile.networkInterfaces[0].id" -o tsv -
Examine SSH daemon logs on VM:
az vm run-command invoke \ --name my-vm \ --resource-group my-rg \ --command-id RunShellScript \ --scripts "sudo tail -50 /var/log/auth.log | grep sshd"
Problem: You notice duplicate keys in authorized_keys after multiple connections.
Cause: This should not happen (sync is idempotent), but if it does:
Solutions:
-
Check the audit log to see if syncs are happening repeatedly:
cat ~/.azlin/logs/key_sync_audit.log | grep my-vm
-
File a bug report:
# Include this information: azlin --version cat ~/.azlin/config.toml cat ~/.azlin/logs/key_sync_audit.log
-
Manually clean up duplicates on VM:
az vm run-command invoke \ --name my-vm \ --resource-group my-rg \ --command-id RunShellScript \ --scripts "sort -u ~/.ssh/authorized_keys -o ~/.ssh/authorized_keys"
No. Auto-sync always uses the append operator (>>) and never the replace operator (>). All existing keys in your authorized_keys file are preserved.
They are safe. Auto-sync adds the Key Vault key without touching existing keys. You can have multiple keys in authorized_keys (Key Vault key, personal keys, CI/CD keys, etc.).
Yes. When connecting through Bastion, azlin still syncs the key to the VM using Azure VM run-command, which works regardless of network configuration.
Not currently. The setting applies globally or per-connection (via --no-auto-sync-keys flag). This is a planned feature for future releases.
For VM run-command method:
Virtual Machine Contributorrole on the VMReaderrole on the resource group
For SSH fallback method:
- Existing SSH access to the VM
No. Auto-sync is designed for Linux VMs with OpenSSH. Windows VMs use a different authentication mechanism.
- First connection: 2-3 seconds (one-time sync)
- Subsequent connections: ~100ms (key check only, no sync needed)
~/.azlin/logs/key_sync_audit.log
Each entry logs: timestamp, VM name, resource group, sync result, method, and username.
Not directly, but you can use dry-run mode to verify:
azlin connect my-vm --dry-runOr manually trigger the sync operation (requires direct access to azlin Python API).
If azlin cannot fetch the key from Key Vault, auto-sync is skipped and the connection proceeds with your local key file. You'll see:
Warning: Could not fetch key from Key Vault (service unavailable)
Skipping auto-sync
Connecting with local key...
Analyze sync patterns:
# Count syncs per VM
cat ~/.azlin/logs/key_sync_audit.log | \
jq -r '.vm_name' | sort | uniq -c
# Find failed syncs
cat ~/.azlin/logs/key_sync_audit.log | \
jq 'select(.synced == false)'
# Average sync duration
cat ~/.azlin/logs/key_sync_audit.log | \
jq -r '.duration_ms' | awk '{sum+=$1; count++} END {print sum/count}'For advanced use cases, you can extend the sync behavior by editing the generated bash script (advanced users only):
-
Export sync script template:
azlin config get-sync-script > custom_sync.sh -
Edit the script to add custom logic (e.g., SELinux contexts, custom permissions)
-
Use the custom script:
azlin connect my-vm --sync-script=custom_sync.sh
Note: Custom sync scripts are not officially supported. Use at your own risk.
For environments with many VMs, reduce sync overhead:
-
Disable sync for VMs you manage manually:
azlin connect managed-vm --no-auto-sync-keys
-
Use SSH method for faster syncs (if SSH access available):
azlin config set ssh.sync_method ssh
- Auto-Detect Resource Groups - Automatic resource group discovery
- Configuration Reference - Complete configuration options
- Troubleshooting Connection Issues - Comprehensive troubleshooting guide
- SSH Key Management - Managing SSH keys in Key Vault
Found a bug or have a feature request? Open an issue on GitHub.
Have questions? Start a discussion.