Skip to content

Commit

Permalink
update/extend deploy user and group handling (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
githubixx authored Dec 20, 2023
1 parent be2ddbe commit 4b6914d
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 46 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## v8.0.0

BREAKING/FEATURE

- introduce `harden_linux_deploy_group` and `harden_linux_deploy_group_gid` variables. Both are optional. But at least `harden_linux_deploy_group` must be specified if `harden_linux_deploy_user` is also set. If `harden_linux_deploy_group` is set to `root` nothing will be changed.
- if `harden_linux_deploy_user` is set to `root` nothing will be changed.
- `harden_linux_deploy_user` is now optional. If not set, no user will be setup. Also all variables that start with `harden_linux_deploy_user_` are only used if `harden_linux_deploy_user` is specified. Additionally `harden_linux_deploy_user_home` variable was added. `harden_linux_deploy_user_shell`, `harden_linux_deploy_user_home`, `harden_linux_deploy_user_uid` and `harden_linux_deploy_user_password` are now optional. $HOME directory of `harden_linux_deploy_user` is only created if `harden_linux_deploy_user_home` is set.

MOLECULE

- update test scenario to reflect deploy user/group changes

## v7.1.0

FEATURE
Expand Down
46 changes: 27 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# ansible-role-harden-linux

This Ansible role was mainly created for my blog series [Kubernetes the not so hard way with Ansible - Harden the instances](https://www.tauceti.blog/posts/kubernetes-the-not-so-hard-way-with-ansible-harden-the-instances/). But it can be used also standalone of course to harden Linux. It has the following features:
This Ansible role was mainly created for my blog series [Kubernetes the not so hard way with Ansible - Harden the instances](https://www.tauceti.blog/posts/kubernetes-the-not-so-hard-way-with-ansible-harden-the-instances/). But it can be used also standalone of course to harden Linux. It has the following features (some of them are optional):

- Optional: Change root password
- Add a regular/deploy user used for administration (e.g. for Ansible or login via SSH)
- Adjust APT update intervals
- Setup `UFW` firewall and allow only SSH access by default (add more rules/allowed networks if you like)
- Adjust security related sysctl settings
- Adjust `sshd` settings e.g disable sshd password authentication, disable sshd root login and disable sshd PermitTunnel
- Install `sshguard` and adjust whitelist
- Optional: Install/configure `Network Time Synchronization` (NTP) e.g. `openntpd`/`ntp`/`systemd-timesyncd`
- Optional: Change `systemd-resolved` configuration
- Change root password
- Install/configure `Network Time Synchronization` (NTP) e.g. `openntpd`/`ntp`/`systemd-timesyncd`
- Change `systemd-resolved` configuration

## Versions

Expand Down Expand Up @@ -83,28 +83,32 @@ roles:
## Role Variables
The following variables don't have defaults. You need to specify them either in a file in `group_vars` or `host_vars` directory. E.g. if this settings should be used only for one specific host create a file for that host called like the FQDN of that host (e.g `host_vars/your-server.example.tld`) and put the variables with the correct values there. If you want to apply this variables to a host group create a file `group_vars/your-group.yml` e.g. Replace `your-group` with the host group name which you created in the Ansible `hosts` file (do not confuse with /etc/hosts...). `harden_linux_deploy_user_public_keys` loads all the public SSH key files specified in the list from your local hard disk. So at least you need to specify:
The following variables don't have defaults. You need to specify them either in a file in `group_vars` or `host_vars` directory. E.g. if this settings should be used only for one specific host create a file for that host called like the FQDN of that host (e.g `host_vars/your-server.example.tld`) and put the variables with the correct values there. If you want to apply this variables to a host group create a file `group_vars/your-group.yml` e.g. Replace `your-group` with the host group name which you created in the Ansible `hosts` file (do not confuse with /etc/hosts...).

```yaml
# This is optional. If not specified "root" account password won't be changed.
harden_linux_root_password: your_encrypted_password_here
harden_linux_deploy_user: deploy
harden_linux_deploy_user_password: your_encrypted_password_here
harden_linux_deploy_user_home: /home/deploy
harden_linux_deploy_user_public_keys:
- /home/your_user/.ssh/id_rsa.pub
```

With `harden_linux_root_password` (optional as mentioned above) and `harden_linux_deploy_user_password` we specify the password for the `root` user and the `deploy` user. Ansible won't encrypt the password for you. How to create an encrypted password is described in the [Ansible FAQs](http://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module). But as Ansible is installed anyways the most easiest way is probably the following command:
If you want to set or change the password of the `root` user set `harden_linux_root_password` variable. This is optional. It expects an encrypted password. Ansible won't encrypt the password for you. How to create an encrypted password is described in the [Ansible FAQs](http://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module). But as Ansible is installed anyways the easiest way is most probably the following command:

```bash
ansible localhost -m debug -a "msg={{ 'mypassword' | password_hash('sha512', 'mysecretsalt') }}"
```

To install a user that can execute commands with `sudo` without password set the following variables:

```yaml
harden_linux_deploy_user: "a_username"
harden_linux_deploy_user_password: "a_password"
harden_linux_deploy_user_home: "/home/a_user"
harden_linux_deploy_user_uid: "9999"
harden_linux_deploy_user_gid: "9999"
harden_linux_deploy_user_shell: "/bin/bash"
```

`harden_linux_deploy_user` specifies the user we want to use to login at the remote host. As already mentioned the `harden_linux` role will disable root user login via SSH for a good reason. So a different user is needed. This user will get "sudo" permission which is need for Ansible (and/or yourself of course) to do it's work.

`harden_linux_deploy_user_public_keys` specifies a list of public SSH key files you want to add to `$HOME/.ssh/authorized_keys` of the deploy user on the remote host. If you specify `/home/deploy/.ssh/id_rsa.pub` e.g. as a value here the content of that **local** file will be added to `$HOME/.ssh/authorized_keys` of the deploy user on the remote host.
In `harden_linux_deploy_user_password` the user's encrypted password stored. Same applies as for `harden_linux_root_password` regarding how to create an encrypted password.

The user's $HOME directory is specified in `harden_linux_root_password`. For the UID and GID set `harden_linux_deploy_user_uid` and `harden_linux_deploy_user_gid`. **Note**: If the user already exists but has a different home directory, UID and/or GID it will be changed according to the settings above! This also applies to `harden_linux_deploy_user_shell` which specifies the shell the user should use after login e.g.

`harden_linux_deploy_user_public_keys` specifies a list of public SSH key files you want to add to `$HOME/.ssh/authorized_keys` of the deploy user on the remote host. If you specify `/home/deploy/.ssh/id_rsa.pub` e.g. as a value here the content of that **local** file (present on the Ansible controller node) will be added to `$HOME/.ssh/authorized_keys` of the deploy user on the remote host.

`harden_linux_optional_packages` (before version `v6.0.0` of this role this variable was called `harden_linux_required_packages`) specifies additional/optional packages to install on the remote host. By default this variable is not specified. E.g.:

Expand Down Expand Up @@ -327,12 +331,16 @@ harden_linux_systemd_resolved_settings:
- DNS=9.9.9.9
```

While the Google DNS server (`8.8.8.8`, `8.8.4.4`) offer speedy DNS lookups it's of course another possibility Google can spy on you. So using some other DNS servers should be at least something to think about. But there is one more thing and that's encrypting DNS requests. One way that `systemd-resolved` supports is `DNSOverTLS`. [Quad9 (9.9.9.9/149.112.112.112)](https://quad9.net) supports it and [Cloudflare (1.1.1.1/1.0.0.1)](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-tls/) support `DNSOverTLS`. So the following `systemd-resolved` settings configure Quad9 and Cloudflare DNS for IPv4 and IPv6. The setting `DNSOverTLS=opportunistic` uses `DNSOverTLS` if the DNS server supports it and falls back to regular unencrypted DNS if not supported (also see [resolved.conf.5](https://man.archlinux.org/man/resolved.conf.5)):
While the Google DNS server (`8.8.8.8`, `8.8.4.4`) offer speedy DNS lookups it's of course another possibility Google can spy on you. So using some other DNS servers should be at least something to think about. But there is one more thing and that's encrypting DNS requests. One way that `systemd-resolved` supports is `DNSOverTLS`. [Quad9 (9.9.9.9/149.112.112.112)](https://quad9.net) and [Cloudflare (1.1.1.1/1.0.0.1)](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-tls/) support `DNSOverTLS`.
So the following `systemd-resolved` settings configure Quad9 and Cloudflare DNS for IPv4 and IPv6. The setting `DNSOverTLS=opportunistic` uses `DNSOverTLS` if the DNS server supports it and falls back to regular unencrypted DNS if not supported (also see [resolved.conf.5](https://man.archlinux.org/man/resolved.conf.5)):

```yaml
harden_linux_systemd_resolved_settings:
- DNS=
- DNS=9.9.9.9 1.1.1.1 2606:4700:4700::1111 2620:fe::fe
- FallbackDNS=
- FallbackDNS=149.112.112.112 1.0.0.1 2620:fe::9 2606:4700:4700::1001
- DNSOverTLS=
- DNSOverTLS=opportunistic
```

Expand Down
51 changes: 44 additions & 7 deletions defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
---
# Some default settings for deploy user
harden_linux_deploy_user_uid: 9999
harden_linux_deploy_user_shell: "/bin/bash"
# If you want to set or change the password of the "root" user set this variable.
#
# The encrypted password can be created with the following command:
# ansible localhost -m debug -a "msg={{ 'mypassword' | password_hash('sha512', 'mysecretsalt') }}"
#
# harden_linux_root_password: "a_password"

# Group name of deploy user. This is mandatory if "harden_linux_deploy_user"
# is also set.
# harden_linux_deploy_group: "a_group"

# The GID of the group name specified in "harden_linux_deploy_group". If not
# specified the next available GID from "/etc/login.defs" will be taken
# (see "GID_MIN/GID_MAX" setting in that file).
# harden_linux_deploy_group_gid: 9999

# Name of deploy user. When not set no user will be created.
# harden_linux_deploy_user: "a_username"

# Encrypted password for deploy user. Only relevant if "harden_linux_deploy_user"
# is set. See "harden_linux_root_password" how to create an encrypted password.
# harden_linux_deploy_user_password: "a_password"

# HOME directory for deploy user. Only relevant when "harden_linux_deploy_user"
# is set.
# harden_linux_deploy_user_home: "/home/a_user"

# List of public keys for deploy user. Only relevant when "harden_linux_deploy_user"
# is set. The public keys will be added to the "authorized_keys" file of the deploy
# user.
# harden_linux_deploy_user_public_keys:
# - /home/a_username/.ssh/id_rsa.pub

# UID for deploy user. Only relevant when "harden_linux_deploy_user" is set.
# If not specified the next available GID from "/etc/login.defs" will be taken
# (see "UID_MIN/UID_MAX" setting in that file).
# harden_linux_deploy_user_uid: "9999"

# Shell for deploy user. Only relevant when "harden_linux_deploy_user" is set.
# harden_linux_deploy_user_shell: "/bin/bash"

# List of files that should be absent on the target host
harden_linux_files_to_delete:
Expand Down Expand Up @@ -85,7 +122,7 @@ harden_linux_files_to_delete:
# on your own by adding a group or host variable called "sysctl_settings_user".
# "sysctl_settings" and "sysctl_settings_user" will get merged by a
# task. You can also override a setting defined in "sysctl_settings"
# by specifing a key with the same name and a different value in
# by specifying a key with the same name and a different value in
# "sysctl_settings_user".
#
# For more information about this settings have a look at:
Expand Down Expand Up @@ -143,14 +180,14 @@ harden_linux_sysctl_settings:
# The "key" here is a regex of a setting you want to replace and the value is
# the setting name + the setting value. E.g. we want to replace the line
# "Port 22" with "Port 22222". The regex (the key) would be "^Port " which
# means "search for a line in "/etc/ssh/sshd_config" that begins with 'Port'
# means "search for a line in "/etc/ssh/sshd_config" that begins with 'Port '
# and replace the whole line with 'Port 22222'". This enables you to replace
# every setting in "sshd_config".
harden_linux_sshd_settings:
"^PasswordAuthentication": "PasswordAuthentication no" # Disable password authentication
"^PermitRootLogin": "PermitRootLogin no" # Disable SSH root login
"^PermitTunnel": "PermitTunnel no" # Disable tun(4) device forwarding
"^Port ": "Port 22" # Set SSHd port
"^Port ": "Port 22" # Set sshd port

# When this variable is set, settings for "systemd-resolved" will be changed.
# A systemd drop-in configuration will be created in "/etc/systemd/resolved.conf.d/99-override.conf"
Expand Down Expand Up @@ -194,7 +231,7 @@ harden_linux_ufw_defaults:
# Disable/enable UFW logging
harden_linux_ufw_logging: 'off'

# sshgard whitelist: sshguard blocks IPs for some time if
# sshguard whitelist: sshguard blocks IPs for some time if
# to many SSH login attempts fail. Specify IP (ranges) that
# should not be blocked.
harden_linux_sshguard_whitelist:
Expand Down
33 changes: 28 additions & 5 deletions molecule/default/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ provisioner:
inventory:
group_vars:
all:
harden_linux_deploy_user: deployer
harden_linux_deploy_user_password: "{{ lookup('file', 'myuserpassword_hash') }}" # mypassword
harden_linux_deploy_user_home: /home/deployer
harden_linux_deploy_user_public_keys:
- "mykey.pub"
harden_linux_sshd_settings:
"^PasswordAuthentication": "PasswordAuthentication yes"
"^X11Forwarding": "X11Forwarding no"
Expand Down Expand Up @@ -111,12 +106,24 @@ provisioner:
- "10.0.0.0/8"
host_vars:
test-harden-linux-ubuntu2004-timesyncd:
harden_linux_deploy_group: "deployer"
harden_linux_deploy_user: "deployer"
harden_linux_deploy_user_password: "{{ lookup('file', 'myuserpassword_hash') }}" # mypassword
harden_linux_deploy_user_home: "/home/deployer"
harden_linux_deploy_user_shell: "/bin/bash"
harden_linux_deploy_user_public_keys:
- "mykey.pub"
harden_linux_ntp: "systemd-timesyncd"
harden_linux_ntp_settings:
"^#NTP=": "NTP=ntp.ubuntu.com"
harden_linux_optional_packages:
- mlocate
test-harden-linux-ubuntu2004-ntp:
harden_linux_deploy_group: "deployer"
harden_linux_deploy_user: "deployer"
harden_linux_deploy_user_home: "/home/deployer"
harden_linux_deploy_user_public_keys:
- "mykey.pub"
harden_linux_root_password: "{{ lookup('file', 'myuserpassword_hash') }}" # mypassword
harden_linux_ntp: "ntp"
harden_linux_ntp_settings:
Expand All @@ -127,13 +134,29 @@ provisioner:
harden_linux_absent_packages:
- dosfstools
test-harden-linux-ubuntu2204-openntpd:
harden_linux_deploy_group: "deployer"
harden_linux_deploy_group_gid: "9999"
harden_linux_deploy_user: "deployer"
harden_linux_deploy_user_uid: "9998"
harden_linux_deploy_user_password: "{{ lookup('file', 'myuserpassword_hash') }}" # mypassword
harden_linux_deploy_user_home: "/home/deployer"
harden_linux_deploy_user_shell: "/bin/bash"
harden_linux_ntp: "openntpd"
harden_linux_ntp_settings:
"^servers 0": "servers 0.debian.pool.ntp.org"
"^servers 1": "servers 1.debian.pool.ntp.org"
"^servers 2": "servers 2.debian.pool.ntp.org"
"^servers 3": "servers 3.debian.pool.ntp.org"
test-harden-linux-arch-timesyncd:
harden_linux_deploy_group: "deployer"
harden_linux_deploy_group_gid: "9999"
harden_linux_deploy_user: "deployer"
harden_linux_deploy_user_uid: "9998"
harden_linux_deploy_user_password: "{{ lookup('file', 'myuserpassword_hash') }}" # mypassword
harden_linux_deploy_user_home: "/home/deployer"
harden_linux_deploy_user_shell: "/bin/bash"
harden_linux_deploy_user_public_keys:
- "mykey.pub"
harden_linux_root_password: "{{ lookup('file', 'myuserpassword_hash') }}" # mypassword
harden_linux_ntp: "systemd-timesyncd"
harden_linux_optional_packages:
Expand Down
34 changes: 19 additions & 15 deletions tasks/deployuser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,34 @@
pkg: "sudo"
state: present

- name: Add deploy user's group
when:
- harden_linux_deploy_group != "root"
ansible.builtin.group:
name: "{{ harden_linux_deploy_group }}"
state: present
gid: "{{ harden_linux_deploy_group_gid | default(omit) }}"

- name: Add deploy user
when:
- harden_linux_deploy_user != "root"
ansible.builtin.user:
name: "{{ harden_linux_deploy_user }}"
password: "{{ harden_linux_deploy_user_password }}"
uid: "{{ harden_linux_deploy_user_uid }}"
shell: "{{ harden_linux_deploy_user_shell }}"
home: "{{ harden_linux_deploy_user_home }}"
tags:
- user
state: present
shell: "{{ harden_linux_deploy_user_shell | default(omit) }}"
create_home: "{{ harden_linux_deploy_user_home is defined }}"
home: "{{ harden_linux_deploy_user_home | default(omit) }}"
uid: "{{ harden_linux_deploy_user_uid | default(omit) }}"
group: "{{ harden_linux_deploy_group }}"
password: "{{ harden_linux_deploy_user_password | default(omit) }}"

- name: Add authorized keys for deploy user
when:
- harden_linux_deploy_user_public_keys is defined
ansible.posix.authorized_key:
user: "{{ harden_linux_deploy_user }}"
key: "{{ lookup('file', item) }}"
loop: "{{ harden_linux_deploy_user_public_keys }}"
when: harden_linux_deploy_user_public_keys is defined
tags:
- user

- name: "Ensure deploy user present in /etc/sudoers.d/{{ harden_linux_deploy_user }}"
ansible.builtin.template:
Expand All @@ -30,15 +40,9 @@
owner: "root"
group: "root"
mode: "0400"
tags:
- user
- sudo

- name: Ensure deploy user is absent in /etc/sudoers
ansible.builtin.lineinfile:
dest: "/etc/sudoers"
regexp: "^{{ harden_linux_deploy_user }} ALL"
state: absent
tags:
- user
- sudo
3 changes: 3 additions & 0 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
- ntpd

- name: Setup deploy user
when:
- harden_linux_deploy_group is defined
- harden_linux_deploy_user is defined
ansible.builtin.include_tasks:
file: "deployuser.yml"
apply:
Expand Down

0 comments on commit 4b6914d

Please sign in to comment.