diff --git a/inventory b/inventory index 72fca4c..6c4afcb 100644 --- a/inventory +++ b/inventory @@ -4,6 +4,9 @@ gitea1.afpy.org [woodpeckers] woodpecker1.afpy.org +[muninservers] +deb2.afpy.org + [webservers] deb2.afpy.org diff --git a/munin.yml b/munin.yml new file mode 100644 index 0000000..5becaba --- /dev/null +++ b/munin.yml @@ -0,0 +1,44 @@ +- hosts: muninservers + vars: + nginx_domain: "munin.afpy.org" + nginx_certificates: ["{{ nginx_domain }}"] + nginx_conf: | + server + { + listen 80; + listen [::]:80; + server_name {{ nginx_domain }}; + return 301 https://$server_name$request_uri; + } + + server + { + listen 443 ssl; + listen [::]:443 ssl; + server_name {{ nginx_domain }}; + root /var/cache/munin/www; + index index.html; + + include snippets/letsencrypt-{{ nginx_domain }}.conf; + + location / { + try_files $uri $uri/ =404; + autoindex on; + } + + location ^~ /munin-cgi/munin-cgi-graph/ { + fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*); + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_pass unix:/var/run/munin/fcgi-graph.sock; + include fastcgi_params; + } + } + + roles: + - munin_server + - nginx + +- hosts: all + roles: + - common # For nftables's *_NEIGHBORS + - munin_client diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index 61b543e..e25e74d 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -1,124 +1,145 @@ --- -- block: - - name: Configure hostname - hostname: - name: "{{ inventory_hostname_short }}" +- name: Configure hostname + hostname: + name: "{{ inventory_hostname_short }}" - - name: Configure localhots - lineinfile: - path: /etc/hosts - regexp: '^127\.0\.0\.1' - line: "127.0.0.1 localhost" - owner: root - group: root - mode: 0644 +- name: Configure localhots + lineinfile: + path: /etc/hosts + regexp: '^127\.0\.0\.1' + line: "127.0.0.1 localhost" + owner: root + group: root + mode: 0644 - - name: Configure FQDN - lineinfile: - path: /etc/hosts - regexp: '^127\.0\.1\.1' - line: "127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname_short }}" - owner: root - group: root - mode: 0644 +- name: Configure FQDN + lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname_short }}" + owner: root + group: root + mode: 0644 - - package: name=nftables state=present +- name: Gather facts from all hosts + setup: + delegate_to: "{{ item }}" + delegate_facts: true + loop: "{{ groups['all'] }}" - - name: Copy nftables rules - copy: - content: | - #!/usr/sbin/nft -f +- package: name=nftables state=present - table inet filter - flush table inet filter +- name: Copy nftables rules + copy: + content: | + #!/usr/sbin/nft -f - table inet filter { - chain input { - type filter hook input priority 0; - iif lo accept - ct state established,related accept - icmp type echo-request counter accept - icmpv6 type echo-request counter accept + table inet filter + flush table inet filter - # accept neighbour discovery otherwise connectivity breaks: - icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept - tcp dport { ssh, http, https, smtp, imap2, imaps} ct state new accept - {{ nft_extra }} - counter drop - } - } + define V4_NEIGHBORS = { + {% for host in groups["all"] %} + {% if hostvars[host]['ansible_facts']['default_ipv4'] %} + {{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }}, # {{ hostvars[host]['ansible_facts']['nodename'] }} + {% endif %} + {% endfor %} + } - dest: /etc/nftables.conf - owner: root - group: root - mode: 0755 - notify: reload nftables + define V6_NEIGHBORS = { + {% for host in groups["all"] %} + {% if hostvars[host]['ansible_facts']['default_ipv6'] %} + {{ hostvars[host]['ansible_facts']['default_ipv6']['address'] }}, # {{ hostvars[host]['ansible_facts']['nodename'] }} + {% endif %} + {% endfor %} + } - - service: name=nftables enabled=yes state=started daemon_reload=yes + table inet filter { + chain input { + type filter hook input priority 0; + iif lo accept + ct state established,related accept + icmp type echo-request counter accept + icmpv6 type echo-request counter accept + ip saddr $V4_NEIGHBORS accept + ip6 saddr $V6_NEIGHBORS accept - - name: Update via apt (mandatory on first run) - apt: - update_cache: yes - cache_valid_time: 86400 + # accept neighbour discovery otherwise connectivity breaks: + icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept + tcp dport { ssh, http, https, smtp, imap2, imaps} ct state new accept + {{ nft_extra }} + counter drop + } + } - - name: Install some usefull packages - apt: - state: present - name: - - aptitude - - emacs-nox - - fail2ban - - git - - htop - - man - - ncdu - - needrestart - - ntp - - python3 - - python3-dev - - python3-pip - - python3-setuptools - - python3-venv - - python3-wheel - - rsync - - sudo - - tcpdump - - vim-nox + dest: /etc/nftables.conf + owner: root + group: root + mode: 0755 + notify: reload nftables - - name: Set authorized SSH keys for root user - blockinfile: - content: "{{ root_authorized_keys }}" - dest: /root/.ssh/authorized_keys - mode: 0600 - owner: root - group: root - marker: "# {mark} ANSIBLE MANAGED BLOCK (SSH keys for root user)" +- service: name=nftables enabled=yes state=started daemon_reload=yes - - name: Ensure mlocate and locate are not installed - apt: - name: ["mlocate", "locate"] - state: absent +- name: Update via apt (mandatory on first run) + apt: + update_cache: yes + cache_valid_time: 86400 - # From https://infosec.mozilla.org/guidelines/openssh - - name: SSHd hardening - blockinfile: - marker: "# {mark} ANSIBLE MANAGED BLOCK (KexAlgorithms, Ciphers, MACs)" - path: /etc/ssh/sshd_config - state: present - create: true - block: | - KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 - Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr - MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com +- name: Install some usefull packages + apt: + state: present + name: + - aptitude + - emacs-nox + - fail2ban + - git + - htop + - man + - ncdu + - needrestart + - ntp + - python3 + - python3-dev + - python3-pip + - python3-setuptools + - python3-venv + - python3-wheel + - rsync + - sudo + - tcpdump + - vim-nox - HostKey /etc/ssh/ssh_host_ed25519_key - HostKey /etc/ssh/ssh_host_rsa_key - HostKey /etc/ssh/ssh_host_ecdsa_key +- name: Set authorized SSH keys for root user + blockinfile: + content: "{{ root_authorized_keys }}" + dest: /root/.ssh/authorized_keys + mode: 0600 + owner: root + group: root + marker: "# {mark} ANSIBLE MANAGED BLOCK (SSH keys for root user)" - AuthenticationMethods publickey - LogLevel VERBOSE - notify: restart sshd - tags: ssh +- name: Ensure mlocate and locate are not installed + apt: + name: ["mlocate", "locate"] + state: absent - tags: common +# From https://infosec.mozilla.org/guidelines/openssh +- name: SSHd hardening + blockinfile: + marker: "# {mark} ANSIBLE MANAGED BLOCK (KexAlgorithms, Ciphers, MACs)" + path: /etc/ssh/sshd_config + state: present + create: true + block: | + KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 + Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com + + HostKey /etc/ssh/ssh_host_ed25519_key + HostKey /etc/ssh/ssh_host_rsa_key + HostKey /etc/ssh/ssh_host_ecdsa_key + + AuthenticationMethods publickey + LogLevel VERBOSE + notify: restart sshd + tags: ssh diff --git a/roles/munin_client/handlers/main.yml b/roles/munin_client/handlers/main.yml new file mode 100644 index 0000000..cd5ea5b --- /dev/null +++ b/roles/munin_client/handlers/main.yml @@ -0,0 +1,4 @@ +--- + +- name: munin + service: name=munin-node state=restarted diff --git a/roles/munin_client/tasks/main.yml b/roles/munin_client/tasks/main.yml new file mode 100644 index 0000000..c391448 --- /dev/null +++ b/roles/munin_client/tasks/main.yml @@ -0,0 +1,50 @@ +--- + +- name: apt install munin-node + apt: + state: present + name: munin-node + register: install_munin + +- name: Configure munin node + shell: munin-node-configure --shell | grep -v ip_ | sh + when: install_munin is changed + notify: munin + +- name: Copy munin-node.conf + copy: + dest: /etc/munin/munin-node.conf + content: | + log_level 4 + log_file /var/log/munin/munin-node.log + pid_file /var/run/munin/munin-node.pid + + background 1 + setsid 1 + + user root + group root + + ignore_file [\#~]$ + ignore_file DEADJOE$ + ignore_file \.bak$ + ignore_file %$ + ignore_file \.dpkg-(tmp|new|old|dist)$ + ignore_file \.rpm(save|new)$ + ignore_file \.pod$ + + {% for host in groups["muninservers"] %} + allow ^{{ hostvars[host]['ansible_facts']['default_ipv6']['address'] }}$ + {% endfor %} + allow ^127.0.0.1$ + + host * + port 4949 + notify: munin + +- name: Cron for munin apt_all + cron: + name: "apt update" + hour: "*/4" + minute: "28" + job: "/usr/bin/apt-get update > /dev/null" diff --git a/roles/munin_server/tasks/main.yml b/roles/munin_server/tasks/main.yml new file mode 100644 index 0000000..cde2320 --- /dev/null +++ b/roles/munin_server/tasks/main.yml @@ -0,0 +1,15 @@ +--- + +- name: Install munin + apt: + state: present + name: munin + +- name: Gather facts from all hosts + setup: + delegate_to: "{{ item }}" + delegate_facts: true + loop: "{{ groups['all'] }}" + +- name: Configure munin + template: src=munin.conf.j2 dest=/etc/munin/munin.conf diff --git a/roles/munin_server/templates/munin.conf.j2 b/roles/munin_server/templates/munin.conf.j2 new file mode 100644 index 0000000..1e4eb3b --- /dev/null +++ b/roles/munin_server/templates/munin.conf.j2 @@ -0,0 +1,17 @@ +dbdir /var/lib/munin +htmldir /var/cache/munin/www +logdir /var/log/munin +rundir /var/run/munin + +contact.email.command mail -s "Munin-notification for ${var:group} :: ${var:host}" {{ admin_email }} + +tmpldir /etc/munin/templates + +graph_width 600 +graph_height 400 +max_graph_jobs 2 + +{% for host in groups["all"] %} +[{{ hostvars[host]['inventory_hostname'] }}] +address [{{ hostvars[host]['ansible_facts']['default_ipv6']['address'] }}] +{% endfor %}