Adds encrypted databag secret support

* Adds ::Openstack::secret library routine to return
  decrypted databag values or supplied parameter values
  when in developer_mode
* Adds documentation on library routine to README
* Adds unit tests for secret to specs/
This commit is contained in:
Jay Pipes 2012-12-18 16:33:16 -05:00
parent 17bea73749
commit 4241aa3b5c
4 changed files with 123 additions and 2 deletions

View File

@ -17,6 +17,63 @@ of all the settable attributes for this cookbook.
Note that all attributes are in the `default["openstack"]` "namespace"
Libraries
=========
This cookbook exposes a set of default library routines:
* `endpoint` -- Used to return a `::URI` object representing the named OpenStack endpoint
* `endpoints` -- Useful for operating on all OpenStack endpoints
* `db` -- Returns a Hash of information about a named OpenStack database
* `db_uri` -- Returns the SQLAlchemy RFC-1738 DB URI (see: http://rfc.net/rfc1738.html) for a named OpenStack database
* `db_create_with_user` -- Creates a database and database user for a named OpenStack database
* `secret` -- Returns the value of an encrypted data bag for a named OpenStack secret key and key-section
Usage
-----
The following are code examples showing the above library routines in action.
Remember when using the library routines exposed by this library to include
the Openstack routines in your recipe's `::Chef::Recipe` namespace, like so:
```ruby
class ::Chef::Recipe
include ::Openstack
end
```
Example of using the `endpoint` routine:
```ruby
nova_api_ep = endpoint "compute-api"
::Chef::Log.info("Using Openstack Compute API endpoint at #{nova_api_ep.to_s}")
# Note that endpoint URIs may contain variable interpolation markers such
# as `%(tenant_id)s`, so you may need to decode them. Do so like this:
require "uri"
puts ::URI.decode nova_api_ap.to_s
```
Example of using the `secret` and `db\_uri` routine:
```ruby
db_pass = secret "passwords", "cinder"
db_user = node["cinder"]["db"]["user"]
sql_connection = db_uri "volume", db_user, db_pass
template "/etc/cinder/cinder.conf" do
source "cinder.conf.erb"
owner node["cinder"]["user"]
group node["cinder"]["group"]
mode 00644
variables(
"sql_connection" => sql_connection
)
end
```
Testing
=====

View File

@ -17,6 +17,24 @@
# limitations under the License.
#
# Setting this to True means that database passwords and service user
# passwords for Keystone will be easy-to-remember values -- they will be
# the same value as the key. For instance, if a cookbook calls the
# ::Openstack::secret routine like so:
#
# pass = secret "passwords", "nova"
#
# The value of pass will be "nova"
default["openstack"]["developer_mode"] = false
# ========================= Encrypted Databag Setup ===========================
#
# The openstack-common cookbook's default library contains a `secret`
# routine that looks up the value of encrypted databag values. This routine
# uses the secret key file located at the following location to decrypt the
# values in the data bag.
default["openstack"]["secret"]["key_path"] = "/etc/chef/openstack_data_bag_secret"
# ========================= Package and Repository Setup ======================
#
# Various Linux distributions provide OpenStack packages and repositories.
@ -188,12 +206,11 @@ default['openstack']['endpoints']['volume-api']['path'] = "/v1/%(tenant_id)s"
# attributes:
#
# node['db']['user'] = 'keystone'
# node['db']['password'] = 'password'
#
# In a "keystone" recipe, you might find the following code:
#
# user = node['db']['user']
# pass = node['db']['password']
# pass = secret 'passwords', 'keystone'
#
# sql_connection = ::Openstack::db_uri('identity', user, pass)
#

View File

@ -146,6 +146,34 @@ module ::Openstack
info
end
# Library routine that returns an encrypted data bag value
# for a supplied string. The key used in decrypting the
# encrypted value should be located at
# node["openstack"]["secret"]["key_path"].
#
# Note that if node["openstack"]["developer_mode"] is true,
# then the value of the index parameter is just returned as-is. This
# means that in developer mode, if a cookbook does this:
#
# class Chef
# class Recipe
# include ::Openstack
# end
# end
#
# nova_password = secret "passwords", "nova"
#
# That means nova_password will == "nova".
def secret section, index
if node["openstack"]["developer_mode"]
return index
end
bag_name = node["openstack"]["secret"]["bag_name"]
key_path = node["openstack"]["secret"]["key_path"]
::Chef::Log.info("Loading encrypted databag #{section}.#{index} using key at #{key_path}")
::Chef::EncryptedDataBagItem.load(section, index, key_path)
end
private
# Instead of specifying the verbose node["openstack"]["endpoints"][name],
# this shortcut allows the simpler and shorter endpoint(name)

View File

@ -173,4 +173,23 @@ describe ::Openstack do
result['port'].should eq "3306"
end
end
describe "#secret" do
it "returns index param when developer_mode is true" do
@chef_run = ::ChefSpec::ChefRunner.new(:log_level => :info) do |n|
n.set["openstack"]["developer_mode"] = true
end
@chef_run.converge "openstack-common::default"
@subject.stub(:node).and_return @chef_run.node
result = @subject.secret("passwords", "nova")
result.should eq "nova"
end
it "returns databag when developer_mode is false" do
value = "this"
::Chef::EncryptedDataBagItem.stub(:load).with("passwords", "nova", "/etc/chef/openstack_data_bag_secret").and_return value
@subject.stub(:node).and_return @chef_run.node
result = @subject.secret("passwords", "nova")
result.should eq value
end
end
end