From 869727d364974befd99d327f8cba19bcf958cf77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20D=C3=A9siles?= <1536672+cdesiles@users.noreply.github.com> Date: Tue, 17 Mar 2026 23:06:42 +0100 Subject: [PATCH] fix: add bootstrap for new hosts --- README.md | 30 +++++++++++++---- playbooks/bootstrap.yml | 73 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 playbooks/bootstrap.yml diff --git a/README.md b/README.md index 4f88a2e..6d621b9 100644 --- a/README.md +++ b/README.md @@ -73,18 +73,34 @@ ansible-playbook -i inventory/hosts.yml playbook.yml \ --ask-become-pass ``` -## Target configuration +## Bootstrapping a new host -Requirements: - -- sshd up and running -- public key copied: +For fresh hosts (only `root` available, no admin user yet): ```sh -ssh-copy-id -i ~/.ssh/id_rsa.pub username@remote_host +ansible-playbook playbooks/bootstrap.yml -l --ask-pass ``` -- python3 installed (`pacman -Syu python3`) +This installs Python and sudo, creates `{{ ansible_user }}` with sudo rights, and copies your local `~/.ssh/id_ed25519.pub`. Supports Arch Linux and Debian/Ubuntu. + +To use a different SSH key: + +```sh +ansible-playbook playbooks/bootstrap.yml -l --ask-pass \ + --extra-vars 'bootstrap_ssh_public_key="ssh-ed25519 AAAA..."' +``` + +Then set a password for the new user (required for sudo `--ask-become-pass`): + +```sh +ssh root@ passwd jambon +``` + +After that, run the host playbook normally: + +```sh +ansible-playbook playbooks/.yml --ask-become-pass +``` ## Developping diff --git a/playbooks/bootstrap.yml b/playbooks/bootstrap.yml new file mode 100644 index 0000000..f8e0344 --- /dev/null +++ b/playbooks/bootstrap.yml @@ -0,0 +1,73 @@ +--- +# Bootstrap a fresh host: create the admin user with sudo and SSH access. +# Run this before any other playbook, when only root access is available: +# +# ansible-playbook playbooks/bootstrap.yml -l somehost +# +# After this, run other playbooks normally. + +- name: Bootstrap admin user + hosts: "{{ target | default('all') }}" + gather_facts: false + vars: + ansible_user: root + ansible_become: false + # bootstrap_user: jambon + # bootstrap_ssh_public_key: "ssh-ed25519 AAAA..." + tasks: + - name: Detect OS and install python3 + sudo + ansible.builtin.raw: | + if command -v pacman > /dev/null 2>&1; then + pacman -Sy --noconfirm python sudo + elif command -v apt-get > /dev/null 2>&1; then + apt-get update -qq && apt-get install -y python3 sudo + else + echo "Unsupported OS" && exit 1 + fi + changed_when: true + + - name: Gather facts + ansible.builtin.setup: + + - name: Create admin user + ansible.builtin.user: + name: "{{ bootstrap_user }}" + groups: "{{ 'wheel' if ansible_facts['os_family'] == 'Archlinux' else 'sudo' }}" + append: true + shell: /bin/bash + create_home: true + state: present + + - name: Allow sudo group to use sudo (Debian) + ansible.builtin.copy: + content: "%sudo ALL=(ALL:ALL) ALL\n" + dest: /etc/sudoers.d/sudo + owner: root + group: root + mode: "0440" + validate: visudo -cf %s + when: ansible_facts['os_family'] == 'Debian' + + - name: Allow wheel group to use sudo (Arch) + ansible.builtin.copy: + content: "%wheel ALL=(ALL:ALL) ALL\n" + dest: /etc/sudoers.d/wheel + owner: root + group: root + mode: "0440" + validate: visudo -cf %s + when: ansible_facts['os_family'] == 'Archlinux' + + - name: Create .ssh directory + ansible.builtin.file: + path: "/home/{{ bootstrap_user }}/.ssh" + state: directory + owner: "{{ bootstrap_user }}" + group: "{{ bootstrap_user }}" + mode: "0700" + + - name: Add SSH authorized key + ansible.posix.authorized_key: + user: "{{ bootstrap_user }}" + key: "{{ bootstrap_ssh_public_key | default(lookup('file', '~/.ssh/id_ed25519.pub')) }}" + state: present