diff --git a/ansible/README.md b/ansible/README.md index 1be880f..e3a7a6c 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -88,9 +88,24 @@ the one operator list, `baseline_sudo_users`. Add other admins there — list yo name) to override the auto-detected head with explicit keys. Set `baseline_sudo_autodetect_runner: false` to skip the runner and provision only the explicit list (e.g. from CI). baseline **asserts a non-root account with a key resolves** before -`ssh_hardening` disables root + password login, so you can't lock yourself out. After the -first deploy, switch each host's `ansible_user` to that admin account (your local username -unless you listed one). +`ssh_hardening` disables root + password login, so you can't lock yourself out. + +The inventory template sets **no `ansible_user`**, so Ansible connects as your local `$USER` +— the same account baseline creates. That account doesn't exist yet on a fresh box, so +bootstrap each new host once as a sudo-capable user (root, or the image's default user such +as `ubuntu`): + +```bash +make deploy LIMIT=decdn-node-1 ANSIBLE_ARGS='-u root' # first converge only; swap root for your image's bootstrap user +make deploy LIMIT=decdn-node-1 # every run after that first converge succeeds +``` + +Set a per-host `ansible_user` only when the admin account's name differs from your `$USER` +(you listed a different name in `baseline_sudo_users`) or you set +`baseline_sudo_autodetect_runner: false`. Never set it to the bootstrap user: an inventory +`ansible_user` beats `-u`, and root login is gone after the first converge. For the same +reason, add a per-host `ansible_user` only after that host's bootstrap run, or `-u` is +ignored on the first converge. --- @@ -141,11 +156,11 @@ make deploy LIMIT='!decdn-node-2' # any ansible host pattern Quote the pattern at your own prompt — your shell runs before make does, and eats a bare `!decdn-node-2` (history expansion) or `decdn-node-*` (globbing). -Use `LIMIT` when **bringing up a new node**: that host's first converge creates the -operator account and then lets `ssh_hardening` disable root + password login — after which -you switch its `ansible_user` by hand (see [Setup](#setup) above; the converge does not -edit your inventory). You do not want that play re-converging nodes already serving -paid traffic. Same when re-running a single node after a config change, a failed play, or a +Use `LIMIT` when **bringing up a new node**: that host's first converge connects as the +bootstrap user (`ANSIBLE_ARGS='-u root'`, see [Setup](#setup) above), creates the operator +account and then lets `ssh_hardening` disable root + password login. Every later run +connects as your `$USER` with no flag. You do not want that bootstrap play — or its `-u root` +— reaching nodes already serving paid traffic. Same when re-running a single node after a config change, a failed play, or a binary bump. `make check`/`make deploy` refuse to run if `LIMIT` or `ANSIBLE_ARGS` reaches them from an diff --git a/ansible/inventory/hosts.yml.example b/ansible/inventory/hosts.yml.example index e526b03..7f0fa0a 100644 --- a/ansible/inventory/hosts.yml.example +++ b/ansible/inventory/hosts.yml.example @@ -3,10 +3,17 @@ # template; your real hosts.yml is yours — commit it in your fork if you like, or keep # it local. (Just never push real host IPs to the upstream template.) # -# First run: connect as a user that can sudo (often root) to bootstrap the box. -# After the baseline role creates your admin account (the auto-detected runner, or an -# entry in baseline_sudo_users) and ssh_hardening disables root login, switch -# ansible_user to that admin account. +# No ansible_user by default: Ansible connects as your local $USER, which is the admin +# account the baseline role creates (the auto-detected runner). A fresh box doesn't have +# it yet, so bootstrap each new host ONCE as a user that can sudo (root, or the image's +# default user such as ubuntu): +# make deploy LIMIT= ANSIBLE_ARGS='-u root' # swap root for your image's bootstrap user +# After that first converge ssh_hardening disables root login, and plain `make deploy` +# connects as $USER. Set a per-host ansible_user only if the admin account's name differs +# from your $USER (you listed another name in baseline_sudo_users) or you set +# baseline_sudo_autodetect_runner: false. Never set it to the bootstrap user: an +# inventory ansible_user overrides -u, and root login is gone after the first converge. +# For the same reason, add a per-host ansible_user only AFTER that host's bootstrap run. # # Ubuntu sudo-rs workaround: 25.10 (Questing) and 26.04 ship sudo-rs as the default # /usr/bin/sudo. Ansible's sudo become plugin passes a custom `-p` prompt sentinel and @@ -29,5 +36,5 @@ decdn_nodes: hosts: decdn-node-1: ansible_host: REPLACE_WITH_NODE_VPS_IP_OR_DNS - ansible_user: root + # ansible_user: alice # post-bootstrap, only if the admin account's name ≠ your $USER — see note above # ansible_become_exe: /usr/bin/sudo.ws # Ubuntu sudo-rs workaround — see note above