Skip to content

Commit

Permalink
Replace erlang cookie fact with type and provider
Browse files Browse the repository at this point in the history
Keeping secrets as facts is a potential security risk since facts
are generally not protected as secrets. This change removes the
rabbitmq_erlang_cookie fact. In order to make this feasible, the
exec that wipes out the rabbitmq db and the file resource managing
the cookie are replaced by a type and provider to reproduce this
functionality.
  • Loading branch information
Colleen Murphy committed Dec 19, 2014
1 parent 04145c1 commit 5c485b8
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 89 deletions.
16 changes: 0 additions & 16 deletions lib/facter/rabbitmq_erlang_cookie.rb

This file was deleted.

38 changes: 38 additions & 0 deletions lib/puppet/provider/rabbitmq_erlang_cookie/ruby.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'puppet'
require 'set'
Puppet::Type.type(:rabbitmq_erlang_cookie).provide(:ruby) do

defaultfor :feature => :posix
has_command(:puppet, 'puppet') do
environment :PATH => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'
end

def exists?
# Hack to prevent the create method from being called.
# We never need to create or destroy this resource, only change its value
true
end

def content=(value)
if resource[:force] == :true # Danger!
puppet('resource', 'service', resource[:service_name], 'ensure=stopped')
FileUtils.rm_rf('/var/lib/rabbitmq/mnesia')
File.open(resource[:path], 'w') do |cookie|
cookie.chmod(0400)
cookie.write(value)
end
FileUtils.chown('rabbitmq', 'rabbitmq', resource[:path])
else
fail("The current erlang cookie needs to change. In order to do this the RabbitMQ database needs to be wiped. Please set force => true to allow this to happen automatically.")
end
end

def content
if File.exists?(resource[:path])
File.read(resource[:path])
else
''
end
end

end
36 changes: 36 additions & 0 deletions lib/puppet/type/rabbitmq_erlang_cookie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Puppet::Type.newtype(:rabbitmq_erlang_cookie) do
desc 'Type to manage the rabbitmq erlang cookie securely'

newparam(:path, :namevar => true)

validate do
# This does pre-validation on the content property and force parameter.
# The intent is to simulate the prior behavior to the invention of this
# type (see https://github.com/puppetlabs/puppetlabs-rabbitmq/blob/4.1.0/manifests/config.pp#L87-L117)
# where validation occurs before the catalog starts being applied.
# This prevents other resources from failing after attempting to apply
# this resource and having it fail due to the force parameter being
# set to false.
is = (File.read(self[:path]) if File.exists?(self[:path])) || ''
should = self[:content]
failstring = 'The current erlang cookie needs to change. In order to do this the RabbitMQ database needs to be wiped. Please set force => true to allow this tohappen automatically.'
fail(failstring) if (is != should && self[:force] != :true)
end

newproperty(:content) do
desc 'Content of cookie'
newvalues(/^\S+$/)
def change_to_s(current, desired)
"The rabbitmq erlang cookie was changed"
end
end

newparam(:force) do
defaultto(:false)
newvalues(:true, :false)
end

newparam(:service_name) do
newvalues(/^\S+$/)
end
end
35 changes: 9 additions & 26 deletions manifests/config.pp
Original file line number Diff line number Diff line change
Expand Up @@ -100,34 +100,17 @@

