diff --git a/roles/base_setup/tasks/main.yml b/roles/base_setup/tasks/main.yml index 3c59dae..228cb42 100644 --- a/roles/base_setup/tasks/main.yml +++ b/roles/base_setup/tasks/main.yml @@ -1,400 +1,408 @@ ---- -# ============================================================================= -# BASE SETUP ROLE -# ============================================================================= - -# ========== System Update ========== -- name: Update and upgrade apt packages (full upgrade) - apt: - upgrade: full - update_cache: yes - cache_valid_time: 3600 - become: yes - tags: [deploy_base, always] - -- name: Install base packages - apt: - name: "{{ base_packages }}" - state: present - update_cache: yes - become: yes - tags: [deploy_base, always] - -- name: Remove unused packages - apt: - autoremove: yes - autoclean: yes - become: yes - tags: [deploy_base] - -# ========== System Configuration ========== -- name: Disable IPv6 via sysctl - sysctl: - name: "{{ item.name }}" - value: "{{ item.value }}" - sysctl_set: yes - state: present - reload: yes - loop: - - { name: 'net.ipv6.conf.all.disable_ipv6', value: '1' } - - { name: 'net.ipv6.conf.default.disable_ipv6', value: '1' } - become: yes - tags: [deploy_base] - -- name: Ensure /root/.bashrc exists - file: - path: /root/.bashrc - state: touch - mode: '0644' - become: yes - tags: [deploy_base] - -- name: Add custom aliases and environment to ~/.bashrc - blockinfile: - path: /root/.bashrc - marker: "# {mark} ANSIBLE MANAGED BLOCK: CUSTOM ALIASES AND ENV" - block: | - # Работа с файлами - alias rm='rm -i' # Удалить с подтверждением - alias cp='cp -i' # Копировать с подтверждением - alias mv='mv -i' # Переместить с подтверждением - - # ls - вывод списка файлов - alias ls='ls --color=auto' # Цветной вывод - alias ll='ls -la' # Показывать скрытые файлы и представлять вывод в виде списка - alias l.='ls -d .* --color=auto' # Показать только скрытые файлы - - # mount - монтирование разделов - alias mount='mount | column -t' # Вывод mount читаемым - - # История - alias h='history' # История команд bash - alias c='clear' # Очистить окно терминала - - # Дата и время - alias now='date +%T' # Время сейчас - alias nowdate='date +%d-%m-%Y' # Только дата - - # Сеть - alias ping5='ping -c 5' # Посылать только пять запросов - alias ports='netstat -tulanp' # Открытые порты - - # Работа с пакетами - alias update='sudo apt update && sudo apt upgrade' # Обновление одной командой - - # Работа с системой - alias meminfo='free -m -l -t' # Сколько памяти занято - alias psmem='ps auxf | sort -nr -k 4 | head -10' # 10 процессов с самой большой нагрузкой на память - - # Переменные окружения - export DISPLAY="{{ x11_display_host }}:0" - export HISTTIMEFORMAT='%F %T ' - owner: root - mode: '0644' - become: yes - tags: [deploy_base] - -- name: Configure timezone - timezone: - name: "{{ timezone }}" - become: yes - tags: [deploy_base] - -- name: Configure locale - locale_gen: - name: "{{ system_locale }}" - state: present - become: yes - tags: [deploy_base] - -- name: Set default locale - lineinfile: - path: /etc/default/locale - line: "LANG={{ system_locale }}" - state: present - create: yes - become: yes - tags: [deploy_base] - -- name: Ensure required directories exist - file: - path: "{{ item }}" - state: directory - mode: '0755' - loop: "{{ custom_directories | default([]) }}" - become: yes - tags: [deploy_base] - -# ========== SSH Configuration ========== -- name: Ensure SSH directory exists for root - file: - path: /root/.ssh - state: directory - mode: '0700' - become: yes - tags: [deploy_base, ssh] - -- name: Add authorized keys for root (exclusive) - authorized_key: - user: root - state: present - key: "{{ item }}" - exclusive: yes - loop: "{{ ssh_public_keys }}" - become: yes - tags: [deploy_base, ssh] - -# ========== Create Admin User zailon ========== -- name: Create admin user zailon - user: - name: zailon - shell: /bin/bash - groups: sudo - append: yes - create_home: yes - state: present - become: yes - tags: [deploy_base, users] - -- name: Set password for zailon from vault - user: - name: zailon - password: "{{ vault_zailon_password | password_hash('sha512') }}" - update_password: always - become: yes - no_log: true - tags: [deploy_base, users] - -- name: Configure passwordless sudo for zailon - copy: - content: "zailon ALL=(ALL) NOPASSWD: ALL\n" - dest: /etc/sudoers.d/zailon - mode: '0440' - owner: root - group: root - validate: 'visudo -cf %s' - become: yes - tags: [deploy_base, users] - -- name: Create .ssh directory for zailon - file: - path: /home/zailon/.ssh - state: directory - mode: '0700' - owner: zailon - group: zailon - become: yes - tags: [deploy_base, users] - -- name: Deploy authorized_keys for zailon - copy: - content: "{{ ssh_public_keys | join('\n') }}\n" - dest: /home/zailon/.ssh/authorized_keys - owner: zailon - group: zailon - mode: '0600' - become: yes - tags: [deploy_base, users] - -- name: Copy bashrc to zailon - copy: - src: /root/.bashrc - dest: /home/zailon/.bashrc - owner: zailon - group: zailon - mode: '0644' - remote_src: yes - become: yes - tags: [deploy_base, users] - -# ========== SSH Security Hardening ========== -- name: Configure SSH security - lineinfile: - path: /etc/ssh/sshd_config - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - state: present - validate: 'sshd -t -f %s' - loop: - - { regexp: '^PasswordAuthentication', line: 'PasswordAuthentication no' } - - { regexp: '^PermitRootLogin', line: 'PermitRootLogin yes' } - - { regexp: '^PubkeyAuthentication', line: 'PubkeyAuthentication yes' } - notify: restart ssh - become: yes - tags: [deploy_base, ssh] - -# ========== Node Exporter Installation ========== -- name: Create node_exporter system user - user: - name: node_exporter - system: yes - shell: /bin/false - create_home: no - become: yes - tags: [node_exporter] - -- name: Set node_exporter architecture - set_fact: - node_exporter_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' if ansible_architecture == 'aarch64' else ansible_architecture }}" - tags: [node_exporter] - -- name: Download node_exporter - get_url: - url: "https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-{{ node_exporter_arch }}.tar.gz" - dest: /tmp/node_exporter.tar.gz - mode: '0644' - timeout: 60 - when: node_exporter_arch in ['amd64', 'arm64'] - become: yes - tags: [node_exporter] - -- name: Fail on unsupported architecture - fail: - msg: "Unsupported architecture {{ ansible_architecture }} for node_exporter" - when: node_exporter_arch not in ['amd64', 'arm64'] - tags: [node_exporter] - -- name: Create temporary extraction directory - file: - path: /tmp/node_exporter_temp - state: directory - mode: '0755' - become: yes - tags: [node_exporter] - -- name: Extract node_exporter - unarchive: - src: /tmp/node_exporter.tar.gz - dest: /tmp/node_exporter_temp - remote_src: yes - creates: /tmp/node_exporter_temp/node_exporter-1.8.2.linux-amd64/node_exporter - become: yes - tags: [node_exporter] - -- name: Install node_exporter binary - copy: - src: /tmp/node_exporter_temp/node_exporter-1.8.2.linux-amd64/node_exporter - dest: /usr/local/bin/node_exporter - owner: root - group: root - mode: '0755' - remote_src: yes - become: yes - notify: restart node_exporter - tags: [node_exporter] - -- name: Clean up temporary files - file: - path: "{{ item }}" - state: absent - loop: - - /tmp/node_exporter.tar.gz - - /tmp/node_exporter_temp - become: yes - tags: [node_exporter] - -- name: Create textfile collector directory - file: - path: /var/lib/node_exporter/textfile_collector - state: directory - owner: node_exporter - group: node_exporter - mode: '0755' - become: yes - tags: [node_exporter] - -- name: Deploy node_exporter systemd service - copy: - content: | - [Unit] - Description=Prometheus Node Exporter - Documentation=https://github.com/prometheus/node_exporter - After=network.target - - [Service] - Type=simple - User=node_exporter - Group=node_exporter - ExecStart=/usr/local/bin/node_exporter \ - --collector.systemd \ - --collector.processes \ - --collector.cpu \ - --collector.meminfo \ - --collector.diskstats \ - --collector.filesystem \ - --collector.loadavg \ - --collector.time \ - --collector.textfile.directory=/var/lib/node_exporter/textfile_collector \ - --no-collector.arp \ - --no-collector.netdev \ - --web.listen-address=0.0.0.0:9100 \ - --web.telemetry-path=/metrics - Restart=always - RestartSec=5 - - # Security settings - NoNewPrivileges=yes - ProtectSystem=strict - ProtectHome=yes - PrivateTmp=yes - ProtectControlGroups=yes - ProtectKernelModules=yes - ProtectKernelTunables=yes - LockPersonality=yes - RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX - - [Install] - WantedBy=multi-user.target - dest: /etc/systemd/system/node_exporter.service - owner: root - group: root - mode: '0644' - become: yes - notify: restart node_exporter - tags: [node_exporter] - -- name: Start and enable node_exporter - systemd: - name: node_exporter - state: started - enabled: yes - daemon_reload: yes - become: yes - tags: [node_exporter] - -- name: Wait for node_exporter to start - wait_for: - host: localhost - port: 9100 - timeout: 30 - state: started - delay: 5 - become: yes - tags: [node_exporter] - -- name: Verify node_exporter is responding - uri: - url: http://localhost:9100/metrics - status_code: 200 - timeout: 10 - register: node_exporter_check - become: yes - tags: [node_exporter] - -- name: Show node_exporter status - debug: - msg: "Node Exporter is running and responding on port 9100" - when: node_exporter_check.status == 200 - tags: [node_exporter] - -- name: Allow port 9100 in ufw (if enabled) - ufw: - rule: allow - port: 9100 - proto: tcp - comment: "Prometheus Node Exporter" - when: - - ansible_facts.services["ufw.service"] is defined - - ansible_facts.services["ufw.service"]["state"] == "running" - become: yes +--- +# ============================================================================= +# BASE SETUP ROLE +# ============================================================================= + +# ========== System Update ========== +- name: Update and upgrade apt packages (full upgrade) + apt: + upgrade: full + update_cache: yes + cache_valid_time: 3600 + become: yes + tags: [deploy_base, always] + +- name: Install base packages + apt: + name: "{{ base_packages }}" + state: present + update_cache: yes + become: yes + tags: [deploy_base, always] + +- name: Remove unused packages + apt: + autoremove: yes + autoclean: yes + become: yes + tags: [deploy_base] + +# ========== System Configuration ========== +- name: Disable IPv6 via sysctl + sysctl: + name: "{{ item.name }}" + value: "{{ item.value }}" + sysctl_set: yes + state: present + reload: yes + loop: + - { name: 'net.ipv6.conf.all.disable_ipv6', value: '1' } + - { name: 'net.ipv6.conf.default.disable_ipv6', value: '1' } + become: yes + tags: [deploy_base] + +- name: Ensure /root/.bashrc exists + file: + path: /root/.bashrc + state: touch + mode: '0644' + become: yes + tags: [deploy_base] + +- name: Add custom aliases and environment to ~/.bashrc + blockinfile: + path: /root/.bashrc + marker: "# {mark} ANSIBLE MANAGED BLOCK: CUSTOM ALIASES AND ENV" + block: | + # Работа с файлами + alias rm='rm -i' # Удалить с подтверждением + alias cp='cp -i' # Копировать с подтверждением + alias mv='mv -i' # Переместить с подтверждением + + # ls - вывод списка файлов + alias ls='ls --color=auto' # Цветной вывод + alias ll='ls -la' # Показывать скрытые файлы и представлять вывод в виде списка + alias l.='ls -d .* --color=auto' # Показать только скрытые файлы + + # mount - монтирование разделов + alias mount='mount | column -t' # Вывод mount читаемым + + # История + alias h='history' # История команд bash + alias c='clear' # Очистить окно терминала + + # Дата и время + alias now='date +%T' # Время сейчас + alias nowdate='date +%d-%m-%Y' # Только дата + + # Сеть + alias ping5='ping -c 5' # Посылать только пять запросов + alias ports='netstat -tulanp' # Открытые порты + + # Работа с пакетами + alias update='sudo apt update && sudo apt upgrade' # Обновление одной командой + + # Работа с системой + alias meminfo='free -m -l -t' # Сколько памяти занято + alias psmem='ps auxf | sort -nr -k 4 | head -10' # 10 процессов с самой большой нагрузкой на память + + # Переменные окружения + export DISPLAY="{{ x11_display_host }}:0" + export HISTTIMEFORMAT='%F %T ' + owner: root + mode: '0644' + become: yes + tags: [deploy_base] + +- name: Configure timezone + timezone: + name: "{{ timezone }}" + become: yes + tags: [deploy_base] + +- name: Configure locale + locale_gen: + name: "{{ system_locale }}" + state: present + become: yes + tags: [deploy_base] + +- name: Set default locale + lineinfile: + path: /etc/default/locale + line: "LANG={{ system_locale }}" + state: present + create: yes + become: yes + tags: [deploy_base] + +- name: Ensure required directories exist + file: + path: "{{ item }}" + state: directory + mode: '0755' + loop: "{{ custom_directories | default([]) }}" + become: yes + tags: [deploy_base] + +# ========== SSH Configuration ========== +- name: Ensure SSH directory exists for root + file: + path: /root/.ssh + state: directory + mode: '0700' + become: yes + tags: [deploy_base, ssh] + +- name: Add authorized keys for root (exclusive) + authorized_key: + user: root + state: present + key: "{{ item }}" + exclusive: yes + loop: "{{ ssh_public_keys }}" + become: yes + tags: [deploy_base, ssh] + +# ========== Create Admin User zailon ========== +- name: Create admin user zailon + user: + name: zailon + shell: /bin/bash + groups: sudo + append: yes + create_home: yes + state: present + become: yes + tags: [deploy_base, users] + +- name: Set password for zailon from vault + user: + name: zailon + password: "{{ vault_zailon_password | password_hash('sha512') }}" + update_password: always + become: yes + no_log: true + tags: [deploy_base, users] + +- name: Configure passwordless sudo for zailon + copy: + content: "zailon ALL=(ALL) NOPASSWD: ALL\n" + dest: /etc/sudoers.d/zailon + mode: '0440' + owner: root + group: root + validate: 'visudo -cf %s' + become: yes + tags: [deploy_base, users] + +- name: Create .ssh directory for zailon + file: + path: /home/zailon/.ssh + state: directory + mode: '0700' + owner: zailon + group: zailon + become: yes + tags: [deploy_base, users] + +- name: Deploy authorized_keys for zailon + copy: + content: "{{ ssh_public_keys | join('\n') }}\n" + dest: /home/zailon/.ssh/authorized_keys + owner: zailon + group: zailon + mode: '0600' + become: yes + tags: [deploy_base, users] + +- name: Copy bashrc to zailon + copy: + src: /root/.bashrc + dest: /home/zailon/.bashrc + owner: zailon + group: zailon + mode: '0644' + remote_src: yes + become: yes + tags: [deploy_base, users] + +# ========== SSH Security Hardening ========== +- name: Ensure privilege separation directory exists for sshd validation + file: + path: /run/sshd + state: directory + mode: '0755' + become: yes + tags: [deploy_base, ssh] + +- name: Configure SSH security + lineinfile: + path: /etc/ssh/sshd_config + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + state: present + validate: 'sshd -t -f %s' + loop: + - { regexp: '^PasswordAuthentication', line: 'PasswordAuthentication no' } + - { regexp: '^PermitRootLogin', line: 'PermitRootLogin yes' } + - { regexp: '^PubkeyAuthentication', line: 'PubkeyAuthentication yes' } + notify: restart ssh + become: yes + tags: [deploy_base, ssh] + +# ========== Node Exporter Installation ========== +- name: Create node_exporter system user + user: + name: node_exporter + system: yes + shell: /bin/false + create_home: no + become: yes + tags: [node_exporter] + +- name: Set node_exporter architecture + set_fact: + node_exporter_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' if ansible_architecture == 'aarch64' else ansible_architecture }}" + tags: [node_exporter] + +- name: Download node_exporter + get_url: + url: "https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-{{ node_exporter_arch }}.tar.gz" + dest: /tmp/node_exporter.tar.gz + mode: '0644' + timeout: 60 + when: node_exporter_arch in ['amd64', 'arm64'] + become: yes + tags: [node_exporter] + +- name: Fail on unsupported architecture + fail: + msg: "Unsupported architecture {{ ansible_architecture }} for node_exporter" + when: node_exporter_arch not in ['amd64', 'arm64'] + tags: [node_exporter] + +- name: Create temporary extraction directory + file: + path: /tmp/node_exporter_temp + state: directory + mode: '0755' + become: yes + tags: [node_exporter] + +- name: Extract node_exporter + unarchive: + src: /tmp/node_exporter.tar.gz + dest: /tmp/node_exporter_temp + remote_src: yes + creates: /tmp/node_exporter_temp/node_exporter-1.8.2.linux-amd64/node_exporter + become: yes + tags: [node_exporter] + +- name: Install node_exporter binary + copy: + src: /tmp/node_exporter_temp/node_exporter-1.8.2.linux-amd64/node_exporter + dest: /usr/local/bin/node_exporter + owner: root + group: root + mode: '0755' + remote_src: yes + become: yes + notify: restart node_exporter + tags: [node_exporter] + +- name: Clean up temporary files + file: + path: "{{ item }}" + state: absent + loop: + - /tmp/node_exporter.tar.gz + - /tmp/node_exporter_temp + become: yes + tags: [node_exporter] + +- name: Create textfile collector directory + file: + path: /var/lib/node_exporter/textfile_collector + state: directory + owner: node_exporter + group: node_exporter + mode: '0755' + become: yes + tags: [node_exporter] + +- name: Deploy node_exporter systemd service + copy: + content: | + [Unit] + Description=Prometheus Node Exporter + Documentation=https://github.com/prometheus/node_exporter + After=network.target + + [Service] + Type=simple + User=node_exporter + Group=node_exporter + ExecStart=/usr/local/bin/node_exporter \ + --collector.systemd \ + --collector.processes \ + --collector.cpu \ + --collector.meminfo \ + --collector.diskstats \ + --collector.filesystem \ + --collector.loadavg \ + --collector.time \ + --collector.textfile.directory=/var/lib/node_exporter/textfile_collector \ + --no-collector.arp \ + --no-collector.netdev \ + --web.listen-address=0.0.0.0:9100 \ + --web.telemetry-path=/metrics + Restart=always + RestartSec=5 + + # Security settings + NoNewPrivileges=yes + ProtectSystem=strict + ProtectHome=yes + PrivateTmp=yes + ProtectControlGroups=yes + ProtectKernelModules=yes + ProtectKernelTunables=yes + LockPersonality=yes + RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX + + [Install] + WantedBy=multi-user.target + dest: /etc/systemd/system/node_exporter.service + owner: root + group: root + mode: '0644' + become: yes + notify: restart node_exporter + tags: [node_exporter] + +- name: Start and enable node_exporter + systemd: + name: node_exporter + state: started + enabled: yes + daemon_reload: yes + become: yes + tags: [node_exporter] + +- name: Wait for node_exporter to start + wait_for: + host: localhost + port: 9100 + timeout: 30 + state: started + delay: 5 + become: yes + tags: [node_exporter] + +- name: Verify node_exporter is responding + uri: + url: http://localhost:9100/metrics + status_code: 200 + timeout: 10 + register: node_exporter_check + become: yes + tags: [node_exporter] + +- name: Show node_exporter status + debug: + msg: "Node Exporter is running and responding on port 9100" + when: node_exporter_check.status == 200 + tags: [node_exporter] + +- name: Allow port 9100 in ufw (if enabled) + ufw: + rule: allow + port: 9100 + proto: tcp + comment: "Prometheus Node Exporter" + when: + - ansible_facts.services["ufw.service"] is defined + - ansible_facts.services["ufw.service"]["state"] == "running" + become: yes tags: [node_exporter] \ No newline at end of file