Linux Hardening Using Ansible
Table of Contents
Lets autotmate what was discussed in previous posts.
Feature
Any of this list can be enabled or disabled and is group as roles. User Management
- User and Group Creation
- Add user to group
- Add user public key
- Option to add to sudo/wheel group
- Set user password aging
Access Control
- Disable root access through SSH
- Disable password authentication
- Set maximum simultaneous login
- Add SSH Login Banner
- Set password complexity
- Enable firewall and add SSH
Package Management
- Update repo and upgrade current package
- Enable automatic install/upgrade security package
- Enable fail2ban
- Enable logrotate
- Enable NTP/Chrony
- Disable unnecessary package
System Hardening
- Removed development pacakge
- Make security dir immutable
- Enable system audit
- Enable Advanced Intrusion Detection Environment
- Kernel hardening
sysctl - Ensure sudo use password and uses log
SSH Login Alert (Bonus)
- Send alert to telegram bot when user login
Environment
I’ve dockerized ansible - tailored to the specific task. Check Dockerfile if you want to run it locally.
First clone the repo.
1git clone https://github.com/mcbtaguiad/libvirt-cloudinit-ansible.git
Build the package or just pull the image from gihub registry.
1cd linux-hardening-playbook
2docker compose build
3docker compose up -d
4
5# or
6docker compose up -d
Configuration
Inventory
This will use sudo so set ansible_user to root or a user with root access.
inventory/hosts.ini
1[all]
2server01 ansible_host=192.168.254.101 ansible_user=mcbtaguiad
3server02 ansible_host=192.168.254.102 ansible_user=mcbtaguiad
4
5[debian-server]
6server01 ansible_host=192.168.254.101 ansible_user=mcbtaguiad
7
8[redhat-server]
9server02 ansible_host=192.168.254.102 ansible_user=mcbtaguiad
Playbook
Run individual role or just run the main playbook.
main.yaml
1---
2- name: main playbook
3 hosts: all
4 become: true # use sudo for all tasks
5 become_method: sudo
6 # ansible_become_pass: "YOUR_SUDO_PASSWORD"
7 roles:
8 - role: user_management
9 vars:
10 password_maxdays: 90
11 password_warndays: 7
12 users:
13 - name: mark
14 sudo: true
15 key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDtf3e9lQR1uAypz4nrq2nDj0DvZZGONku5wO+M87wUVTistrY8REsWO2W1N/v4p2eX30Bnwk7D486jmHGpXFrpHM0EMf7wtbNj5Gt1bDHo76WSci/IEHpMrbdD5vN8wCW2ZMwJG4JC8lfFpUbdmUDWLL21Quq4q9XDx7/ugs1tCZoNybgww4eCcAi7/GAmXcS/u9huUkyiX4tbaKXQx1co7rTHd7f2u5APTVMzX0C1V9Ezc6l8I+LmjZ9rvQav5N1NgFh9B60qk9QJAb8AK9+aYy7bnBCBJ/BwIkWKYmLoVBi8j8v8UVhVdQMvQxLax41YcD8pbgU5s1O2nxM1+TqeGxrGHG6f7jqxhGWe21I7i8HPvOHNJcW4oycxFC5PNKnXNybEawE23oIDQfIG3+EudQKfAkJ3YhmrB2l+InIo0Wi9BHBIUNPzTldMS53q2teNdZR9UDqASdBdMgp4Uzfs1+LGdE5ExecSQzt4kZ8+o9oo9hmee4AYNOTWefXdip0= mtaguiad@tags-p51"
16 groups:
17 - admins
18 - developers
19 - name: christian
20 sudo: false
21 key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDtf3e9lQR1uAypz4nrq2nDj0DvZZGONku5wO+M87wUVTistrY8REsWO2W1N/v4p2eX30Bnwk7D486jmHGpXFrpHM0EMf7wtbNj5Gt1bDHo76WSci/IEHpMrbdD5vN8wCW2ZMwJG4JC8lfFpUbdmUDWLL21Quq4q9XDx7/ugs1tCZoNybgww4eCcAi7/GAmXcS/u9huUkyiX4tbaKXQx1co7rTHd7f2u5APTVMzX0C1V9Ezc6l8I+LmjZ9rvQav5N1NgFh9B60qk9QJAb8AK9+aYy7bnBCBJ/BwIkWKYmLoVBi8j8v8UVhVdQMvQxLax41YcD8pbgU5s1O2nxM1+TqeGxrGHG6f7jqxhGWe21I7i8HPvOHNJcW4oycxFC5PNKnXNybEawE23oIDQfIG3+EudQKfAkJ3YhmrB2l+InIo0Wi9BHBIUNPzTldMS53q2teNdZR9UDqASdBdMgp4Uzfs1+LGdE5ExecSQzt4kZ8+o9oo9hmee4AYNOTWefXdip0= mtaguiad@tags-p51"
22 groups:
23 - developers
24
25 - role: access_control
26 vars:
27 max_logins: 2
28 password_minlen: 12
29
30 - role: package
31 vars:
32 unnecessary_services:
33 - cups
34 - rpcbind
35 - nfs-server
36 - vsftpd
37
38 - role: system_hardening
39 vars:
40 devel_packages_debian:
41 - gcc
42 - g++
43 - make
44 - build-essential
45 - kernel-devel
46 - linux-headers-$(uname -r)
47 devel_packages_redhat:
48 - gcc
49 - gcc-c++
50 - make
51 - kernel-devel
52 - redhat-lsb-core
53 - perl
54 secure_dirs:
55 - /etc/ssh
56 - /etc/sudoers.d
57 kernel_hardening:
58 net.ipv4.ip_forward: 0
59 net.ipv4.conf.all.accept_redirects: 0
60 net.ipv4.conf.all.send_redirects: 0
61 net.ipv4.conf.all.accept_source_route: 0
62 net.ipv4.tcp_syncookies: 1
63 net.ipv4.conf.all.rp_filter: 1
64 kernel.randomize_va_space: 2
65
66 - role: ssh_login_alert
67 vars:
68 telegram_bot_token: "xxxxxxxxxxxxxxx"
69 telegram_chat_id: "xxxxxxxxx"
Disable and set what you need to be configured in your host/server.
Exec to docker container.
1docker exec -it ansible-linux-hardening bash
Run playbook.
1ansible-playbook playbook/main.yml -i inventory/hosts.ini