Commit 22ab021d authored by Maciej Delmanowski's avatar Maciej Delmanowski

[debops.sshd] Implement PAM access control rules

The OpenSSH service configured by the 'debops.sshd' role will use PAM
access control rules to manage what UNIX accounts and groups can connect
to the hosts via SSH.
parent d9713de0
......@@ -171,6 +171,18 @@ Changed
:ref:`debops.system_groups` role was applied before the :ref:`debops.ldap`
role.
- [debops.sshd] The access control based on UNIX groups defined in the
:file:`/etc/ssh/sshd_config` file has been removed. Instead, the OpenSSH
server uses the PAM access control configuration, managed by the
:ref:`debops.pam_access` Ansible role, to control access by
users/groups/origins. OpenSSH service uses its own access control file,
separate from the global :file:`/etc/security/access.conf` file.
- [debops.sshd] The role will enable client address resolving using DNS by
setting the ``UseDNS yes`` option in OpenSSH server configuration. This
parameter is disabled by default in Debian and upstream, however it is
required for the domain-based access control rules to work as expected.
Removed
~~~~~~~
......
......@@ -113,6 +113,8 @@
- role: debops.pam_access
tags: [ 'role::pam_access', 'skip::pam_access' ]
pam_access__dependent_rules:
- '{{ sshd__pam_access__dependent_rules }}'
- role: debops.etc_services
tags: [ 'role::etc_services', 'skip::etc_services' ]
......
......@@ -25,5 +25,10 @@
tcpwrappers_dependent_allow:
- '{{ sshd__tcpwrappers__dependent_allow }}'
- role: debops.pam_access
tags: [ 'role::pam_access', 'skip::pam_access' ]
pam_access__dependent_rules:
- '{{ sshd__pam_access__dependent_rules }}'
- role: debops.sshd
tags: [ 'role::sshd', 'skip::sshd' ]
......@@ -294,6 +294,14 @@ sshd__compression: 'yes'
# since privilege separation became mandatory.
sshd__privilege_separation: 'sandbox'
# ]]]
# .. envvar:: sshd__use_dns [[[
#
# Enable or disable support for client hostname lookups by the SSH service.
# This is required if access control based on hostnames is used in the SSH
# server configuration, authorized keys or PAM access rules.
sshd__use_dns: 'yes'
# ]]]
# .. envvar:: sshd__custom_options [[[
#
......@@ -304,15 +312,17 @@ sshd__custom_options: ''
# Group-based access control [[[
# ------------------------------
# .. warning::
# The user and group access control on the :file:`sshd_config` level is
# deprecated. Use the PAM access control rules managed by the
# :ref:`debops.pam_access` role instead. Default rules are defined in the
# :envvar:`sshd__pam_access__dependent_rules` variable.
# .. envvar:: sshd__default_allow_groups [[[
#
# List of UNIX system groups which allow connections to SSH service defined by
# default. The ``root`` UNIX group is used for backup connections, temporarily.
sshd__default_allow_groups: '{{ ([ "root" ] + ansible_local.system_groups.access.sshd)
if (ansible_local|d() and ansible_local.system_groups|d() and
ansible_local.system_groups.access|d() and
ansible_local.system_groups.access.sshd|d())
else [] }}'
# default.
sshd__default_allow_groups: []
# ]]]
# .. envvar:: sshd__allow_groups [[[
......@@ -612,6 +622,26 @@ sshd__ldap_filter_map:
'service+host': '(&(objectClass=posixAccount)(uid=$username)(authorizedService=$service)(|(host=$hostname)(host=$fqdn)(host=\\*.$domain)(host=\\*)))'
# ]]]
# ]]]
# PAM configuration [[[
# ---------------------
# .. envvar:: sshd__pam_deploy_state [[[
#
# Enable or disable support for custom PAM configuration for the ``sshd``
# service. Set to ``absent`` to remove the customizations.
sshd__pam_deploy_state: 'present'
# ]]]
# .. envvar:: sshd__pam_access_file [[[
#
# Specify the absolute path of the PAM access file to use for the ``sshd``
# service.
sshd__pam_access_file: '{{ "/etc/security/access-sshd.conf"
if (ansible_local|d() and ansible_local.pam_access|d() and
"sshd" in ansible_local.pam_access.rules|d([]))
else "/etc/security/access.conf" }}'
# ]]]
# ]]]
# Match conditional blocks [[[
# ----------------------------
......@@ -761,6 +791,70 @@ sshd__tcpwrappers__dependent_allow:
weight: '30'
filename: 'sshd_dependent_allow'
comment: 'List of hosts allowed to connect to ssh'
# ]]]
# .. envvar:: sshd__pam_access__dependent_rules [[[
#
# Configuration for the :ref:`debops.pam_access` Ansible role.
sshd__pam_access__dependent_rules:
- name: 'sshd'
options:
- name: 'allow-root'
comment: 'Grant access via SSH to root account on the same DNS domain'
permission: 'allow'
users: 'root'
origins: '.{{ ansible_local.core.domain
if (ansible_local|d() and ansible_local.core|d() and
ansible_local.core.domain|d())
else (ansible_domain if ansible_domain else ansible_hostname) }}'
- name: 'deny-root'
comment: 'Deny access to root account via SSH from anywhere else'
permission: 'deny'
users: 'root'
origins: 'ALL'
- name: 'allow-system-groups'
comment: |
Grant access via SSH to members of UNIX groups defined on this host
permission: 'allow'
groups: '{{ ansible_local.system_groups.access.sshd
if (ansible_local|d() and ansible_local.system_groups|d() and
ansible_local.system_groups.access|d() and
ansible_local.system_groups.access.sshd|d())
else [ "admins", "sshusers", "sftponly" ] }}'
origins: 'ALL'
- name: 'allow-ldap-groups'
comment: |
Grant access via SSH to members of UNIX groups defined in LDAP
permission: 'allow'
groups: [ 'admins', 'sshusers', 'sftponly' ]
origins: 'ALL'
state: '{{ "present"
if (ansible_local|d() and ansible_local.ldap|d() and
(ansible_local.ldap.enabled|d())|bool)
else "absent" }}'
- name: 'allow-domain'
comment: |
Grant access via SSH to users on the same DNS domain. The SSH server
needs to have UseDNS option enabled for this rule to work correctly.
permission: 'allow'
users: 'ALL'
origins: '.{{ ansible_local.core.domain
if (ansible_local|d() and ansible_local.core|d() and
ansible_local.core.domain|d())
else (ansible_domain if ansible_domain else ansible_hostname) }}'
- name: 'deny-all'
comment: 'Deny access via SSH by anyone from anywhere'
permission: 'deny'
users: 'ALL'
origins: 'ALL'
weight: 99999
# ]]]
# ]]]
# ]]]
......@@ -184,6 +184,30 @@
state: 'absent'
notify: [ 'Test sshd configuration and restart' ]
- name: Divert PAM configuration for sshd
command: dpkg-divert --quiet --local
--divert "/etc/pam.d/sshd.dpkg-divert"
--rename "/etc/pam.d/sshd"
args:
creates: '/etc/pam.d/sshd.dpkg-divert'
when: sshd__pam_deploy_state == 'present'
- name: Generate PAM configuration for sshd
template:
src: 'etc/pam.d/sshd.j2'
dest: '/etc/pam.d/sshd'
mode: '0644'
when: sshd__pam_deploy_state == 'present'
- name: Revert default sshd PAM configuration if requested
shell: set -o nounset -o pipefail -o errexit &&
rm -f /etc/pam.d/sshd &&
dpkg-divert --quiet --local --rename --remove /etc/pam.d/sshd
args:
executable: '/bin/bash'
removes: '/etc/pam.d/sshd.dpkg-divert'
when: sshd__pam_deploy_state != 'present'
- name: Make sure that Ansible local fact directory exists
file:
path: '/etc/ansible/facts.d'
......
# {{ ansible_managed }}
# PAM configuration for the Secure Shell service
# Standard Un*x authentication.
@include common-auth
# Disallow non-root logins when /etc/nologin exists.
account required pam_nologin.so
# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
account required pam_access.so nodefgroup accessfile={{ sshd__pam_access_file }}
# Standard Un*x authorization.
@include common-account
# SELinux needs to be the first session rule. This ensures that any
# lingering context has been cleared. Without this it is possible that a
# module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
# Set the loginuid process attribute.
session required pam_loginuid.so
# Create a new session keyring.
session optional pam_keyinit.so force revoke
# Standard Un*x session setup and teardown.
@include common-session
# Print the message of the day upon successful login.
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
# Print the status of the user's mailbox upon successful login.
session optional pam_mail.so standard noenv # [1]
# Set up user limits from /etc/security/limits.conf.
session required pam_limits.so
# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
session required pam_env.so # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
# SELinux needs to intervene at login time to ensure that the process starts
# in the proper default security context. Only sessions which are intended
# to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
# Standard Un*x password updating.
@include common-password
......@@ -121,6 +121,12 @@ RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# If enabled, sshd will resolve the client hostnames and check their reverse
# PTR records to see if they are the same. This is required for hostname
# matching in authorized keys, Allow/Deny options and PAM access rules that use
# hostnames/domains.
UseDNS {{ sshd__use_dns }}
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes
......
......@@ -4,6 +4,21 @@ Getting started
.. contents::
:local:
Changes from Debian defaults
----------------------------
The ``debops.sshd`` role will configure the OpenSSH server to lookup the client
hostnames in DNS by setting the ``UseDNS`` option to ``yes`` (the Debian and
upstream default is ``no``). This allows use of the DNS hostnames and domains
in the authorized keys files and PAM access control rules. DNS lookup can be
controlled using the :envvar:`sshd__use_dns` variable.
The role will divert the original :file:`/etc/pam.d/sshd` configuration file
and generate a new one, with PAM access control enabled and using the separate
:file:`/etc/security/access-sshd.conf` configuration file. The ACL rules are
defined in the :envvar:`sshd__pam_access__dependent_rules` variable and are
managed by the :ref:`debops.pam_access` Ansible role.
Useful variables
----------------
......
......@@ -94,6 +94,19 @@ Inventory variable changes
| ``auth_nslcd_pam_authz_search_host_and_service`` | Removed | No |
+--------------------------------------------------+----------------------------------+--------------------------------------------------+
- The :envvar:`sshd__default_allow_groups` default variable has been changed to
an empty list. The group-based access control has been moved to a PAM access
control rules defined in the :envvar:`sshd__pam_access__dependent_rules`
variable.
Access to the OpenSSH service by the ``admins``, ``sshusers`` and
``sftponly`` UNIX groups members should work the same as before. Access to
the ``root`` account has been limited to hosts in the same DNS domain. UNIX
accounts not in the aforementioned UNIX groups can access the OpenSSH service
from hosts in the same DNS domain (other restrictions like public key
presence still apply). See :ref:`debops.pam_access` documentation for more
details about defining the PAM access rules.
v0.8.1 (2019-02-02)
-------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment