Salt Sesame - emergency sudoers access
Sysinfo: salt 2018.3.2 (Oxygen), Centos 7
Problem
sometimes non-sysadmin users need root level access to managed hosts. Need a good way to give users access temporary sudo access to a host, while also auditing who received access to the box
The following setup uses a custom Salt module, to inject a temporary password into a service user account and returns the password back to the user.
Users who can grant themselves this permission are controlled via Salt Master ACL, once they receive the password, they can login to target host as 'salt' user and then do 'sudo su'
Sequence
user Joe is one of authorized users who can request sudo access to host named "Atlas"
Joe SSHs into Salt Master (as his own account), and runs the command to grant himself temporary sudo access to "atlas"
joe@saltmaster> salt atlas sesame.open
Salt will generate a new password for the service account user called "salt" (this user has to be present on Atlas)
atlas:
your temporary password has been generated.
SSH as 'salt@atlas'
Password: uI_UcGAJQTPbglVMNNiNNxhdzV4I
This password will expire in 1 day
To secure SSH access now, run 'salt atlas sesame.close
Joe then SSHs into Atlas using the generated password
joe@joeMac> ssh salt@atlas
salt@atlas password: <types in generated password>
salt@atlas> sudo su
root@atlas>
Once Joe is done with work on Atlas, he logs out. He then secures access to it by running (this command removes the password from 'salt' user)
joe@saltmaster> salt atlas sesame.close
or the password will expire automatically in 1 day.
Joe's request is audited and recorded using 'lascomm', showing all users who ran 'salt' command recently
root@saltmaster> lastcomm salt
salt S root pts/0 0.27 secs Fri Aug 24 17:49
salt joe pts/2 0.19 secs Fri Aug 24 17:46
Prerequisites
make sure all your managed hosts have a 'salt' service account created, you can use the following state,
Add this to your user pillar,
/srv/salt/pillar/users/salt.sls
{% set user = 'salt' %}
{% set fullname = 'Salt Service Account' %}
{% set uid = '2001' %}
users:
{{ user }}:
status: present # present / absent
uid: {{ uid }}
groups:
- sysadmin
fullname: {{ fullname }}
home: /home/{{ user }}
shell: /bin/bash
createhome: True
now the State to create the user
/srv/salt/state/formula/users/init.sls
## Add Salt user to box
{% set args = salt['pillar.get']('users:salt') %}
salt:
group.present:
- gid: {{ args.uid }}
user.present:
- fullname: {{ args.fullname }}
- uid: {{ args.uid }}
- gid: {{ args.uid }}
- allow_uid_change: True
- allow_gid_change: True
- createhome: True
{% if 'shell' in args %}
- shell: {{ args.shell }}
{% endif %}
{% if 'home' in args %}
- home: {{ args.home }}
{% endif %}
{% if 'groups' in args %}
- groups: {{ args.groups }}
{% endif %}
add_custom_sudoers:
file.managed:
- name: /etc/sudoers.d/custom_sudo
- source: salt://formula/group/files/custom_sudo
- user: root
- group: root
- mode: 440
this will create a new 'salt' user on any managed host, add 'salt' to group called 'sysadmin' and add this group to Sudoers using a custom_sudo file,
/srv/salt/state/formula/group/files/custom_sudo
## Custom sudoers
## File Managed by Saltstack
%sysadmin ALL=(ALL) NOPASSWD:ALL
Run this on all your managed hosts
Also make sure your hosts /etc/ssh/sshd_config allows Password Authentication
Custom Execution Module - Sesame
to make Sesame module work, add this to your State directory (my file_roots is set to /srv/salt/state), my custom module path is /srv/salt/state/_modules
add a new file called sesame.py
cat /srv/salt/state/_modules/sesame.py
import salt
# Custom Execution Module
# gives temporary sudoers access to 'salt' service account
def open():
''' opens up Salt user account '''
pw = __salt__['random.get_str']('28')
hashed_pw = __salt__['shadow.gen_password'](pw)
target = __salt__['grains.get']('id')
__salt__['shadow.set_password']('salt', hashed_pw)
__salt__['cmd.run']('chage -M 1 salt')
return "your temporary password has been generated.\n\nSSH as 'salt@{0}'\nPassword: ".format(target) + pw + "\
\n\nThis password will expire in 1 day\n\nTo secure SSH access now, run 'salt {0} sesame.close".format(target)
def close():
__salt__['shadow.del_password']('salt')
return "'salt' user password has been removed. Target SSH access is secure."
this py module generates a random password, hashes it, injects it into the "salt" user account on the target box (with lifetime of 1 day)
Sync the new module across all managed nodes,
salt \* saltutil.sync_all
Salt Master Config
To enable ACL-controlled users to grant sudo access, you need to add them to the "publisher_acl"
edit /etc/salt/master
add the user that you want to access your custom module
publisher_acl:
joe:
- sesame.open
- sesame.close
This allows Joe to execute the following commands: sesame.open, sesame.close
restart salt master service
change /var/log/salt/master + /var/log/salt/minion log permissions to allow r/w by other users
chgrp -R usergroup /var/log/salt
chmod -R g+rw /var/log/salt
Grant Access to a minion
as Joe, run
salt minion1 sesame.open
minion1:
your temporary password has been generated.
SSH as 'salt@saltdev1'
Password: tVkBn5Il20vVo7Ti_N17UwYUSgd1
This password will expire in 1 day
To secure SSH access now, run 'salt minion1 sesame.close
Audit users
check for users who ran 'salt' command
lastcomm salt
root@saltmaster /srv# lastcomm salt
salt S root pts/0 0.27 secs Fri Aug 24 17:49
salt joe pts/2 0.19 secs Fri Aug 24 17:46