diff --git a/galaxy.yml b/galaxy.yml index 8d6cc92..8ee080a 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -45,6 +45,7 @@ tags: dependencies: "community.general": ">=8.3.0" "ansible.posix": ">=1.5.4" + "community.crypto": ">=2.17.1" # The URL of the originating SCM repository repository: https://github.com/roles-ansible/ansible_collection_users.git diff --git a/roles/admin/tasks/user_ansible.yml b/roles/admin/tasks/user_ansible.yml index e0f553b..43eab15 100644 --- a/roles/admin/tasks/user_ansible.yml +++ b/roles/admin/tasks/user_ansible.yml @@ -5,6 +5,6 @@ name: 'ansible_superpowers' commands: 'ALL' nopassword: true - user: "{{ l3d_users__ansible_user_state | ternary('present', 'absent') }}" + user: 'ansible' + state: "{{ l3d_users__ansible_user_state | ternary('present', 'absent') }}" validation: 'required' - state: 'present' diff --git a/roles/sshd/README.md b/roles/sshd/README.md new file mode 100644 index 0000000..a125504 --- /dev/null +++ b/roles/sshd/README.md @@ -0,0 +1,68 @@ + Ansible Role SSHD +==================== + +Ansible role l3d.users.sshd to Manage SSHD Configuration of the system and which Users are allowed to login. + +# WORK IN PROGRESS + +There are two variables to define users. The ``l3d_users__default_users`` is ment to put to your group_vars to define a default for your system. The ``l3d_users__local_users`` could be put in your host_vars to define host-specific user and admin roles. + + Variables: +----------- + +### User Management + ++ The dictionary-variable for your group_vars to set your general users and admins is ``l3d_users__default_users``. ++ The dictionary-variable for your host_vars to set your host-specific users and admins is: ``l3d_users__local_users``. +The Option of these directory-variables are the following. + +| option | values | description | +| ------ | ------ | --- | +| name | string | The user you want to create | +| state | ``present`` | Create or delete user | +| shell | ``/bin/bash`` | The Shell of the User | +| create_home | ``true`` | create a user home *(needed to store ssh keys)* | +| admin | ``false`` | enable it to give the user superpowers | +| admin_commands | string or list | Commands that are allows to be run as admin, eg. 'ALL' or specific script | +| admin_nopassword | false | Need no Password for sudo | +| pubkeys | string or lookup | see examples | +| exklusive_pubkeys | ``true`` | delete all undefined ssh keys | +| password | password hash | See [official FAQ](https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module) | +| remove | ``false`` | completly remove user if state is absent | + +### Other + +| name | default value | description | +| --- | --- | --- | +| submodules_versioncheck | ``false`` | Optionaly enable simple versionscheck of this role | + + Example Playbook +----------------- +```yaml +- name: Create System with User and Passwords + hosts: example.com + roles: + - {role: l3d.users.user, tags: 'user'} + vars: + l3d_users__local_users: + - name: 'alice' + state: 'present' + shell: '/bin/bash' + create_home: true + admin: true + admin_commands: 'ALL' + pubkeys: | + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPvvXN33GwkTF4ZOwPgF21Un4R2z9hWUuQt1qIfzQyhC + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAG65EdcM+JLv0gnzT9LcqVU47Pkw0SqiIg7XipXENi8 + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJz7zEvUVgJJJsIgfG3izsqYcM22IaKz4jGVUbNRL2PX + exklusive_pubkeys: true + - name: 'bob' + state: 'present' + admin: false + pubkeys: "{{ lookup('url', 'https://github.com/do1jlr.keys', split_lines=False) }}" + + l3d_users__create_ansible: true + l3d_users__set_ansible_ssh_keys: true + l3d_users__ansible_ssh_keys: "{{ lookup('url', 'https://github.com/do1jlr.keys', split_lines=False) }}" + submodules_versioncheck: true +``` diff --git a/roles/sshd/defaults/main.yml b/roles/sshd/defaults/main.yml new file mode 100644 index 0000000..c34e9af --- /dev/null +++ b/roles/sshd/defaults/main.yml @@ -0,0 +1,91 @@ +--- +# create users +l3d_users__default_users: [] +# - name: 'alice' +# state: 'present' +# shell: '/bin/bash' +# create_home: true +# pubkeys: | +# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPvvXN33GwkTF4ZOwPgF21Un4R2z9hWUuQt1qIfzQyhC +# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAG65EdcM+JLv0gnzT9LcqVU47Pkw0SqiIg7XipXENi8 +# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJz7zEvUVgJJJsIgfG3izsqYcM22IaKz4jGVUbNRL2PX +# exklusive_pubkeys: true +# password: "$Password_hash" +# admin: true +# admin_commands: 'ALL' +# admin_nopassword: false +# - name: 'bob' +# state: 'present' +# shell: '/bin/zsh' +# admin: false +# pubkeys: "{{ lookup('url', 'https://github.com/do1jlr.keys', split_lines=False) }}" +# exklusive_pubkeys: false + +l3d_users__local_users: [] +# - name: 'charlie' +# state: 'present' +# admin: false +# pubkeys: "{{ lookup('url', 'https://github.com/do1jlr.keys', split_lines=False) }}" + +l3d_users__ssh_login: [] +# - name: 'dora' + +l3d_users__limit_login: true + +l3d_users__sshd_port: 22 +l3d_users__sshd_password_authentication: false + +l3d_users__sshd_manage_server_key_types: true +l3d_users__sshd_server_key_types: + - ed25519 + # - rsa + # - ecdsa + +l3d_users__sshd_manage_key_algorithmus: true +l3d_users__sshd_key_algorithmus: + - 'ssh-ed25519-cert-v01@openssh.com' + - 'ssh-ed25519' + - 'ecdsa-sha2-nistp521-cert-v01@openssh.com' + - 'ecdsa-sha2-nistp384-cert-v01@openssh.com' + - 'ecdsa-sha2-nistp256-cert-v01@openssh.com' + # - 'rsa-sha2-512-cert-v01@openssh.com' + # - 'rsa-sha2-256-cert-v01@openssh.com' + # - 'ssh-rsa-cert-v01@openssh.com' + # - 'ecdsa-sha2-nistp521' + # - 'ecdsa-sha2-nistp384' + # - 'ecdsa-sha2-nistp256' + # - 'rsa-sha2-512' + # - 'rsa-sha2-256' + # - 'ssh-rsa' + +l3d_users__sshd_manage_kex_algorithmus: true +l3d_users__sshd_kex_algorithmus: + - 'curve25519-sha256@libssh.org' + - 'diffie-hellman-group-exchange-sha256' + - 'diffie-hellman-group-exchange-sha1' + # - 'diffie-hellman-group14-sha1' + # - 'diffie-hellman-group1-sha1' + +l3d_users__sshd_manage_ciphers: true +l3d_users__sshd_ciphers: + - 'chacha20-poly1305@openssh.com' + - 'aes256-gcm@openssh.com' + - 'aes256-ctr' + # - 'aes256-cbc' + # - 'aes128-ctr' + # - 'aes128-cbc' + +l3d_users__sshd_manage_macs: true +l3d_users__sshd_macs: + - 'hmac-sha2-512-etm@openssh.com' + - 'hmac-sha2-256-etm@openssh.com' + - 'hmac-sha2-512' + # - 'hmac-sha2-256' + # - 'hmac-ripemd160-etm@openssh.com' + # - 'umac-128-etm@openssh.com' + # - 'hmac-sha1' + +l3d_users__sshd_xforwarding: true + +# run simple versionscheck +submodules_versioncheck: false diff --git a/roles/sshd/handlers/main.yml b/roles/sshd/handlers/main.yml new file mode 100644 index 0000000..9c3acd9 --- /dev/null +++ b/roles/sshd/handlers/main.yml @@ -0,0 +1,8 @@ +--- +- name: Restart SSHD Server + become: true + listen: 'systemctl restart sshd' + ansible.builtin.systemd: + name: "{{ l3d_users__sshd_service }}" + state: restarted + when: sshd__service is defined and ansible_service_mgr == 'systemd' diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml new file mode 100644 index 0000000..16a03e1 --- /dev/null +++ b/roles/sshd/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- name: Perform optional versionscheck + ansible.builtin.include_tasks: + file: 'versioncheck.yml' + when: submodules_versioncheck | bool + +- name: Load l3d_users_sshd_service variable + ansible.builtin.include_vars: "{{ lookup('first_found', l3d_users_sshd__service_var_path) }}" + +- name: Install openssh server + ansible.builtin.include_tasks: + file: 'packages.yml' + +- name: Merge default and locale Users + ansible.builtin.set_fact: + _l3d_users__merged_users: "{{ l3d_users__default_users + l3d_users__local_users + l3d_users__ssh_login }}" + +- name: Manage Server SSH Keys + ansible.builtin.include_tasks: + file: 'server_keys.yml' + when: l3d_users__sshd_manage_server_key_types | bool + +- name: Create SSHD Config + ansible.builtin.include_tasks: + file: 'sshd_config.yml' diff --git a/roles/sshd/tasks/packages.yml b/roles/sshd/tasks/packages.yml new file mode 100644 index 0000000..8a5b7fc --- /dev/null +++ b/roles/sshd/tasks/packages.yml @@ -0,0 +1,15 @@ +--- +- name: Update apt cache + become: true + ansible.builtin.apt: + cache_valid_time: 3600 + update_cache: true + when: + - ansible_pkg_mgr == "apt" + +- name: Install openssh server + become: true + ansible.builtin.package: + name: "{{ item }}" + state: 'present' + with_items: "{{ l3d_users__sshd_package }}" diff --git a/roles/sshd/tasks/server_keys.yml b/roles/sshd/tasks/server_keys.yml new file mode 100644 index 0000000..4dc882b --- /dev/null +++ b/roles/sshd/tasks/server_keys.yml @@ -0,0 +1,34 @@ +--- +- name: Generate new ssh host key pair if necessary + become: true + community.crypto.openssh_keypair: + path: "/etc/ssh/ssh_host_{{ item }}_key" + type: "{{ item }}" + group: root + mode: '0600' + owner: 'root' + with_items: "{{ l3d_users__sshd_server_key_types }}" + when: + - l3d_users__sshd_manage_server_key_types | bool + notify: + - 'systemctl restart sshd' + +- name: Make sure only the correct keys are available + ansible.builtin.file: + path: '/etc/ssh/ssh_host_{{ item }}_key' + state: absent + become: true + with_items: + - "{{ l3d_users__sshd_key_types_list | difference(l3d_users__sshd_server_key_types) }}" + notify: + - 'systemctl restart sshd' + +- name: Make sure only the correct pubkeys are available + ansible.builtin.file: + path: '/etc/ssh/ssh_host_{{ item }}_key.pub' + state: absent + become: true + with_items: + - "{{ l3d_users__sshd_key_types_list | difference(l3d_users__sshd_server_key_types) }}" + notify: + - 'systemctl restart sshd' diff --git a/roles/sshd/tasks/sshd_config.yml b/roles/sshd/tasks/sshd_config.yml new file mode 100644 index 0000000..c25083b --- /dev/null +++ b/roles/sshd/tasks/sshd_config.yml @@ -0,0 +1,28 @@ +--- +- name: Get sshd version + ansible.builtin.command: + cmd: "/usr/bin/ssh -V" + register: _sshd_version_cmd + changed_when: false + +- name: Strip sshd output to Version + ansible.builtin.set_fact: + _sshd_version: "{{ _sshd_version_cmd.stderr.split('_')[1].split(',')[0].split('p')[0] }}" + +- name: Show detected ssh version + ansible.builtin.debug: + msg: "SSH Version: {{ _sshd_version }}" + verbosity: 1 + +# - name: Create SSHD configuration +# become: true +# ansible.builtin.template: +# src: 'templates/sshd_config.j2' +# dest: '/etc/ssh/sshd_config' +# owner: 'root' +# group: 'root' +# mode: 'u=rw,g=r,o=r' +# validate: '/usr/sbin/sshd -t -f %s' +# backup: true +# notify: +# - 'systemctl restart sshd' diff --git a/roles/sshd/tasks/versioncheck.yml b/roles/sshd/tasks/versioncheck.yml new file mode 100644 index 0000000..7dd80c5 --- /dev/null +++ b/roles/sshd/tasks/versioncheck.yml @@ -0,0 +1,44 @@ +--- +# Copyright (c) 2021 L3D +# this file is released with the MIT license. +# License: https://github.com/roles-ansible/ansible_role_template/blob/main/LICENSE +- name: Create directory for versionscheck + become: true + ansible.builtin.file: + path: '/etc/.ansible-version' + state: directory + mode: '0755' + when: submodules_versioncheck | bool + +- name: Check playbook version + become: true + ansible.builtin.slurp: + src: "/etc/.ansible-version/{{ playbook_version_path }}" + register: playbook_version + when: submodules_versioncheck | bool + failed_when: false + +- name: Print remote role version # noqa: H500 + ansible.builtin.debug: + msg: "Remote role version: {{ playbook_version.content | default('Y3VycmVudGx5IG5vdCBkZXBsb3llZAo=') | b64decode | string }}" + when: submodules_versioncheck | bool + +- name: Print locale role version # noqa: H500 + ansible.builtin.debug: + msg: "Local role version: '{{ playbook_version_number | string }}'." + when: submodules_versioncheck | bool + +- name: Check if your version is outdated + ansible.builtin.fail: + msg: "Your ansible module has the version '{{ playbook_version_number }}' and is outdated. You need to update it!" + when: + - playbook_version.content|default("Mgo=")|b64decode|int - 1 >= playbook_version_number|int and submodules_versioncheck | bool + +- name: Write new version to remote disk + become: true + ansible.builtin.copy: + content: "{{ playbook_version_number }}" + dest: "/etc/.ansible-version/{{ playbook_version_path }}" + mode: '0644' + when: submodules_versioncheck | bool + tags: skip_ansible_lint_template-instead-of-copy diff --git a/roles/sshd/templates/sshd_config.j2 b/roles/sshd/templates/sshd_config.j2 new file mode 100644 index 0000000..ebd536a --- /dev/null +++ b/roles/sshd/templates/sshd_config.j2 @@ -0,0 +1,130 @@ +# Attention, local changew will be overwritten +# MIT (C) L3D +# {{ ansible_managed }} +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +{% if sshd__version_is_above_eight | default(false) | bool %} +# Include SSHD config snippets +Include /etc/ssh/sshd_config.d/*.conf +{% endif %} + +# Networking +Port {{ sshd__port }} +AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +TCPKeepAlive yes + +# SSHD Key exchange +# -> HostkeyAlgorithms +{% if not sshd__manage_key_algorithmus | bool %}#{% endif -%} +{{ 'HostkeyAlgorithms ' }} +{%- for algo in sshd__key_algorithmus -%} + {{- algo -}} + {{- "," if not loop.last -}} +{%- endfor %} + +# -> KexAlgorithms +{% if not sshd__manage_kex_algorithmus | bool %}#{% endif -%} +{{ 'KexAlgorithms ' }} +{%- for algo in sshd__kex_algorithmus -%} + {{- algo -}} + {{- "," if not loop.last -}} +{%- endfor %} + + +# Ciphers and keying +# RekeyLimit default none +# -> Ciphers +{% if not sshd__manage_ciphers | bool %}#{% endif -%} +{{ 'Ciphers ' }} +{%- for cipher in sshd__ciphers -%} + {{- cipher -}} + {{- "," if not loop.last -}} +{%- endfor %} + + +# -> Macs +{% if not sshd__manage_macs | bool %}#{% endif -%} +{{ 'MACs ' }} +{%- for mac in sshd__macs -%} + {{- mac -}} + {{- "," if not loop.last -}} +{%- endfor %} + +# Server Authentication +Protocol 2 + +# Logging +SyslogFacility AUTH +LogLevel INFO + +# SSHD Host Keys +{% for key in sshd__key_types %} +# -> {{ key }} +{% if not sshd__manage_key_types | bool %}#{% endif -%} +HostKey /etc/ssh/ssh_host_{{ key }}_key +{% endfor %} + + +# Client authentication +MaxAuthTries 6 +MaxSessions 10 +PasswordAuthentication {{ sshd__password_authentication | ternary('yes', 'no') }} +ChallengeResponseAuthentication no +PubkeyAuthentication yes +PermitRootLogin without-password +LoginGraceTime 120 +StrictModes yes +X11Forwarding {{ sshd__xforwarding | ternary('yes', 'no') }} + +AllowTcpForwarding yes +#GatewayPorts no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes + +PrintMotd no +PrintLastLog yes +TCPKeepAlive yes + +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS no +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + + +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +UsePAM yes + +# User Authentication +{% if not sshd__restrict_users -%}#{%- endif -%} +AllowUsers {{ sshd__allowed_users|join(' ') }} + +# Group Authentication +{% if not sshd__restrict_groups -%}#{%- endif -%} +AllowGroups {{ sshd__allowed_groups|join(' ') }} + +# Allow client to pass locale environment variables +AcceptEnv LANG LC_* + +# sftp (required by ansible) +# Subsystem sftp /usr/lib/openssh/sftp-server +{% if ansible_os_family == 'RedHat' %} +Subsystem sftp /usr/libexec/openssh/sftp-server +{% else %} +Subsystem sftp /usr/lib/openssh/sftp-server +{% endif %} diff --git a/roles/sshd/vars/main.yml b/roles/sshd/vars/main.yml new file mode 100644 index 0000000..e4c873c --- /dev/null +++ b/roles/sshd/vars/main.yml @@ -0,0 +1,11 @@ +--- +playbook_version_number: 2 +playbook_version_path: 'l3d.users.sshd.version' + +l3d_users_sshd__service_var_path: + files: + - "sshd_{{ ansible_distribution | lower }}.yml" + - "sshd_{{ ansible_os_family }}.yml" + - 'sshd_default.yml' + paths: + - 'vars' diff --git a/roles/sshd/vars/sshd_archlinux.yml b/roles/sshd/vars/sshd_archlinux.yml new file mode 100644 index 0000000..d1f9a37 --- /dev/null +++ b/roles/sshd/vars/sshd_archlinux.yml @@ -0,0 +1,12 @@ +--- +l3d_users__sshd_service: 'sshd' +l3d_users__sshd_key_types_list: + - 'ed25519' + - 'rsa' + - 'ecdsa' + - 'dsa' + +l3d_users__sshd_xauth: + - 'xorg-xauth' + +l3d_users__sshd_package: 'openssh' diff --git a/roles/sshd/vars/sshd_centos.yml b/roles/sshd/vars/sshd_centos.yml new file mode 100644 index 0000000..50513e1 --- /dev/null +++ b/roles/sshd/vars/sshd_centos.yml @@ -0,0 +1,12 @@ +--- +l3d_users__sshd_service: 'sshd' +l3d_users__sshd_key_types_list: + - 'ed25519' + - 'rsa' + - 'ecdsa' + - 'dsa' + +l3d_users__sshd_xauth: + - 'xorg-xauth' + +l3d_users__sshd_package: 'openssh-server' diff --git a/roles/sshd/vars/sshd_debian.yml b/roles/sshd/vars/sshd_debian.yml new file mode 100644 index 0000000..0a7ad67 --- /dev/null +++ b/roles/sshd/vars/sshd_debian.yml @@ -0,0 +1,12 @@ +--- +l3d_users__sshd_service: 'ssh' +l3d_users__sshd_key_types_list: + - 'ed25519' + - 'rsa' + - 'ecdsa' + - 'dsa' + +l3d_users__sshd_xauth: + - 'xorg-xauth' + +l3d_users__sshd_package: 'openssh-server' diff --git a/roles/sshd/vars/sshd_default.yml b/roles/sshd/vars/sshd_default.yml new file mode 100644 index 0000000..0a7ad67 --- /dev/null +++ b/roles/sshd/vars/sshd_default.yml @@ -0,0 +1,12 @@ +--- +l3d_users__sshd_service: 'ssh' +l3d_users__sshd_key_types_list: + - 'ed25519' + - 'rsa' + - 'ecdsa' + - 'dsa' + +l3d_users__sshd_xauth: + - 'xorg-xauth' + +l3d_users__sshd_package: 'openssh-server' diff --git a/roles/sshd/vars/sshd_fedora.yml b/roles/sshd/vars/sshd_fedora.yml new file mode 100644 index 0000000..50513e1 --- /dev/null +++ b/roles/sshd/vars/sshd_fedora.yml @@ -0,0 +1,12 @@ +--- +l3d_users__sshd_service: 'sshd' +l3d_users__sshd_key_types_list: + - 'ed25519' + - 'rsa' + - 'ecdsa' + - 'dsa' + +l3d_users__sshd_xauth: + - 'xorg-xauth' + +l3d_users__sshd_package: 'openssh-server'