SSH Key Sync Security Boundary
Related Issues: #2182, #2328
Security Guarantee
Open ACE never propagates root private keys to workspace users.
When secure SSH sync is unavailable or fails, the system:
- Skips all file sync (it never falls back to the legacy sync logic)
- Writes a structured security log to
/var/log/openace/ssh-sync-failure.json - Creates a deployment alert file
/var/log/openace/ssh-sync-failure.warning - Returns a non-zero exit status to signal failure
Under no circumstances does the system fall back to an implementation that copies root private keys. This is the core of the fail-closed security principle.
Overview
Open ACE implements a secure SSH key synchronization mechanism that prevents private keys of the platform control plane from being propagated to workspace users.
Security Boundary
┌─────────────────────────────────────────────────────────────┐
│ Platform Layer (root) │
│ /root/.ssh │
│ ├── id_rsa (sync denied) │
│ ├── id_ed25519 (sync denied) │
│ ├── *.pem, *.key (sync denied) │
│ ├── known_hosts (sync allowed) │
└── allowed_keys/*.pub (allowed only when explicitly enabled) │
├───────────────────────────────────────────── ────────────────┤
│ User/Tenant Layer (per-user) │
│ /home/<user>/.ssh │
│ ├── known_hosts (synced from platform) │
│ ├── id_rsa (user-configured, not synced from root) │
└── deploy_key_<project> (per-project or explicitly mounted)│
└─────────────────────────────────────────────────────────────┘
Core Principles
1. Default Deny
- By default, no files are synced to a user's
~/.ssh - Only files explicitly listed in the allowlist may be synced
- Files in the denylist can never be synced, even if configured to be
2. Allowlist Mechanism
Safe files allowed to sync by default:
known_hosts- known hosts listknown_hosts.old- known_hosts backupknown_hosts.old.*- historical known_hosts backups
Extended allowlist (requires security review):
- Company public key files (
*.pub) - SSH config snippets that have passed a security review
3. Denylist
Files that are absolutely forbidden from syncing:
Private key files:
id_rsa,id_dsa,id_ecdsa,id_ed25519id_*(all private key patterns)*_rsa,*_dsa,*_ecdsa,*_ed25519
Certificate/key files:
*.pem,*.key,*.p12,*.pfx
Socket files:
*.socket,agent.*,control_*
Token files:
token_*,*.token
SSH config files:
config,config_*
File types:
- Symbolic links (symlink)
- Hard links
- Unix sockets
- Device files
- Named pipes (FIFO)
Security Mechanisms
1. TOCTOU Protection
File descriptor operations are used to prevent race conditions:
- Use
os.open()with theO_NOFOLLOWflag - Use
fstat()instead ofstat() - Read data from the file descriptor
2. Hard-link Detection
Detect st_nlink > 1 to guard against hard-link attacks.
3. Content Detection
Check whether file content contains private key markers:
- RSA private key format (markers starting with
-----BEGIN RSA...) - OpenSSH private key format (markers starting with
-----BEGIN OPENSSH...) - Other private key formats
Note: Ellipses are used above to avoid complete markers, so that this document itself does not trigger security detection.
4. Path Validation
Validate the canonical path:
- The source path must be under
/root/.ssh - The destination path must be under
/home/<user>/.ssh - Prevents path escape attacks
5. Owner Validation
Ensure synced files have the correct owner:
- Verify the user exists
- Verify the UID/GID are valid
- Set the correct owner/group
Upgrade Handling
Legacy Private Key Detection
When upgrading from an older version, the system detects:
- Private keys with file permission 600
- File names matching the
id_*pattern - Content identical to the file with the same name in
/root/.ssh(content fingerprint)
Handling Policies
warn: warn only, do not deletebackup: back up to~/.ssh/legacy_backup_YYYYMMDD_HHMMSS/, then deletedelete: delete directly (only files whose content fingerprint matches)
Secure Alternatives
Option A: Per-User Deploy Key (recommended)
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 deploy keys of the Git repository.
Option B: Explicit Mount for a Specific User
Configure in Docker Compose:
volumes:
- ./secrets/user1/.ssh:/home/user1/.ssh:ro
Option C: SSH Certificate Broker (enterprise grade)
Deploy a standalone SSH broker service that issues short-lived certificates.
Audit Log
All sync operations are recorded in: /var/log/openace/ssh-sync.log
Log format:
[TIMESTAMP] [LEVEL] [USER] MESSAGE
Example:
[2026-01-15T10:30:00] [INFO] [alice] SYNC_SUCCESS file=known_hosts
[2026-01-15T10:30:00] [WARN] [alice] SYNC_DENIED file=id_rsa reason=denylist
[2026-01-15T10:30:00] [ERROR] [alice] LEGACY_KEY_DETECTED file=/home/alice/.ssh/id_rsa
Environment Variables
| Variable | Description | Default |
|---|---|---|
OPENACE_SSH_UPGRADE_ACTION | Upgrade handling policy | backup |
OPENACE_SSH_UPGRADE_REQUIRE_CONFIRM | Whether manual confirmation is required | false |
OPENACE_SSH_DETECT_ENCODED_KEYS | Whether to detect encoded private keys | false |
Best Practices
-
Do not put private keys into
/root/.ssh- Use per-user deploy keys
- Or use explicit mounts
-
Review audit logs regularly
- Check SYNC_DENIED records
- Check LEGACY_KEY_DETECTED alerts
-
Back up data before upgrading
- Back up user
~/.sshdirectories - Check upgrade alerts
- Back up user
-
Use secure alternatives
- Avoid depending on root private keys
- Configure dedicated credentials for each user/project
Related Documents
Changelog
- 2026-01-15: Initial version (Issue #2182)
- Implemented the secure SSH key sync mechanism
- Blocked private key sync by default
- Provided the per-user deploy key solution