Skip to content

Commit

Permalink
Create mco client config if also using sshkeyauth
Browse files Browse the repository at this point in the history
Added support for sshkey client and server configuration.

Changed the default value for server send_key to align with sshkey module.  This is because the setting both specifies and enables sending the public key.  If you're using a static deployment method for key data, you may want to shuffle those around yourself in puppet profile code.

Fixed syntax error & disabled resource enforcement on the public_key directory if you don't need it.

Added new parameters to specify the user certificate and private keys as content instead of a source.  This permits providing the data through hiera rather than a file reference.

Moving the private key declaration into the existing SSL section for now for clarity.  There also appears to be an assumption that the CA for the user and the middleware are the same.  Also go ahead and split the private key of the server into its own local file for middleware TLS communication so it doesn't require the SSL securityprovider plugin.

Moved & Added more to the client implementation.  In the process refactored to pull all client code away from a central definition to being user based.

Add version selection for sshkey required gem. (+1 squashed commit)
Squashed commits:
[67133ae] Moved gem installation to init where it should have been.

The file function gives an unhelpful error if given a file that doesn't exist on the puppet master at compile time.

Changed middleware ssl files name for clarity on what it contains.

Provide an empty response when it asks for the passphrase (+1 squashed commit)
Squashed commits:
[fa93e7f] Add the option to regenerate the private key if it's not provided.

Discovered you can't use both publickey_dir and known_hosts when it comes to the client.

Changed default for user pubkey_dir to avoid permissions issues with $mcollective::confdir

Variable interpolation inside class parameters can be inconsistent (PUP-1080)

Add sshkey documentation

Puppet-lint cleanup

Preserve old behavior that the server's private key gets reused as the default user ssl private key.

Attempt to fix tests.

Fixed a bad syntax error I'd introduced.  Yay tests!

