diff options
| author | Ahmed Abdelhalim <[email protected]> | 2025-08-11 00:32:07 +0200 |
|---|---|---|
| committer | Ahmed Abdelhalim <[email protected]> | 2025-08-11 00:32:07 +0200 |
| commit | 652734b570bc728f02df99a7c570b119ddc5c4be (patch) | |
| tree | 356460fb60f2d8d13e6e1a8b1a7aaba9d04aa501 /roles/password_policy | |
| parent | 2d45a9b60a008581672af7a901258f488d3cde16 (diff) | |
Refactor: move password policy to its own role
Diffstat (limited to 'roles/password_policy')
| -rw-r--r-- | roles/password_policy/README.md | 21 | ||||
| -rw-r--r-- | roles/password_policy/defaults/main.yml | 14 | ||||
| -rw-r--r-- | roles/password_policy/meta/argument_specs.yml | 51 | ||||
| -rw-r--r-- | roles/password_policy/meta/main.yml | 19 | ||||
| -rw-r--r-- | roles/password_policy/tasks/main.yml | 25 | ||||
| -rw-r--r-- | roles/password_policy/templates/archlinux-pam-pw.j2 | 45 | ||||
| -rw-r--r-- | roles/password_policy/templates/debian-pam-pw.j2 | 49 | ||||
| -rw-r--r-- | roles/password_policy/vars/archlinux.yml | 2 | ||||
| -rw-r--r-- | roles/password_policy/vars/debian.yml | 2 |
9 files changed, 228 insertions, 0 deletions
diff --git a/roles/password_policy/README.md b/roles/password_policy/README.md new file mode 100644 index 00000000..c499dcdc --- /dev/null +++ b/roles/password_policy/README.md @@ -0,0 +1,21 @@ +# Ansible Role: password_policy + +This role configure the machine password quality policy + +## Role Variables + +- `password_policy_enabled` boolean to enable or disable the enforcement of password policy +- `password_policy_difok` the number of differences between new and old password (default 0 - disabled) +- `password_policy_minlen` min password length (default 8) +- `password_policy_dcredit` required digits in password (default 0) +- `password_policy_ucredit` required uppercase chars in password (default 0) +- `password_policy_ocredit` required other chars in password (default 0) +- `password_policy_lcredit` required lowercase chars in password (default 0) +- `password_policy_minclass` required minimum classes in password upper/lower/digit/other (default 0 - disabled) +- `password_policy_maxrepeat` allowed maximum repeats in password (default 0 - disabled) +- `password_policy_maxclassrepeat` maximum allowed consecutive class repeats (default 0 -disabled) +- `password_policy_gecoscheck` (default 0 - disabled) + +## Docs + +- https://linux.die.net/man/8/pam_pwquality diff --git a/roles/password_policy/defaults/main.yml b/roles/password_policy/defaults/main.yml new file mode 100644 index 00000000..1c5f7254 --- /dev/null +++ b/roles/password_policy/defaults/main.yml @@ -0,0 +1,14 @@ +--- +# Password policy +# https://linux.die.net/man/8/pam_pwquality +password_policy_enabled: true +password_policy_difok: 0 +password_policy_minlen: 8 +password_policy_dcredit: 0 +password_policy_ucredit: 0 +password_policy_ocredit: 0 +password_policy_lcredit: 0 +password_policy_minclass: 0 +password_policy_maxrepeat: 0 +password_policy_maxclassrepeat: 0 +password_policy_gecoscheck: 0 diff --git a/roles/password_policy/meta/argument_specs.yml b/roles/password_policy/meta/argument_specs.yml new file mode 100644 index 00000000..8c312a8c --- /dev/null +++ b/roles/password_policy/meta/argument_specs.yml @@ -0,0 +1,51 @@ +--- +argument_specs: + main: + options: + password_policy_enabled: + type: "bool" + description: "Enable password policy" + default: true + password_policy_difok: + type: "int" + description: "The number of differences between new and old password" + default: 0 + password_policy_minlen: + type: "int" + description: "Min password length" + default: 8 + password_policy_dcredit: + type: "int" + description: "Num of digits required in password" + default: 0 + password_policy_ucredit: + type: "int" + description: "Num of uppercase chars required in password" + default: 0 + password_policy_ocredit: + type: "int" + description: "Num of special chars required in password" + default: 0 + password_policy_lcredit: + type: "int" + description: "Num of lowercase chars required in password" + default: 0 + password_policy_minclass: + type: "int" + description: "Num of required classes (upper/lower/digit/special) chars required in password" + default: 0 + password_policy_maxrepeat: + type: "int" + description: "Num of allowed repeats in password" + default: 0 + password_policy_maxclassrepeat: + type: "int" + description: "Maximum number of consecutive class repeats in password" + default: 0 + password_policy_gecoscheck: + type: "int" + description: | + If nonzero, check whether the individual words longer than 3 characters from the + passwd GECOS field of the user are contained in the new password. + The default is 0 which means that this check is disabled. + default: 0 diff --git a/roles/password_policy/meta/main.yml b/roles/password_policy/meta/main.yml new file mode 100644 index 00000000..fdcf75a1 --- /dev/null +++ b/roles/password_policy/meta/main.yml @@ -0,0 +1,19 @@ +--- +dependencies: [] +galaxy_info: + role_name: password_policy + author: a14m + description: "Configure the linux distro password policy" + company: "kartoffeln.work GmbH." + license: "license MIT" + min_ansible_version: "2.18" + platforms: + - name: ArchLinux + versions: + - all + - name: Ubuntu + versions: + - noble + - name: Debian + versions: + - bookworm diff --git a/roles/password_policy/tasks/main.yml b/roles/password_policy/tasks/main.yml new file mode 100644 index 00000000..10aa3837 --- /dev/null +++ b/roles/password_policy/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- name: "Include OS-specific variables" + ansible.builtin.include_vars: "{{ ansible_os_family | lower }}.yml" + +- name: "Ensure password_policy package is installed" + become: true + ansible.builtin.package: + name: "{{ password_policy_pkg }}" + state: "present" + +- name: "Configure archlinux password policy" + become: true + ansible.builtin.template: + src: "archlinux-pam-pw.j2" + dest: "/etc/pam.d/system-auth" + mode: "0644" + when: ansible_os_family == "Archlinux" + +- name: "Configure debian password policy" + become: true + ansible.builtin.template: + src: "debian-pam-pw.j2" + dest: "/etc/pam.d/common-password" + mode: "0644" + when: ansible_os_family == "Debian" diff --git a/roles/password_policy/templates/archlinux-pam-pw.j2 b/roles/password_policy/templates/archlinux-pam-pw.j2 new file mode 100644 index 00000000..b5e3914e --- /dev/null +++ b/roles/password_policy/templates/archlinux-pam-pw.j2 @@ -0,0 +1,45 @@ +#%PAM-1.0 + +auth required pam_faillock.so preauth +# Optionally use requisite above if you do not want to prompt for the password +# on locked accounts. +-auth [success=2 default=ignore] pam_systemd_home.so +auth [success=1 default=bad] pam_unix.so try_first_pass nullok +auth [default=die] pam_faillock.so authfail +auth optional pam_permit.so +auth required pam_env.so +auth required pam_faillock.so authsucc +# If you drop the above call to pam_faillock.so the lock will be done also +# on non-consecutive authentication failures. + +-account [success=1 default=ignore] pam_systemd_home.so +account required pam_unix.so +account optional pam_permit.so +account required pam_time.so + +{% if password_policy_enabled %} +-password [success=2 default=ignore] pam_systemd_home.so +password requisite pam_pwquality.so retry=3 \ + difok={{ password_policy_difok }} \ + minlen={{ password_policy_minlen }} \ + dcredit={{ password_policy_dcredit }} \ + ucredit={{ password_policy_ucredit }} \ + ocredit={{ password_policy_ocredit }} \ + lcredit={{ password_policy_lcredit }} \ + minclass={{ password_policy_minclass }} \ + maxrepeat={{ password_policy_maxrepeat }} \ + maxclassrepeat={{ password_policy_maxclassrepeat }} \ + gecoscheck={{ password_policy_gecoscheck }} +{% else %} +-password [success=1 default=ignore] pam_systemd_home.so +{% endif %} +password required pam_unix.so try_first_pass \ + nullok \ + shadow \ + minlen={{ password_policy_minlen }} +password optional pam_permit.so + +-session optional pam_systemd_home.so +session required pam_limits.so +session required pam_unix.so +session optional pam_permit.so diff --git a/roles/password_policy/templates/debian-pam-pw.j2 b/roles/password_policy/templates/debian-pam-pw.j2 new file mode 100644 index 00000000..dceedf97 --- /dev/null +++ b/roles/password_policy/templates/debian-pam-pw.j2 @@ -0,0 +1,49 @@ +# +# /etc/pam.d/common-password - password-related modules common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of modules that define the services to be +# used to change user passwords. The default is pam_unix. + +# Explanation of pam_unix options: +# The "yescrypt" option enables +#hashed passwords using the yescrypt algorithm, introduced in Debian +#11. Without this option, the default is Unix crypt. Prior releases +#used the option "sha512"; if a shadow password hash will be shared +#between Debian 11 and older releases replace "yescrypt" with "sha512" +#for compatibility . The "obscure" option replaces the old +#`OBSCURE_CHECKS_ENAB' option in login.defs. See the pam_unix manpage +#for other options. + +# As of pam 1.0.1-6, this file is managed by pam-auth-update by default. +# To take advantage of this, it is recommended that you configure any +# local modules either before or after the default block, and use +# pam-auth-update to manage selection of other modules. See +# pam-auth-update(8) for details. + +# here are the per-package modules (the "Primary" block) +{% if password_policy_enabled %} +password requisite pam_pwquality.so retry=3 \ + difok={{ password_policy_difok }} \ + minlen={{ password_policy_minlen }} \ + dcredit={{ password_policy_dcredit }} \ + ucredit={{ password_policy_ucredit }} \ + ocredit={{ password_policy_ocredit }} \ + lcredit={{ password_policy_lcredit }} \ + minclass={{ password_policy_minclass }} \ + maxrepeat={{ password_policy_maxrepeat }} \ + maxclassrepeat={{ password_policy_maxclassrepeat }} \ + gecoscheck={{ password_policy_gecoscheck }} +password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt +{% else %} +password [success=1 default=ignore] pam_unix.so obsecure sha512 minlen={{ password_policy_minlen }} +{% endif %} +# here's the fallback if no module succeeds +password requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +password required pam_permit.so +# and here are more per-package modules (the "Additional" block) +password optional pam_gnome_keyring.so +# end of pam-auth-update config diff --git a/roles/password_policy/vars/archlinux.yml b/roles/password_policy/vars/archlinux.yml new file mode 100644 index 00000000..59d439d6 --- /dev/null +++ b/roles/password_policy/vars/archlinux.yml @@ -0,0 +1,2 @@ +--- +password_policy_pkg: "libpwquality" diff --git a/roles/password_policy/vars/debian.yml b/roles/password_policy/vars/debian.yml new file mode 100644 index 00000000..cb52b37d --- /dev/null +++ b/roles/password_policy/vars/debian.yml @@ -0,0 +1,2 @@ +--- +password_policy_pkg: "libpam-pwquality" |
