diff options
-rw-r--r-- | README | 68 | ||||
-rw-r--r-- | files/etc/cron.d/update-monkeysphere-auth | 1 | ||||
-rw-r--r-- | lib/facter/monkeysphere.rb | 2 | ||||
-rw-r--r-- | manifests/add_id_certifier.pp | 8 | ||||
-rw-r--r-- | manifests/auth_capable_user.pp | 44 | ||||
-rw-r--r-- | manifests/authorized_user_ids.pp | 53 | ||||
-rw-r--r-- | manifests/email_server_keys.pp | 9 | ||||
-rw-r--r-- | manifests/import_key.pp | 20 | ||||
-rw-r--r-- | manifests/init.pp | 70 | ||||
-rw-r--r-- | manifests/owner_trust.pp | 25 | ||||
-rw-r--r-- | manifests/publish_server_keys.pp | 7 | ||||
-rw-r--r-- | manifests/publish_user_key.pp | 15 | ||||
-rw-r--r-- | manifests/sshserver.pp | 10 | ||||
-rw-r--r-- | templates/authorized_user_ids.erb | 6 | ||||
-rw-r--r-- | templates/monkeysphere-authentication.conf.erb | 37 | ||||
-rw-r--r-- | templates/monkeysphere-host.conf.erb | 15 | ||||
-rw-r--r-- | templates/monkeysphere.conf.erb | 39 |
17 files changed, 372 insertions, 57 deletions
@@ -1,21 +1,65 @@ -puppet module for monkeysphere +The monkeysphere puppet module is designed to help you manage your servers +and users using the monkeysphere[0]. -for information about monkeysphere, see http://web.monkeysphere.info/ +To install the monkeypshere module, storeconfigs should be enabled in +your puppet server to use certain features. See: -To install the monkeypshere module: +http://projects.puppetlabs.com/projects/1/wiki/Using_Stored_Configuration#Configuring+basic+storeconfigs -* storeconfigs should be enabled in your puppet server to use certain features. - see: http://projects.puppetlabs.com/projects/1/wiki/Using_Stored_Configuration#Configuring+basic+storeconfigs +Example usage for server setup: -* in node definitions that should export a ssh host key via - monkeyshere, add: + # Assuming you are using the sshd puppet module... + $sshd_authorized_keys_file = "/var/lib/monkeysphere/authorized_keys/%u" + include sshd - include monkeysphere::sshserver + # Optionally, indicate your preferred keyserver. You can specify a server + # under your control and not accessible to the public or + # pool.sks-keyservers.net if you want to publish to the public pool. The + # value you specify here will be used for all monkeysphere and gpg commands + $monkeysphere_keyserver = "zimmermann.mayfirst.org" + include monkeysphere -* You can specify pgpids of identity certifiers: + # Ensure the server's ssh key is imported into your monkeysphere key ring + monkeysphere::import_key { "main": } - identity_certifier { "A3AE44A4": - ensure => present + # Optionally publish the server key to a keyserver (as indicated above) + monkeysphere::publish_server_keys { "main": } + + # Optionally email the server key to your self + monkeysphere::email_server_keys { "we@ourdomain.org": } + + # Be sure to sign the server's key! + + # Indiciate the fingerprint of the gpg key that should be used + # to verify user ids. You can repeat this for as many certifiers + # as you need + monkeysphere::add_id_certifier { "jamie": + keyid => "1CB57C59F2F42470238F53ABBB0B7EE15F2E4935" + } + + # Indicate who should have root access on the server + monkeysphere::authorized_user_ids { "root": + user_ids => [ "sarah <sarah@ourgroup.org>" , "jose <josue@ourgroup.org" ] + } + +In addition, you may want to create a password-less key for a user to use +when logging into another server (e.g. if you want automated backups from +one server to another). + +Example usage for user setup: + + # Ensure that the root user has authentication capable + # monkeysphere key + monkeysphere::auth_capable_user { "root": } + + # Optionally publish the key + monkeysphere::publish_user_key { "root": } + + # Grant full trust to a gpg key so the root user can properly + # authenticate servers to which it connects + # You can run this as many times as you want + monkeysphere::owner_trust { "jamie": + fingerprint => "0EE5BE979282D80B9F7540F1CCD2ED94D21739E9" } A host can be configured as a host you would use to sign the gpg keys by placing: @@ -26,3 +70,5 @@ into the node definition. ON this host, a file will be placed in /var/lib/puppet/modules/monkeysphere/hosts for each host configured as a sshserver. Each file will contin the gpg id, the gpg fingerprint, and the ssh fingerprint of the sshserver. + +0. http://monkeysphere.info/ diff --git a/files/etc/cron.d/update-monkeysphere-auth b/files/etc/cron.d/update-monkeysphere-auth deleted file mode 100644 index 06bb5ae..0000000 --- a/files/etc/cron.d/update-monkeysphere-auth +++ /dev/null @@ -1 +0,0 @@ -*/5 * * * * root /usr/sbin/monkeysphere-authentication update-users diff --git a/lib/facter/monkeysphere.rb b/lib/facter/monkeysphere.rb index 1d7d68e..6f48a4d 100644 --- a/lib/facter/monkeysphere.rb +++ b/lib/facter/monkeysphere.rb @@ -5,7 +5,7 @@ ssh_fingerprint = ' ' if File.exist?('/usr/sbin/monkeysphere-host') - sk = %x{/usr/sbin/monkeysphere-host show-keys} + sk = %x{/usr/sbin/monkeysphere-host show-keys 2>/dev/null} if $? == 0 has_hostkey = true sk.lines.each do |line| diff --git a/manifests/add_id_certifier.pp b/manifests/add_id_certifier.pp new file mode 100644 index 0000000..726551e --- /dev/null +++ b/manifests/add_id_certifier.pp @@ -0,0 +1,8 @@ +# add certifiers +define monkeysphere::add_id_certifier( $keyid ) { + exec { "monkeysphere-authentication add-id-certifier $keyid": + environment => "MONKEYSPHERE_PROMPT=false", + require => [ Package["monkeysphere"], File["monkeysphere_authentication_conf"] ], + unless => "/usr/sbin/monkeysphere-authentication list-id-certifiers | grep $keyid > /dev/null" + } +} diff --git a/manifests/auth_capable_user.pp b/manifests/auth_capable_user.pp new file mode 100644 index 0000000..497407c --- /dev/null +++ b/manifests/auth_capable_user.pp @@ -0,0 +1,44 @@ +# ensure that the user has a gpg key created and it is authentication capable +# in the monkeysphere. This is intended to be the same as generated a +# password-less ssh key +# +define monkeysphere::auth_capable_user ( + $expire = "1y", + $length = "2048", + $uid_name = undef, + $email = undef ) { + + $user = $title + + # The goal is no passphrase, monkeysphere won't work without a passphrase. + $calculated_passphrase = $gpg_auto_password ? { + '' => 'monkeys', + default => $gpg_auto_password + } + + $calculated_name = $uid_name ? { + '' => "$user user", + default => $uid_name + } + $calculated_email = $email ? { + '' => "$user@$fqdn", + default => $email + } + exec { "monkeysphere-gen-key-$user": + command => "printf 'Key-Type: RSA\nKey-Length: 2048\nKey-Usage: encrypt,sign\nSubkey-Type: RSA\nSubkey-Length: 2048\nSubkey-Usage: encrypt\nName-Real: $calculated_name\nName-Email: $calculated_email\nPassphrase: $calculated_passphrase\nExpire-Date: 1y\n' | gpg --batch --gen-key", + require => [ Package["monkeysphere"] ], + user => $user, + unless => "gpg --list-secret-key | grep ^sec >/dev/null" + } + + #FIXME - we should check expiration date and extend it if we're < n days before expiration + + # handle auth subkey + exec { "monkeysphere-gen-subkey-$user": + command => "printf '$calculated_passphrase\n' | monkeysphere gen-subkey", + require => [ Package["monkeysphere"], Exec["monkeysphere-gen-key-$user" ] ], + user => $user, + unless => "gpg --list-key --with-colons $(gpg --list-secret-key --with-colons | grep ^sec | cut -d: -f5) | grep ^sub | cut -d: -f12 | grep a >/dev/null" + } + +} diff --git a/manifests/authorized_user_ids.pp b/manifests/authorized_user_ids.pp new file mode 100644 index 0000000..09fd182 --- /dev/null +++ b/manifests/authorized_user_ids.pp @@ -0,0 +1,53 @@ +define monkeysphere::authorized_user_ids( + $user_ids, + $dest_dir = '/root/.monkeysphere', + $dest_file = 'authorized_user_ids', + $group = '') { + + $user = $title + $calculated_group = $group ? { + '' => $user, + default => $group + } + + # don't require user if it's root because root is not handled + # by puppet + case $user { + root: { + file { + $dest_dir: + owner => $user, + group => $calculated_group, + mode => 755, + ensure => directory, + } + } + default: { + file { + $dest_dir: + owner => $user, + group => $calculated_group, + mode => 755, + ensure => directory, + require => User[$user] + } + } + } + + file { + "${dest_dir}/${dest_file}": + owner => $user, + group => $calculated_group, + mode => 644, + content => template('monkeysphere/authorized_user_ids.erb'), + ensure => present, + recurse => true, + require => File[$dest_dir] + } + + exec { "monkeysphere-authentication update-users $user": + refreshonly => true, + require => [ File["monkeysphere_authentication_conf"], Package["monkeysphere"] ], + subscribe => File["${dest_dir}/${dest_file}"] + } +} diff --git a/manifests/email_server_keys.pp b/manifests/email_server_keys.pp new file mode 100644 index 0000000..0a0bd4b --- /dev/null +++ b/manifests/email_server_keys.pp @@ -0,0 +1,9 @@ +# optionally, mail key somehwere +define monkeysphere::email_server_keys ( ) { + $email = $title + exec { "mail -s 'monkeysphere host pgp keys for $fqdn' $email < /var/lib/monkeysphere/host_keys.pub.pgp": + require => Package["monkeysphere"], + subscribe => Exec["monkeysphere-import-key"], + refreshonly => true, + } +} diff --git a/manifests/import_key.pp b/manifests/import_key.pp new file mode 100644 index 0000000..ba965ce --- /dev/null +++ b/manifests/import_key.pp @@ -0,0 +1,20 @@ +define monkeysphere::import_key ( + $scheme = 'ssh://', + $port = '', + $path = '/etc/ssh/ssh_host_rsa_key', + $hostname = $fqdn ) { + + # if we're getting a port number, prefix with a colon so it's valid + $prefixed_port = $port ? { + '' => '', + default => ":$port" + } + + $key = "${scheme}${fqdn}${prefixed_port}" + + exec { "monkeysphere-host import-key $path $key": + alias => "monkeysphere-import-key", + require => [ Package["monkeysphere"], File["monkeysphere_host_conf"] ], + unless => "/usr/sbin/monkeysphere-host s | grep $key > /dev/null" + } +} diff --git a/manifests/init.pp b/manifests/init.pp index 6885b45..31c341d 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -19,56 +19,50 @@ # # Class for monkeysphere management # + class monkeysphere( $ssh_port = '', - $publish_key = false, - $ensure_version = 'installed' + $ensure_version = 'installed', + # if not false, will override the path for MONKEYSPHERE_RAW_AUTHORIZED_KEYS + # use 'none' to disable appending the authorized_keys file + # see monkeysphere-authentication for more information + $raw_authorized_keys = false, + $keyserver = 'pool.sks-keyservers.net' ) { # The needed packages - package{'monkeysphere': + package { 'monkeysphere': ensure => $ensure_version, } - $port = $monkeysphere::ssh_port ? { - '' => '', - default => ":${monkeysphere::ssh_port}", - } - $key = "ssh://${::fqdn}${port}" - common::module_dir { [ 'monkeysphere', 'monkeysphere/hosts', 'monkeysphere/plugins' ]: } + modules_dir { [ 'monkeysphere', 'monkeysphere/hosts', 'monkeysphere/plugins' ]: } + file { + # This was the old way which the module checked monkeysphere keys '/usr/local/sbin/monkeysphere-check-key': - ensure => present, + ensure => absent, owner => root, group => root, - mode => '0755', - content => "#!/bin/bash\n/usr/bin/gpg --homedir /var/lib/monkeysphere/host --list-keys '=${key}' &> /dev/null || false", - } - - # Server host key publication - Exec{ - unless => '/usr/local/sbin/monkeysphere-check-key', - user => 'root', - require => [ Package['monkeysphere'], File['/usr/local/sbin/monkeysphere-check-key'] ], - } - case $monkeysphere::publish_key { - false: { - exec { "/usr/sbin/monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key ${key}": } - } - 'mail': { - $mail_loc = $::operatingsystem ? { - 'centos' => '/bin/mail', - default => '/usr/bin/mail', - } - exec { "/usr/sbin/monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key ${key} && \ - ${mail_loc} -s 'monkeysphere host pgp key for ${::fqdn}' root < /var/lib/monkeysphere/host_keys.pub.pgp": - } - } - default: { - exec { "/usr/sbin/monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key ${key} && \ - echo Y | /usr/sbin/monkeysphere-host publish-key": - } - } + mode => 0755, + content => "#!/bin/bash\n/usr/bin/gpg --homedir /var/lib/monkeysphere/host --list-keys '=$key' &> /dev/null || false"; + 'monkeysphere_conf': + path => '/etc/monkeysphere/monkeysphere.conf', + mode => 644, + ensure => present, + content => template('monkeysphere/monkeysphere.conf.erb'), + require => Package['monkeysphere']; + 'monkeysphere_host_conf': + path => '/etc/monkeysphere/monkeysphere-host.conf', + mode => 644, + ensure => present, + content => template('monkeysphere/monkeysphere-host.conf.erb'), + require => Package['monkeysphere']; + 'monkeysphere_authentication_conf': + path => '/etc/monkeysphere/monkeysphere-authentication.conf', + mode => 644, + ensure => present, + content => template('monkeysphere/monkeysphere-authentication.conf.erb'), + require => Package['monkeysphere']; } } diff --git a/manifests/owner_trust.pp b/manifests/owner_trust.pp new file mode 100644 index 0000000..0e0af7f --- /dev/null +++ b/manifests/owner_trust.pp @@ -0,0 +1,25 @@ +define monkeysphere::owner_trust ( + $fingerprint, + $user = 'root', + $level = 6 ) { + + $keyserver_arg = $monkeysphere_keyserver ? { + '' => '', + default => "--keyserver $monkeysphere_keyserver" + } + + # ensure the key is in the key ring + exec { "monkeysphere-gpg-recv-key-$user-$fingerprint": + command => "gpg $keyserver_arg --recv-key $fingerprint", + require => [ Package["monkeysphere"] ], + user => $user, + unless => "gpg --list-key $fingerprint 2>&1 >/dev/null" + } + # provide ownertrust + exec { "monkeysphere-gpg-ownertrust-$user-$fingerprint": + command => "printf '$fingerprint:$level\n'\$(gpg --export-ownertrust) | gpg --import-ownertrust", + require => [ Package["monkeysphere"] ], + user => $user, + unless => "gpg --export-ownertrust | grep $fingerprint >/dev/null" + } +} diff --git a/manifests/publish_server_keys.pp b/manifests/publish_server_keys.pp new file mode 100644 index 0000000..33e070e --- /dev/null +++ b/manifests/publish_server_keys.pp @@ -0,0 +1,7 @@ +# Server host key publication +define monkeysphere::publish_server_keys ( $keyid = '--all' ) { + exec { "monkeysphere-host publish-keys $keyid": + environment => "MONKEYSPHERE_PROMPT=false", + require => [ Package["monkeysphere"], Exec["monkeysphere-import-key"], File["monkeysphere_host_conf"] ]; + } +} diff --git a/manifests/publish_user_key.pp b/manifests/publish_user_key.pp new file mode 100644 index 0000000..f76c408 --- /dev/null +++ b/manifests/publish_user_key.pp @@ -0,0 +1,15 @@ +define monkeysphere::publish_user_key ( ){ + $user = $title + + $keyserver_arg = $monkeysphere_keyserver ? { + '' => '', + default => "--keyserver $monkeysphere_keyserver" + } + + exec { "monkeysphere-gpg-send-key-$user": + command => "gpg $keyserver_arg --send-key $(gpg --list-secret-key --with-colons | grep ^sec | cut -d: -f5)", + require => [ Package["monkeysphere"], Exec["monkeysphere-gen-key-$user" ] ], + user => $user, + } + +} diff --git a/manifests/sshserver.pp b/manifests/sshserver.pp index 43c0f6f..a525b55 100644 --- a/manifests/sshserver.pp +++ b/manifests/sshserver.pp @@ -10,12 +10,10 @@ class monkeysphere::sshserver { } } - file{'/etc/cron.d/update-monkeysphere-auth': - ensure => present, - source => 'puppet:///modules/monkeysphere/etc/cron.d/update-monkeysphere-auth', + cron {'update-monkeysphere-auth': + command => '/usr/sbin/monkeysphere-authentication update-users > /dev/null 2>&1', + user => root, + minute => fqdn_rand(60), require => Package['monkeysphere'], - mode => '0644', - owner => root, - group => root, } } diff --git a/templates/authorized_user_ids.erb b/templates/authorized_user_ids.erb new file mode 100644 index 0000000..9313c6b --- /dev/null +++ b/templates/authorized_user_ids.erb @@ -0,0 +1,6 @@ +# This file is maintained by puppet, changes will be overwritten +<% if user_ids.is_a? String -%> +<%= user_ids %> +<% elsif user_ids.is_a? Array -%> +<%= user_ids.map { |i| "#{i}" }.join("\n") %> +<% end -%> diff --git a/templates/monkeysphere-authentication.conf.erb b/templates/monkeysphere-authentication.conf.erb new file mode 100644 index 0000000..b489a68 --- /dev/null +++ b/templates/monkeysphere-authentication.conf.erb @@ -0,0 +1,37 @@ +# Monkeysphere authentication configuration file. + +# This is an sh-style shell configuration file. Variable names should +# be separated from their assignments by a single '=' and no spaces. +# Environment variables with the same names as these variables but +# prefaced by "MONKEYSPHERE_" will take precedence over the values +# specified here. + +# Log level. Can be SILENT, ERROR, INFO, VERBOSE, DEBUG, in +# increasing order of verbosity. +#LOG_LEVEL=INFO + +# OpenPGP keyserver +#KEYSERVER=pool.sks-keyservers.net +<%= 'KEYSERVER='+keyserver if keyserver and keyserver != 'pool.sks-keyservers.net' %> +# User who controls the monkeysphere 'sphere' keyring. +#MONKEYSPHERE_USER=monkeysphere + +# Whether or not to query keyservers by default +#CHECK_KEYSERVER=true + +# Path to authorized_user_ids file to process to create +# authorized_keys file. '%h' will be replaced by the home directory +# of the user, and '%u' will be replaced by the username of the user. +# For purely admin-controlled authorized_user_ids, you might put them +# in /etc/monkeysphere/authorized_user_ids/%u, for instance. +#AUTHORIZED_USER_IDS="%h/.monkeysphere/authorized_user_ids" + +# Path to a user controlled authorized_keys file to be added to the +# monkeysphere-generated authorized_keys file. '%h' will be replaced +# by the home directory of the user, and '%u' will by replaced by the +# username of the user. Setting this variable to 'none' prevents the +# inclusion of user controlled authorized_keys file. +#RAW_AUTHORIZED_KEYS="%h/.ssh/authorized_keys" +<% if @raw_authorized_keys -%> +RAW_AUTHORIZED_KEYS=<%= @raw_authorized_keys -%> +<% end -%> diff --git a/templates/monkeysphere-host.conf.erb b/templates/monkeysphere-host.conf.erb new file mode 100644 index 0000000..418c696 --- /dev/null +++ b/templates/monkeysphere-host.conf.erb @@ -0,0 +1,15 @@ +# Monkeysphere host configuration file. + +# This is an sh-style shell configuration file. Variable names should +# be separated from their assignments by a single '=' and no spaces. +# Environment variables with the same names as these variables but +# prefaced by "MONKEYSPHERE_" will take precedence over the values +# specified here. + +# Log level. Can be SILENT, ERROR, INFO, VERBOSE, DEBUG, in +# increasing order of verbosity. +#LOG_LEVEL=INFO + +# OpenPGP keyserver +#KEYSERVER=pool.sks-keyservers.net +<%= 'KEYSERVER='+keyserver if keyserver and keyserver != 'pool.sks-keyservers.net' %> diff --git a/templates/monkeysphere.conf.erb b/templates/monkeysphere.conf.erb new file mode 100644 index 0000000..53e4b9e --- /dev/null +++ b/templates/monkeysphere.conf.erb @@ -0,0 +1,39 @@ +# Monkeysphere system-wide client configuration file. + +# This is an sh-style shell configuration file. Variable names should +# be separated from their assignments by a single '=' and no spaces. +# Environment variables with the same names as these variables but +# prefaced by "MONKEYSPHERE_" will take precedence over the values +# specified here. + +# Log level. Can be SILENT, ERROR, INFO, VERBOSE, DEBUG, in +# increasing order of verbosity. +#LOG_LEVEL=INFO + +# GPG home directory. If not specified either here or in the +# MONKEYSPHERE_GNUPGHOME environment variable, then the value of the +# GNUPGHOME environment variable will be used. If GNUPGHOME is not +# set either, then the default value is listed below. +#GNUPGHOME=~/.gnupg + +# GPG keyserver to search for keys. +#KEYSERVER=pool.sks-keyservers.net +<%= 'KEYSERVER='+keyserver if keyserver and keyserver != 'pool.sks-keyservers.net' %> +# Set whether or not to check keyservers at every monkeysphere +# interaction, including all ssh connections if you use the +# monkeysphere ssh-proxycommand. Leave unset for default behavior +# (see KEYSERVER CHECKING in monkeysphere(1)), or set to true or false. +# NOTE: setting CHECK_KEYSERVER explicitly to true will leak +# information about the timing and frequency of your ssh connections +# to the maintainer of the keyserver. +#CHECK_KEYSERVER=true + +# The path to the SSH known_hosts file. +#KNOWN_HOSTS=~/.ssh/known_hosts + +# Whether or not to hash the generated known_hosts lines. +# Should be "true" or "false". +#HASH_KNOWN_HOSTS=false + +# The path to the SSH authorized_keys file. +#AUTHORIZED_KEYS=~/.ssh/authorized_keys |