Added argument to tell factor to load puppet facts as well (Issue #262).

Fixed autolayout puppet-lint error (+2 squashed commits)
Squashed commits:
[9587b06] moving around for more standard module layout
[d428859] Fixing puppet-lint errors

Update Test based on changes to middleware ssl key being renamed.

Fixed the test again from copy/paste error.
  • Loading branch information
jhg03a authored and DavidS committed May 19, 2016
1 parent 0a620c1 commit 931f79b
Show file tree
Hide file tree
Showing 22 changed files with 447 additions and 42 deletions.
103 changes: 100 additions & 3 deletions README.md
Expand Up @@ -164,6 +164,28 @@ node 'control.example.com' {
}
```

### I'd like to secure the transport channel and authenticate users with just their private key, how do I do that?

The Mcollective standard deployment guide uses the 'ssl' securityprovider to handle
authentication. If you're interested in performing the authentication without
creating SSL certificates for each user, one alternative is to use the 'sshkey'
securityprovider. As far as the transport channel encryption goes, it's no different
than the above example's use of 'middleware_ssl*' parameters.

Sshkey adds additional flexibility with regards to deployment as it currently supports
both a static and a dynamic key management philosophy. You can seperate sshkey from
your normal system authentication's backend (known\_hosts / authorized\_keys) and
permit it to send and record its key data for you. If you do this, you should strongly
consider using an authorization plugin with mcollective. Alternatively, you can use
puppet to enforce the available set of key data to use with requests and responses.
Because this could reuse an existing user's ssh private key, it could work along-side
your existing user management module.

The use of sshkey is optional. For further information, you can review a sample
deployment in the /examples folder, review the [sshkey module documentation](https://github.com/puppetlabs/mcollective-sshkey-security),
and review the [sshkeyauth rubygem documentation](https://github.com/jordansissel/ruby-sshkeyauth) (helpful for debugging errors).


### The `::mcollective::` class

The `mcollective` class is the main entry point to the module. From here you
Expand Down Expand Up @@ -369,6 +391,36 @@ String: defaults to 'puppet:///modules/mcollective/empty'. A file source that
contains a directory of user certificates which are used by the ssl security
provider in authenticating user requests.

##### `sshkey_server_learn_public_keys`

Boolean: defaults to false. Allow writing sshkey public keys to
`sshkey_server_publickey_dir`.

##### `sshkey_server_overwrite_stored_keys`

Boolean: defaults to false. Overwrite learned keys.

##### `sshkey_server_publickey_dir`

String: defaults to `${confdir}/sshkey_pubdir`. Directory to store
received keys

##### `sshkey_server_private_key`

String: defaults to '/etc/ssh/ssh\_host\_rsa\_key'. The private key used to
sign replies with.

##### `sshkey_server_authorized_keys`

String: defaults to undefined. The authorized_key file to use. Undefined
is interpreted by sshkey to mean the caller's authorized key file.

##### `sshkey_server_send_key`

String: defaults to undefined. Specifies the public key
sent back with the response for validation. You probably want
'/etc/ssh/ssh\_host\_rsa\_key.pub'.

### `mcollective::user` defined type

`mcollective::user` installs a client configuration and any needed client
Expand All @@ -392,13 +444,58 @@ install for.
##### `certificate`

String: defaults to undef. A file source for the certificate of the user.
Used by the 'ssl' securityprovider to set the identity of the user.
Used by the 'ssl' securityprovider to set the identity of the user. This is
mutually exclusive with `certificate_content`.

##### `certificate_content`

String: defaults to undef. The file content for the certificate of the user.
Used by the 'ssl' securityprovider to set the identity of the user. This is
mutually exclusive with `certificate`.

##### `private_key`

String: defaults to undef. A file source for the private key of the user.
Used when `mcollective::middleware_ssl` is true to connect to the middleware
and by the 'ssl' securityprovider to sign messages as from this user.
Used by the 'ssl' & 'sshkey' securityprovider to sign messages as from this user.
When not supplied to sshkey, this is interpreted to use the user's ssh-agent.
This is mutually exclusive with `private_key_content`.

##### `private_key_content`

String: defaults to undef. The file content for the private key of the user.
Used by the 'ssl' & 'sshkey' securityprovider to sign messages as from this user.
This is mutually exclusive with `private_key`.

##### `sshkey_learn_public_keys`

Boolean: defaults to false. Allow writing sshkey public keys to
`sshkey_client_publickey_dir`.

##### `sshkey_overwrite_stored_keys`

Boolean: defaults to false. Overwrite learned keys.

##### `sshkey_publickey_dir`

String: defaults to `${homedir}/.mcollective.d/public_keys`. Directory to store
received keys.

##### `sshkey_enable_private_key`

Boolean: defaults to false. Enable manual specification of the private key to
sign requests with. False is interpreted by sshkey to use the
user's ssh-agent.

##### `sshkey_known_hosts`

String: defaults to '${homedir}/${callerid}/.ssh/known\_hosts'. The known\_hosts
file to use. This is mutually exclusive with `sshkey_publickey_dir` and is disabled
by `sshkey_learn_public_keys`.

##### `sshkey_enable_send_key`

Boolean: defaults to false. Enable sending the user public key inside the
request.

### `mcollective::plugin` defined type

Expand Down
5 changes: 1 addition & 4 deletions examples/README.md
Expand Up @@ -10,7 +10,4 @@ manage those middleware services. The examples included in this directory show
how a site-specific profile might be built that leverages the
puppet/mcollective technology module in conjunction with other Puppet Labs
modules, puppetlabs/rabbitmq or puppetlabs/activemq, to build out a complete
technology stack.

To show these examples, a structurally correct module named "mco_profile" is
rooted in this directory.
technology stack.
7 changes: 7 additions & 0 deletions examples/sshkey_example/README.md
@@ -0,0 +1,7 @@
# MCollective Sshkey Example #

This directory is not a structurally correct example, but rather the essential code needed
to demonstrate the use of the sshkey security provider in a dynamic key setup. It does
assume a basic knowledge of both puppet and hiera. The example provided also uses hiera-eyaml
to facilitate the deployment of the user sshkey private key, but this can be accomplished in
many other ways as your environment dictates.
@@ -0,0 +1,7 @@
mcollective::userconfigs:
jsmith:
group: 'wheel'
private_key_content: ENC[PKCS7,MIIOHQYJKoZIhvcNAQc...snip...bSBN7XAvw=]
bob:
group: 'admins'
private_key_content: ENC[PKCS7,ASDGADSIIFGHDFGNAQc...snip...bFKLAOXTW=]
22 changes: 22 additions & 0 deletions examples/sshkey_example/mco_profile/hieradata/common.yaml
@@ -0,0 +1,22 @@
---
mcollective::middleware_hosts:
- 'middleware.domain.com'
mcollective::middleware_user: 'mcollective'
mcollective::middleware_password: ENC[PKCS7,MIIBuQYJKoZIh...snip...qn8NT9EkEJenQ==]
mcollective::middleware_ssl_port: '61614'
mcollective::middleware_ssl: true
mcollective::middleware_admin_user: 'admin'
mcollective::middleware_admin_password: ENC[PKCS7,MIIBeQYJKoZIh...snip...+AzSGTSq]
mcollective::securityprovider: 'sshkey'
# Adjusted for puppet 4
mcollective::confdir: '/etc/puppetlabs/mcollective'
# Adjusted for puppet 4
mcollective::libdir: '/usr/local/libexec/mcollective:/usr/libexec/mcollective:/opt/puppetlabs/mcollective'
# Reuse puppet ssl infrastructure for secure communications
mcollective::middleware_ssl_cert: "/etc/puppetlabs/puppet/ssl/certs/%{::clientcert}.pem"
mcollective::middleware_ssl_key: "/etc/puppetlabs/puppet/ssl/private_keys/%{::clientcert}.pem"
mcollective::middleware_ssl_ca: "/etc/puppetlabs/puppet/ssl/certs/ca.pem"
# Use the dynamic learning method for sshkey
mcollective::sshkey_server_learn_public_keys: true
mcollective::sshkey_server_overwrite_stored_keys: true
mcollective::sshkey_server_send_key: '/etc/ssh/ssh_host_rsa_key.pub'
17 changes: 17 additions & 0 deletions examples/sshkey_example/mco_profile/manifests/client.pp
@@ -0,0 +1,17 @@
# Installs Mcollective client code and deploys user credentials
# This utilizes the dynamic sshkey deployment method
# This also assumes that your client is going to be deployed
# on the same system as your server code
class mco_profile::client {
$mcollective_users = hiera_hash('mcollective::userconfigs')

# Set defaults for all mcollective::user resources
Mcollective::User {
sshkey_learn_public_keys => true,
sshkey_overwrite_stored_keys => true,
sshkey_enable_private_key => true,
sshkey_enable_send_key => true,
}
# Refer to hiera documentation on merging if a more complex scenario is needed
create_resources('mcollective::user',$mcollective_users)
}
34 changes: 34 additions & 0 deletions examples/sshkey_example/mco_profile/manifests/server.pp
@@ -0,0 +1,34 @@
# Installs mcollective server components and configuration
class mco_profile::server (
$server_pubkey = '/etc/ssh/ssh_host_rsa_key.pub',
$server_privkey = '/etc/ssh/ssh_host_rsa_key',
) {
# Validate the ssh keys for the server exist
file { [$server_pubkey, $server_privkey]:
ensure => 'file',
before => Class['mcollective'],
}

# Install sshkey plugin
# Requires you to have obtained the security directory from https://github.com/puppetlabs/mcollective-sshkey-security
# and placed it on your puppetmaster's file server
mcollective::plugin { 'sshkey':
source => 'puppet:///modules/profile/mco/plugins/sshkey',
}

# Enable syslog output
# mcollective::common::setting { 'use_syslog_logging':
# setting => 'logger_type',
# value => 'syslog',
# order => '90',
# }

# Set syslog facility
# mcollective::common::setting { 'use_syslog_logging_facility':
# setting => 'logfacility',
# value => 'user',
# order => '90',
# }

include ::mcollective
}
7 changes: 7 additions & 0 deletions examples/ssl_example/README.md
@@ -0,0 +1,7 @@
# MCollective SSL Example #

This directory contains example business-logic level Puppet configuration to
build a complete ssl-based infrastructure for MCollective.

To show this example, a structurally correct module named "mco_profile" is
rooted in this directory.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions manifests/client/config.pp
Expand Up @@ -4,8 +4,8 @@
fail("Use of private class ${name} by ${caller_module_name}")
}

if $mcollective::securityprovider == 'ssl' {
# if securityprovider == ssl each user will want their own ~/.mcollective
if $mcollective::securityprovider == 'ssl' or $mcollective::securityprovider == 'sshkey' {
# if using the ssl or sshkey securityprovider each user will want their own ~/.mcollective
# with their own identity in, so don't publish the global client.cfg
file { 'mcollective::client':
ensure => 'absent',
Expand Down
27 changes: 24 additions & 3 deletions manifests/init.pp
Expand Up @@ -5,9 +5,10 @@
$client = false,

# installing packages
$manage_packages = true,
$version = 'present',
$ruby_stomp_ensure = 'installed',
$manage_packages = true,
$version = 'present',
$ruby_stomp_ensure = 'installed',
$sshkeyauth_gem_version = 'present',

# core configuration
$confdir = $mcollective::defaults::confdir,
Expand Down Expand Up @@ -70,6 +71,15 @@

# Action policy settings
$allowunconfigured = '1',

# Sshkey security provider settings
# Module defaults: https://github.com/puppetlabs/mcollective-sshkey-security/blob/master/security/sshkey.rb
$sshkey_server_learn_public_keys = false,
$sshkey_server_overwrite_stored_keys = false,
$sshkey_server_publickey_dir = undef, #overwritten below
$sshkey_server_private_key = '/etc/ssh/ssh_host_rsa_key',
$sshkey_server_authorized_keys = undef,
$sshkey_server_send_key = undef,
) inherits mcollective::defaults {

# Because the correct default value for several parameters is based on another
Expand All @@ -93,6 +103,17 @@
$middleware_ssl_cert_path = "${ssldir}/middleware_cert.pem"
$middleware_ssl_ca_path = "${ssldir}/middleware_ca.pem"

if $securityprovider == 'sshkey' {
package{'sshkeyauth':
ensure => $sshkeyauth_gem_version,
provider => 'puppet_gem',
}
}

if $sshkey_server_learn_public_keys {
$sshkey_server_publickey_dir_real = pick($sshkey_server_publickey_dir,"${confdir}/sshkey_pubkeys")
}

if $client or $server {
contain mcollective::common
}
Expand Down
4 changes: 2 additions & 2 deletions manifests/server/config/factsource/yaml.pp
Expand Up @@ -32,14 +32,14 @@
if $yaml_fact_cron {
if versioncmp($::facterversion, '3.0.0') >= 0 {
cron { 'refresh-mcollective-metadata':
command => "facter --yaml >${yaml_fact_path_real} 2>&1",
command => "facter -p --yaml >${yaml_fact_path_real} 2>&1",
environment => 'PATH=/opt/puppet/bin:/opt/puppetlabs/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
user => 'root',
minute => $cron_minutes,
}
exec { 'create-mcollective-metadata':
path => "/opt/puppet/bin:/opt/puppetlabs/bin:${::path}",
command => "facter --yaml >${yaml_fact_path_real} 2>&1",
command => "facter -p --yaml >${yaml_fact_path_real} 2>&1",
creates => $yaml_fact_path_real,
}
} else {
Expand Down
48 changes: 48 additions & 0 deletions manifests/server/config/securityprovider/sshkey.pp
@@ -0,0 +1,48 @@
# private class
class mcollective::server::config::securityprovider::sshkey {
if $caller_module_name != $module_name {
fail("Use of private class ${name} by ${caller_module_name}")
}

if $mcollective::sshkey_server_learn_public_keys {
# In the event the node is both a server and a client and they share a public key directory
ensure_resource('file', $mcollective::sshkey_server_publickey_dir_real, {
'ensure' => 'directory',
'mode' => '0755', }
)
}

# https://github.com/puppetlabs/mcollective-sshkey-security/blob/master/security/sshkey.rb

mcollective::server::setting { 'plugin.sshkey.server.learn_public_keys':
value => bool2num($mcollective::sshkey_server_learn_public_keys),
}

mcollective::server::setting { 'plugin.sshkey.server.overwrite_stored_keys':
value => bool2num($mcollective::sshkey_server_overwrite_stored_keys),
}

if $mcollective::sshkey_server_publickey_dir_real {
mcollective::server::setting { 'plugin.sshkey.server.publickey_dir':
value => $mcollective::sshkey_server_publickey_dir_real,
}
}

if $mcollective::sshkey_server_private_key {
mcollective::server::setting { 'plugin.sshkey.server.private_key':
value => $mcollective::sshkey_server_private_key,
}
}

if $mcollective::sshkey_server_authorized_keys {
mcollective::server::setting { 'plugin.sshkey.server.authorized_keys':
value => $mcollective::sshkey_server_authorized_keys,
}
}

if $mcollective::sshkey_server_send_key {
mcollective::server::setting { 'plugin.sshkey.server.send_key':
value => $mcollective::sshkey_server_send_key,
}
}
}

0 comments on commit 931f79b

Please sign in to comment.