Skip to content

ansible

install

# apt install ansible
$ ansible -i hosts_init playbook.yml --ask-become-password

hosts

hosts_sshd
---
servers:
  hosts:
    <HOSTNAME>:
      ansible_host: <IP>
      ansible_user: <USERNAME>
      ansible_private_key_file: ~/.ssh/<PRIVATE_KEY>
      ansible_port: 22
      apps:
        - name: test_app
          mode: dev
          version: "1.0"
          python_minor: 12
hosts_users
---
servers:
  hosts:
    <HOSTNAME>:
      ansible_host: <IP>
      ansible_user: <USERNAME>
      ansible_private_key_file: ~/.ssh/<PRIVATE_KEY>
      ansible_port: <SSHD_PORT>
hosts
---
servers:
  hosts:
    <HOSTNAME>:
      ansible_host: <IP>
      ansible_become_method: su
      ansible_become_exe: "su -"
      ansible_become_user: root
      ansible_user: <USERNAME>
      ansible_private_key_file: ~/.ssh/<PRIVATE_KEY>
      ansible_port: <SSHD_PORT>
      apps:
        - name: test_app
          mode: dev
          version: "1.0"
          python_minor: 12

system

sshd config

sshd.yml
---
- name: Change sshd config
  hosts: all
  become: true
  vars:
    sshd_config_path: "/etc/ssh/sshd_config"
    sshd_port: <PORT>

  tasks:
    - name: Update SSHD config to change port
      ansible.builtin.lineinfile:
        path: "{{ sshd_config_path }}"
        regexp: '^#?Port '
        line: "Port {{ sshd_port }}"
        state: present

    - name: Restart SSH service to apply changes
      ansible.builtin.service:
        name: ssh
        state: restarted

nftables

nftables.yml
---
- name: Configure nftables (+remove iptables)
  hosts: all
  become: true

  tasks:
    - name: Remove iptables if present
      ansible.builtin.package:
        name: iptables
        state: absent

    - name: Remove iptables-persistent if present
      ansible.builtin.package:
        name: iptables-persistent
        state: absent

    - name: Install nftables
      ansible.builtin.package:
        name: nftables
        state: present

    - name: Configure nftables rules
      ansible.builtin.template:
        src: templates/nftables_conf.j2
        dest: /etc/nftables.conf
        mode: '0644'

    - name: Enable nftables service
      ansible.builtin.systemd:
        name: nftables
        enabled: true
        state: started

    - name: Apply nftables rules
      ansible.builtin.command:
        cmd: nft -f /etc/nftables.conf
templates/nftables_conf.j2
table ip filter {
    chain INPUT {
        type filter hook input priority 0; policy drop;
        iifname "lo" counter accept
        {% for interface in ansible_facts['interfaces'] if 'lo' not in interface %}
        iifname "{{ interface }}" tcp dport 53 counter accept
        iifname "{{ interface }}" udp dport 53 counter accept
        iifname "{{ interface }}" tcp dport 80 counter accept
        iifname "{{ interface }}" tcp dport 443 counter accept
        iifname "{{ interface }}" tcp dport <SSHD_PORT> counter accept
        iifname "{{ interface }}" tcp dport smtp counter accept
        iifname "{{ interface }}" udp dport ntp counter accept
        iifname "{{ interface }}" icmp type echo-request counter accept
        iifname "{{ interface }}" ct state established,related counter accept
        iifname "{{ interface }}" counter log prefix "[NFTABLES IN] : " level debug
        {% endfor %}
    }

    chain FORWARD {
        type filter hook forward priority 0; policy drop;
        {% for interface in ansible_facts['interfaces'] if 'lo' not in interface %}
        iifname "{{ interface }}" counter log prefix "[NFTABLES FWD] : " level debug
        {% endfor %}
    }

    chain OUTPUT {
        type filter hook output priority 0; policy drop;
        oifname "lo" counter accept
        {% for interface in ansible_facts['interfaces'] if 'lo' not in interface %}
        oifname "{{ interface }}" udp dport ntp counter accept
        oifname "{{ interface }}" tcp dport domain counter accept
        oifname "{{ interface }}" udp dport domain counter accept
        oifname "{{ interface }}" tcp dport http counter accept
        oifname "{{ interface }}" tcp dport https counter accept
        oifname "{{ interface }}" tcp dport ssh counter accept
        oifname "{{ interface }}" tcp dport smtp counter accept
        oifname "{{ interface }}" tcp dport imaps counter accept
        oifname "{{ interface }}" tcp dport postgresql counter accept
        oifname "{{ interface }}" tcp dport <SSHD_PORT> counter accept
        oifname "{{ interface }}" ct state established,related counter accept
        oifname "{{ interface }}" icmp type echo-request counter accept
        oifname "{{ interface }}" counter log prefix "[NFTABLES OUT] : " level debug
        {% endfor %}
    }
}

setup users

