Introduction – The Allure of “Password‑Less” Automation
Many teams chasing speed automate their CI/CD pipelines by configuring ssh host‑based authentication. The idea is simple: if a build server can prove it runs on a trusted host, the remote target will accept any user without a password or key pair. On paper this removes the need to manage per‑user keys, but it also opens a subtle attack surface that most operators overlook.
How Host‑Based Authentication Works
When a client initiates an SSH connection, the server checks the client’s /etc/ssh/ssh_known_hosts file for an entry that matches the client’s hostname and IP address. If a matching line exists, the server trusts the host and grants access based on the AuthorizedPrincipalsFile directive in sshd_config. No public‑key exchange happens during the session.
# /etc/ssh/sshd_config (excerpt)
HostbasedAuthentication yes
IgnoreRhosts no
EnableSSHKeysign yes
AuthorizedPrincipalsFile /etc/ssh/authorized_principals/%u
The ssh_known_hosts entry looks like this:
# /etc/ssh/ssh_known_hosts (on the target)
build‑agent.example.com,10.0.2.45 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7...
Once the target trusts the host, any local user listed in /etc/ssh/authorized_principals/<user> can log in without a personal key. This seems convenient for automated scripts that run as a generic ci user.
The Hidden Internals – Why It’s a Bad Idea in Cloud Environments
Cloud VMs are highly dynamic. Their IP addresses change, hostnames are often generated on‑the‑fly, and instances can be replaced by autoscaling groups in seconds. Embedding static host entries therefore creates a false sense of permanence. An attacker who compromises a single instance can impersonate the trusted host from any location, because the target never validates the actual SSH key fingerprint.
Moreover, the ssh_known_hosts file is world‑readable by default, leaking the public key of the trusted host. An adversary can copy that key, spin up a rogue VM with the same hostname/IP, and gain unfettered access.
Demo: Setting Up Host‑Based Auth (What Not to Do)
Below is a step‑by‑step example that demonstrates the configuration. Follow it only in an isolated lab; never use it in production.
# On the build agent (client)
$ sudo apt-get install openssh-client
$ sudo ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
# Export the public key for the target
$ sudo cat /etc/ssh/ssh_host_rsa_key.pub > host_rsa.pub
# On the target server (remote)
$ sudo apt-get install openssh-server
$ sudo mkdir -p /etc/ssh/authorized_principals/ci
$ echo "ci" | sudo tee /etc/ssh/authorized_principals/ci/ci
$ sudo cp host_rsa.pub /etc/ssh/ssh_known_hosts
$ sudo sed -i 's/#HostbasedAuthentication no/HostbasedAuthentication yes/' /etc/ssh/sshd_config
$ sudo systemctl restart sshd
After this setup, the build agent can run:
$ ssh [email protected] hostname
target-host
The connection succeeds without any user‑specific private key. At this point the attacker only needs to duplicate the host’s key and hostname to gain the same access.
Why It Breaks in Modern CI/CD Workflows
1. Ephemeral Infrastructure: Autoscaling groups replace instances frequently. Updating ssh_known_hosts on every replacement is a race condition waiting to happen.
2. Privilege Escalation: The ci user typically runs build scripts with sudo rights. If the host is compromised, the attacker inherits those rights on the target.
3. Lack of Auditing: Host‑based auth bypasses the public‑key verification step, which means audit logs lose the fingerprint information that would otherwise identify the exact client key used.
Secure Alternatives – Use Per‑User Keys or Short‑Lived Certificates
The recommended approach is to generate a dedicated SSH key pair for the CI service and store the private key in a secret manager (e.g., AWS Secrets Manager, HashiCorp Vault). The public key is added to ~ci/.ssh/authorized_keys on the target. Even better, use OpenSSH‑certified short‑lived certificates that expire after a few minutes, eliminating the need for long‑term key rotation.
# Generate a key pair for CI
$ ssh-keygen -t ed25519 -f ci_deploy_key -N ""
# Upload the private key to Vault (example)
$ vault kv put secret/ci/ssh key=@ci_deploy_key
# Add the public key to the target
$ echo "$(cat ci_deploy_key.pub)" >> ~ci/.ssh/authorized_keys
CI scripts then retrieve the private key at runtime, use it for a single SSH session, and discard it immediately. This eliminates the persistent trust relationship that host‑based auth creates.
Security and Best Practices
- Never store static host entries for cloud VMs. Use dynamic inventory tools (e.g., Ansible, Terraform) to refresh SSH configurations.
- Enforce
PubkeyAuthentication yesand disableHostbasedAuthenticationglobally. - Rotate CI keys frequently. Automation tools can request a new certificate every build.
- Log every SSH connection with
LogLevel VERBOSEto capture the client key fingerprint. - Restrict the CI user’s sudo rights. Use
sudoersto allow only the commands required for deployment.
"Trusting a hostname is like trusting a mailbox address; anyone who can spoof the address can read the mail."
Conclusion
Host‑based SSH authentication may look like a shortcut for “password‑less” automation, but in cloud‑native environments it trades convenience for a brittle trust model that is easy to subvert. By understanding the underlying mechanics and replacing static host trust with per‑user keys or short‑lived certificates, you preserve the speed of automation without exposing your production servers to a silent, yet potent, attack vector.
The hidden internals of host‑based auth reveal why it is fundamentally mismatched with the dynamic nature of modern CI/CD pipelines. Adopt key‑centric or certificate‑centric workflows, enforce strict logging, and keep your deployment pipeline both fast and secure.