Skip to content

feat: [#411] detect passphrase-protected SSH key and warn during create environment#421

Merged
josecelano merged 2 commits intotorrust:mainfrom
josecelano:411-ssh-key-passphrase-detection
Apr 7, 2026
Merged

feat: [#411] detect passphrase-protected SSH key and warn during create environment#421
josecelano merged 2 commits intotorrust:mainfrom
josecelano:411-ssh-key-passphrase-detection

Conversation

@josecelano
Copy link
Copy Markdown
Member

Summary

Closes #411

When a passphrase-protected SSH private key is configured in ssh_credentials, the deployer previously failed silently during provision with a misleading Permission denied (publickey,password) error. This PR adds an early non-blocking warning during create environment so users can make an informed decision before reaching provision.

Changes

Detection (src/adapters/ssh/key_inspector.rs — new module)

  • Moved passphrase detection out of credentials.rs into a dedicated key_inspector module (cleaner separation of concerns)
  • is_passphrase_protected(path: &Path) -> bool — best-effort heuristic:
    • Legacy PEM: checks for BEGIN ENCRYPTED PRIVATE KEY / Proc-Type: 4,ENCRYPTED header
    • OpenSSH format: base64-decodes the body and scans first 100 bytes for bcrypt KDF marker
  • Uses the base64 crate (now a direct dependency; was already transitive at v0.22.1) instead of an inline decoder
  • 4 unit tests covering: unencrypted key, passphrase-protected key, missing file, legacy PEM header

Warning (src/presentation/cli/views/progress/mod.rs, handler.rs)

  • Added ProgressReporter::warn() for advisory user-facing messages
  • CreateEnvironmentCommandController::execute() calls warn_if_ssh_key_passphrase_protected() after config load — emits a detailed warning with 3 resolution options but does not block environment creation

Test fixture

  • fixtures/testing_ed25519_encrypted — real ed25519 key protected with passphrase "password", used in unit tests

ADR

  • docs/decisions/ssh-key-passphrase-detection.md — documents the byte inspection approach and why ssh-keygen -y probe was rejected

Documentation

  • docs/user-guide/ssh-keys.md — new page covering SSH key requirements, 3 supported workflows, how to remove a passphrase, and security notes
  • docs/user-guide/providers/hetzner.md — added SSH Key Requirements section with warning callout
  • docs/user-guide/commands/create.md — added passphrase warning subsection in Troubleshooting
  • docs/user-guide/README.md — added SSH Keys subsection under Security with link

Testing

All pre-commit checks pass:

  • cargo machete
  • cargo run --bin linter all (clippy stable + nightly, rustfmt, cspell, shellcheck, markdownlint, yamllint, taplo) ✅
  • cargo test (417 tests) ✅
  • cargo doc
  • E2E infrastructure lifecycle tests ✅
  • E2E deployment workflow tests ✅

…ng create environment

- Add is_passphrase_protected() in new src/adapters/ssh/key_inspector.rs
- Detection uses byte inspection: bcrypt KDF scan for OpenSSH format,
  header check for legacy PEM (ENCRYPTED/Proc-Type: 4,ENCRYPTED)
- Use base64 crate (already transitive, now direct) instead of inline decoder
- Add ProgressReporter::warn() for advisory user-facing warnings
- Emit non-blocking warning in CreateEnvironmentCommandController::execute()
  when the configured SSH private key appears passphrase-protected
- Add encrypted ed25519 test fixture (fixtures/testing_ed25519_encrypted)
- Add ADR: docs/decisions/ssh-key-passphrase-detection.md
- Add user guide: docs/user-guide/ssh-keys.md
- Update docs/user-guide/providers/hetzner.md with SSH key requirements
- Update docs/user-guide/commands/create.md with passphrase warning note
- Update docs/user-guide/README.md with ssh-keys link

Closes torrust#411
@josecelano josecelano self-assigned this Apr 7, 2026
@josecelano
Copy link
Copy Markdown
Member Author

ACK e688a7c

@josecelano josecelano merged commit 0d362a9 into torrust:main Apr 7, 2026
20 checks passed
@josecelano josecelano deleted the 411-ssh-key-passphrase-detection branch April 7, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Passphrase-Protected SSH Key Silently Fails During Automated Deployment

1 participant