Skip to content

Commit

Permalink
admin module for user/group/permissions cleanup
Browse files Browse the repository at this point in the history
Users/groups/perms are meant to be defined in yaml.

Applied like:

yaml:

  groups:
    test1:
      gid: 1
      members: [foo]
    test2:
      gid: 2
      members: []

  users:
    foo:
      uid: 1
      ...

.pp
  node /foo/ {
    #groups create their users (can overlap) and permissions
    #as well as system groups and handling user membership
    class { 'admin': groups => ['test', 'test2'], }
  }

More info see: admin/README

Change-Id: I6982bfced50a22faac37246dff4d52ff163a34ed
  • Loading branch information
chasemp committed May 19, 2014
1 parent 78c9da0 commit 057dc2f
Show file tree
Hide file tree
Showing 16 changed files with 721 additions and 24 deletions.
4 changes: 2 additions & 2 deletions files/sudo/sudoers.default → files/sudo/sudoers.labs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# See the man page for details on how to write a sudoers file.
#

Defaults env_reset
Defaults env_reset

# Host alias specification

Expand All @@ -14,7 +14,7 @@ Defaults env_reset
# Cmnd alias specification

# User privilege specification
root ALL=(ALL) ALL
root ALL=(ALL) ALL

# Allow members of group sudo to execute any command after they have
# provided their password
Expand Down
39 changes: 17 additions & 22 deletions manifests/sudo.pp
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,23 @@

class sudo::labs_project {

if $realm == labs {
include sudo::default

# Was handled via sudo ldap, now handled via puppet
sudo_group { ops: privileges => ['ALL=(ALL) NOPASSWD: ALL'] }
# Old way of handling this.
sudo_group { $instanceproject: ensure => absent }
# Another old way, before per-project sudo
sudo_group { $projectgroup: ensure => absent }
}

}

class sudo::default {

file { "/etc/sudoers":
owner => root,
group => root,
mode => 0440,
source => "puppet:///files/sudo/sudoers.default";
}

if $realm == labs {

#labs specific sudo default
file { "/etc/sudoers":
owner => root,
group => root,
mode => 0440,
source => "puppet:///files/sudo/sudoers.labs";
}

# Was handled via sudo ldap, now handled via puppet
sudo_group { ops: privileges => ['ALL=(ALL) NOPASSWD: ALL'] }
# Old way of handling this.
sudo_group { $instanceproject: ensure => absent }
# Another old way, before per-project sudo
sudo_group { $projectgroup: ensure => absent }
}
}

