CFEngine 3 creating admin and restricted users and setting their groups
Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
CFEngine 3 creating admin and restricted users and setting their groups
I am building CFEngine 3 promise to set up 2 types of system users : admins with sudo permission and developers with no sudo but able to delete each other's files in specific folders
Say we have user dev1
Primary group: developers ( so that other developers can edit/delete the files )
Secondary groups:
adm - to viev logs
www-data - to be able to delete files created by web server
dev1 - unique group to protect home folder
home folder owned by dev1:dev1 so that others cannot look in there
and admin1 user with similar settings, but also added to sudoers
See me promise code below, works fine, adds users, but when I set primary group to developers the unique group for the user is not created and the code perms => og("$(login)","$(login)") fails because there is no such group.
How can I force creation of this unique group if it's not primary for the user ?
Or is there any other way I can be sure files and directories created under /www folder can be deleted and edited by all developers without sudo access. Some of these files are created by web server user and have to be owned by it's user and group
I am setting umask 002 for both shell access and web server so that files are rw for group
Or is there any other solution, maybe I'm stuck on the wrong mountain top ? All I want is to allow developers to update each others code when they take over the project, allow them to clear cache created by web server user but not allow them to run commands as root as they tend to change server configuration to make their code work and do not tell anyone.
The promise code below, works with CFEngine 3.9.1 on Debian 9
And of course I have more admins and developers than in the example below, that's why the code is more complex
Code:
body common control
{
inputs => { "$(sys.libdir)/users.cf" };
inputs => { "$(sys.libdir)/files.cf" };
inputs => { "$(sys.libdir)/stdlib.cf" }; }
# Add "developers" grouup
bundle agent add_groups
{
classes:
"group_developers_absent"
not => groupexists("developers");
commands:
linux.group_developers_absent::
"$(paths.groupadd)"
args => "developers";
}
# Create users
bundle agent it_users
{
vars:
# Admin users
"users[john][fullname]" string => "John Doe";
"users[john][pass_hash]" string => "$................................../";
"users[john][ssh_key]" string => "ssh-rsa xxxxxxxxxxx" ;
# Additiona example variables
# "users[winnie][fullname]" string => "Winnie The Pooh ";
# "users[winnie][uid]" string => "501";
# "users[winnie][gid]" string => "users";
# "users[winnie][home]" string => "/home/winnie";
# "users[winnie][shell]" string => "/bin/bash";
# "users[winnie][flags]" string => "-m";
methods:
"any" usebundle => add_users ("it_users.users"); }
bundle agent dev_users
{
vars:
# Developers users - only on specific servers
"users[winnie][fullname]" string => "Winnie the Pooh";
"users[winnie][pass_hash]" string => "$...................................../";
"users[winnie][ssh_key]" string => "ssh-rsa xxxxxxxxxxxxxxxxxxxx ";
methods:
dev_users_present::
"any" usebundle => add_users ("dev_users.users"); }
bundle agent add_users (user_array)
{
vars:
"login" slist => getindices("$(user_array)");
"skel" string => "/etc/skel";
reports:
linux::
"Setting up user $(login) - full name $($(user_array)[$(login)][fullname])" ;
users:
linux::
"$(login)"
home_dir => "/home/$(login)",
description => "$($(user_array)[$(login)][fullname])",
# If the below is commented out a group for user is created eg group winnie for user winnie
# if I uncomment that the group will not be created and the lines below setting perms for home dir will fail as they would be setting o/g to winnie:winnie
# group_primary => "developers",
groups_secondary => { "adm", "developers", "www-data" },
# this also works, provided the group exists
# groups_secondary => { "adm", "developers", "www-data", "$(login)"},
shell => "/bin/bash",
policy => "present" ,
password => hashed_password( "$($(user_array)[$(login)][pass_hash])" );
files:
# files promisses get repaired on every run - need to check why
linux::
"/home/$(login)/."
create => "true",
perms => og("$(login)","$(login)"),
copy_from => seed_cp( $(skel) ),
depth_search => recurse( "inf" );
"/home/$(login)"
perms => og("$(login)","$(login)") ;
"/home/$(login)/.ssh/."
perms => mog("700","$(login)","$(login)"),
create => "true";
"/home/$(login)/.ssh/authorized_keys"
perms => mog("600","$(login)","$(login)"),
edit_line => append_if_no_line("$($(user_array)[$(login)][ssh_key])"),
create => "true";
reports:
"adding user = $(login) - full name = $($(user_array)[$(login)][fullname]) hash $($(user_array)[$(login)][pass_hash])";
}
# Users that need to be removed
bundle agent remove_users
{
vars:
"login" slist
=> {
"roy",
"maurice",
"jen",
};
users:
linux::
"$(login)"
policy => "absent"; # Remove home directories - need to work on that, content of $HOME removed but the directory stays
files:
linux::
"/home/$(login)/."
file_select => all,
depth_search => recurse("inf"),
delete => tidy ;
}
How can I force creation of this unique group if it's not primary for the user ?
Unfortunately, there is currently no groups type promise to just make promises about a groups state. But you can check for the presence of the group and create it using either a commands type promise or a files type promise if you know the GID you want to use. I would look to just make sure the group exists instead of trying to make sure it exists if it's not primary.
Example editing groups directly:
Code:
bundle agent example
{
vars:
"groups[developers]" string => "developers:x:1010:";
"groups_file" string => "/tmp/group";
files:
# Insert the group if no entry exists, note this doesn't deal with users nor
# does it handle changing the gid. Those can be done with set_colon_field,
# and append_user_field from the stdlib
"$(groups_file)"
edit_line => append_groups_starting( "$(this.bundle).groups" );
}
bundle agent __main__
{
methods:
"example";
}
Or is there any other way I can be sure files and directories created under /www folder can be deleted and edited by all developers without sudo access. Some of these files are created by web server user and have to be owned by it's user and group
Extended attributes is quite flexible. Have you considered using those?
Quote:
The promise code below, works with CFEngine 3.9.1
And of course I have more admins and developers than in the example below,
that's why the code is more complex
I just made some direct edits to the code:
Code:
body common control
{
inputs => {
"$(sys.libdir)/users.cf",
"$(sys.libdir)/files.cf",
"$(sys.libdir)/stdlib.cf"
};
}
# Add "developers" grouup
bundle agent add_groups
{
classes:
"group_developers_absent"
not => groupexists("developers");
commands:
linux.group_developers_absent::
"$(paths.groupadd)"
args => "developers";
}
# Create users
bundle agent it_users
{
vars:
# Admin users
"users[john][fullname]" string => "John Doe";
"users[john][pass_hash]" string => "$................................../";
"users[john][ssh_key]" string => "ssh-rsa xxxxxxxxxxx" ;
# Additiona example variables
# "users[winnie][fullname]" string => "Winnie The Pooh ";
# "users[winnie][uid]" string => "501";
# "users[winnie][gid]" string => "users";
# "users[winnie][home]" string => "/home/winnie";
# "users[winnie][shell]" string => "/bin/bash";
# "users[winnie][flags]" string => "-m";
methods:
"any" usebundle => add_users ("it_users.users");
"any" usebundle => add_groups;
}
bundle agent dev_users
{
vars:
# Developers users - only on specific servers
"users[winnie][fullname]" string => "Winnie the Pooh";
"users[winnie][pass_hash]" string => "$...................................../";
"users[winnie][ssh_key]" string => "ssh-rsa xxxxxxxxxxxxxxxxxxxx ";
methods:
dev_users_present::
"any" usebundle => add_groups;
"any" usebundle => add_users ("dev_users.users"); }
bundle agent add_users (user_array)
{
vars:
"login" slist => getindices("$(user_array)");
"skel" string => "/etc/skel";
reports:
linux::
"Setting up user $(login) - full name $($(user_array)[$(login)][fullname])" ;
users:
linux::
"$(login)"
home_dir => "/home/$(login)",
description => "$($(user_array)[$(login)][fullname])",
# If the below is commented out a group for user is created eg group winnie for user winnie
# if I uncomment that the group will not be created and the lines below setting perms for home dir will fail as they would be setting o/g to winnie:winnie
# group_primary => "developers",
groups_secondary => { "adm", "developers", "www-data" },
# this also works, provided the group exists
# groups_secondary => { "adm", "developers", "www-data", "$(login)"},
shell => "/bin/bash",
policy => "present" ,
password => hashed_password( "$($(user_array)[$(login)][pass_hash])" );
files:
# files promisses get repaired on every run - need to check why
linux::
"/home/$(login)/."
create => "true",
perms => og("$(login)","$(login)"),
copy_from => seed_cp( $(skel) ),
depth_search => recurse( "inf" );
"/home/$(login)"
perms => og("$(login)","$(login)") ;
"/home/$(login)/.ssh/."
perms => mog("700","$(login)","$(login)"),
create => "true";
"/home/$(login)/.ssh/authorized_keys"
perms => mog("600","$(login)","$(login)"),
edit_line => append_if_no_line("$($(user_array)[$(login)][ssh_key])"),
create => "true";
reports:
"adding user = $(login) - full name = $($(user_array)[$(login)][fullname]) hash $($(user_array)[$(login)][pass_hash])";
}
# Users that need to be removed
bundle agent remove_users
{
vars:
"login" slist
=> {
"roy",
"maurice",
"jen",
};
users:
linux::
"$(login)"
policy => "absent"; # Remove home directories - need to work on that, content of $HOME removed but the directory stays
files:
linux::
"/home/$(login)/."
file_select => all,
depth_search => recurse("inf"),
delete => tidy ;
}
- I am surprised that defining inputs multiple times worked. It's a list, it
should be defined just once.
- From the description above, I didn't understand that you already had a commands promise to groupadd developers. Looking at your policy, I don't
see where add_groups is called. If add_groups is called first, then the
group should exist before perms => mog("700","$(login)","$(login)"), I just
edited it so that add_groups is called before add_users in both the it_users and dev_users bundles are called. You could instead call it
before it_users and dev_users is called.
Also, the cfengine help list and #cfengine on irc.freenode.net are great resources.
in my promise and bootstrap a new machine I get the following error when creating users
Code:
verbose: Creating user 'winnie'. (command: '/usr/sbin/useradd -c "Winnie the Pooh" -g "winnie" -G "adm,developers,www-data,sudo" -d "/home/winnie" -s "/bin/bash" -M winnie')
error: Command returned error while creating user 'winnie'. (Command line: '/usr/sbin/useradd -c "Winnie the Pooh" -g "winnie" -G "adm,developers,www-data,sudo" -d "/home/winnie" -s "/bin/bash" -M winnie')
info: User promise not kept
Groups 'adm,developers,www-data,sudo' exist. Group 'winnie' does not and is not created.
When I comment group_primary promise out and do not promise primary group user 'winnie' gets created fine, with the right primary group 'winnie' which also gets created
Code:
~# groups winnie
winnie : winnie adm sudo www-data developers
but on the consecutive runs of cf-agent I get the following
Code:
verbose: Getting user 'winnie' password hash from shadow database.
verbose: Getting user 'winnie' password hash from shadow database.
verbose: Verifying password hash for user 'winnie': correct.
verbose: Modifying user 'winnie'. (command: '/usr/sbin/usermod -G "" winnie')
verbose: Modifying user 'winnie'. (command: '/usr/sbin/usermod -G "adm,developers,www-data,sudo" winnie')
info: User promise repaired
verbose: A: Promise REPAIRED
Not sure why it's running
Code:
usr/sbin/usermod -G "" winnie
every time, trying to change secondary groups fro the user
Not sure what you mean by
Quote:
- I am surprised that defining inputs multiple times worked. It's a list, it should be defined just once.
Are you referring to me calling bundle 'add_users' with different user arrays as parameters? I am treating this bundle as a function or a method within a class with parameters passed to it and it seems to work with one exception. That is what I tend to do with any code I write. Try to build reusable classes and methods. I actually have 4 types of users, each type needs to be assigned to different secondary groups and be set up on different servers. These users come and go, and servers are sometimes built per project and need to have set of users created, so looking for a flexible solution.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.