From 3ae2463c8ccb79bb63f215914d40e3567b477eb9 Mon Sep 17 00:00:00 2001 From: Kevin Gilpin Date: Wed, 3 Sep 2014 11:28:54 -0400 Subject: [PATCH] initial commit --- .project | 18 ++++++++ README.md | 51 ++++++++++++++++++++ attributes/default.rb | 4 ++ libraries/conjur_host_identity_chef.rb | 62 +++++++++++++++++++++++++ metadata.rb | 31 +++++++++++++ recipes/default.rb | 64 ++++++++++++++++++++++++++ 6 files changed, 230 insertions(+) create mode 100644 .project create mode 100644 README.md create mode 100644 attributes/default.rb create mode 100644 libraries/conjur_host_identity_chef.rb create mode 100644 metadata.rb create mode 100644 recipes/default.rb diff --git a/.project b/.project new file mode 100644 index 0000000..fdf5ac3 --- /dev/null +++ b/.project @@ -0,0 +1,18 @@ + + + conjur-cookbooks-host-identity-chef + + + + + + com.aptana.ide.core.unifiedBuilder + + + + + + com.aptana.ruby.core.rubynature + com.aptana.projects.webnature + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc64042 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ += Description + +Creates and installs Conjur host identity using Chef attributes and the Conjur +[host factory](http://developer.conjur.net/reference/services/host_factory). + +## Attributes + +See the Chef metadata.rb for detailed information about the attributes used by this recipe. + +Basically, you should populate attributes which configure the connection to Conjur: + +* appliance URL +* organization account name +* SSL certificate + +You also need to provide two other pieces of information: + +* A host factory token. +* The id of the host. You can use some data from OHAI (such as the AWS instance id), or the Chef node name, +or whatever you like. But it needs to be unique across your Conjur system. + +## Conjur gem installation + +The Conjur API and Conjur CLI gems are installed using by [chef_gem](https://docs.getchef.com/resource_chef_gem.html). +Therefore they can be used in any other subsequent cookbook as well. + +## Conjur configuration + +This cookbook builds `/etc/conjur.conf` from the Conjur connection information. This will be used +by all the downstream Conjur functionality. + +File permissions are `0644`. + +## Conjur host identity + +Next, this cookbook looks for a host identity in `/etc/conjur.identity`. If that file exists, it's left intact. + +If it doesn't exist, the host factory token is used to create a new host identity, which is then saved to the file. +File permissions are `0600`. + +The `netrc_path` entry in `conjur.conf` points to `/etc/conjur.identity`. Therefore, downstream Conjur tools such as the +Conjur CLI will automatically pick up the host identity from this file and use it. + +# Testing + +Once the cookbook has run, you can verify the host identity by running `conjur authn whoami`. For example: + + # /opt/chef/embedded/bin/conjur authn whoami + {"account":"demo","username":"host/kgilpin@spudling.local/chef-tutorial-1-0/vagrant/ff849c12-95d7-4720-9fb7-2c2be88582f7"} + +In downstream processes, you can rely on the Conjur API and CLI being installed as Chef gems. diff --git a/attributes/default.rb b/attributes/default.rb new file mode 100644 index 0000000..de4bf99 --- /dev/null +++ b/attributes/default.rb @@ -0,0 +1,4 @@ +default['conjur'] ||= {} + +default['conjur']['configuration_file'] = '/etc/conjur.conf' +default['conjur']['configuration']['netrc_path'] = '/etc/conjur.identity' diff --git a/libraries/conjur_host_identity_chef.rb b/libraries/conjur_host_identity_chef.rb new file mode 100644 index 0000000..56f7c55 --- /dev/null +++ b/libraries/conjur_host_identity_chef.rb @@ -0,0 +1,62 @@ +module ConjurHostIdentityChef + module ConjurHelper + extend self + + def config_file node + node.conjur.configuration_file + end + + def netrc_file + require 'conjur/config' + Conjur::Config[:netrc_path] + end + + def config? node + File.exists?(config_file node) + end + + def configure! node + require 'conjur/api' + require 'conjur/config' + require 'conjur/authn' + + Conjur::Config.load [ config_file(node) ] + Conjur::Config.apply + end + + # Updates the Conjur configuration. Yields the existing config (which may be an + # empty hash), then writes the config to the proper location. + def update_config node, &block + c = if config?(node) + config(node) + else + {} + end + yield c + File.write(config_file(node), YAML.dump(c)) + end + + def config node + YAML.load(File.read(config_file(node))) + end + + def save_credentials credentials + require 'conjur/authn' + netrc = Conjur::Authn.netrc + netrc[Conjur::Authn.host] = credentials + netrc.save + end + + def credentials? + require 'conjur/authn' + Conjur::Authn.get_credentials noask: true + true + rescue + false + end + end +end + +class Chef::Recipe + include ConjurHostIdentityChef +end \ No newline at end of file diff --git a/metadata.rb b/metadata.rb new file mode 100644 index 0000000..07273dc --- /dev/null +++ b/metadata.rb @@ -0,0 +1,31 @@ +name 'conjur-client' +maintainer 'Conjur, Inc.' +maintainer_email 'kgilpin@conjur.net' +license 'MIT' +description 'Obtains and istalls the Conjur host identity from Chef attributes' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '0.3.0' + +attribute "conjur/host_factory_token", + description: "Conjur host factory token used to create the host identity.", + required: "required" +attribute "conjur/host_identity/id", + description: "Identity which will be assigned to the new host.", + required: "required" +attribute "conjur/configuration/appliance_url", + description: "URL of the Conjur service, for example https://conjur/api.", + required: "required" +attribute "conjur/configuration/account", + description: "Conjur organization account name", + required: "required" +attribute "conjur/configuration/ssl_certificate", + description: %Q{SSL certificate of the Conjur service. Substitute line breaks with the \n newline character.}, + required: "required" +attribute "conjur/configuration_file", + description: "Alternate location for the Conjur configuration file. Default is /etc/conjur.conf" +attribute "conjur/configuration/netrc_path", + description: "Alternate location for the Conjur login cache. Default is /etc/conjur.identity" + +%w(debian ubuntu centos fedora).each do |platform| + supports platform +end diff --git a/recipes/default.rb b/recipes/default.rb new file mode 100644 index 0000000..5a2ccf7 --- /dev/null +++ b/recipes/default.rb @@ -0,0 +1,64 @@ +# +# Copyright 2014, Kevin Gilpin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Alternatively, package 'ruby-devel' +package 'ruby-json' + +chef_gem 'conjur-cli' +chef_gem 'conjur-asset-host-factory' + +appliance_url = node.conjur.configuration.appliance_url +account = node.conjur.configuration.account +netrc_path = node.conjur.configuration.netrc_path + +ConjurHelper.update_config(node) do |conjur_config| + conjur_config['appliance_url'] = appliance_url + conjur_config['account'] = account + conjur_config['netrc_path'] = netrc_path +end + +# Store the Conjur SSL certificate, if it's available. +if node.conjur.configuration['ssl_certificate'] + require 'fileutils' + cert_file = "/etc/conjur-#{account}.pem" + File.write(cert_file, node.conjur.configuration.ssl_certificate) + File.chmod 0644, cert_file + ConjurHelper.update_config(node) do |conjur_config| + conjur_config['cert_file'] = cert_file + end +end + +# Configure the Conjur client using the config we've just written. +ConjurHelper.configure! node + +# Create the host identity if it doesn't exist. +unless ConjurHelper.credentials? + require 'uri' + require 'conjur-asset-host-factory' + + Chef::Log.debug "Conjur host identity not found in #{ConjurHelper.netrc_file}" + + token = node.conjur.host_factory_token + host_id = node.conjur.host_identity.id + + Chef::Log.info "Creating Conjur host identity '#{host_id}'" + + host = Conjur::API.host_factory_create_host token, host_id + + ConjurHelper.save_credentials [ "host/#{host['id']}", host['api_key'] ] +else + Chef::Log.debug "Conjur host identity already exists in #{ConjurHelper.netrc_file}" +end