Add sudo state, salt-managed aliases,users,groups
- apply review comments
- add visudo check cmd
diff --git a/README.rst b/README.rst
index 7f38c2a..1b5cc7a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,3 @@
-
=====
Linux
=====
@@ -31,7 +30,7 @@
timezone: 'Europe/Prague'
utc: true
-Linux with system users, sowe with password set
+Linux with system users, some with password set
.. code-block:: yaml
@@ -54,6 +53,115 @@
home: '/home/jsmith'
password: userpassword
+Configure sudo for users and groups under ``/etc/sudoers.d/``.
+This ways ``linux.system.sudo`` pillar map to actual sudo attributes:
+
+.. code-block:: jinja
+ # simplified template:
+ Cmds_Alias {{ alias }}={{ commands }}
+ {{ user }} {{ hosts }}=({{ runas }}) NOPASSWD: {{ commands }}
+ %{{ group }} {{ hosts }}=({{ runas }}) NOPASSWD: {{ commands }}
+
+ # when rendered:
+ saltuser1 ALL=(ALL) NOPASSWD: ALL
+
+
+.. code-block:: yaml
+ linux:
+ system:
+ sudo:
+ enabled: true
+ alias:
+ host:
+ LOCAL:
+ - localhost
+ PRODUCTION:
+ - db1
+ - db2
+ runas:
+ DBA:
+ - postgres
+ - mysql
+ SALT:
+ - root
+ command:
+ # Note: This is not 100% safe when ALL keyword is used, user still may modify configs and hide his actions.
+ # Best practice is to specify full list of commands user is allowed to run.
+ SUPPORT_RESTRICTED:
+ - /bin/vi /etc/sudoers*
+ - /bin/vim /etc/sudoers*
+ - /bin/nano /etc/sudoers*
+ - /bin/emacs /etc/sudoers*
+ - /bin/su - root
+ - /bin/su -
+ - /bin/su
+ - /usr/sbin/visudo
+ SUPPORT_SHELLS:
+ - /bin/sh
+ - /bin/ksh
+ - /bin/bash
+ - /bin/rbash
+ - /bin/dash
+ - /bin/zsh
+ - /bin/csh
+ - /bin/fish
+ - /bin/tcsh
+ - /usr/bin/login
+ - /usr/bin/su
+ - /usr/su
+ ALL_SALT_SAFE:
+ - /usr/bin/salt state*
+ - /usr/bin/salt service*
+ - /usr/bin/salt pillar*
+ - /usr/bin/salt grains*
+ - /usr/bin/salt saltutil*
+ - /usr/bin/salt-call state*
+ - /usr/bin/salt-call service*
+ - /usr/bin/salt-call pillar*
+ - /usr/bin/salt-call grains*
+ - /usr/bin/salt-call saltutil*
+ SALT_TRUSTED:
+ - /usr/bin/salt*
+ users:
+ # saltuser1 with default values: saltuser1 ALL=(ALL) NOPASSWD: ALL
+ saltuser1: {}
+ saltuser2:
+ hosts:
+ - LOCAL
+ # User Alias DBA
+ DBA:
+ hosts:
+ - ALL
+ commands:
+ - ALL_SALT_SAFE
+ groups:
+ db-ops:
+ hosts:
+ - ALL
+ - '!PRODUCTION'
+ runas:
+ - DBA
+ commands:
+ - /bin/cat *
+ - /bin/less *
+ - /bin/ls *
+ salt-ops:
+ hosts:
+ - 'ALL'
+ runas:
+ - SALT
+ commands:
+ - SUPPORT_SHELLS
+ salt-ops-2nd:
+ name: salt-ops
+ nopasswd: false
+ runas:
+ - DBA
+ commands:
+ - ALL
+ - '!SUPPORT_SHELLS'
+ - '!SUPPORT_RESTRICTED'
+
Linux with package, latest version
.. code-block:: yaml
diff --git a/linux/files/sudoer b/linux/files/sudoer
index 3b682af..549d5f9 100644
--- a/linux/files/sudoer
+++ b/linux/files/sudoer
@@ -1,5 +1,6 @@
-# managed by salt
-
+# sudoer file managed by salt-minion
+# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
+#
# user {{ user_name }} is system administrator.
# It has passwordless sudo functionality.
{{ user_name }} ALL=(ALL) NOPASSWD:ALL
diff --git a/linux/files/sudoer-aliases b/linux/files/sudoer-aliases
new file mode 100644
index 0000000..9e44886
--- /dev/null
+++ b/linux/files/sudoer-aliases
@@ -0,0 +1,19 @@
+# sudoer aliases, file managed by salt-minion
+# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
+
+{%- for alias,commands in aliases.get('command',{}).iteritems() %}
+Cmnd_Alias {{ alias }}={{ commands|join(', ') }}
+{%- endfor %}
+
+{%- for alias,users in aliases.get('user',{}).iteritems() %}
+User_Alias {{ alias }}={{ users|join(', ') }}
+{%- endfor %}
+
+{%- for alias,users in aliases.get('runas',{}).iteritems() %}
+Runas_Alias {{ alias }}={{ users|join(', ') }}
+{%- endfor %}
+
+{%- for alias,hosts in aliases.get('host',{}).iteritems() %}
+Host_Alias {{ alias }}={{ hosts|join(', ') }}
+{%- endfor %}
+
diff --git a/linux/files/sudoer-groups b/linux/files/sudoer-groups
new file mode 100644
index 0000000..b0c1fdf
--- /dev/null
+++ b/linux/files/sudoer-groups
@@ -0,0 +1,7 @@
+# sudoer groups, file managed by salt-minion
+# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
+
+{%- for group,spec in groups.iteritems() %}
+%{{ spec.name|default(group) }} {{ spec.get('hosts', ['ALL'])|join(',') }}=({{ spec.get('runas', ['ALL'])|join(', ') }}) {% if spec.get('nopasswd', True) %}NOPASSWD: {% endif %}{{ spec.get('commands', ['ALL'])|join(', ') }}
+{%- endfor %}
+
diff --git a/linux/files/sudoer-users b/linux/files/sudoer-users
new file mode 100644
index 0000000..4e05269
--- /dev/null
+++ b/linux/files/sudoer-users
@@ -0,0 +1,7 @@
+# sudoer users, file managed by salt-minion
+# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
+
+{%- for user,spec in users.iteritems() %}
+{{ spec.name|default(user) }} {{ spec.get('hosts', ['ALL'])|join(',') }}=({{ spec.get('runas', ['ALL'])|join(', ') }}) {% if spec.get('nopasswd', True) %}NOPASSWD: {% endif %}{{ spec.get('commands', ['ALL'])|join(', ') }}
+{%- endfor %}
+
diff --git a/linux/system/group.sls b/linux/system/group.sls
index 4963829..2c1c769 100644
--- a/linux/system/group.sls
+++ b/linux/system/group.sls
@@ -26,3 +26,4 @@
{%- endfor %}
{%- endif %}
+
diff --git a/linux/system/init.sls b/linux/system/init.sls
index 1ce8100..9d4d4f0 100644
--- a/linux/system/init.sls
+++ b/linux/system/init.sls
@@ -75,3 +75,6 @@
{%- if system.config is defined %}
- linux.system.config
{%- endif %}
+{%- if system.sudo is defined %}
+- linux.system.sudo
+{%- endif %}
diff --git a/linux/system/sudo.sls b/linux/system/sudo.sls
new file mode 100644
index 0000000..5cee4b3
--- /dev/null
+++ b/linux/system/sudo.sls
@@ -0,0 +1,73 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- if system.get('sudo', {}).get('enabled', False) %}
+
+{%- if system.get('sudo', {}).get('aliases', False) is mapping %}
+/etc/sudoers.d/90-salt-sudo-aliases:
+ file.managed:
+ - source: salt://linux/files/sudoer-aliases
+ - template: jinja
+ - user: root
+ - group: root
+ - mode: 440
+ - defaults:
+ aliases: {{ system.sudo.aliases|yaml }}
+ - check_cmd: /usr/sbin/visudo -c -f
+{%- else %}
+/etc/sudoers.d/90-salt-sudo-aliases:
+ file.absent:
+ - name: /etc/sudoers.d/90-salt-sudo-aliases
+{%- endif %}
+
+
+{%- if system.get('sudo', {}).get('users', False) is mapping %}
+/etc/sudoers.d/91-salt-sudo-users:
+ file.managed:
+ - source: salt://linux/files/sudoer-users
+ - template: jinja
+ - user: root
+ - group: root
+ - mode: 440
+ - defaults:
+ users: {{ system.sudo.users|yaml }}
+ - check_cmd: /usr/sbin/visudo -c -f
+{%- else %}
+/etc/sudoers.d/91-salt-sudo-users:
+ file.absent:
+ - name: /etc/sudoers.d/91-salt-sudo-users
+{%- endif %}
+
+{%- if system.get('sudo', {}).get('groups', False) is mapping %}
+/etc/sudoers.d/91-salt-sudo-groups:
+ file.managed:
+ - source: salt://linux/files/sudoer-groups
+ - template: jinja
+ - user: root
+ - group: root
+ - mode: 440
+ - defaults:
+ groups: {{ system.sudo.groups|yaml }}
+ - check_cmd: /usr/sbin/visudo -c -f
+{%- else %}
+/etc/sudoers.d/91-salt-sudo-groups:
+ file.absent:
+ - name: /etc/sudoers.d/91-salt-sudo-groups
+{%- endif %}
+
+{%- else %}
+
+/etc/sudoers.d/90-salt-sudo-aliases:
+ file.absent:
+ - name: /etc/sudoers.d/90-salt-sudo-aliases
+
+/etc/sudoers.d/91-salt-sudo-users:
+ file.absent:
+ - name: /etc/sudoers.d/91-salt-sudo-users
+
+/etc/sudoers.d/91-salt-sudo-groups:
+ file.absent:
+ - name: /etc/sudoers.d/91-salt-sudo-groups
+
+{%- endif %}
+{%- endif %}
diff --git a/linux/system/user.sls b/linux/system/user.sls
index 4232e65..997f6fa 100644
--- a/linux/system/user.sls
+++ b/linux/system/user.sls
@@ -48,6 +48,7 @@
user_name: {{ name }}
- require:
- user: system_user_{{ name }}
+ - check_cmd: /usr/sbin/visudo -c -f
{%- endif %}
diff --git a/tests/pillar/system.sls b/tests/pillar/system.sls
index 30968e2..f4bbdfd 100644
--- a/tests/pillar/system.sls
+++ b/tests/pillar/system.sls
@@ -2,10 +2,11 @@
system:
enabled: true
cluster: default
- name: test01
+ name: linux
timezone: Europe/Prague
domain: local
environment: prd
+ hostname: system.pillar.local
apparmor:
enabled: false
haveged:
@@ -18,7 +19,7 @@
rate: 115200
term: xterm
prompt:
- default: "test01.local$"
+ default: "linux.ci.local$"
kernel:
sriov: True
isolcpu: 1,2,3,4
@@ -55,12 +56,43 @@
uid: 9999
full_name: Test User
home: /home/test
+ groups:
+ - root
+ salt_user1:
+ enabled: true
+ name: saltuser1
+ sudo: false
+ uid: 9991
+ full_name: Salt User1
+ home: /home/saltuser1
+ salt_user2:
+ enabled: true
+ name: saltuser2
+ sudo: false
+ uid: 9992
+ full_name: Salt Sudo User2
+ home: /home/saltuser2
group:
test:
enabled: true
name: test
gid: 9999
system: true
+ db-ops:
+ enabled: true
+ name: testgroup
+ salt-ops:
+ enabled: true
+ name: sudogroup0
+ sudogroup1:
+ enabled: true
+ name: sudogroup1
+ sudogroup2:
+ enabled: true
+ name: sudogroup2
+ sudogroup3:
+ enabled: false
+ name: sudogroup3
job:
test:
enabled: true
@@ -88,3 +120,103 @@
enabled: true
autoupdates:
enabled: true
+ sudo:
+ enabled: true
+ alias:
+ runas:
+ DBA:
+ - postgres
+ - mysql
+ SALT:
+ - root
+ host:
+ LOCAL:
+ - localhost
+ PRODUCTION:
+ - db1
+ - db2
+ command:
+ SUDO_RESTRICTED_SU:
+ - /bin/vi /etc/sudoers
+ - /bin/su - root
+ - /bin/su -
+ - /bin/su
+ - /usr/sbin/visudo
+ SUDO_SHELLS:
+ - /bin/sh
+ - /bin/ksh
+ - /bin/bash
+ - /bin/rbash
+ - /bin/dash
+ - /bin/zsh
+ - /bin/csh
+ - /bin/fish
+ - /bin/tcsh
+ - /usr/bin/login
+ - /usr/bin/su
+ - /usr/su
+ SUDO_SALT_SAFE:
+ - /usr/bin/salt state*
+ - /usr/bin/salt service*
+ - /usr/bin/salt pillar*
+ - /usr/bin/salt grains*
+ - /usr/bin/salt saltutil*
+ - /usr/bin/salt-call state*
+ - /usr/bin/salt-call service*
+ - /usr/bin/salt-call pillar*
+ - /usr/bin/salt-call grains*
+ - /usr/bin/salt-call saltutil*
+ SUDO_SALT_TRUSTED:
+ - /usr/bin/salt*
+ users:
+ saltuser1: {}
+ saltuser2:
+ hosts:
+ - LOCAL
+ # User Alias:
+ DBA:
+ hosts:
+ - ALL
+ commands:
+ - SUDO_SALT_SAFE
+ groups:
+ db-ops:
+ hosts:
+ - ALL
+ - '!PRODUCTION'
+ runas:
+ - DBA
+ commands:
+ - /bin/cat *
+ - /bin/less *
+ - /bin/ls *
+ - SUDO_SALT_SAFE
+ - '!SUDO_SHELLS'
+ - '!SUDO_RESTRICTED_SU'
+ salt-ops:
+ hosts:
+ - 'ALL'
+ runas:
+ - SALT
+ commands:
+ - SUDO_SALT_TRUSTED
+ salt-ops2:
+ name: salt-ops
+ runas:
+ - DBA
+ commands:
+ - SUDO_SHELLS
+ sudogroup1:
+ commands:
+ - ALL
+ sudogroup2:
+ commands:
+ - ALL
+ hosts:
+ - localhost
+ users:
+ - test
+ nopasswd: false
+ sudogroup3:
+ commands:
+ - ALL