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:
parent
5269c48085
commit
3dc247767d
20
README.rst
20
README.rst
@ -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.
|
having a fallback method to access the VMs.
|
||||||
|
|
||||||
Tatu's policy is that any role containing the word "admin" results in a user
|
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
|
account with sudo privileges. Note that because of this policy, an OpenStack
|
||||||
integration (not yet merged as of March 9, 2018) sudo privilege is revoked as
|
user may not have sudo privileges on VMs she herself launched.
|
||||||
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.
|
|
||||||
|
|
||||||
Note that because of this policy, an OpenStack user may not have sudo
|
Uber's pam-ussh module
|
||||||
privileges on VMs she herself launched.
|
----------------------
|
||||||
|
|
||||||
|
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
|
Bastion Management
|
||||||
------------------
|
------------------
|
||||||
|
@ -53,6 +53,7 @@ function configure_tatu {
|
|||||||
iniset $TATU_CONF tatu pat_dns_zone_email $TATU_DNS_ZONE_EMAIL
|
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 sqlalchemy_engine `database_connection_url tatu`
|
||||||
iniset $TATU_CONF tatu api_endpoint_for_vms $TATU_API_FOR_VMS
|
iniset $TATU_CONF tatu api_endpoint_for_vms $TATU_API_FOR_VMS
|
||||||
|
iniset $TATU_CONF tatu pam_sudo True
|
||||||
|
|
||||||
# Need Keystone and Nova notifications
|
# Need Keystone and Nova notifications
|
||||||
iniset $KEYSTONE_CONF oslo_messaging_notifications topics notifications,tatu_notifications
|
iniset $KEYSTONE_CONF oslo_messaging_notifications topics notifications,tatu_notifications
|
||||||
|
@ -20,6 +20,9 @@ write_files:
|
|||||||
host_id=$(echo $metadata | grep -Po 'uuid": "\K[^"]*')
|
host_id=$(echo $metadata | grep -Po 'uuid": "\K[^"]*')
|
||||||
echo host_id=$host_id
|
echo host_id=$host_id
|
||||||
vendordata=$(cat /mnt/config/openstack/latest/vendor_data2.json)
|
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[^"]*')
|
token=$(echo $vendordata | grep -Po '"token": "\K[^"]*')
|
||||||
if [ -z $token ]; then
|
if [ -z $token ]; then
|
||||||
echo Failed to extract the Tatu token ID from vendordata
|
echo Failed to extract the Tatu token ID from vendordata
|
||||||
@ -68,14 +71,19 @@ write_files:
|
|||||||
adduser $i
|
adduser $i
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
x=0
|
||||||
for i in ${sudoers//,/ }; do
|
for i in ${sudoers//,/ }; do
|
||||||
if [ $(getent group sudo) ]; then
|
prefix=$((130 + x++))
|
||||||
usermod -aG sudo $i
|
if [ "$pam_sudo" = true ]; then
|
||||||
fi
|
echo $i ALL= ALL > /etc/sudoers.d/$prefix-$i
|
||||||
if [ $(getent group wheel) ]; then
|
echo Defaults:$i timestamp_timeout=1 >> /etc/sudoers.d/$prefix-$i
|
||||||
usermod -aG wheel $i
|
else
|
||||||
|
echo $i ALL= NOPASSWD: ALL > /etc/sudoers.d/$prefix-$i
|
||||||
fi
|
fi
|
||||||
done
|
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
|
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
|
# 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.
|
# – 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
|
sed -i -e '$aPort 22' /etc/ssh/sshd_config
|
||||||
setenforce permissive
|
setenforce permissive
|
||||||
systemctl restart sshd
|
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
|
- path: /root/tatu-manage-revoked-keys.sh
|
||||||
permissions: '0700'
|
permissions: '0700'
|
||||||
owner: root:root
|
owner: root:root
|
||||||
|
@ -301,6 +301,7 @@ class NovaVendorData(object):
|
|||||||
'sudoers': ','.join([r for r in roles if "admin" in r]),
|
'sudoers': ','.join([r for r in roles if "admin" in r]),
|
||||||
'ssh_port': CONF.tatu.ssh_port,
|
'ssh_port': CONF.tatu.ssh_port,
|
||||||
'api_endpoint': CONF.tatu.api_endpoint_for_vms,
|
'api_endpoint': CONF.tatu.api_endpoint_for_vms,
|
||||||
|
'pam_sudo': CONF.tatu.pam_sudo,
|
||||||
}
|
}
|
||||||
resp.body = json.dumps(vendordata)
|
resp.body = json.dumps(vendordata)
|
||||||
resp.location = '/hosttokens/' + token.token_id
|
resp.location = '/hosttokens/' + token.token_id
|
||||||
|
@ -26,6 +26,8 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# 1) register options; 2) read the config file; 3) use the options
|
# 1) register options; 2) read the config file; 3) use the options
|
||||||
opts = [
|
opts = [
|
||||||
|
cfg.BoolOpt('pam_sudo', default=False,
|
||||||
|
help='Use pam-ussh module to validate certificates on sudo calls'),
|
||||||
cfg.BoolOpt('use_barbican', default=False,
|
cfg.BoolOpt('use_barbican', default=False,
|
||||||
help='Use OpenStack Barbican to store sensitive data'),
|
help='Use OpenStack Barbican to store sensitive data'),
|
||||||
cfg.BoolOpt('use_pat_bastions', default=True,
|
cfg.BoolOpt('use_pat_bastions', default=True,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user