Here is the list of playbooks itself (only 2 so far):
Playbook №1 - Creating a user with group membership, password setup, and SSH key
YAML
1---
2- name: User configuration
3 hosts: all
4 gather_facts: true
5 become: true
6
7 vars:
8 user_name: "ivan"
9 user_home: "/home/{{ user_name }}"
10 # Use 'openssl passwd -6' command to get password hash
11 user_password: "$6$k/YKu6N6imR5hAwF$/vodWuLNNnlkE9WjKOPYqanOuiCLZeW2Vhj0z66f7t0HQNfd6URhpEGvM6CyHSUnIFjTG7sY44iKyCD609QFT0"
12 user_groups: ["users", "adm", "sudo"]
13 user_shell: "/usr/bin/zsh"
14 user_ssh_pubkey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICJxrVhV4XaBZIxm4FWoCb+RlLkUqq4VCQxe4qepDcqh ivan@r4ven-me"
15
16 tasks:
17 - name: Create user with shell, groups and password
18 ansible.builtin.user:
19 name: "{{ user_name }}"
20 shell: "{{ user_shell }}"
21 groups: "{{ user_groups }}"
22 append: true
23 password: "{{ user_password }}"
24 skeleton: "/etc/skel"
25 when: [user_name, user_shell, user_groups, user_password]
26 tags: [user, user_create]
27
28 - name: User SSH configuration
29 block:
30 - name: Create user ssh directory
31 ansible.builtin.file:
32 path: "{{ user_home }}/.ssh/"
33 state: directory
34 owner: "{{ user_name }}"
35 group: "{{ user_name }}"
36 mode: "0700"
37
38 - name: Add user ssh public key
39 ansible.builtin.lineinfile:
40 path: "{{ user_home }}/.ssh/authorized_keys"
41 line: "{{ user_ssh_pubkey }}"
42 owner: "{{ user_name }}"
43 group: "{{ user_name }}"
44 mode: "0600"
45 create: true
46 when: [user_name, user_home, user_ssh_pubkey]
47 tags: [user, user_ssh]Description
The playbook performs the following actions:
- Creates a local user (
ivan) with the specified shell (/usr/bin/zsh); - Adds the user to the specified groups (
users,adm,sudo); - Sets a hashed password for the user (generated with the
openssl passwd -6command); - Creates the
.sshdirectory with the correct permissions (0700) and owner; - Adds the public SSH key specified in the
user_ssh_pubkeyvariable to theauthorized_keysfile.
Playbook №2 - System update and package installation (apt)
YAML
1---
2- name: System upgrade and packages installation
3 hosts: all
4 gather_facts: true
5 become: true
6 force_handlers: true
7
8 vars:
9 pkgs_upgrade: true
10 pkgs_list:
11 - "sudo"
12 - "vim"
13 - "ncat"
14 - "ncdu"
15 - "curl"
16 - "git"
17
18 tasks:
19 - name: Upgrade system and install packages
20 block:
21 - name: Upgrade system
22 ansible.builtin.apt:
23 upgrade: true # dist | full
24 update_cache: true
25 retries: 3
26 when: pkgs_upgrade
27 tags: [pkgs, pkgs_upgrade]
28
29 - name: Install packages
30 ansible.builtin.apt:
31 name: "{{ pkgs_list }}"
32 state: present
33 update_cache: true
34 retries: 3
35 notify:
36 - Remove useless packages
37 - Remove useless dependencies
38 # - Clean cache
39 when: pkgs_list
40 tags: [pkgs, pkgs_install]
41 when: ansible_distribution in ['Debian', 'Ubuntu']
42
43 handlers:
44 - name: Remove useless packages
45 ansible.builtin.apt:
46 autoclean: true
47
48 - name: Remove useless dependencies
49 ansible.builtin.apt:
50 autoremove: true
51
52 - name: Clean cache
53 ansible.builtin.apt:
54 clean: trueDescription
The playbook performs the following actions:
- Updates the APT package cache on hosts running Debian and Ubuntu;
- Performs a system update (installed packages) when the
pkgs_upgradevariable is enabled; - Installs the set of basic packages listed in the
pkgs_listvariable (sudo,vim,ncat,ncdu,curl,git); - After installing packages, runs system cleanup handlers:
- removes unused packages (
autoclean); - removes unused dependencies (
autoremove);
- removes unused packages (
Playbook №3 - SSH daemon configuration
YAML
1---
2- name: SSH deamon configuration
3 hosts: all
4 gather_facts: true
5 become: true
6 #force_handlers: true
7
8 vars:
9 ssh_config: "/etc/ssh/sshd_config"
10 ssh_params:
11 Port: "22"
12 AddressFamily: "inet"
13 PermitEmptyPasswords: "no"
14 PermitRootLogin: "no"
15 PubkeyAuthentication: "yes"
16 PasswordAuthentication: "no"
17
18 tasks:
19 - name: Configure SSH daemon
20 ansible.builtin.lineinfile:
21 path: "{{ ssh_config }}"
22 regexp: "^{{ item.key }}.*"
23 line: "{{ item.key }} {{ item.value }}"
24 validate: "/usr/sbin/sshd -t -f %s"
25 owner: "root"
26 group: "root"
27 mode: "0644"
28 backup: true
29 create: true
30 loop: "{{ ssh_params | dict2items }}"
31 notify: Restart sshd service
32 when: ssh_params
33 tags: ssh_daemon
34
35 handlers:
36 - name: Restart sshd service
37 ansible.builtin.systemd_service:
38 name: >-
39 {%- if ansible_facts['distribution'] == 'Debian' -%}
40 sshd
41 {%- elif ansible_facts['distribution'] == 'Ubuntu' -%}
42 ssh
43 {%- else -%}
44 ssh
45 {%- endif -%}
46 daemon_reload: true
47 state: restarted
48 enabled: trueDescription
✍️ The playbook performs the following actions:
- Defines a set of SSH daemon configuration parameters as a YAML dictionary;
- Applies SSH configuration parameters (
Port,PermitRootLogin,PasswordAuthentication, and others) to the/etc/ssh/sshd_configfile using thelineinfilemodule; - Ensures idempotency: each directive is either updated or added if absent;
- Checks the correctness (
validate) of the SSH configuration after each change before applying it; - If changes are successful, runs the handler to restart the
sshdservice.
🔍 Interesting points:
- Backup creation - when
/etc/ssh/sshd_configis changed, a backup copy of the file is automatically created (backup: true), which allows you to roll back quickly in case of errors; - Validation - before applying each change, the SSH configuration is checked with the
sshd -tcommand through thevalidateparameter, and incorrect edits are not applied; - Handler - restarting
sshduses additional handling with thejinja2templating engine, because different distributions use differentsystemdunit names.
Playbook №4 - Connecting an APT repository using Docker as an example
YAML
1---
2- name: Add repo and install Docker Engine
3 hosts: all
4 gather_facts: true
5 become: true
6
7 vars:
8 docker_apt_keyring_dir: "/etc/apt/keyrings"
9 docker_apt_gpg_filename: "docker.gpg"
10 docker_apt_gpg_url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg"
11 docker_apt_repo_url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}"
12
13 tasks:
14 - name: Install required packages
15 ansible.builtin.apt:
16 name:
17 - ca-certificates
18 - curl
19 - gnupg
20 - lsb-release
21 state: present
22 update_cache: true
23 retries: 3
24 tags: docker_prepare
25
26 - name: Create directory for apt keyrings
27 ansible.builtin.file:
28 path: "{{ docker_apt_keyring_dir }}"
29 state: directory
30 owner: root
31 group: root
32 mode: "0755"
33 tags: docker_keyring
34
35 - name: Download Docker GPG key
36 ansible.builtin.get_url:
37 url: "{{ docker_apt_gpg_url }}"
38 dest: "{{ docker_apt_keyring_dir }}/{{ docker_apt_gpg_filename }}"
39 mode: "0644"
40 force: false
41 tags: docker_gpg
42
43 - name: Add Docker apt repository
44 ansible.builtin.apt_repository:
45 repo: >
46 deb [signed-by={{ docker_apt_keyring_dir }}/{{ docker_apt_gpg_filename }}]
47 {{ docker_apt_repo_url }}
48 {{ ansible_distribution_release }} stable
49 state: present
50 update_cache: true
51 filename: docker
52 tags: docker_repo
53
54 - name: Install Docker packages
55 ansible.builtin.apt:
56 name:
57 - docker-ce
58 - docker-ce-cli
59 - containerd.io
60 - docker-buildx-plugin
61 - docker-compose-plugin
62 state: present
63 update_cache: true
64 retries: 3
65 tags: docker_install
66
67 - name: Enable and start Docker service
68 ansible.builtin.systemd:
69 name: docker
70 state: started
71 enabled: true
72 tags: docker_enableDescription
✍️ The playbook performs the following actions:
- Installs the required system packages for working with APT repositories (
ca-certificates,curl,gnupg,lsb-release); - Creates a directory for storing APT GPG keys (
/etc/apt/keyrings); - Downloads the official Docker GPG key and saves it in the key directory;
- Adds the official Docker APT repository using the downloaded GPG key for signing;
- Installs the main Docker packages (
docker-ce,docker-ce-cli,containerd.io, thebuildxandcomposeplugins); - After successful package installation, starts/configures autostart for the Docker Systemd service.
🔍 Interesting points:
- Dynamic configuration - uses Ansible facts (
ansible_distribution,ansible_distribution_release) to automatically determine the distribution and its version; - Key management - the Docker GPG key is downloaded and stored in
/etc/apt/keyrings, and the repository is added using thesigned-byoption; - APT retries - package installation tasks include
retries: 3for retrying in case of temporary network problems, short-term repository unavailability, or whenaptperforms periodic updates/checks on a schedule🤷♂️.
👨💻Ну и…
Don’t forget about our Telegram channel 📱 and chat 💬 All the best ✌️
That should be it. If not, check the logs 🙂


