diff --git a/LICENSE b/LICENSE index c285c6e..5fdbd3a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 ansible-roles +Copyright (c) 2026 ansible-roles Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 497d79e..eaa3c63 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,73 @@ brainsys base configuration =========================== -This roles simply set up some locale, date and packages for my own usage. +This role sets up a base configuration for servers, including locales, timezone, time synchronization, standard packages, SSH hardening, and Python utilities. It handles differences between Debian versions (e.g., NTP vs systemd-timesyncd, Python venv management). + +Supported Platforms +------------------- + +- Debian 10+ (Buster, Bullseye, Bookworm, Trixie...) + +Features & Details +------------------ + +### 1. Locales & Timezone +- Sets locale to `fr_FR.UTF-8`. +- Sets timezone to `Europe/Paris` (customizable). +- Configures NTP: + - **Debian < 13**: Installs `ntp` package. + - **Debian >= 13**: Installs and enables `systemd-timesyncd`. + +### 2. Standard Packages +Installs a set of essential tools including: +- `bash-completion`, `curl`, `git-core`, `htop`, `iotop`, `ncdu`, `rsync`, `screen`, `tmux`, `vim`, `net-tools`, `telnet`, `sudo`, etc. + +### 3. Python Utilities (ps_mem, bpytop) +Installs `ps_mem` and `bpytop`. +- **Debian < 12**: Installed globally via `pip3`. +- **Debian >= 12**: Installed in a dedicated virtual environment at `/opt/python/venv/brainsys`. Binaries are symlinked to `/usr/local/bin`. + +### 4. Needrestart (Debian only) +Installs and configures `needrestart` to automatically restart services after upgrades. +- Sets auto-restart mode. +- Allows defining exclusions via variables (see below). + +### 5. SSH Configuration +- Hardens SSH root login: + - `PermitRootLogin` set to `no` by default. + - Allows `prohibit-password` login only from specific IP addresses defined in variables (see below). +- Manages `/root/.ssh/authorized_keys` with a list of keys (see below). + +Role Variables +-------------- + +| Variable | Description | Default | +|----------|-------------|---------| +| `timezone` | System timezone to configure. | `Europe/Paris` | +| `needrestart_exclude` | List of services to exclude from needrestart checks (keys in perl hash format). | `[]` | +| `ssh_root_authorized_ips` | List of IP addresses allowed to SSH as root (with key only). | `undefined` | +| `ssh_root_authorized_keys` | List of public keys to add to `/root/.ssh/authorized_keys`. **Warning: Overwrites file**. | `undefined` | +| `ssh_root_authorized_keys_file` | Custom path for the authorized_keys file destination. | `/root/.ssh/authorized_keys` | + +Usage Example +------------- + +```yaml +- hosts: servers + roles: + - role: base + vars: + timezone: "Etc/UTC" + needrestart_exclude: + - mysql + - postgresql + ssh_root_authorized_ips: + - "192.168.1.10" + - "10.0.0.5" + ssh_root_authorized_keys: + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..." + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAA..." +``` License ------- diff --git a/tasks/date.yml b/tasks/date.yml deleted file mode 100644 index 8d1c69b..0000000 --- a/tasks/date.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -- name: base | install ntp - apt: - name: ntp - state: present - when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int < 13 - -- name: base | ensure ntp is running - service: - name: ntp - state: started - enabled: yes - when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int < 13 - -- name: base | set date - shell: - cmd: /usr/bin/timedatectl set-timezone Europe/Paris - when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int >= 13 diff --git a/tasks/datetime.yml b/tasks/datetime.yml new file mode 100644 index 0000000..944db4d --- /dev/null +++ b/tasks/datetime.yml @@ -0,0 +1,31 @@ +--- +- name: datetime | install ntp + apt: + name: ntp + state: present + when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int < 13 + +- name: datetime | ensure ntp is running + service: + name: ntp + state: started + enabled: yes + when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int < 13 + +- name: datetime | install systemd-timesyncd + apt: + name: systemd-timesyncd + state: present + when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int >= 13 + +- name: datetime | ensure systemd-timesyncd is running + service: + name: systemd-timesyncd + state: started + enabled: yes + when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int >= 13 + +- name: datetime | set date + timezone: + name: "{{ timezone | default('Europe/Paris') }}" + when: ansible_os_family == 'Debian' \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml index d1992c1..06b2c79 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -10,8 +10,14 @@ - name: base | configure locales include_tasks: locales.yml -#- name: base | install pip3 packages -# include_tasks: pip.yml +- name: base | install python packages + include_tasks: pip.yml + +- name: base | install needrestart + include_tasks: needrestart.yml + +- name: base | configure SSH + include_tasks: ssh.yml - name: base | set datetime - include_tasks: date.yml + include_tasks: datetime.yml diff --git a/tasks/needrestart.yml b/tasks/needrestart.yml new file mode 100644 index 0000000..6339a1a --- /dev/null +++ b/tasks/needrestart.yml @@ -0,0 +1,21 @@ +--- +- name: needrestart | install + apt: + name: needrestart + state: present + update_cache: true + +- name: needrestart | configure auto restart + copy: + dest: /etc/needrestart/conf.d/override.conf + content: | + $nrconf{restart} = 'a'; + mode: '0644' + +- name: needrestart | configure exclusions + template: + src: needrestart_exclude.j2 + dest: /etc/needrestart/conf.d/exclude.conf + mode: '0644' + when: needrestart_exclude is defined + diff --git a/tasks/packages.yml b/tasks/packages.yml index 5b3508a..b37d739 100644 --- a/tasks/packages.yml +++ b/tasks/packages.yml @@ -7,6 +7,8 @@ with_items: - bash-completion - bsd-mailx + - cron + - cron-daemon-common - curl - deborphan - git-core @@ -14,10 +16,11 @@ - iotop - less - locales - - needrestart - net-tools - ncdu - python3-pip + - python3-venv + - python3-xyz - rsync - rsyslog - screen diff --git a/tasks/pip.yml b/tasks/pip.yml index 4760491..0f78be8 100644 --- a/tasks/pip.yml +++ b/tasks/pip.yml @@ -1,5 +1,5 @@ --- -- name: pip3 | install package +- name: python | install package (legacy) pip: name: - ps_mem @@ -7,3 +7,45 @@ executable: pip3 when: - ansible_distribution == 'Debian' + - ansible_distribution_major_version | int < 12 + +- name: python | install python3-venv + apt: + name: python3-venv + state: present + when: + - ansible_distribution == 'Debian' + - ansible_distribution_major_version | int >= 12 + +- name: python | create venv directory + file: + path: /opt/python/venv + state: directory + mode: '0755' + when: + - ansible_distribution == 'Debian' + - ansible_distribution_major_version | int >= 12 + +- name: python | install packages in venv + pip: + name: + - ps_mem + - bpytop + virtualenv: /opt/python/venv/brainsys + virtualenv_command: /usr/bin/python3 -m venv + when: + - ansible_distribution == 'Debian' + - ansible_distribution_major_version | int >= 12 + +- name: python | link binaries + file: + src: "/opt/python/venv/brainsys/bin/{{ item }}" + dest: "/usr/local/bin/{{ item }}" + state: link + loop: + - ps_mem + - bpytop + when: + - ansible_distribution == 'Debian' + - ansible_distribution_major_version | int >= 12 + diff --git a/tasks/ssh.yml b/tasks/ssh.yml new file mode 100644 index 0000000..61b99f2 --- /dev/null +++ b/tasks/ssh.yml @@ -0,0 +1,27 @@ +- name: SSH | configure root login restrictions + template: + src: sshd_root_conf.j2 + dest: /etc/ssh/sshd_config.d/root.conf + mode: '0644' + validate: /usr/sbin/sshd -t -f %s + when: ssh_root_authorized_ips is defined + +- name: SSH | configure root authorized keys + template: + src: root_authorized_keys.j2 + dest: "{{ ssh_root_authorized_keys_file | default('/root/.ssh/authorized_keys') }}" + owner: root + group: root + mode: '0600' + when: ssh_root_authorized_keys is defined + +- name: SSH | test SSH configuration + command: /usr/sbin/sshd -t + register: sshd_config_check + changed_when: false + +- name: SSH | reload SSH service + service: + name: ssh + state: reloaded + when: sshd_config_check.rc == 0 diff --git a/templates/needrestart_exclude.j2 b/templates/needrestart_exclude.j2 new file mode 100644 index 0000000..f3439f6 --- /dev/null +++ b/templates/needrestart_exclude.j2 @@ -0,0 +1,5 @@ +$nrconf{override_rc} = { +{% for item in needrestart_exclude %} + '{{ item }}' => 0, +{% endfor %} +}; diff --git a/templates/root_authorized_keys.j2 b/templates/root_authorized_keys.j2 new file mode 100644 index 0000000..3b278fb --- /dev/null +++ b/templates/root_authorized_keys.j2 @@ -0,0 +1,5 @@ +{% if ssh_root_authorized_keys is defined %} +{% for key in ssh_root_authorized_keys %} +{{ key }} +{% endfor %} +{% endif %} diff --git a/templates/sshd_root_conf.j2 b/templates/sshd_root_conf.j2 new file mode 100644 index 0000000..ea282b6 --- /dev/null +++ b/templates/sshd_root_conf.j2 @@ -0,0 +1,8 @@ +PermitRootLogin no + +{% if ssh_root_authorized_ips is defined %} +{% for ip in ssh_root_authorized_ips %} +Match Address {{ ip }} + PermitRootLogin prohibit-password +{% endfor %} +{% endif %}