if $config_cluster {

file { 'erlang_cookie':
ensure => 'present',
path => '/var/lib/rabbitmq/.erlang.cookie',
owner => 'rabbitmq',
group => 'rabbitmq',
mode => '0400',
content => $erlang_cookie,
replace => true,
before => File['rabbitmq.config'],
notify => Class['rabbitmq::service'],
}

# rabbitmq_erlang_cookie is a fact in this module.
if $erlang_cookie != $::rabbitmq_erlang_cookie {
# Safety check.
if $wipe_db_on_cookie_change {
exec { 'wipe_db':
command => "puppet resource service ${service_name} ensure=stopped; rm -rf /var/lib/rabbitmq/mnesia",
path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin',
}
File['erlang_cookie'] {
require => Exec['wipe_db'],
}
} else {
fail("ERROR: The current erlang cookie is ${::rabbitmq_erlang_cookie} and needs to change to ${erlang_cookie}. In order to do this the RabbitMQ database needs to be wiped. Please set the parameter called wipe_db_on_cookie_change to true to allow this to happen automatically.")
if $erlang_cookie == undef {
fail('You must set the $erlang_cookie value in order to configure clustering.')
} else {
rabbitmq_erlang_cookie { '/var/lib/rabbitmq/.erlang.cookie':
content => $erlang_cookie,
force => $wipe_db_on_cookie_change,
service_name => $service_name,
before => File['rabbitmq.config'],
notify => Class['rabbitmq::service'],
}
}
}


Expand Down
30 changes: 28 additions & 2 deletions spec/acceptance/clustering_spec.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
require 'spec_helper_acceptance'

describe 'rabbitmq clustering' do
context 'rabbitmq::config_cluster => true' do
context 'rabbitmq::wipe_db_on_cookie_change => false' do
it 'should run successfully' do
pp = <<-EOS
class { 'rabbitmq':
config_cluster => true,
cluster_nodes => ['rabbit1', 'rabbit2'],
cluster_node_type => 'ram',
erlang_cookie => 'TESTCOOKIE',
wipe_db_on_cookie_change => false,
}
if $::osfamily == 'RedHat' {
class { 'erlang': epel_enable => true}
Class['erlang'] -> Class['rabbitmq']
}
EOS

apply_manifest(pp, :expect_failures => true)
end

describe file('/var/lib/rabbitmq/.erlang.cookie') do
it { should_not contain 'TESTCOOKIE' }
end

end
context 'rabbitmq::wipe_db_on_cookie_change => true' do
it 'should run successfully' do
pp = <<-EOS
class { 'rabbitmq':
config_cluster => true,
cluster_nodes => ['rabbit1', 'rabbit2'],
cluster_node_type => 'ram',
erlang_cookie => 'TESTCOOKIE',
wipe_db_on_cookie_change => true,
}
if $::osfamily == 'RedHat' {
class { 'erlang': epel_enable => true}
Class['erlang'] -> Class['rabbitmq']
}
EOS

apply_manifest(pp, :catch_failures => true)
end

Expand All @@ -29,6 +54,7 @@ class { 'erlang': epel_enable => true}

describe file('/var/lib/rabbitmq/.erlang.cookie') do
it { should be_file }
it { should contain 'TESTCOOKIE' }
end
end
end
31 changes: 5 additions & 26 deletions spec/classes/rabbitmq_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@
context "on #{distro}" do
let(:facts) {{
:osfamily => distro,
:rabbitmq_erlang_cookie => 'EOKOWXQREETZSHFNTPEY',
:lsbdistcodename => 'squeeze',
:lsbdistid => 'Debian'
}}
Expand Down Expand Up @@ -278,45 +277,30 @@
end

context 'configures config_cluster' do
let(:facts) {{ :osfamily => distro, :rabbitmq_erlang_cookie => 'ORIGINAL', :lsbdistid => 'Debian' }}
let(:facts) {{ :osfamily => distro, :lsbdistid => 'Debian' }}
let(:params) {{
:config_cluster => true,
:cluster_nodes => ['hare-1', 'hare-2'],
:cluster_node_type => 'ram',
:erlang_cookie => 'TESTCOOKIE',
:wipe_db_on_cookie_change => false
}}

describe 'with defaults' do
it 'fails' do
expect{subject}.to raise_error(/^ERROR: The current erlang cookie is ORIGINAL/)
expect{subject}.to raise_error(/^You must set the \$erlang_cookie value/)
end
end

describe 'with wipe_db_on_cookie_change set' do
describe 'with erlang_cookie set' do
let(:params) {{
:config_cluster => true,
:cluster_nodes => ['hare-1', 'hare-2'],
:cluster_node_type => 'ram',
:erlang_cookie => 'TESTCOOKIE',
:wipe_db_on_cookie_change => true
}}
it 'wipes the database' do
should contain_exec('wipe_db')
should contain_file('erlang_cookie')
end
end

describe 'correctly when cookies match' do
let(:params) {{
:config_cluster => true,
:cluster_nodes => ['hare-1', 'hare-2'],
:cluster_node_type => 'ram',
:erlang_cookie => 'ORIGINAL',
:wipe_db_on_cookie_change => true
}}
it 'and doesnt wipe anything' do
should contain_file('erlang_cookie')
it 'contains the rabbitmq_erlang_cookie' do
should contain_rabbitmq_erlang_cookie('/var/lib/rabbitmq/.erlang.cookie')
end
end

Expand All @@ -334,11 +318,6 @@
})
end

it 'for erlang_cookie' do
should contain_file('erlang_cookie').with({
'content' => 'ORIGINAL',
})
end
end
end

Expand Down
19 changes: 0 additions & 19 deletions spec/unit/facts/rabbitmq_erlang_cookie_spec.rb

This file was deleted.

45 changes: 45 additions & 0 deletions spec/unit/puppet/type/rabbitmq_erlang_cookie_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'mocha'
require 'puppet'
require 'puppet/type/rabbitmq_exchange'
RSpec.configure do |config|
config.mock_with :mocha
end
describe Puppet::Type.type(:rabbitmq_erlang_cookie) do
context 'when content needs to change and force is unset' do
it 'fails' do
File.expects(:read).with('/var/lib/rabbitmq/.erlang.cookie').returns('OLDCOOKIE')
File.expects(:exists?).returns(true)
expect {
Puppet::Type.type(:rabbitmq_erlang_cookie).new(
:name => '/var/lib/rabbitmq/.erlang.cookie',
:content => 'NEWCOOKIE',
)
}.to raise_error(Puppet::Error, /The current erlang cookie needs to change/)
end
end

context 'when content needs to change and force is true' do
it 'sets the cookie' do
File.expects(:read).with('/var/lib/rabbitmq/.erlang.cookie').returns('OLDCOOKIE')
File.expects(:exists?).returns(true)
cookie = Puppet::Type.type(:rabbitmq_erlang_cookie).new(
:name => '/var/lib/rabbitmq/.erlang.cookie',
:content => 'NEWCOOKIE',
:force => true,
)
expect(cookie[:content]).to eq('NEWCOOKIE')
end
end

context 'when content does not need to change' do
it 'still sets the cookie' do
File.expects(:read).with('/var/lib/rabbitmq/.erlang.cookie').returns('NEWCOOKIE')
File.expects(:exists?).returns(true)
cookie = Puppet::Type.type(:rabbitmq_erlang_cookie).new(
:name => '/var/lib/rabbitmq/.erlang.cookie',
:content => 'NEWCOOKIE',
)
expect(cookie[:content]).to eq('NEWCOOKIE')
end
end
end

0 comments on commit 5c485b8

Please sign in to comment.