idk
This commit is contained in:
1 parent
b745376a65
commit
c49055d4dd
3 files changed
+126
-5
No files matched your search
@@ -0,0 +1,98 @@
|
||||
---
|
||||
# One-job playbook: connect as root, create the automation user that every
|
||||
# later run uses — key-only auth, passwordless sudo — verify it actually
|
||||
# works, then lock sshd down to keys. Run once per fresh VPS:
|
||||
#
|
||||
# ansible-playbook bootstrap.yml # root already has your key
|
||||
# ansible-playbook bootstrap.yml -k # root still uses a password
|
||||
# # (needs sshpass installed)
|
||||
#
|
||||
# Afterwards set `ansible_user: ansible` in inventory.yml and never
|
||||
# connect as root again. Overridable with -e:
|
||||
# bootstrap_user=ansible
|
||||
# bootstrap_ssh_public_key_file=~/.ssh/id_ed25519.pub
|
||||
# bootstrap_harden_ssh=true
|
||||
#
|
||||
# Safe by construction: play 2 logs in AS the new user and proves key +
|
||||
# sudo work; sshd is only hardened in play 3, which never runs if play 2
|
||||
# fails. Play 3 disables root SSH login entirely — from then on the only
|
||||
# way in is the automation user's key (console access via the RackNerd
|
||||
# panel remains the break-glass path).
|
||||
|
||||
- name: Create the automation user (connects as root)
|
||||
hosts: vpnhub
|
||||
gather_facts: false
|
||||
vars:
|
||||
ansible_user: root # play var — outranks inventory on purpose
|
||||
bootstrap_user: ansible
|
||||
bootstrap_ssh_public_key_file: "~/.ssh/id_ed25519.pub"
|
||||
tasks:
|
||||
- name: Create the user (no password hash set, account password locked)
|
||||
ansible.builtin.user:
|
||||
name: "{{ bootstrap_user }}"
|
||||
shell: /bin/bash
|
||||
create_home: true
|
||||
password_lock: true
|
||||
|
||||
- name: Install the SSH public key
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ bootstrap_user }}"
|
||||
key: "{{ lookup('file', bootstrap_ssh_public_key_file) }}"
|
||||
|
||||
- name: Grant passwordless sudo
|
||||
ansible.builtin.copy:
|
||||
dest: "/etc/sudoers.d/{{ bootstrap_user }}"
|
||||
content: "{{ bootstrap_user }} ALL=(ALL) NOPASSWD:ALL\n"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0440"
|
||||
validate: /usr/sbin/visudo -cf %s
|
||||
|
||||
- name: Prove the new user works before touching sshd
|
||||
hosts: vpnhub
|
||||
gather_facts: false
|
||||
become: true
|
||||
vars:
|
||||
bootstrap_user: ansible
|
||||
ansible_user: "{{ bootstrap_user }}"
|
||||
tasks:
|
||||
- name: Key login and passwordless sudo both work
|
||||
ansible.builtin.command: whoami
|
||||
register: bootstrap_whoami
|
||||
changed_when: false
|
||||
failed_when: bootstrap_whoami.stdout != "root"
|
||||
|
||||
- name: Lock sshd down to key-only auth, no root login
|
||||
hosts: vpnhub
|
||||
gather_facts: false
|
||||
become: true
|
||||
vars:
|
||||
bootstrap_user: ansible
|
||||
ansible_user: "{{ bootstrap_user }}"
|
||||
bootstrap_harden_ssh: true
|
||||
handlers:
|
||||
- name: restart sshd
|
||||
ansible.builtin.service:
|
||||
name: ssh
|
||||
state: restarted
|
||||
tasks:
|
||||
- name: Key-only sshd drop-in
|
||||
# Named 01-* on purpose: sshd honors the FIRST value it reads per
|
||||
# keyword, and cloud-init images ship 50-cloud-init.conf that may
|
||||
# set PasswordAuthentication yes — we must sort before it.
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/ssh/sshd_config.d/01-vpnhub.conf
|
||||
content: |
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
PermitRootLogin no
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: bootstrap_harden_ssh | bool
|
||||
notify: restart sshd
|
||||
|
||||
- name: Validate full sshd config before the restart fires
|
||||
ansible.builtin.command: /usr/sbin/sshd -t
|
||||
when: bootstrap_harden_ssh | bool
|
||||
changed_when: false
|
||||
Reference in new issue
Block a user