Distribute ssh keys
Let's say we have a list of users that are trusted to login to a set of servers managed by CFEngine.
We are going to implement this trust relationship by ensuring the users' accounts on managed servers have a .ssh/authorized_keys file with each user's public key.
Let's assume we collected all users' public keys into a single directory on the server and that users exist on the clients (and have corresponding home directory). The following CFEngine policy distributes the keys from /var/cfengine/masterfiles/ssh_keys on the policy server to /var/cfengine/inputs/ssh_keys on the managed servers and from there each user's key will go to each user's .ssh/authorized_keys file.
Note: special variable $(sys.policy_hub) contains the hostname of the policy server.
You have to adapt this policy in the mentioned places for it to work in your environment.
body common control {
bundlesequence => { "distribute_ssh_keys" };
inputs => { "libraries/cfengine_stdlib.cf" };
}
bundle agent distribute_ssh_keys
{
vars:
"users" slist => { "user1", "user2" }; # List of users to be included in key distribution.
# Modify to include actual users.
"source_server" string => "$(sys.policy_hub)"; # Server where keys are stored
"source_directory" string => "/var/cfengine/masterfiles/ssh_keys"; # Source directory of key files
"local_cache" string => "/var/cfengine/inputs/ssh_keys"; # Local cache of key files
files:
"$(local_cache)/$(users).pub"
comment => "Copy public keys from an authorized source into a cache on localhost",
perms => mo("600","root"),
copy_from => remote_cp("$(source_directory)/$(users).pub","$(source_server)"),
action => if_elapsed("60"); # wait 60 min before checking this promise again
# Ensure that authorized_keys file exists and has permissions 600 and call a file editing promise
"/home/$(users)/.ssh/authorized_keys"
comment => "Edit the authorized keys into the user's personal keyring",
create => "true",
perms => m("600"),
edit_line => insert_file_if_no_line_matching("$(users)","$(local_cache)/$(users).pub"),
action => if_elapsed("60");
}
#####
bundle edit_line insert_file_if_no_line_matching(user,file)
{
# Check if user exists in the authorized_keys file
classes:
"have_user"
expression => regline("$(user).*","$(this.promiser)");
# Insert the content of the key file into authorized_keys if the user's key is not already there
insert_lines:
!have_user::
"$(file)"
insert_type => "file";
}
Example run:
First, let's setup for the run. Put users' SSH keys into the key distribution point on the policy hub:
policy_hub# ls /var/cfengine/masterfiles/ssh_keys/*pub
/var/cfengine/masterfiles/ssh_keys/user1.pub /var/cfengine/masterfiles/ssh_keys/user2.pub
policy_hub#
There are no authorized_keys files on the managed servers, but the home (and .ssh) directories exist:
# ls -d /home/user*/.ssh
/home/user1/.ssh /home/user2/.ssh
# ls /home/user?/.ssh/authorized_keys
ls: cannot access /home/user?/.ssh/authorized_keys: No such file or directory
#
Run CFEngine on one of the managed servers to create and populate /var/cfengine/inputs/ssh_keys from source (policy_hub:/var/cfengine/masterfiles/ssh_keys) and then install each user's key into that user's authorized_keys file:
# cf-agent -f ssh.cf
2013-06-08T15:49:29-0700 error: Failed to chdir into '/var/cfengine/inputs/ssh_keys'
#
Note: the above error only happens on the first run. Then /var/cfengine/inputs/ssh_keys is created and this error does not recur.
The local cache now contains the users' public keys:
ls /var/cfengine/inputs/ssh_keys/
user1.pub
user2.pub
#
CFEngine created authorized_keys files:
# ls /home/user?/.ssh/auth*keys
/home/user1/.ssh/authorized_keys
/home/user2/.ssh/authorized_keys
#
CFEngine installed the user's keys:
# more /home/user?/.ssh/auth*keys
::::::::::::::
/home/user1/.ssh/authorized_keys
::::::::::::::
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjtmJf9QfME2KIV19C96EyRg1dizxKMTjLRsPtwsmC2fRyA3fRFvpUVKApigDTNxF5nDqfgGtY9
0KhnuqjhOgYWnpm4dmiTdFXJ5XHuNPCc4JpsXBeyMy2f8e1aobb/dN5UhSSZmYb84FkYwbI/EkxJ46CmmOpOi6C5AjYfqwzshIGNgJS39hbtsUimc
qBAOYTHzVpm5+KfHbNryZ9ORWEVcPvnchKtEfNu8iuDdecOxmWWUPhEyhUz7/SfZ4cPs7692JcIX2XQCsvsGWS5JPiVXGDPCcLz7WNI2A7rohoC9f
vpE11CBigl7zTlB0M7nQYzpjaf7qS3AvOXw5CLUPD user1@examplehost
::::::::::::::
/home/user2/.ssh/authorized_keys
::::::::::::::
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDhaBkZg7t63kNXqduU1LzLH+8DEkTGAhOjharGf6TMWL9fkWXS+Xjj2iD7KZgT2VBC9Hf8o+HhL
al5kyHYH8qRxtPXMm5UVhIHnq8hxDQQPo/jW62wwxB0N2pF8oU4sMzMzCANJYE3C6H0rjIzgloiCIkBwL21WoFhxZ145z7VoKTEf0ICRk2+xmCc2W
hX1pQVJzs5GlKlWEsJUp8Skqt+OuJTtIS4R3nJALvo7zindvum12DcbWfsrV5oW3gl89GkyDAdi1mWaqBmGX5qF5b19KaP4qdth61foUTR7NyHuCs
C/hNB84Loy+2nMU8QpKJ7Ha6UyBtU2YrzDxL3YPgJ user2@examplehost
#