users.yml
---
- name: Configure root/non-root users
  hosts: all
  become: true
  vars:
    new_root_pwd: <PASSWD>
    new_user: <NON_ROOT_USER>
    ssh_public_key: "{{ lookup('file', '~/.ssh/<FILE_PUBKEY>.pub') }}"

  tasks:
    - name: Set root password
      ansible.builtin.command:
        cmd: echo "root:{{ new_root_pwd }}" | chpasswd

    - name: Add new user
      ansible.builtin.user:
        name: "{{ new_user }}"
        shell: /bin/bash
        state: present

    - name: Create .ssh directory for the new user
      ansible.builtin.file:
        path: "/home/{{ new_user }}/.ssh"
        state: directory
        owner: "{{ new_user }}"
        group: "{{ new_user }}"
        mode: '0700'

    - name: Add public key to authorized_keys for the new user
      ansible.builtin.copy:
        dest: "/home/{{ new_user }}/.ssh/authorized_keys"
        content: "{{ ssh_public_key }}"
        owner: "{{ new_user }}"
        group: "{{ new_user }}"
        mode: '0600'

    - name: Remove sudo package
      ansible.builtin.package:
        name: sudo
        state: absent

remove "debian" user

remove_debian.yml
---
- name: Configure root/non-root users
  hosts: all
  become: true
    - name: Remove user debian
      ansible.builtin.user:
          name: "debian"
          state: absent

remove ipv6

sys_ipv6_off.yml
---
- name: Disable IPv6
  hosts: all
  become: yes
  tasks:
    - name: Disable IPv6
      ansible.builtin.lineinfile:
        path: /etc/sysctl.conf
        line: 'net.ipv6.conf.all.disable_ipv6 = 1'
        state: present
      notify:
        - Sysctl reload

  handlers:
    - name: Sysctl reload
      ansible.builtin.command:
        cmd: sysctl -p

postgreSQL

postgresql.yml
---
- name: Install and configure postgreSQL
  hosts: all
  become: yes

  tasks:
    - name: Update apt
      apt:
        update_cache: yes

    - name: Install package
      apt:
        name:
          - postgres
        state: present

uwsgi

uwsgi.yml
---
- name: Config uwsgi
  hosts: all
  become: yes

  tasks:
    - name: Create virtualenv directory
      ansible.builtin.file:
        path: /var/srvr/{{ item.name }}
        state: directory
        owner: {{ ansible_user }}
        group: {{ ansible_user }}
      loop: "{{ apps }}"

    - name: Create socket directory
      ansible.builtin.file:
        path: /var/uwsgi
        state: directory
        owner: nginx
        group: nginx

    - name: Check if sockets exist
      ansible.builtin.stat:
        path: /var/uwsgi/{{ item}}.socket
      loop: "{{ apps }}"
      register: sockets_stats

    - name: Create socket
      ansible.builtin.file:
        path: /var/uwsgi/{{ item.item.name }}.socket
        state: touch
        owner: nginx
        group: nginx
      when: not item.stat.exists
      loop: "{{ sockets_stats.results }}"

    - name: Check if log files exist
      ansible.builtin.stat:
        path: /var/log/uwsgi/{{ item.name }}.log
      loop: "{{ apps }}"
      register: logfiles_stats

    - name: Create log file
      ansible.builtin.file:
        path: /var/log/uwsgi/{{ item.item.name }}.log
        state: touch
        owner: nginx
        group: nginx
      when: not item.stat.exists
      loop: "{{ logfiles_stats.results }}"

    - name: Config emperor.ini
      ansible.builtin.template:
        src: /home/rico/ansible/templates/uwsgi_emperor.j2
        dest: /etc/uwsgi-emperor/emperor.ini
        owner: root
        group: root

    - name: Config app.ini
      ansible.builtin.template:
        src: /home/rico/ansible/templates/uwsgi_app.j2
        dest: /etc/uwsgi-emperor/vassals/{{ item.name }}.ini
      loop: "{{ apps }}"

templates

templates/uwsgi_emperor.j2
[uwsgi]
master = true
workers = {{ ansible_processor_vcpus }}
no-orphans = true
log-data = true
uid = nginx
gid = nginx
emperor = /etc/uwsgi-emperor/vassals
templates/uwsgi_app.j2
[uwsgi]
env = APP_HOST={{ ansible_hostname}}
env = APP_ENV={{ item.mode }}
env = APP_VERSION={{ item.version }}
virtualenv = /var/srvr/{{ item.name }}
chdir = /var/srvr/{{ item.name }}
socket = /var/uwsgi/{{ item.name }}.socket
plugins-dir = /usr/lib/uwsgi/plugins/
plugins = python3{{ python_minor }}
wsgi-file = main.py
callable = application
logto = /var/log/{{ item.name }}.log
stats = /tmp/stats_%n
{% if item.mode == 'dev' %}py-autoreload = 3{% endif %}