diff --git a/.gitignore b/.gitignore index 697bfb9..86a17cd 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,9 @@ id_rsa id_ed25519 id_ecdsa -# Локально сохранённые ключи k8s пользователя (публичный ключ — ок коммитить) +# Локально сохранённые приватные ключи (публичные ключи *_id_rsa.pub — ок коммитить) keys/k8s_id_rsa +keys/devops_id_rsa # Docker артефакты .docker/ diff --git a/group_vars/all/main.yml b/group_vars/all/main.yml index 5cf802e..aa83486 100644 --- a/group_vars/all/main.yml +++ b/group_vars/all/main.yml @@ -207,8 +207,18 @@ k8s_service_user_key_comment: "k8s@cluster" k8s_service_user_ssh_dir: ".ssh" k8s_service_user_sudo: true -# Локальная директория для сохранения сгенерированных SSH ключей k8s пользователя +# ─── devops-user ────────────────────────────────────────────────────────────── +# Дополнительный пользователь для инженеров DevOps +# Создаётся на тех же серверах что и k8s, та же RSA 4096 схема с ключами +devops_service_user: devops +devops_service_user_shell: /bin/bash +devops_service_user_comment: "DevOps Engineer" +devops_service_user_key_comment: "devops@cluster" +devops_service_user_sudo: true + +# Локальная директория для сохранения сгенерированных SSH ключей # Сохраняется на машине запуска Ansible (./keys/ относительно корня проекта) +# Файлы: keys/k8s_id_rsa, keys/k8s_id_rsa.pub, keys/devops_id_rsa, keys/devops_id_rsa.pub k8s_local_keys_dir: "./keys" # ─── k3s-certs — автоматическая ротация сертификатов K3S ───────────────────── diff --git a/playbooks/k8s-user.yml b/playbooks/k8s-user.yml index 049ef00..2c1c152 100644 --- a/playbooks/k8s-user.yml +++ b/playbooks/k8s-user.yml @@ -1,9 +1,13 @@ --- # ───────────────────────────────────────────────────────────────────────────── -# k8s-user: создание сервисного пользователя k8s на всех серверах +# k8s-user: создание сервисных пользователей на всех серверах # -# Последовательность: -# 1. Создать пользователя k8s + sudo на всех нодах кластера +# Роль k8s-user универсальна — вызывается дважды: +# • для пользователя k8s (автоматизация кластера) +# • для пользователя devops (инженеры DevOps) +# +# Для каждого пользователя: +# 1. Создать пользователя + sudo на всех нодах кластера # 2. Сгенерировать RSA 4096 ключевую пару на первом мастере (один раз) # 3. Сохранить ключи локально в ./keys/ # 4. Разложить ключи на все ноды кластера (SSH в любую сторону) @@ -11,32 +15,36 @@ # 6. То же самое для lab_hosts (через пароль из vault) # # Запуск: ansible-playbook playbooks/k8s-user.yml --ask-vault-pass -# Только кластер: ansible-playbook playbooks/k8s-user.yml --limit k3s_cluster +# Только один пользователь: ansible-playbook playbooks/k8s-user.yml --tags k8s # ───────────────────────────────────────────────────────────────────────────── -# ── 1. Создать пользователя k8s на всех нодах кластера ─────────────────────── -- name: Create k8s service user on cluster nodes +# ════════════════════════════════════════════════════════════════════════════ +# ПОЛЬЗОВАТЕЛЬ k8s +# ════════════════════════════════════════════════════════════════════════════ + +- name: "[k8s] Create service user on cluster nodes" hosts: k3s_cluster gather_facts: true become: true + tags: [k8s, k8s_user] roles: - role: k8s-user -# ── 2. Сгенерировать ключевую пару на первом мастере ───────────────────────── -- name: Generate k8s SSH key pair (first master only) +- name: "[k8s] Generate SSH key pair (first master only)" hosts: "{{ groups['k3s_master'][0] }}" gather_facts: false become: true + tags: [k8s, k8s_user] tasks: - name: Generate RSA key pair and store facts ansible.builtin.include_role: name: k8s-user tasks_from: generate_keys.yml -# ── 3. Сохранить ключи локально в ./keys/ ──────────────────────────────────── -- name: Save k8s SSH keys to local machine +- name: "[k8s] Save SSH keys to local machine" hosts: "{{ groups['k3s_master'][0] }}" gather_facts: false + tags: [k8s, k8s_user] tasks: - name: Create local keys directory ansible.builtin.file: @@ -48,52 +56,51 @@ - name: Save private key locally ansible.builtin.copy: - content: "{{ k8s_ssh_private_key }}" - dest: "{{ k8s_local_keys_dir }}/k8s_id_rsa" + content: "{{ lookup('vars', k8s_service_user + '_ssh_private_key') }}" + dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa" mode: '0600' delegate_to: localhost become: false - name: Save public key locally ansible.builtin.copy: - content: "{{ k8s_ssh_public_key }}\n" - dest: "{{ k8s_local_keys_dir }}/k8s_id_rsa.pub" + content: "{{ lookup('vars', k8s_service_user + '_ssh_public_key') }}\n" + dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa.pub" mode: '0644' delegate_to: localhost become: false - name: Show where keys were saved ansible.builtin.debug: - msg: "SSH keys saved to {{ k8s_local_keys_dir }}" + msg: "SSH keys saved to {{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa" -# ── 4. Разложить ключи на все ноды кластера ────────────────────────────────── -- name: Distribute k8s SSH keys to all cluster nodes +- name: "[k8s] Distribute SSH keys to all cluster nodes" hosts: k3s_cluster gather_facts: false become: true + tags: [k8s, k8s_user] tasks: - name: Deploy keys to node ansible.builtin.include_role: name: k8s-user tasks_from: distribute_keys.yml -# ── 5. Обновить /etc/hosts на нодах кластера ───────────────────────────────── -- name: Update /etc/hosts on cluster nodes +- name: "[k8s] Update /etc/hosts on cluster nodes" hosts: k3s_cluster gather_facts: false become: true + tags: [k8s, k8s_user] tasks: - name: Update hosts file ansible.builtin.include_role: name: k8s-user tasks_from: update_hosts.yml -# ── 6. Bootstrap lab_hosts: создать пользователя, разложить ключи, обновить hosts -# Подключение через логин/пароль из host_vars//vault.yml -- name: Setup k8s user on lab hosts +- name: "[k8s] Setup user on lab hosts" hosts: lab_hosts gather_facts: true become: true + tags: [k8s, k8s_user] vars: ansible_user: "{{ bootstrap_user }}" ansible_password: "{{ bootstrap_password }}" @@ -103,17 +110,133 @@ -o PasswordAuthentication=yes -o PubkeyAuthentication=no tasks: - - name: Create k8s user on lab host - ansible.builtin.include_role: + - ansible.builtin.include_role: name: k8s-user tasks_from: create_user.yml + - ansible.builtin.include_role: + name: k8s-user + tasks_from: distribute_keys.yml + - ansible.builtin.include_role: + name: k8s-user + tasks_from: update_hosts.yml - - name: Distribute k8s SSH keys to lab host +# ════════════════════════════════════════════════════════════════════════════ +# ПОЛЬЗОВАТЕЛЬ devops +# ════════════════════════════════════════════════════════════════════════════ + +- name: "[devops] Create service user on cluster nodes" + hosts: k3s_cluster + gather_facts: true + become: true + tags: [devops, devops_user] + vars: + k8s_service_user: "{{ devops_service_user }}" + k8s_service_user_comment: "{{ devops_service_user_comment }}" + k8s_service_user_key_comment: "{{ devops_service_user_key_comment }}" + k8s_service_user_sudo: "{{ devops_service_user_sudo }}" + k8s_service_user_shell: "{{ devops_service_user_shell }}" + roles: + - role: k8s-user + +- name: "[devops] Generate SSH key pair (first master only)" + hosts: "{{ groups['k3s_master'][0] }}" + gather_facts: false + become: true + tags: [devops, devops_user] + vars: + k8s_service_user: "{{ devops_service_user }}" + tasks: + - name: Generate RSA key pair and store facts + ansible.builtin.include_role: + name: k8s-user + tasks_from: generate_keys.yml + +- name: "[devops] Save SSH keys to local machine" + hosts: "{{ groups['k3s_master'][0] }}" + gather_facts: false + tags: [devops, devops_user] + vars: + k8s_service_user: "{{ devops_service_user }}" + tasks: + - name: Create local keys directory + ansible.builtin.file: + path: "{{ k8s_local_keys_dir }}" + state: directory + mode: '0700' + delegate_to: localhost + become: false + + - name: Save private key locally + ansible.builtin.copy: + content: "{{ lookup('vars', k8s_service_user + '_ssh_private_key') }}" + dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa" + mode: '0600' + delegate_to: localhost + become: false + + - name: Save public key locally + ansible.builtin.copy: + content: "{{ lookup('vars', k8s_service_user + '_ssh_public_key') }}\n" + dest: "{{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa.pub" + mode: '0644' + delegate_to: localhost + become: false + + - name: Show where keys were saved + ansible.builtin.debug: + msg: "SSH keys saved to {{ k8s_local_keys_dir }}/{{ k8s_service_user }}_id_rsa" + +- name: "[devops] Distribute SSH keys to all cluster nodes" + hosts: k3s_cluster + gather_facts: false + become: true + tags: [devops, devops_user] + vars: + k8s_service_user: "{{ devops_service_user }}" + tasks: + - name: Deploy keys to node ansible.builtin.include_role: name: k8s-user tasks_from: distribute_keys.yml - - name: Update /etc/hosts on lab host +- name: "[devops] Update /etc/hosts on cluster nodes" + hosts: k3s_cluster + gather_facts: false + become: true + tags: [devops, devops_user] + vars: + k8s_service_user: "{{ devops_service_user }}" + tasks: + - name: Update hosts file ansible.builtin.include_role: name: k8s-user tasks_from: update_hosts.yml + +- name: "[devops] Setup user on lab hosts" + hosts: lab_hosts + gather_facts: true + become: true + tags: [devops, devops_user] + vars: + k8s_service_user: "{{ devops_service_user }}" + k8s_service_user_comment: "{{ devops_service_user_comment }}" + k8s_service_user_key_comment: "{{ devops_service_user_key_comment }}" + k8s_service_user_sudo: "{{ devops_service_user_sudo }}" + k8s_service_user_shell: "{{ devops_service_user_shell }}" + 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 PasswordAuthentication=yes + -o PubkeyAuthentication=no + tasks: + - ansible.builtin.include_role: + name: k8s-user + tasks_from: create_user.yml + - ansible.builtin.include_role: + name: k8s-user + tasks_from: distribute_keys.yml + - ansible.builtin.include_role: + name: k8s-user + tasks_from: update_hosts.yml diff --git a/roles/k8s-user/tasks/distribute_keys.yml b/roles/k8s-user/tasks/distribute_keys.yml index 1e076c3..b1927b7 100644 --- a/roles/k8s-user/tasks/distribute_keys.yml +++ b/roles/k8s-user/tasks/distribute_keys.yml @@ -2,27 +2,27 @@ # Раскладывает приватный и публичный ключ k8s пользователя на текущий хост # Ключи берутся из hostvars первого мастера (сгенерированы там play'ем generate_keys) -- name: Deploy private key to k8s user +- name: Deploy private key to {{ k8s_service_user }} user ansible.builtin.copy: - content: "{{ hostvars[groups['k3s_master'][0]]['k8s_ssh_private_key'] }}" + content: "{{ hostvars[groups['k3s_master'][0]][k8s_service_user + '_ssh_private_key'] }}" dest: "/home/{{ k8s_service_user }}/{{ k8s_service_user_ssh_dir }}/id_rsa" owner: "{{ k8s_service_user }}" group: "{{ k8s_service_user }}" mode: '0600' become: true -- name: Deploy public key to k8s user +- name: Deploy public key to {{ k8s_service_user }} user ansible.builtin.copy: - content: "{{ hostvars[groups['k3s_master'][0]]['k8s_ssh_public_key'] }}\n" + content: "{{ hostvars[groups['k3s_master'][0]][k8s_service_user + '_ssh_public_key'] }}\n" dest: "/home/{{ k8s_service_user }}/{{ k8s_service_user_ssh_dir }}/id_rsa.pub" owner: "{{ k8s_service_user }}" group: "{{ k8s_service_user }}" mode: '0644' become: true -- name: Add k8s public key to authorized_keys +- name: Add {{ k8s_service_user }} public key to authorized_keys ansible.posix.authorized_key: user: "{{ k8s_service_user }}" - key: "{{ hostvars[groups['k3s_master'][0]]['k8s_ssh_public_key'] }}" + key: "{{ hostvars[groups['k3s_master'][0]][k8s_service_user + '_ssh_public_key'] }}" state: present become: true diff --git a/roles/k8s-user/tasks/generate_keys.yml b/roles/k8s-user/tasks/generate_keys.yml index 5b9b404..499819a 100644 --- a/roles/k8s-user/tasks/generate_keys.yml +++ b/roles/k8s-user/tasks/generate_keys.yml @@ -45,6 +45,6 @@ - name: Store key content as persistent facts (доступны во всех последующих plays) ansible.builtin.set_fact: - k8s_ssh_private_key: "{{ k8s_private_key_raw.content | b64decode }}" - k8s_ssh_public_key: "{{ k8s_public_key_raw.content | b64decode | trim }}" + "{{ k8s_service_user }}_ssh_private_key": "{{ k8s_private_key_raw.content | b64decode }}" + "{{ k8s_service_user }}_ssh_public_key": "{{ k8s_public_key_raw.content | b64decode | trim }}" cacheable: true