class sudo::appserver {
Expand Down
190 changes: 190 additions & 0 deletions modules/admin/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
This module is meant to manage all users, groups, and permissions (sudo).

All managed resources should be defined in yaml.

see: admin/data/data.yaml

-- Examples --

Adding a group:

groups:
mygroup:
ensure: present
gid: 551
members: [foo, bar]

Managing members for a default system group:

-> For groups without a set GID we do not attempt creation

groups:
adm:
members: [foo, bar]

Removing a member from a group:

-> Removing 'bar' user from mygroup means removal from members array

groups:
mygroup:
ensure: present
gid: 551
members: [foo, bar] -> members: [foo]

Removing a group:

-> absenting a group will remove it where it was applied

groups:
mygroup:
foo:
ensure: absent
gid: 679
members: []

Adding user 'foo':

-> Since assignment is group centric this user won't be created anywhere yet

users:
foo:
uid: 1146
gid: 500
realname: Foo Bar
ssh_keys: [ssh-rsa mykeyhash foobar@mac]

Adding user 'foo' to adm:

groups:
adm:
members: [foo]

Removing user foo:

-> absented users cannot be members of a group -- other than absent --
-> users who are not a member of a supplementary group are removed
-> Therefore, removing a user from all groups means they will be removed
everywhere they existed because of those groups.

groups:
adm:
members: [foo, bar] -> members: [bar]

-> User garbage collection logs to syslog and console:

#manual ensure absent example output
notice: /Stage[main]/Admin/Admin::Yamluser[foo]/Admin::User[foo]/User[foo]/ensure: removed

#straggling user cleanup puppet output
notice: /Stage[main]/Admin/Exec[enforce-users-groups-cleanup]/returns: \
/usr/local/bin/enforce-users-groups removing user/id: foo/1001

#straggling user cleanup syslog output
May 6 10:54:43 uone logger: /usr/local/bin/enforce-users-groups removing user/id: foo/1001

-> However, if you want to ensure a user is especially missing globally
-> Mark the user as 'ensure: absent'
-> Add the user to the meta 'absent' group

groups:
absent:
members: [foo]

users:
foo:
ensure: absent
uid: 510
gid: 500
realname: Foo Bar
ssh_keys: [ssh-rsa mykeyhash foobar@mac]

-> absent group users:
-> * are _always_ included in every batch of assignments
-> * should never have 'ensure: present'
-> * cannot be a member of any other group

Assigning groups/users:

-> one 'class admin' assignment per node must be done since we need state information on all assigned users
-> 'ops' and 'absent' groups are always included

#create group and assign users
node /myhost/ {
class { 'admin': groups => ['mygroup'], }
}

or (including managed members of a system group):

#this creates both groups, and all relevant users of both groups even with overlap
node /myhost/ {
class { 'admin': groups => ['mygroup', 'adm'], }
}

#creates three groups and all relevants users and permissions details
node /myhost/ {
class { 'admin': groups => ['mygroup',
'adm',
'foo'], }
}

Assigning sudo permissions to a group:

groups:
adm:
members: [foo, bar]
privs: [ALL=(ALL:ALL) ALL]

Creates: '/etc/sudoers.d/adm'

# This file is managed by Puppet!
%adm ALL=(ALL:ALL) ALL

Removing sudo permissions from a group:

-> if you remove a group the permissions are removed as well
-> the 'absent' keyword will also remove all sudo permissions while
-> retaining the group and members

bar:
gid: 680
privs: [absent]
members: [a, b, c]

Users can be given sudo permissions in the same way:

-> this is a limited use approach. these permissions would apply across the entire env.

foo:
ensure: present
privs: [ALL=(ALL:ALL) ALL]

Assigning one-off (single user, single case) sudo permissions:

admin::sudo { "foo_user_only_should_do_x":
user=>'bob',
comment=>'this is good karma',
privs=>['ALL = NOPASSWD: X'],
}

Creates '/etc/sudoers.d/foo_user_only_should_do_x':

# This file is managed by Puppet!
#this is good karma
bob ALL = NOPASSWD: X

Getting your /home/ stuff wherever you are:

-> if you define a dir for your username in '${module}/files/home' all contents are managed

├── files
│   ├── home
│   │   ├── foo
│   │   │   └── .vimrc


#Notes:
#* Individual /home data is intended to live somewhere other than our Puppet repo once
figure out where it should live permanently
#* Groups with no members get root by default
#* admin::user and admin::group are not dependent on yaml
1 change: 1 addition & 0 deletions modules/admin/data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#placeholder
37 changes: 37 additions & 0 deletions modules/admin/files/enforce-users-groups.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash

# This is a user garbage collection script that removes
# users who do not have a supplementary group that also have
# a UID above the ID_BOUNDARY. Removals are logged to syslog.
# with 'dryrun' as first arg exits 1 if cleanup is needed

ID_BOUNDRY='500'
ARCHIVE_DIR='/var/userarchive'

function log() {
logger $1
echo $1
}

if [ ! -d $ARCHIVE_DIR ]
then
log "creating new user files archive ${ARCHIVE_DIR}"
mkdir $ARCHIVE_DIR
fi

IFS=$'\r\n' PASSWD_USERS=($(/usr/bin/getent passwd))
for var in "${PASSWD_USERS[@]}"
do
username=`echo $var | cut -d ':' -f 1`
uid=`echo $var | cut -d ':' -f 3`
if [[ "$uid" -gt "$ID_BOUNDRY" ]]; then
if [[ `/usr/bin/id $username` != *","* ]]; then
if [ "${1}" == "dryrun" ]
then
exit 1
fi
log "${0} removing user/id: ${username}/${uid}"
/usr/sbin/deluser --remove-home --backup-to=$ARCHIVE_DIR $username &> /dev/null
fi
fi
done
1 change: 1 addition & 0 deletions modules/admin/files/home/skel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#place holder for git
25 changes: 25 additions & 0 deletions modules/admin/files/sudoers
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# /etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# See the man page for details on how to write a sudoers file.
#

Defaults env_reset

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root ALL=(ALL) ALL

# Allow members of group sudo to execute any command after they have
# provided their password
# (Note that later entries override this, so you might need to move
# it further down)
%sudo ALL=(ALL) ALL
#
#includedir /etc/sudoers.d
13 changes: 13 additions & 0 deletions modules/admin/lib/puppet/parser/functions/unique_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Puppet::Parser::Functions
newfunction(:unique_users, :type => :rvalue) do |args|
myhash = args[0]
applied_groups = args[1]
users = Array.new
for group in applied_groups
if myhash['groups'].key?(group)
users.push(myhash['groups'][group]['members'])
end
end
return users.flatten(1).uniq
end
end
42 changes: 42 additions & 0 deletions modules/admin/manifests/group.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# A defined type for system group mangement
#
# === Parameters
#
# [*name*]
# Group name
#
# [*ensure*]
# Add or remove the user group [ "present" | "absent" ]
#
# [*gid*]
# Sets the group id
#
# [*privs*]
# An array of priviledges to setup via admin::sudo
#

define admin::group(
$ensure = 'present',
$gid = undef,
$privs = [],
)
{

# sans specified $gid we assume system group and do not create
if ($ensure == 'absent') or ($gid) {
group { $name:
ensure => $ensure,
name => $name,
allowdupe => false,
gid => $gid,
}
}

if !empty($privs) {
admin::sudo { $name:
ensure => $ensure,
privs => $privs,
is_group => true,
}
}
}
Loading

0 comments on commit 057dc2f

Please sign in to comment.