From b3ff52f5a8055bc6995740b60353002a3abefb17 Mon Sep 17 00:00:00 2001 From: Adam Henry Lewenberg <adamhl@stanford.edu> Date: Thu, 5 Nov 2015 12:49:26 -0800 Subject: [PATCH] Set up base::ssh for duo --- manifests/ssh.pp | 40 +++++++++----- manifests/ssh/config/sshd.pp | 4 ++ manifests/ssh/pam.pp | 28 ++++++++++ manifests/sudo.pp | 18 ++++++- templates/ssh/etc/pam.d/sshd.erb | 79 ++++++++++++++++++++++++++++ templates/ssh/sshd_config.erb | 6 +++ templates/sudo/etc/sudoers.d/duo.erb | 1 + 7 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 manifests/ssh/pam.pp create mode 100644 templates/ssh/etc/pam.d/sshd.erb diff --git a/manifests/ssh.pp b/manifests/ssh.pp index eae9e09..1be9188 100644 --- a/manifests/ssh.pp +++ b/manifests/ssh.pp @@ -3,10 +3,27 @@ # system, we lock connections down to campus with iptables by default, and we # have a few subclasses that allow things like host keys. -class base::ssh { +# If you want to require Duo on login, set pam_duo to true. This flag will +# load the appropriate Duo code (via base::duo) and change the sshd_config +# file so that Duo is required for non-root logins. If you want Duo for +# sudo, see the base::sudo class. +# Default: false + +class base::ssh( + $pam_duo = false +){ package { 'openssh-server': ensure => present } - # Our default ssh rules allow connectiosn from all of campus. This is + if ($pam_duo) { + include base::duo + } + + # Setup /etc/pam.d/sshd to require Duo on regular logins. + class { 'ssh::pam': + pam_duo => $pam_duo, + } + + # Our default ssh rules allow connections from all of campus. This is # mostly for legacy reasons, since it historically had always done this and # we weren't sure what would break. # @@ -29,24 +46,21 @@ class base::ssh { # Ensure the daemon is running. service { 'ssh': + ensure => running, name => $::osfamily ? { - Debian => 'ssh', - RedHat => 'sshd', + Debian => 'ssh', + RedHat => 'sshd', }, - ensure => running, require => Package['openssh-server'], } - # Install our configuration files. - base::ssh::config::sshd { '/etc/ssh/sshd_config': ensure => present } + # Install ssh (client) configuration file. base::ssh::config::ssh { '/etc/ssh/ssh_config': ensure => present } - # Configure PAM for sshd on RHEL 6. - if ($::lsbdistcodename == 'santiago') { - file { '/etc/pam.d/sshd': - ensure => link, - target => '/etc/pam.d/system-auth', - } + # Install sshd (server) configuration file. + base::ssh::config::sshd { '/etc/ssh/sshd_config': + ensure => present, + pam_duo => $pam_duo, } # Make sure public key authentication to root does not work and clean up diff --git a/manifests/ssh/config/sshd.pp b/manifests/ssh/config/sshd.pp index 5c2605c..e3b3464 100644 --- a/manifests/ssh/config/sshd.pp +++ b/manifests/ssh/config/sshd.pp @@ -17,6 +17,9 @@ # If you want to allow root to log in with a password, set # rootloginwithpswd 'yes'. Otherwise, root logins with a password # are not allowed. +# +# If you want to require Duo on login, set pam_duo to true (defaults to +# false). define base::ssh::config::sshd( $ensure = 'present', @@ -28,6 +31,7 @@ define base::ssh::config::sshd( $max_tries = 5, $listen_addresses = 'all', $rootloginwithpswd = 'no', + $pam_duo = false, ) { if $source { $template = undef diff --git a/manifests/ssh/pam.pp b/manifests/ssh/pam.pp new file mode 100644 index 0000000..88d85dd --- /dev/null +++ b/manifests/ssh/pam.pp @@ -0,0 +1,28 @@ +# Install /etc/pam.d/sshd. + +# If $pam_duo is set to true, use a pam stack that requires Duo for +# regular logins. +# +# Currently, only Debian is supported when $pam_duo is true. + +class ssh::pam ( + $pam_duo = false +){ + + # Configure PAM for sshd on RHEL 6. + if ($::lsbdistcodename == 'santiago') { + file { '/etc/pam.d/sshd': + ensure => link, + target => '/etc/pam.d/system-auth', + } + } elsif ($pam_duo) { + if ($::osfamily =~ /Debian/) { + file {'/etc/pam.d/sshd': + ensure => present, + source => template('base/ssh/etc/pam.d/sshd.erb'), + } + } else { + fail("cannot call ssh::pam with pam_duo true under OS '$::osfamily'") + } + } +} diff --git a/manifests/sudo.pp b/manifests/sudo.pp index ca3f7df..0a2725f 100644 --- a/manifests/sudo.pp +++ b/manifests/sudo.pp @@ -5,6 +5,9 @@ # $duo_sudoers: A list of users that are allowed to call sudo. # Defaults to the empty array. # +# $timeout: how long (in minutes) between requiring a new Duo re-auth. +# Default: 30 +# # Example. # To install sudo with no Duo support: # @@ -14,13 +17,24 @@ # To install sudo WITH Duo support # # class { 'base::sudo': -# duo => true, -# duo_sudoers => ['adamhl', 'yuelu'] +# duo => true, +# duo_sudoers => ['adamhl', 'yuelu'], +# } +# +# Example. +# To install sudo WITH Duo support and require Duo auths +# after 4 minutes. +# +# class { 'base::sudo': +# duo => true, +# duo_sudoers => ['adamhl', 'yuelu'], +# timeout => 4, # } class base::sudo( $duo = false, $duo_sudoers = [], + $timeout = 30, ){ package { 'sudo': ensure => installed diff --git a/templates/ssh/etc/pam.d/sshd.erb b/templates/ssh/etc/pam.d/sshd.erb new file mode 100644 index 0000000..8674f6a --- /dev/null +++ b/templates/ssh/etc/pam.d/sshd.erb @@ -0,0 +1,79 @@ +# Configuration requiring duo authentication for normal logins and +# allowing root logins without duo authentication. + +############################################################################## +# auth +############################################################################## + +# 1. If the user is already logged in as root (presumably by using a root +# credential), then "jump over" the pam_duo module to step 3. If not, +# go to the next module in the stack (2). +# 2. If the user is _not_ root, require Duo. +# 3. Set up the AFS session and then, whether the AFS sesssion setup works +# or not, quit the pam stack + +auth [success=1 default=ignore] pam_succeed_if.so uid eq 0 +auth required pam_duo.so conf=/etc/security/pam_duo_su.conf +auth [success=done default=die] pam_afs_session.so + +############################################################################## +# account +############################################################################## + +# 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 + +# Standard Un*x authorization. +@include common-account + +############################################################################## +# session +############################################################################## + +# 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 + +############################################################################## +# Password +############################################################################## + +@include common-password diff --git a/templates/ssh/sshd_config.erb b/templates/ssh/sshd_config.erb index 446657f..2ec0b43 100644 --- a/templates/ssh/sshd_config.erb +++ b/templates/ssh/sshd_config.erb @@ -66,6 +66,12 @@ GSSAPIStoreCredentialsOnRekey yes GSSAPIStoreCredentialsOnRekey yes <% end -%> +<% if (@pam_duo) then -%> +# Require both (GSS-API|PASSWORD) and PAM. +AuthenticationMethods gssapi-with-mic,keyboard-interactive:pam password,keyboard-interactive:pam +KerberosAuthentication yes +<% end -%> + <%- if (@rootloginwithpswd == 'yes') -%> # Allow root login with a password (use with care!) PermitRootLogin yes diff --git a/templates/sudo/etc/sudoers.d/duo.erb b/templates/sudo/etc/sudoers.d/duo.erb index 7527c35..c0be278 100644 --- a/templates/sudo/etc/sudoers.d/duo.erb +++ b/templates/sudo/etc/sudoers.d/duo.erb @@ -1,3 +1,4 @@ +Defaults timestamp_timeout=<%= @timeout %> <% @duo_sudoers.each do |sudoer| -%> -- GitLab