refactor: bootstrap использует cluster_service_users вместо отдельного ansible-пользователя

Проблема: bootstrap создавал отдельного пользователя ansible (k3s_admin_user),
хотя у нас уже есть cluster_service_users с k8s и devops.

Решение:
- k3s_admin_user: devops (один из cluster_service_users, не отдельный пользователь)
- bootstrap phase 1: создаёт ВСЕХ пользователей из cluster_service_users через k8s-user role
- bootstrap phase 2: деплоит SSH ключ Ansible runner только в authorized_keys k3s_admin_user
- roles/bootstrap/tasks/main.yml: удалено создание пользователя/группы/sudoers (теперь в k8s-user)
- roles/bootstrap/defaults/main.yml: удалены k3s_admin_shell/comment/groups (не нужны)
- добавлена проверка: k3s_admin_user должен быть в cluster_service_users (assert)

group_vars/all/main.yml:
- ansible_user: "{{ k3s_admin_user }}" — все playbooks подключаются как k3s_admin_user
- ansible_ssh_private_key_file: "~/.ssh/id_rsa"
- k3s_admin_ssh_additional_keys: [] — для нескольких инженеров через vault

inventory/hosts.ini:
- убраны ansible_user=ubuntu с каждого хоста (теперь в group_vars)
- убран ansible_ssh_private_key_file из group vars (теперь в group_vars/all/main.yml)
This commit is contained in:
Sergey Antropoff
2026-04-24 07:18:57 +03:00
parent c6f3c60434
commit e99f1d5dfb
5 changed files with 98 additions and 97 deletions

View File

@@ -59,16 +59,24 @@ k3s_common_packages:
- tcpdump
- traceroute
# ─── Bootstrap (первичная настройка нод) ──────────────────────────────────────
# Пользователь, который создаётся при make bootstrap и используется для деплоя
k3s_admin_user: ansible
k3s_admin_shell: /bin/bash
# ─── Bootstrap первичная настройка нод ─────────────────────────────────────
# k3s_admin_user — ДОЛЖЕН быть одним из cluster_service_users.
# Используется для SSH-подключений Ansible после bootstrap.
# Пользователь создаётся bootstrap'ом через роль k8s-user.
k3s_admin_user: devops
# Файл SSH публичного ключа внутри контейнера (из примонтированного ~/.ssh)
# После bootstrap все playbook подключаются как k3s_admin_user
ansible_user: "{{ k3s_admin_user }}"
ansible_ssh_private_key_file: "~/.ssh/id_rsa"
# SSH публичный ключ Ansible-машины (монтируется в контейнер из ~/.ssh)
k3s_admin_ssh_public_key_files:
- /root/.ssh/id_ed25519.pub
# Отключить пароль SSH после деплоя ключа
# Дополнительные публичные ключи строками (для нескольких инженеров, из vault)
k3s_admin_ssh_additional_keys: []
# Отключить SSH вход по паролю после деплоя ключа (рекомендуется в prod)
k3s_admin_disable_password_auth: false
# Адрес для подключения новых нод — по умолчанию первый мастер (для initial install).

View File

