mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 20:31:30 +00:00
docs(ssh): operator playbook for InsecureIgnoreHostKey design choice
Closes Top-10 fix #7 of the 2026-05-02 deployment-target audit re-run (see cowork/deployment-target-audit-2026-05-02-rerun/ RESULTS.md). Pre-fix, the SSH connector's ssh.InsecureIgnoreHostKey() at internal/connector/target/ssh/ ssh.go (realSSHClient.Connect) had only an inline comment justifying the design choice. An acquirer's diligence engineer reading the connector cold pattern-matches "MITM hazard" without seeing the comment. This commit lands a doc-side operator playbook in docs/connectors.md SSH section covering: 1. Why the connector accepts any host key (operator-configured target infrastructure; mirrors network scanner's InsecureSkipVerify and F5's Insecure flag). 2. Threat model the choice accepts (passive eavesdropper on operator-controlled network; layered SSH-key auth limits blast radius). 3. Threat model the choice does NOT accept (public-internet ephemeral hosts, multi-tenant networks, strict MITM- resistance regulatory requirements). 4. Mitigations operators can layer (custom SSHClient via NewWithClient + golang.org/x/crypto/ssh/knownhosts; SSH certificate authentication via @cert-authority pinning; network segmentation; per-target key rotation). 5. When to NOT use the SSH connector (regulatory environments, dynamic IPs, multi-tenant networks). 6. V3-Pro forward path (built-in known_hosts management, tracked in WORKSPACE-ROADMAP.md). Inline comment in ssh.go realSSHClient.Connect updated to forward-reference the new doc subsection (no logic change; same HostKeyCallback: ssh.InsecureIgnoreHostKey() call). Same shape Bundle 8 used for "Operator playbook: keytool argv password exposure" in docs/connectors.md JavaKeystore section. No code-behavior changes. No test changes. Verified locally: - gofmt / go vet clean. - go test -short ./internal/connector/target/ssh/... green. Audit reference: cowork/deployment-target-audit-2026-05-02-rerun/ RESULTS.md Top-10 fix #7.
This commit is contained in:
@@ -1108,6 +1108,43 @@ The SSH target connector enables agentless certificate deployment to any Linux/U
|
||||
|
||||
Location: `internal/connector/target/ssh/ssh.go`
|
||||
|
||||
#### Operator playbook: SSH host-key verification
|
||||
|
||||
certctl's SSH connector dials each target with `HostKeyCallback: ssh.InsecureIgnoreHostKey()`, meaning **the connector accepts any server host key without comparison against `known_hosts`**. This is a documented design choice (see `internal/connector/target/ssh/ssh.go` near `realSSHClient.Connect`) and not an oversight. The rationale + when it's safe + what to layer on top when it isn't:
|
||||
|
||||
**Why the connector accepts any host key:**
|
||||
|
||||
- certctl deploys to **operator-configured target infrastructure**. Each target is registered explicitly in the control plane with hostname + auth credentials + cert/key paths; the operator implicitly trusts the host they're deploying to (otherwise why give it a TLS cert).
|
||||
- Mirrors the same posture certctl applies to the network scanner (`InsecureSkipVerify` for cert-monitoring TLS handshakes) and the F5 connector (`Insecure` flag for self-signed BIG-IP management interfaces).
|
||||
- Avoids a heavyweight per-target `known_hosts` management layer that would shift complexity onto operators with no proportional security gain when the network model is "operator-configured infrastructure on operator-controlled network".
|
||||
|
||||
**Threat model the design choice accepts:**
|
||||
|
||||
- A **passive eavesdropper** on the agent-to-target link. SSH's transport encryption still applies — host-key acceptance affects MITM vulnerability, not on-the-wire confidentiality.
|
||||
- A **MITM attacker** on the agent-to-target link who can intercept the SSH TCP handshake AND has positioned themselves on a hostname the operator has registered as a deploy target. Layered authentication (per-target SSH keys with strong passphrases stored at the agent) limits the blast radius — the MITM gets one target's cert+key payload, not the agent's broader credentials.
|
||||
|
||||
**Threat model the design choice does NOT accept:**
|
||||
|
||||
- Deploying across the **public internet** to a host whose IP rotates (e.g. ephemeral cloud instances behind a load balancer that doesn't pin SSH host keys). In that scenario, `InsecureIgnoreHostKey` opens an MITM window during IP rotation — register a `known_hosts` file path or use SSH certificates (below) instead.
|
||||
- **Multi-tenant networks** where another tenant could plausibly impersonate the target host. certctl's design assumes operator-controlled network paths.
|
||||
|
||||
**Mitigations operators can layer on:**
|
||||
|
||||
- **`known_hosts` enforcement**: implement a custom `SSHClient` (the connector's `SSHClient` interface accepts injected clients via `NewWithClient`) whose `Connect` method builds an `ssh.ClientConfig` with `HostKeyCallback` set to `knownhosts.New("/path/to/known_hosts")` from `golang.org/x/crypto/ssh/knownhosts`. Configure the agent to use that client.
|
||||
- **SSH certificate authentication**: use OpenSSH 5.4+ host certificates signed by an organizational CA. Configure the agent's `known_hosts` CA pinning via `@cert-authority` lines so any host presenting a certificate signed by the CA is trusted, regardless of IP rotation.
|
||||
- **Network segmentation**: run the certctl agent on the same private network segment as its targets; require VPN tunnels for cross-network deploys; use bastion hosts with their own host-key validation.
|
||||
- **Per-target SSH keys**: rotate the agent's SSH credentials per target so a successful MITM compromise is bounded to that one target's cert+key, not the agent's broader credential set.
|
||||
|
||||
**When you should NOT use the SSH connector:**
|
||||
|
||||
- Deploying to **unknown / dynamic / multi-tenant** hosts where the IP-to-hostname binding isn't operator-controlled.
|
||||
- Environments with strict **regulatory MITM-resistance** requirements (PCI-DSS Level 1, FedRAMP High, etc.) — the inline-comment "out of scope" framing doesn't satisfy compliance auditors who want documented host-key verification at the connector level.
|
||||
- For these cases, switch to a different connector (Kubernetes Secrets, WinCertStore, F5 with iControl REST under operator-managed cert pinning) **OR** layer a custom `SSHClient` with full `known_hosts` validation per the mitigations above.
|
||||
|
||||
**V3-Pro forward path:**
|
||||
|
||||
The operator-managed `known_hosts` integration (config field + `HostKeyCallback` plumbing + per-target root-of-trust enforcement) is documented as V3-Pro work. Tracking: `WORKSPACE-ROADMAP.md` (search for "SSH known_hosts").
|
||||
|
||||
### Windows Certificate Store
|
||||
|
||||
The Windows Certificate Store connector imports certificates into the Windows cert store via PowerShell, without managing IIS site bindings. Use this for non-IIS Windows services that read certificates from the cert store (Exchange, RDP, SQL Server, ADFS, etc.). Same injectable `PowerShellExecutor` pattern as the IIS connector, with optional WinRM proxy mode.
|
||||
|
||||
@@ -668,11 +668,17 @@ func (c *realSSHClient) Connect(ctx context.Context) error {
|
||||
User: c.config.User,
|
||||
Auth: authMethods,
|
||||
Timeout: time.Duration(c.config.Timeout) * time.Second,
|
||||
// InsecureIgnoreHostKey is used intentionally: certctl deploys to known
|
||||
// infrastructure (the operator explicitly configures each target host).
|
||||
// This is the same security rationale as network scanner's InsecureSkipVerify
|
||||
// and F5 connector's insecure flag. Host key verification would require
|
||||
// an additional known_hosts management layer that is out of scope.
|
||||
// InsecureIgnoreHostKey is used intentionally — see "Operator playbook:
|
||||
// SSH host-key verification" in docs/connectors.md (SSH section) for
|
||||
// the threat model accepted, the threat model rejected, available
|
||||
// mitigations (custom HostKeyCallback via NewWithClient + known_hosts;
|
||||
// SSH certificate authentication; network segmentation), and when not
|
||||
// to use this connector. Same security rationale as the network
|
||||
// scanner's InsecureSkipVerify and the F5 connector's insecure flag:
|
||||
// certctl deploys to operator-configured target infrastructure on
|
||||
// operator-controlled networks. Built-in known_hosts management is
|
||||
// V3-Pro work (see WORKSPACE-ROADMAP.md). Top-10 fix #7 of the
|
||||
// 2026-05-02 deployment-target audit re-run.
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user