jenkinsci / jenkinsci/google-compute-engine-plugin
Support modern SSH key/signature algorithms (rsa-sha2, Ed25519) for agent connections
- Dominant language
- Java
- Stars
- 58
- Forks
- 97
- PR merge metrics
- No merged PRs in 30d
Description
> **Edit (correction):** an earlier version of this issue claimed the current plugin fails to
> connect to stock modern-OpenSSH agents. Hands-on testing **disproves that for the latest release**
> — `rsa-sha2` already works end-to-end on 4.3.17.1. The body below is corrected and the scope is
> narrowed accordingly. Details + evidence in the "Verification" section.
## Summary
Historically the plugin's SSH agent launcher negotiated only `ssh-rsa` (RSA + SHA-1), which breaks
against OpenSSH 8.8+ (where `ssh-rsa` is disabled by default). **That gap is already closed for
`rsa-sha2` in current releases** — the bundled `trilead-api` negotiates `rsa-sha2-256/512` for both
host-key verification and client public-key auth. The remaining, genuinely-missing capability is
**Ed25519 (and modern key types) for the plugin's auto-generated client key**, plus making the key
type configurable. This issue proposes adding that, and would value maintainer input on scope before
a PR.
## What already works (verified, latest release)
`rsa-sha2` requires no new code on a current plugin. The SSH client (`trilead-api`, currently
`build-217-jenkins-371` on `develop`; `build-217-jenkins-247` in release 4.3.17.1) registers
`rsa-sha2-256`/`rsa-sha2-512` ahead of `ssh-rsa` and `AuthenticationManager` selects from that list,
so the existing RSA-2048 key authenticates with a SHA-2 signature.
The capability first shipped in **4.3.5** (trilead-api 1.0.13). Releases **4.3.0–4.3.4** (trilead-api
1.0.3) are `ssh-rsa`-only.
## What's actually missing
1. **Ed25519 client keys.** `ssh/SshKeysHelper.generate()` hardcodes JSch `KeyPair.RSA, 2048` and an
`"ssh-rsa "` public-key prefix. There is no way to provision an `ssh-ed25519` (or ECDSA) auto-key.
The bundled mwiede JSch can already generate these; trilead can authenticate Ed25519 (it bundles
`ED25519KeyAlgorithm`, with `eddsa` present transitively via `trilead-api`).
2. **No key-type configurability.** `SshConfiguration` only exposes `customPrivateKeyCredentialsId`;
there's no selector for the generated key type.
3. **(To confirm) host-key guest-attribute naming.** `ComputeEngineComputerLauncher.verifyServerHostKey()`
looks up the GCE guest attribute `hostkeys/` by `serverHostKeyAlgorithm.toLowerCase()`. With
`rsa-sha2-*` negotiated, the lookup for that name won't match the `ssh-rsa`-named attribute. This
path is currently **fail-open** (returns `true` on miss), so it does not break connections, but it
silently skips host-key verification — worth tightening alongside this work.
## Verification
Isolated reproduction of the plugin's SSH bring-up (`connectToSsh()` → `Connection.connect()` then
`authenticateWithPublicKey(user, key, "")`), using the plugin's **exact bundled trilead jars** and an
RSA-2048 client key, against a **real `sshd`**:
| Plugin (trilead) | Server | Host-key | Client auth | Result |
|---|---|---|---|---|
| 4.3.0 / jenkins-16 (ssh-rsa only) | stock Debian 12 (OpenSSH 9.2), no override | ssh-ed25519 | **rejected** (signs ssh-rsa) | FAIL |
| 4.3.0 / jenkins-16 | Debian 12 + `PubkeyAcceptedAlgorithms +ssh-rsa` | ssh-ed25519 | ssh-rsa accepted | PASS |
| **4.3.17.1 / jenkins-247 (latest)** | **stock Debian 12 (OpenSSH 9.2), no override** | ssh-ed25519 | **rsa-sha2** | **PASS** |
| **4.3.17.1 / jenkins-247** | **stock Debian 13 (OpenSSH 10.0), no override** | ssh-ed25519 | **rsa-sha2** | **PASS** |
| 4.3.17.1 / jenkins-247 | ssh-rsa force-disabled both legs, RSA-only host key | rsa-sha2-256 | rsa-sha2 | PASS |
Takeaways: on the latest release, `rsa-sha2` host-key + client-auth already work against stock Debian
12/13 with `ssh-rsa` disabled; the only legacy-`ssh-rsa` failures are on pre-4.3.5 plugins, on the
**client-auth** leg.
## Proposed scope
**Add Ed25519 (and optionally ECDSA) as a selectable type for the auto-generated client key**, default
unchanged (RSA):
- Thread a key-type param through `GoogleKeyPair.generate()` / `SshKeysHelper.generate()` (use JSch
`KeyPairEd25519`; emit the correct `ssh-ed25519` public-key prefix).
- Add a key-type selector to `SshConfiguration` (`config.jelly` + `help-*.html` + `doCheck`), **default
RSA**. Migration follows the `preemptible` → `provisioningType` precedent (`readResolve()` +
JCasC-compat setter); old serialized configs keep producing RSA.
- Preserve the SECURITY-2045 invariant (private key stays `hudson.util.Secret`).
- Tighten `verifyServerHostKey` so `rsa-sha2-*` maps to the `ssh-rsa` guest-attribute name (stop the
silent fail-open for RSA host keys).
A separate, optional hardening: a regression IT that provisions a stock Ubuntu 22.04 / Debian 12 agent
(no `sshd_config` overrides) and asserts the handshake succeeds — to lock in the `rsa-sha2` behavior
that already works.
## Backward compatibility
Default behavior unchanged: RSA auto-key, existing negotiation. The new key-type field is opt-in and
defaults to RSA, with serialized-config migration.
## Testing plan
- Unit: extend `SshKeysHelper`/`GoogleKeyPairTest` (keep the SECURITY-2045 plaintext-never-persisted
assertion); update `InstanceConfigurationTest#testConfigRoundtrip` and `ConfigAsCodeTest` round-trip
+ fixture YAML for the new field.
- Integration: a `*IT.java` provisioning a real GCE VM that authenticates with an Ed25519 auto-key;
plus the stock-image `rsa-sha2` regression IT above.
## Open questions for maintainers
1. Is "Ed25519 client key + key-type selector" the scope you'd want, with RSA staying the default?
2. Worth adding the stock-image `rsa-sha2` regression IT even though no production code changes for it?
3. Should `verifyServerHostKey`'s `rsa-sha2-*` → `ssh-rsa` naming fix land in this issue or separately?
4. Given #465's history, comfortable relying on `eddsa` via `trilead-api` for Ed25519?
Happy to implement whichever scope you prefer — would appreciate a steer before I open the PR.
Contributor guide
Research direction
Start with ssh/SshKeysHelper.generate(), GoogleKeyPair.generate(), and SshConfiguration, then review config.jelly, help-*.html, and doCheck for the proposed key-type selector. Read the existing SshKeysHelper/GoogleKeyPair, InstanceConfigurationTest, and ConfigAsCodeTest coverage, including the SECURITY-2045 assertion. Done should include the maintainer-approved scope, Ed25519 coverage, RSA-default migration behavior, and any agreed host-key or integration tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- google-cloud, java
- Domain
- cloud, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 45/100