128. Bootstrap SSH Key Strategy
Status: Accepted Date: 2025-07-06
Context
When provisioning a new server, we face a classic "chicken-and-egg" problem with SSH keys. To run our Ansible automation, we need to be able to SSH into the server. But to SSH into the server, we need our SSH keys to be present in the ~/.ssh/authorized_keys file.
Furthermore, we manage our complete set of personal SSH keys, configs, and identities through our dotfiles repository, deployed via chezmoi (adr://chezmoi-integration). We don't want to duplicate all these private keys inside our Ansible vault.
Decision
We will use a two-phase bootstrap strategy for SSH keys.
Phase 1: Ansible Bootstrap
- A single, dedicated public SSH key, which we'll call the "bootstrap key", will be stored as a variable within the Ansible project.
- The very first task in our common Ansible roles (
02_ssh) will be to ensure this single bootstrap public key is present in the user'sauthorized_keysfile. - This key is used only for the initial connection and execution of the Ansible playbook.
Phase 2: Dotfile Deployment
- A later Ansible role (
27_chezmoi) is responsible for installingchezmoiand running it to deploy our full dotfiles configuration. - Our dotfiles repository contains the complete
~/.sshdirectory, including theauthorized_keysfile with all our personal and work keys, as well as our SSH config. - When
chezmoiruns, it will overwrite theauthorized_keysfile with the complete version from our dotfiles.
This strategy ensures that Ansible has a minimal, dedicated key to get started, but the true source of truth for our SSH configuration remains our secure, personal dotfiles repository.
Consequences
Positive:
- Solves the Chicken-and-Egg Problem: Provides a clean, reliable solution for initial server access.
- Secure: We are not storing our sensitive, primary private keys inside the Ansible project. Only a single, purpose-specific public key is stored there. If the bootstrap key is ever compromised, we can simply replace it without having to rotate all our personal keys.
- Single Source of Truth: The user's dotfiles repository remains the single source of truth for their SSH identity, which is the correct separation of concerns. The infrastructure code provisions the system, the dotfiles provision the user's environment.
Negative:
- Brief Window of Limited Access: There is a brief period during the initial provisioning where only the bootstrap key will grant access.
- Dependency on
chezmoi: This strategy is dependent on thechezmoirole running successfully to establish full, normal SSH access.
Mitigation:
- Automated Process: The window of limited access is very short, as it only exists for the duration of the Ansible run. Since the process is fully automated, this is not a practical issue.
- Critical Role Ordering: The
chezmoirole is one of the last and most critical roles to run. The Ansible playbook is designed to be idempotent. If thechezmoirole fails, the playbook can simply be re-run until it succeeds, at which point full access will be established.