bootstrap: set hostname racknerd1, ansible-key safety check, harden root login (prohibit-password), /var/log/bootstrap log+sha256
This commit is contained in:
parent
bdd915dcfd
commit
ed661af1db
@ -2,63 +2,61 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# bootstrap.yml — prepare a fresh host for managed deployments
|
# bootstrap.yml — prepare a fresh host for managed deployments
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PLAY 1 (precheck, on the Semaphore runner): authenticate to Infisical, pull
|
# PLAY 1 (precheck, Semaphore runner): Infisical login + pull/validate secrets +
|
||||||
# secrets, validate them, and test SSH reachability to the target.
|
# test root reachability. Aborts with a reason if anything fails —
|
||||||
# If ANYTHING fails, the run stops here with a clear reason — BEFORE
|
# BEFORE any change to the target.
|
||||||
# any change is made to the target host.
|
# PLAY 2 (bootstrap, target as root):
|
||||||
# PLAY 2 (bootstrap, on the target as root): cleanup (allowlist) -> create the
|
# 1. confirm root
|
||||||
# `ansible` user + install SSH key -> verify.
|
# 2. cleanup (explicit allowlist only; empty = nothing removed)
|
||||||
|
# 3. set hostname -> racknerd1 (+ /etc/hosts)
|
||||||
|
# 4. create `ansible` user + password (from Infisical)
|
||||||
|
# 5. install SSH public key -> /home/ansible/.ssh/authorized_keys + sudoers
|
||||||
|
# 6. SAFETY CHECK: verify ansible-user key login works
|
||||||
|
# 7. ONLY IF key login passed: PermitRootLogin prohibit-password
|
||||||
|
# (sshd -t validate -> restart -> verify up). If key test failed: ABORT,
|
||||||
|
# leave root auth untouched (no lockout).
|
||||||
|
# 8. write timestamped run log + SHA256 to /var/log/bootstrap/
|
||||||
#
|
#
|
||||||
# Infisical auth (Universal Auth) — provide these to the runner as env vars
|
# Infisical auth env vars (Semaphore Variable Group 'infisical-dev', Secrets):
|
||||||
# (Semaphore Environment / Variable Group), NOT committed:
|
# INFISICAL_CLIENT_ID / _CLIENT_SECRET / _PROJECT_ID (URL+ENV_SLUG optional)
|
||||||
# INFISICAL_CLIENT_ID
|
# Secrets read: SSH_PUBLIC_KEY, SSH_PRIVATE_KEY, ANSIBLE_USER_PASS, ANSIBLE_BECOME_ROOT_PASS
|
||||||
# INFISICAL_CLIENT_SECRET
|
|
||||||
# INFISICAL_PROJECT_ID
|
|
||||||
# INFISICAL_URL (default http://192.168.122.41:8080)
|
|
||||||
# INFISICAL_ENV_SLUG (default dev)
|
|
||||||
#
|
#
|
||||||
# Secrets READ from Infisical (must exist in the project/env):
|
# Usage: extra vars: target=racknerd1 connect_user=root new_hostname=racknerd1
|
||||||
# SSH_PUBLIC_KEY, ANSIBLE_USER_PASS, ANSIBLE_BECOME_ROOT_PASS
|
# optional: cleanup_paths='["/opt/old"]'
|
||||||
#
|
|
||||||
# Usage (Semaphore Task Template):
|
|
||||||
# playbook: playbooks/bootstrap.yml
|
|
||||||
# inventory: inventory/hosts.yml
|
|
||||||
# extra vars: target=racknerd1 connect_user=root
|
|
||||||
# (optional) cleanup_paths='["/opt/old-thing"]'
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# PLAY 1 — PRECHECK (runs on the Semaphore runner / localhost). No target changes.
|
# PLAY 1 — PRECHECK (runner/localhost). No target changes.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
- name: "PRECHECK — Infisical + connectivity (no changes made)"
|
- name: "PRECHECK — Infisical + connectivity (no changes)"
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
vars:
|
|
||||||
infisical_url: "{{ lookup('env','INFISICAL_URL') | default('http://192.168.122.41:8080', true) }}"
|
|
||||||
infisical_project_id: "{{ lookup('env','INFISICAL_PROJECT_ID') }}"
|
|
||||||
infisical_env_slug: "{{ lookup('env','INFISICAL_ENV_SLUG') | default('dev', true) }}"
|
|
||||||
target_host: "{{ target | default('racknerd1') }}"
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: "[precheck] Infisical auth vars present?"
|
- name: "[pre] resolve Infisical auth (env, else extra-var)"
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
infisical_client_id: "{{ lookup('env','INFISICAL_CLIENT_ID') | default(lookup('vars','INFISICAL_CLIENT_ID', default=''), true) }}"
|
||||||
|
infisical_client_secret: "{{ lookup('env','INFISICAL_CLIENT_SECRET') | default(lookup('vars','INFISICAL_CLIENT_SECRET', default=''), true) }}"
|
||||||
|
infisical_project_id: "{{ lookup('env','INFISICAL_PROJECT_ID') | default(lookup('vars','INFISICAL_PROJECT_ID', default=''), true) }}"
|
||||||
|
infisical_url: "{{ lookup('env','INFISICAL_URL') | default(lookup('vars','INFISICAL_URL', default='http://192.168.122.41:8080'), true) }}"
|
||||||
|
infisical_env_slug: "{{ lookup('env','INFISICAL_ENV_SLUG') | default(lookup('vars','INFISICAL_ENV_SLUG', default='dev'), true) }}"
|
||||||
|
|
||||||
|
- name: "[pre] Infisical auth present?"
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- lookup('env','INFISICAL_CLIENT_ID') | length > 0
|
- infisical_client_id | length > 0
|
||||||
- lookup('env','INFISICAL_CLIENT_SECRET') | length > 0
|
- infisical_client_secret | length > 0
|
||||||
- infisical_project_id | length > 0
|
- infisical_project_id | length > 0
|
||||||
fail_msg: >-
|
fail_msg: "Missing Infisical creds in the Variable Group (INFISICAL_CLIENT_ID/_SECRET/_PROJECT_ID)."
|
||||||
Missing Infisical auth. Set INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET,
|
|
||||||
and INFISICAL_PROJECT_ID in the Semaphore Environment for this template.
|
|
||||||
|
|
||||||
- name: "[precheck] Log in to Infisical"
|
- name: "[pre] Log in to Infisical"
|
||||||
infisical.vault.login:
|
infisical.vault.login:
|
||||||
url: "{{ infisical_url }}"
|
url: "{{ infisical_url }}"
|
||||||
auth_method: universal_auth
|
auth_method: universal_auth
|
||||||
universal_auth_client_id: "{{ lookup('env','INFISICAL_CLIENT_ID') }}"
|
universal_auth_client_id: "{{ infisical_client_id }}"
|
||||||
universal_auth_client_secret: "{{ lookup('env','INFISICAL_CLIENT_SECRET') }}"
|
universal_auth_client_secret: "{{ infisical_client_secret }}"
|
||||||
register: infisical_login
|
register: infisical_login
|
||||||
# if this fails, the play stops here with the SDK error (bad creds / unreachable Infisical)
|
|
||||||
|
|
||||||
- name: "[precheck] Read required secrets from Infisical"
|
- name: "[pre] Read secrets"
|
||||||
infisical.vault.read_secrets:
|
infisical.vault.read_secrets:
|
||||||
login_data: "{{ infisical_login.login_data }}"
|
login_data: "{{ infisical_login.login_data }}"
|
||||||
project_id: "{{ infisical_project_id }}"
|
project_id: "{{ infisical_project_id }}"
|
||||||
@ -66,45 +64,51 @@
|
|||||||
path: "/"
|
path: "/"
|
||||||
as_dict: true
|
as_dict: true
|
||||||
register: infisical_secrets
|
register: infisical_secrets
|
||||||
|
no_log: true
|
||||||
|
|
||||||
- name: "[precheck] Validate the secrets we need are present + well-formed"
|
- name: "[pre] Validate required secrets"
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- infisical_secrets.secrets.SSH_PUBLIC_KEY is defined
|
- infisical_secrets.secrets.SSH_PUBLIC_KEY is defined
|
||||||
- infisical_secrets.secrets.SSH_PUBLIC_KEY.startswith('ssh-')
|
- infisical_secrets.secrets.SSH_PUBLIC_KEY.startswith('ssh-')
|
||||||
- infisical_secrets.secrets.ANSIBLE_USER_PASS is defined
|
- infisical_secrets.secrets.SSH_PRIVATE_KEY is defined
|
||||||
- infisical_secrets.secrets.ANSIBLE_USER_PASS | length > 0
|
- infisical_secrets.secrets.ANSIBLE_USER_PASS | length > 0
|
||||||
- infisical_secrets.secrets.ANSIBLE_BECOME_ROOT_PASS is defined
|
|
||||||
- infisical_secrets.secrets.ANSIBLE_BECOME_ROOT_PASS | length > 0
|
- infisical_secrets.secrets.ANSIBLE_BECOME_ROOT_PASS | length > 0
|
||||||
fail_msg: >-
|
fail_msg: "Required secrets missing/invalid in env '{{ infisical_env_slug }}'."
|
||||||
Infisical is reachable but required secrets are missing/invalid in env
|
|
||||||
'{{ infisical_env_slug }}'. Need: SSH_PUBLIC_KEY (OpenSSH format),
|
|
||||||
ANSIBLE_USER_PASS, ANSIBLE_BECOME_ROOT_PASS.
|
|
||||||
|
|
||||||
- name: "[precheck] Test SSH reachability to target ({{ target_host }})"
|
- name: "[pre] stash secrets + write private key to a temp file for the key-login safety test"
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
pc_ssh_pubkey: "{{ infisical_secrets.secrets.SSH_PUBLIC_KEY }}"
|
||||||
|
pc_ssh_privkey: "{{ infisical_secrets.secrets.SSH_PRIVATE_KEY }}"
|
||||||
|
pc_user_pass: "{{ infisical_secrets.secrets.ANSIBLE_USER_PASS }}"
|
||||||
|
pc_root_pass: "{{ infisical_secrets.secrets.ANSIBLE_BECOME_ROOT_PASS }}"
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: "[pre] write deploy private key to runner temp (0600) for safety test"
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "/tmp/bootstrap_deploy_key"
|
||||||
|
content: "{{ pc_ssh_privkey }}\n"
|
||||||
|
mode: "0600"
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: "[pre] test SSH reachability to target as root"
|
||||||
ansible.builtin.command: >-
|
ansible.builtin.command: >-
|
||||||
ansible {{ target_host }} -i {{ inventory_file }}
|
ansible {{ target | default('racknerd1') }} -i {{ inventory_file }}
|
||||||
-m ansible.builtin.ping
|
-m ansible.builtin.ping
|
||||||
-e "ansible_user={{ connect_user | default('root') }}"
|
-e "ansible_user={{ connect_user | default('root') }}"
|
||||||
-e "ansible_password={{ infisical_secrets.secrets.ANSIBLE_BECOME_ROOT_PASS }}"
|
-e "ansible_password={{ pc_root_pass }}"
|
||||||
-e "ansible_ssh_common_args=-o StrictHostKeyChecking=accept-new"
|
-e "ansible_ssh_common_args=-o StrictHostKeyChecking=accept-new"
|
||||||
register: reach
|
register: reach
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: reach.rc != 0
|
failed_when: reach.rc != 0
|
||||||
no_log: true # avoid leaking the password in output
|
no_log: true
|
||||||
|
|
||||||
- name: "[precheck] PASSED — stash secrets for the bootstrap play"
|
- name: "[pre] PASSED"
|
||||||
ansible.builtin.set_fact:
|
|
||||||
pc_ssh_pubkey: "{{ infisical_secrets.secrets.SSH_PUBLIC_KEY }}"
|
|
||||||
pc_user_pass: "{{ infisical_secrets.secrets.ANSIBLE_USER_PASS }}"
|
|
||||||
pc_root_pass: "{{ infisical_secrets.secrets.ANSIBLE_BECOME_ROOT_PASS }}"
|
|
||||||
|
|
||||||
- name: "[precheck] Result"
|
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "Precheck OK — Infisical reachable, secrets valid, {{ target_host }} reachable. Proceeding."
|
msg: "Precheck OK — Infisical + secrets valid, {{ target | default('racknerd1') }} reachable as root."
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# PLAY 2 — BOOTSTRAP the target (only runs if PLAY 1 succeeded)
|
# PLAY 2 — BOOTSTRAP (target, as root)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
- name: "BOOTSTRAP target host"
|
- name: "BOOTSTRAP target host"
|
||||||
hosts: "{{ target | default('racknerd1') }}"
|
hosts: "{{ target | default('racknerd1') }}"
|
||||||
@ -112,28 +116,44 @@
|
|||||||
become: true
|
become: true
|
||||||
vars:
|
vars:
|
||||||
managed_user: ansible
|
managed_user: ansible
|
||||||
|
new_hostname: "{{ new_hostname | default('racknerd1') }}"
|
||||||
ansible_user: "{{ connect_user | default('root') }}"
|
ansible_user: "{{ connect_user | default('root') }}"
|
||||||
ansible_password: "{{ hostvars['localhost'].pc_root_pass }}"
|
ansible_password: "{{ hostvars['localhost'].pc_root_pass }}"
|
||||||
ansible_become_password: "{{ hostvars['localhost'].pc_root_pass }}"
|
ansible_become_password: "{{ hostvars['localhost'].pc_root_pass }}"
|
||||||
ansible_ssh_common_args: "-o StrictHostKeyChecking=accept-new"
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=accept-new"
|
||||||
managed_ssh_pubkey: "{{ hostvars['localhost'].pc_ssh_pubkey }}"
|
managed_ssh_pubkey: "{{ hostvars['localhost'].pc_ssh_pubkey }}"
|
||||||
managed_user_password: "{{ hostvars['localhost'].pc_user_pass }}"
|
managed_user_password: "{{ hostvars['localhost'].pc_user_pass }}"
|
||||||
cleanup_paths: [] # SAFETY: only removes paths explicitly listed. Empty = nothing.
|
cleanup_paths: []
|
||||||
tasks:
|
tasks:
|
||||||
- name: "[1] Connection confirmed as root"
|
- name: "[1] confirm root"
|
||||||
ansible.builtin.command: id
|
ansible.builtin.command: id
|
||||||
register: idc
|
register: idc
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: "'uid=0' not in idc.stdout"
|
failed_when: "'uid=0' not in idc.stdout"
|
||||||
|
|
||||||
- name: "[2] Cleanup — remove ONLY explicitly-listed paths"
|
- name: "[2] cleanup — remove ONLY explicitly listed paths"
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
state: absent
|
state: absent
|
||||||
loop: "{{ cleanup_paths | default([]) }}"
|
loop: "{{ cleanup_paths | default([]) }}"
|
||||||
when: cleanup_paths | length > 0
|
when: cleanup_paths | length > 0
|
||||||
|
|
||||||
- name: "[3] Create '{{ managed_user }}' user"
|
- name: "[3] record old hostname"
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
old_hostname: "{{ ansible_hostname }}"
|
||||||
|
|
||||||
|
- name: "[3] set hostname -> {{ new_hostname }}"
|
||||||
|
ansible.builtin.hostname:
|
||||||
|
name: "{{ new_hostname }}"
|
||||||
|
|
||||||
|
- name: "[3] ensure /etc/hosts maps 127.0.1.1 to new hostname"
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1'
|
||||||
|
line: "127.0.1.1 {{ new_hostname }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: "[4] create '{{ managed_user }}' user"
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "{{ managed_user }}"
|
name: "{{ managed_user }}"
|
||||||
password: "{{ managed_user_password | password_hash('sha512') }}"
|
password: "{{ managed_user_password | password_hash('sha512') }}"
|
||||||
@ -143,7 +163,7 @@
|
|||||||
create_home: true
|
create_home: true
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
- name: "[4] Ensure ~/.ssh for {{ managed_user }}"
|
- name: "[5] ~/.ssh for {{ managed_user }}"
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/home/{{ managed_user }}/.ssh"
|
path: "/home/{{ managed_user }}/.ssh"
|
||||||
state: directory
|
state: directory
|
||||||
@ -151,25 +171,125 @@
|
|||||||
group: "{{ managed_user }}"
|
group: "{{ managed_user }}"
|
||||||
mode: "0700"
|
mode: "0700"
|
||||||
|
|
||||||
- name: "[4] Install public key to {{ managed_user }} authorized_keys"
|
- name: "[5] install public key"
|
||||||
ansible.posix.authorized_key:
|
ansible.posix.authorized_key:
|
||||||
user: "{{ managed_user }}"
|
user: "{{ managed_user }}"
|
||||||
key: "{{ managed_ssh_pubkey }}"
|
key: "{{ managed_ssh_pubkey }}"
|
||||||
state: present
|
state: present
|
||||||
exclusive: false
|
exclusive: false
|
||||||
|
|
||||||
- name: "[3] sudoers entry for {{ managed_user }}"
|
- name: "[5] sudoers entry"
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
dest: "/etc/sudoers.d/{{ managed_user }}"
|
dest: "/etc/sudoers.d/{{ managed_user }}"
|
||||||
content: "{{ managed_user }} ALL=(ALL) ALL\n"
|
content: "{{ managed_user }} ALL=(ALL) ALL\n"
|
||||||
mode: "0440"
|
mode: "0440"
|
||||||
validate: "visudo -cf %s"
|
validate: "visudo -cf %s"
|
||||||
|
|
||||||
- name: "[5] Verify user + key"
|
# ---------- SAFETY CHECK: ansible key login must work ----------
|
||||||
ansible.builtin.command: "id {{ managed_user }}"
|
- name: "[6] SAFETY — verify {{ managed_user }} can log in via SSH key (from the runner)"
|
||||||
register: uv
|
ansible.builtin.command: >-
|
||||||
|
ssh -i /tmp/bootstrap_deploy_key
|
||||||
|
-o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10
|
||||||
|
{{ managed_user }}@{{ ansible_host | default(inventory_hostname) }} id
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
register: keytest
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
- name: "[5] Bootstrap complete"
|
- name: "[6] ABORT if key login failed (root auth left UNTOUCHED)"
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that: "keytest.rc == 0 and 'uid=' in keytest.stdout"
|
||||||
|
fail_msg: >-
|
||||||
|
ansible-user SSH key login FAILED (rc={{ keytest.rc }}). Aborting BEFORE
|
||||||
|
touching root login so we can't lock ourselves out. Fix the key/user, re-run.
|
||||||
|
success_msg: "ansible-user key login verified — safe to harden root login."
|
||||||
|
|
||||||
|
# ---------- HARDEN: disable root password auth (key still works) ----------
|
||||||
|
- name: "[7] set PermitRootLogin prohibit-password"
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
regexp: '^\s*#?\s*PermitRootLogin'
|
||||||
|
line: "PermitRootLogin prohibit-password"
|
||||||
|
state: present
|
||||||
|
validate: "sshd -t -f %s"
|
||||||
|
register: sshd_change
|
||||||
|
|
||||||
|
- name: "[7] restart sshd"
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}"
|
||||||
|
state: restarted
|
||||||
|
when: sshd_change is changed
|
||||||
|
|
||||||
|
- name: "[7] verify sshd is up"
|
||||||
|
ansible.builtin.service_facts:
|
||||||
|
|
||||||
|
- name: "[7] assert sshd running"
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that: >-
|
||||||
|
(ansible_facts.services['ssh.service'] is defined and ansible_facts.services['ssh.service'].state == 'running')
|
||||||
|
or (ansible_facts.services['sshd.service'] is defined and ansible_facts.services['sshd.service'].state == 'running')
|
||||||
|
fail_msg: "sshd did not come back up after restart — investigate immediately."
|
||||||
|
success_msg: "sshd is running after hardening."
|
||||||
|
|
||||||
|
# ---------- LOG: write run record + SHA256 to /var/log/bootstrap/ ----------
|
||||||
|
- name: "[8] ensure /var/log/bootstrap exists"
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /var/log/bootstrap
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: "[8] timestamp for the log file"
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ts: "{{ lookup('pipe','date -u +%Y-%m-%d-%H%M%S') }}"
|
||||||
|
ts_iso: "{{ lookup('pipe','date -u +%Y-%m-%dT%H:%M:%SZ') }}"
|
||||||
|
|
||||||
|
- name: "[8] write bootstrap log"
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "/var/log/bootstrap/bootstrap-{{ ts }}.log"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
Bootstrap record
|
||||||
|
=================
|
||||||
|
Host (new): {{ new_hostname }}
|
||||||
|
Host (previous): {{ old_hostname }}
|
||||||
|
Completed (UTC): {{ ts_iso }}
|
||||||
|
Managed user: {{ managed_user }} (groups: {{ 'sudo' if ansible_os_family == 'Debian' else 'wheel' }})
|
||||||
|
SSH key install: yes
|
||||||
|
Key login test: PASS (rc={{ keytest.rc }})
|
||||||
|
Root login: PermitRootLogin prohibit-password (changed: {{ sshd_change is changed }})
|
||||||
|
sshd validated: yes (sshd -t) | sshd restarted: {{ sshd_change is changed }}
|
||||||
|
Cleanup paths: {{ cleanup_paths | default([]) }}
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Run by Semaphore. This file is root-owned; integrity hash in the .sha256 sibling.
|
||||||
|
register: logwrite
|
||||||
|
|
||||||
|
- name: "[8] write SHA256 of the log"
|
||||||
|
ansible.builtin.shell: >-
|
||||||
|
sha256sum "/var/log/bootstrap/bootstrap-{{ ts }}.log"
|
||||||
|
| awk '{print $1}' > "/var/log/bootstrap/bootstrap-{{ ts }}.log.sha256"
|
||||||
|
args:
|
||||||
|
creates: "/var/log/bootstrap/bootstrap-{{ ts }}.log.sha256"
|
||||||
|
|
||||||
|
- name: "[done] Bootstrap complete"
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ inventory_hostname }} ready — {{ uv.stdout }}. Deploys can now run as '{{ managed_user }}'."
|
msg:
|
||||||
|
- "{{ old_hostname }} -> {{ new_hostname }} bootstrapped."
|
||||||
|
- "ansible user ready (key login PASS), root password auth disabled."
|
||||||
|
- "Log: /var/log/bootstrap/bootstrap-{{ ts }}.log (+ .sha256)"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# CLEANUP — remove the temp deploy key from the runner
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
- name: "Cleanup runner temp key"
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
tasks:
|
||||||
|
- name: "remove temp deploy key from runner"
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/bootstrap_deploy_key
|
||||||
|
state: absent
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user