@@ -2,34 +2,35 @@
# K3S HA кластер — inventory
# Мастера: k3s server с embedded etcd (участвуют в Raft-кворуме)
# Воркеры: k3s agent — только рабочие ноды, без etcd
#
# ansible_user НЕ указывается здесь — он берётся из group_vars:
# k3s_admin_user: devops → ansible_user: "{{ k3s_admin_user }}"
# Bootstrap подключается с паролем из host_vars/<node>/vault.yml
# ─────────────────────────────────────────────────────────────────────────────
[k3s_master]
master01 ansible_host=192.168.1.10 ansible_user=ubuntu
worker01 ansible_host=192.168.1.11 ansible_user=ubuntu
rpi01 ansible_host=192.168.1.12 ansible_user=pi ansible_python_interpreter=/usr/bin/python3
master01 ansible_host=192.168.1.10
worker01 ansible_host=192.168.1.11
rpi01 ansible_host=192.168.1.12 ansible_python_interpreter=/usr/bin/python3
# Дополнительные мастера — добавляй сюда:
# master04 ansible_host=192.168.1.14 ansible_user=ubuntu
# master04 ansible_host=192.168.1.14
[k3s_workers]
# Чистые воркеры (только k3s agent, без etcd) — добавляй сюда:
# worker04 ansible_host=192.168.1.14 ansible_user=ubuntu
# worker05 ansible_host=192.168.1.15 ansible_user=ubuntu
# worker04 ansible_host=192.168.1.14
# worker05 ansible_host=192.168.1.15
[k3s_cluster:children]
k3s_master
k3s_workers
[k3s_cluster:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa
# NFS сервер — по умолчанию master, но можно вынести на отдельную машину
[nfs_server]
master01
# Если NFS на отдельной машине — закомментируй строку выше и раскомментируй:
# nfshost ansible_host=192.168.1.20 ansible_user=ubuntu
# nfshost ansible_host=192.168.1.20
# ─────────────────────────────────────────────────────────────────────────────
# Лабораторные серверы (не входят в k3s кластер)

View File

@@ -1,29 +1,29 @@
---
# ─────────────────────────────────────────────────────────────────────────────
# Bootstrap — первоначальная настройка нод
# Bootstrap — первичная настройка нод
#
# Запускать ОДИН РАЗ перед make install.
# Подключается с начальными логином/паролем из vault (host_vars/<node>/vault.yml).
# Создаёт пользователя k3s_admin_user, раскладывает SSH ключ.
# После этого все playbook работают по ключу без пароля.
# Подключается с начальными логин/пароль из vault (host_vars/<node>/vault.yml).
#
# Использование:
# make bootstrap
# make bootstrap NODE=master01 — только одна нода
# Выполняет:
# 1. Создаёт всех пользователей из cluster_service_users (sudo, SSH dir)
# 2. Раскладывает SSH ключ Ansible runner в k3s_admin_user
# После этого все playbook работают по ключу без пароля.
#
# Требования vault (в host_vars/<node>/vault.yml для каждой ноды):
# bootstrap_user: ubuntu # начальный пользователь
# bootstrap_password: "секрет" # пароль SSH
# bootstrap_sudo_password: "секрет" # пароль sudo (часто тот же)
# k3s_admin_user — должен быть одним из cluster_service_users (см. group_vars).
# По умолчанию: devops
#
# Требования (host_vars/<node>/vault.yml для каждой ноды):
# bootstrap_user: ubuntu
# bootstrap_password: "пароль"
# ─────────────────────────────────────────────────────────────────────────────
- name: Bootstrap cluster nodes
# ── Фаза 1: Создать всех пользователей из cluster_service_users ──────────────
- name: "Bootstrap phase 1: create service users"
hosts: "{{ node_to_bootstrap | default('k3s_cluster') }}"
gather_facts: false
gather_facts: true
serial: 1
vars:
# Подключаемся с первоначальными credentials из vault каждой ноды
ansible_user: "{{ bootstrap_user }}"
ansible_password: "{{ bootstrap_password }}"
ansible_become_password: "{{ bootstrap_sudo_password | default(bootstrap_password) }}"
@@ -34,23 +34,57 @@
-o PubkeyAuthentication=no
pre_tasks:
- name: Validate bootstrap credentials are defined
- name: Validate bootstrap credentials
ansible.builtin.assert:
that:
- bootstrap_user is defined
- bootstrap_user | length > 0
- bootstrap_password is defined
- bootstrap_password | length > 0
- bootstrap_user is defined and bootstrap_user | length > 0
- bootstrap_password is defined and bootstrap_password | length > 0
fail_msg: >
Для {{ inventory_hostname }} не заданы bootstrap credentials.
Создай host_vars/{{ inventory_hostname }}/vault.yml с полями:
Создай host_vars/{{ inventory_hostname }}/vault.yml:
bootstrap_user: ubuntu
bootstrap_password: "пароль"
Зашифруй файл: ansible-vault encrypt host_vars/{{ inventory_hostname }}/vault.yml
Зашифруй: ansible-vault encrypt host_vars/{{ inventory_hostname }}/vault.yml
- name: Validate k3s_admin_user is in cluster_service_users
ansible.builtin.assert:
that:
- cluster_service_users | selectattr('name', 'equalto', k3s_admin_user) | list | length > 0
fail_msg: >
k3s_admin_user="{{ k3s_admin_user }}" не найден в cluster_service_users.
Добавь пользователя в список или измени k3s_admin_user в group_vars.
- name: Test initial SSH connection
ansible.builtin.ping:
register: ping_result
tasks:
- name: Create user {{ item.name }}
ansible.builtin.include_role:
name: k8s-user
tasks_from: create_user.yml
vars:
k8s_service_user: "{{ item.name }}"
k8s_service_user_comment: "{{ item.comment | default(item.name) }}"
k8s_service_user_shell: "{{ item.shell | default('/bin/bash') }}"
k8s_service_user_sudo: "{{ item.sudo | default(true) }}"
k8s_service_user_ssh_dir: "{{ item.ssh_dir | default('.ssh') }}"
loop: "{{ cluster_service_users }}"
loop_control:
label: "{{ item.name }}"
# ── Фаза 2: Задеплоить SSH ключ Ansible runner в k3s_admin_user ──────────────
- name: "Bootstrap phase 2: deploy Ansible runner SSH key"
hosts: "{{ node_to_bootstrap | default('k3s_cluster') }}"
gather_facts: false
serial: 1
vars:
ansible_user: "{{ bootstrap_user }}"
ansible_password: "{{ bootstrap_password }}"
ansible_become_password: "{{ bootstrap_sudo_password | default(bootstrap_password) }}"
ansible_ssh_common_args: >-
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o PasswordAuthentication=yes
-o PubkeyAuthentication=no
roles:
- role: bootstrap

View File

@@ -1,23 +1,17 @@
---
# ─── Bootstrap — создание пользователя и деплой SSH ключа ────────────────────
# Пользователь, который будет создан для управления кластером
k3s_admin_user: ansible
k3s_admin_shell: /bin/bash
k3s_admin_comment: "K3S Ansible Admin"
# Дополнительные группы для k3s_admin_user (sudo добавляется отдельно)
k3s_admin_groups: []
# ─── Bootstrap — деплой SSH ключа Ansible runner ─────────────────────────────
# Пользователь создаётся роль k8s-user (cluster_service_users), здесь только
# добавляется SSH ключ Ansible-машины в authorized_keys k3s_admin_user.
# Путь к SSH публичному ключу внутри контейнера (монтируется из ~/.ssh)
# Поддерживает несколько ключей — укажи список файлов или строк
# Поддерживает несколько ключей — укажи список файлов
k3s_admin_ssh_public_key_files:
- /root/.ssh/id_ed25519.pub
# Дополнительные публичные ключи (строки) — добавляются помимо файлов выше
# Дополнительные публичные ключи строками (из vault, для нескольких инженеров)
k3s_admin_ssh_additional_keys: []
# Отключить вход по паролю для SSH после деплоя ключа (рекомендуется)
# Отключить вход по паролю для SSH после деплоя ключа (рекомендуется в prod)
k3s_admin_disable_password_auth: false
# Перезапустить SSH после изменения конфигурации

View File

@@ -1,8 +1,9 @@
---
# ─────────────────────────────────────────────────────────────────────────────
# Bootstrap — создание пользователя для управления кластером + деплой SSH ключа
# Запускается один раз с первоначальными credentials (логин/пароль из vault)
# После этого все playbook работают через SSH ключ без пароля
# Bootstrap — деплой SSH ключа Ansible runner → k3s_admin_user
#
# Пользователь k3s_admin_user уже создан на предыдущем шаге (k8s-user role).
# Эта задача только добавляет публичный ключ Ansible-машины в authorized_keys.
# ─────────────────────────────────────────────────────────────────────────────
- name: Gather minimal facts
@@ -10,41 +11,7 @@
gather_subset:
- min
- name: Create admin group (if not exists)
ansible.builtin.group:
name: "{{ k3s_admin_user }}"
state: present
become: true
- name: Create k3s admin user
ansible.builtin.user:
name: "{{ k3s_admin_user }}"
comment: "{{ k3s_admin_comment }}"
shell: "{{ k3s_admin_shell }}"
groups: "{{ ([k3s_admin_user] + k3s_admin_groups) | unique }}"
append: true
create_home: true
state: present
become: true
- name: Configure passwordless sudo for admin user
ansible.builtin.copy:
dest: /etc/sudoers.d/{{ k3s_admin_user }}
content: "{{ k3s_admin_user }} ALL=(ALL) NOPASSWD:ALL\n"
mode: '0440'
validate: visudo -cf %s
become: true
- name: Ensure .ssh directory exists
ansible.builtin.file:
path: "/home/{{ k3s_admin_user }}/.ssh"
state: directory
owner: "{{ k3s_admin_user }}"
group: "{{ k3s_admin_user }}"
mode: '0700'
become: true
- name: Deploy SSH public keys from files
- name: Deploy SSH public keys from files to {{ k3s_admin_user }}
ansible.posix.authorized_key:
user: "{{ k3s_admin_user }}"
key: "{{ lookup('file', item) }}"
@@ -55,7 +22,7 @@
label: "{{ item | basename }}"
ignore_errors: true
- name: Deploy additional SSH public keys (from vault strings)
- name: Deploy additional SSH public keys (from vault strings) to {{ k3s_admin_user }}
ansible.posix.authorized_key:
user: "{{ k3s_admin_user }}"
key: "{{ item }}"
@@ -75,7 +42,7 @@
when: k3s_admin_disable_password_auth | bool
notify: Restart sshd
- name: Ensure PermitRootLogin is disabled
- name: Disable root SSH login
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin"
@@ -103,15 +70,12 @@
failed_when: false
when: k3s_admin_ssh_public_key_files | length > 0
- name: Show bootstrap result
- name: Bootstrap result for {{ inventory_hostname }}
ansible.builtin.debug:
msg: >
Нода {{ inventory_hostname }}:
Пользователь '{{ k3s_admin_user }}' создан.
SSH ключ задеплоен.
{{ inventory_hostname }}: SSH ключ задеплоен для '{{ k3s_admin_user }}'.
{% if ssh_test is defined and ssh_test.rc == 0 %}
✓ SSH вход по ключу подтверждён.
{% else %}
⚠ SSH вход по ключу не проверен (возможно, ключ ещё не в ssh-agent).
⚠ SSH ключ задеплоен, проверь вход вручную: ssh {{ k3s_admin_user }}@{{ ansible_host | default(inventory_hostname) }}
{% endif %}
Добавь в inventory: ansible_user={{ k3s_admin_user }}