# Bootstrap the `infra-ops` agent identity on a PFI-OWNED box. # # Creates a dedicated, key-authenticated, NOPASSWD-sudo system user so the # infra-ops agent can complete DevOps work (apt, systemctl, service lifecycle) # end-to-end instead of handing sudo steps back to the operator. # # WHY a dedicated identity (not the agent borrowing lkraven/vh sudo): # - Clean audit trail — every agent action attributable to `infra-ops`, # separate from human accounts, with sudo I/O logging on. # - Revocation = pull one authorized_keys line + one sudoers file. # - No human password ever in the agent's reach (key-gated NOPASSWD). # # RUN (operator, with YOUR sudo — infra-ops doesn't exist yet, so you bootstrap # it as your normal account; elway prompts for your sudo password once, lazily # on the first sudo step): # scripts/elway --playbook playbooks/bootstrap-infra-ops-user.yaml # Fleet (a lot of servers): # scripts/bootstrap-infra-ops-fleet.sh # # SCOPE — PFI-owned Linux boxes ONLY. NEVER run on: # - SureFire sf-* / sfsrv-ana (tenant property — coordinate, don't own) # - corviduo-dev (Worldtree partner app-layer) # - esh-* app VMs (ESH home lab — non-PFI). EXCEPTION, operator 2026-09-06: # ALL FOUR PVE HYPERVISORS (pfi-pve, nh3-pve, esh-pve, # esh-pve-nas) DO get infra-ops — done that day. # PVE ships without sudo: `apt-get install sudo` first. # - nh3-nas (Synology DSM) (no standard useradd / sudoers.d) # # Idempotent: re-running reconciles the key + sudoers without error. vars: ops_user: infra-ops ops_pubkey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN+1HBwfXrkfTYWdcnWCjLJ6VLAGC87gxH5h5vKaaA3c infra-ops@pfi-fleet" # Optional authorized_keys from="..." source restriction. Empty = none. # Hardening follow-up once per-path source IPs (LAN vs WG tunnel) are pinned. ssh_from: "" steps: - name: Create the infra-ops system user (home + bash shell) sudo: true shell: useradd -m -s /bin/bash {{ ops_user }} when: "! id {{ ops_user }} >/dev/null 2>&1" - name: Add infra-ops to the docker group (only if docker is installed) sudo: true shell: getent group docker >/dev/null && usermod -aG docker {{ ops_user }} || echo "no docker group — skipped" - name: Ensure infra-ops ~/.ssh exists (700, owned) sudo: true shell: install -d -m 700 -o {{ ops_user }} -g {{ ops_user }} /home/{{ ops_user }}/.ssh - name: Install infra-ops authorized_keys (exact line, mode 600) sudo: true shell: | line='{{ ops_pubkey }}' [ -n '{{ ssh_from }}' ] && line='from="{{ ssh_from }}" {{ ops_pubkey }}' printf '%s\n' "$line" > /home/{{ ops_user }}/.ssh/authorized_keys chown {{ ops_user }}:{{ ops_user }} /home/{{ ops_user }}/.ssh/authorized_keys chmod 600 /home/{{ ops_user }}/.ssh/authorized_keys - name: Install NOPASSWD sudoers + command logging (visudo-validated before install) sudo: true shell: | f=/etc/sudoers.d/{{ ops_user }} printf 'Defaults:%s log_output\n%s ALL=(ALL) NOPASSWD:ALL\n' '{{ ops_user }}' '{{ ops_user }}' > "$f.tmp" chmod 440 "$f.tmp" if visudo -cf "$f.tmp"; then mv "$f.tmp" "$f"; else rm -f "$f.tmp"; echo "VISUDO VALIDATION FAILED"; exit 1; fi verify: - name: infra-ops user exists shell: id {{ ops_user }} changed_when: "false" - name: authorized_keys present, mode 600, correct key sudo: true shell: test "$(stat -c %a /home/{{ ops_user }}/.ssh/authorized_keys)" = 600 && grep -q 'infra-ops@pfi-fleet' /home/{{ ops_user }}/.ssh/authorized_keys changed_when: "false" - name: sudoers file valid + NOPASSWD present sudo: true shell: visudo -cf /etc/sudoers.d/{{ ops_user }} && grep -q 'NOPASSWD:ALL' /etc/sudoers.d/{{ ops_user }} changed_when: "false"