Enable pam-ussh module to check user ssh cert on sudo authentication.

Change-Id: Iffde339572885b21673731dd69fb9b2ba4df6073
Signed-off-by: Pino de Candia <giuseppe.decandia@gmail.com>
This commit is contained in:
Pino de Candia 2018-03-12 16:50:31 +00:00
parent 5269c48085
commit 3dc247767d
5 changed files with 62 additions and 12 deletions

View File

@ -162,14 +162,20 @@ KeyPairs continue to work as designed, which is useful for debugging Tatu or
having a fallback method to access the VMs.
Tatu's policy is that any role containing the word "admin" results in a user
account with passwordless sudo privileges. Thanks to the uber/pam-ussh
integration (not yet merged as of March 9, 2018) sudo privilege is revoked as
soon as the VM learns that the user's certificate has been revoked. However,
uber/pam-ussh requires the client to run ssh-agent and ssh-add their
certificate.
account with sudo privileges. Note that because of this policy, an OpenStack
user may not have sudo privileges on VMs she herself launched.
Note that because of this policy, an OpenStack user may not have sudo
privileges on VMs she herself launched.
Uber's pam-ussh module
----------------------
Thanks to the uber/pam-ussh integration sudo privilege is revoked as soon as
the VM learns that the user's certificate has been revoked. However,
uber/pam-ussh requires the client to run ssh-agent, ssh-add their key
(corresponding to their certificate) and launch ssh with the -A option.
This feature is enabled/disabled by setting pam_sudo to True/False in tatu's
configuration. When the feature is disabled, sudo access is not authenticated,
it's password-less (since we don't use passwords in our user account setup).
Bastion Management
------------------

View File

@ -53,6 +53,7 @@ function configure_tatu {
iniset $TATU_CONF tatu pat_dns_zone_email $TATU_DNS_ZONE_EMAIL
iniset $TATU_CONF tatu sqlalchemy_engine `database_connection_url tatu`
iniset $TATU_CONF tatu api_endpoint_for_vms $TATU_API_FOR_VMS
iniset $TATU_CONF tatu pam_sudo True
# Need Keystone and Nova notifications
iniset $KEYSTONE_CONF oslo_messaging_notifications topics notifications,tatu_notifications

View File

@ -20,6 +20,9 @@ write_files:
host_id=$(echo $metadata | grep -Po 'uuid": "\K[^"]*')
echo host_id=$host_id
vendordata=$(cat /mnt/config/openstack/latest/vendor_data2.json)
pam_sudo=$(echo $vendordata | grep -Po '"pam_sudo": \K[^,]*' | tr '[:upper:]' '[:lower:]')
pam_sudo=${pam_sudo:-false}
echo pam_sudo=$pam_sudo
token=$(echo $vendordata | grep -Po '"token": "\K[^"]*')
if [ -z $token ]; then
echo Failed to extract the Tatu token ID from vendordata
@ -68,14 +71,19 @@ write_files:
adduser $i
fi
done
x=0
for i in ${sudoers//,/ }; do
if [ $(getent group sudo) ]; then
usermod -aG sudo $i
fi
if [ $(getent group wheel) ]; then
usermod -aG wheel $i
prefix=$((130 + x++))
if [ "$pam_sudo" = true ]; then
echo $i ALL= ALL > /etc/sudoers.d/$prefix-$i
echo Defaults:$i timestamp_timeout=1 >> /etc/sudoers.d/$prefix-$i
else
echo $i ALL= NOPASSWD: ALL > /etc/sudoers.d/$prefix-$i
fi
done
if [ "$pam_sudo" = true ]; then
(crontab -l; echo "* * * * * /root/tatu-setup-pam.sh >> /var/log/tatu-setup-pam.log") | crontab -
fi
sed -i -e '$aTrustedUserCAKeys /etc/ssh/ca_user.pub' /etc/ssh/sshd_config
# man sshd_config, under AuthorizedPrincipalsFile: The default is none, i.e. not to use a principals file
# in this case, the username of the user must appear in a certificate's principals list for it to be accepted.
@ -89,6 +97,38 @@ write_files:
sed -i -e '$aPort 22' /etc/ssh/sshd_config
setenforce permissive
systemctl restart sshd
echo Completed!
- path: /root/tatu-setup-pam.sh
permissions: '0700'
owner: root:root
content: |
#!/bin/bash
# Name: tatu-setup-pam.sh
#
# Purpose: Install uber/pam-ussh so that every sudo call authenticates the user's certificate in the background.
# If the user's certificate expires or is revoked, sudo authentication will fail. They lose sudo privileges even if
# they are still logged in.
crontab -l | grep -v 'tatu-setup-pam' | crontab -
cd /root
rm -rf /root/pam-ussh
inst=`which dnf`
inst=${inst:-`which yum`}
inst=${inst:-`which apt-get`}
$inst install -y pam-devel golang git
git clone https://github.com/pinodeca/pam-ussh
cd pam-ussh
git checkout -b krl origin/krl
export GOPATH=/root/pam-ussh/.go
go get golang.org/x/crypto/ssh
go get github.com/stretchr/testify/require
go get github.com/stripe/krl
make
mv pam_ussh.so /lib64/security/
vendordata=$(cat /mnt/config/openstack/latest/vendor_data2.json)
sudoers=$(echo $vendordata | grep -Po '"sudoers": "\K[^"]*')
echo setting up pam-ussh sudo authentication for $sudoers
sed -i -e '/auth.*pam_unix/i \
auth sufficient /lib64/security/pam_ussh.so ca_file=/etc/ssh/ca_user.pub authorized_principals='"$sudoers"' revoked_keys_file=/etc/ssh/revoked-keys' /etc/pam.d/system-auth
- path: /root/tatu-manage-revoked-keys.sh
permissions: '0700'
owner: root:root

View File

@ -301,6 +301,7 @@ class NovaVendorData(object):
'sudoers': ','.join([r for r in roles if "admin" in r]),
'ssh_port': CONF.tatu.ssh_port,
'api_endpoint': CONF.tatu.api_endpoint_for_vms,
'pam_sudo': CONF.tatu.pam_sudo,
}
resp.body = json.dumps(vendordata)
resp.location = '/hosttokens/' + token.token_id

View File

@ -26,6 +26,8 @@ LOG = logging.getLogger(__name__)
# 1) register options; 2) read the config file; 3) use the options
opts = [
cfg.BoolOpt('pam_sudo', default=False,
help='Use pam-ussh module to validate certificates on sudo calls'),
cfg.BoolOpt('use_barbican', default=False,
help='Use OpenStack Barbican to store sensitive data'),
cfg.BoolOpt('use_pat_bastions', default=True,