hiera-secrets-manager 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddb4e09c2998f196711cd698067557e0ba49e66c315a8bb77cabdf75cc4d309b
4
- data.tar.gz: bc5fab11b745e1d8b42054a652f9bc0a704642d84fae56c2fe59b77f10265d5a
3
+ metadata.gz: c62c6220168593608f0c75ea45f2c6669cfeab3394d3a00ea8471e9df634b6df
4
+ data.tar.gz: 0ff04f5c3f5def5bb5251017d475c30217ac9e1f338ccfd3be76efa1c8e773b3
5
5
  SHA512:
6
- metadata.gz: 61f468931ae0cc0ec27c9b312c511b95f607d994bd4ddd2489feb9db7ab7968861e0c4dd402b063d25c02043d76cf6a07ddb1ae30df3876e8e5720b20356fa6c
7
- data.tar.gz: 1c4fac048ab6cc8083bc28d97f7f0e0b712b8b4e06767f82fa01b0d64a69469afa4f56bc4ec3301dfa4fbf263bd13f2fefd61e7de9c9b54dbb541e0d0a9974b7
6
+ metadata.gz: 296c97802ac92301ae42ae581edb461bc570e63564a5732bd14b1acd0453c68eec7ece9461be07573f6ac145c2ea51fcf50f4a29f687eb2cf28e8f0dedee6b6d
7
+ data.tar.gz: 317abde2b8f974939dd5282f5dd4e42d3c86cfbc947826b0a24c074dab95cb80002520cb0584e9104be84492a1454925b32ca8eef786ba37665c5d188f201c29
@@ -3,16 +3,23 @@ class Hiera
3
3
  class Secrets_manager_backend
4
4
  def initialize
5
5
  require 'aws-sdk-secretsmanager'
6
- @client = Aws::SecretsManager::Client.new(
7
- region: Config[:secrets_manager][:region]
8
- )
9
-
10
- Hiera.debug('AWS Secrets Manager backend starting')
6
+ @config = Config
7
+ @client = create_client
11
8
  end
12
9
 
13
10
  def lookup(key, scope, order_override, resolution_type)
14
11
  answer = nil
15
12
 
13
+ if @client.nil?
14
+ Hiera.debug('Key lookup failed. AWS Secrets Manager backend is in a bad state.')
15
+ return answer
16
+ end
17
+
18
+ if contains_illegal_characters?(key)
19
+ Hiera.debug("#{key} contains illegal characters. Skipping lookup.")
20
+ return answer
21
+ end
22
+
16
23
  key_to_query = format_key(key, scope, Config[:secrets_manager])
17
24
 
18
25
  begin
@@ -26,6 +33,12 @@ class Hiera
26
33
 
27
34
  private
28
35
 
36
+ # AWS Secrets Manager only allows alphanumeric characters or (/_+=.@-) in key names
37
+ # GetSecret requests will fail for keys which have illegal characters
38
+ def contains_illegal_characters?(key)
39
+ %r{^[a-zA-Z0-9\/_+=.@\-]+$}.match(key).nil?
40
+ end
41
+
29
42
  def get_prefix(environments, scope)
30
43
  if environments && environments.key?(scope['environment'])
31
44
  environments[scope['environment']]
@@ -35,7 +48,7 @@ class Hiera
35
48
  end
36
49
 
37
50
  def format_key(key, scope, config)
38
- if scope.key?('environment')
51
+ if scope.include?('environment') && scope['environment']
39
52
  environments = config[:environments]
40
53
  prefix = get_prefix(environments, scope)
41
54
  "#{prefix}/#{key}"
@@ -43,6 +56,39 @@ class Hiera
43
56
  key
44
57
  end
45
58
  end
59
+
60
+ def create_client
61
+ if missing_config?
62
+ Hiera.debug('Warning! Config is empty. Starting in a bad state.')
63
+ return nil
64
+ end
65
+
66
+ if missing_keys?
67
+ Hiera.debug("Warning! Missing key(s) #{missing_keys} in Config. Starting in a bad state.")
68
+ return nil
69
+ end
70
+
71
+ Hiera.debug('AWS Secrets Manager backend starting')
72
+ Aws::SecretsManager::Client.new(
73
+ region: @config[:secrets_manager][:region],
74
+ access_key_id: @config[:secrets_manager][:access_key_id],
75
+ secret_access_key: @config[:secrets_manager][:secret_access_key]
76
+ )
77
+ end
78
+
79
+ def missing_config?
80
+ @config[:secrets_manager].nil?
81
+ end
82
+
83
+ def missing_keys?
84
+ !missing_keys.empty?
85
+ end
86
+
87
+ def missing_keys
88
+ %i[region access_key_id secret_access_key].reject do |key|
89
+ @config[:secrets_manager].include?(key)
90
+ end
91
+ end
46
92
  end
47
93
  end
48
94
  end
@@ -4,23 +4,38 @@ require 'hiera/backend/secrets_manager_backend'
4
4
  class Hiera
5
5
  module Backend
6
6
  describe Secrets_manager_backend do
7
- before do
7
+ before(:each) do
8
8
  @region_object = { region: 'some_region' }
9
+ @credentials = { access_key_id: 'some_id',
10
+ secret_access_key: 'some_access_key' }
9
11
  @config_object = { secrets_manager:
10
- {
11
- region: @region_object[:region],
12
- environments:
13
- {
14
- 'env1' => 'production',
15
- 'env2' => 'staging',
16
- 'env3' => 'development'
17
- }
18
- } }
12
+ {
13
+ region: @region_object[:region],
14
+ access_key_id: @credentials[:access_key_id],
15
+ secret_access_key: @credentials[:secret_access_key],
16
+ environments:
17
+ {
18
+ 'env1' => 'production',
19
+ 'env2' => 'staging',
20
+ 'env3' => 'development'
21
+ }
22
+ } }
23
+
19
24
  Config.load(@config_object)
20
25
  Hiera.stubs(:debug)
26
+ @mock_client = mock('client')
21
27
  Aws::SecretsManager::Client
22
28
  .stubs(:new)
23
- .with(@region_object)
29
+ .with(region: @region_object[:region],
30
+ access_key_id: @credentials[:access_key_id],
31
+ secret_access_key: @credentials[:secret_access_key])
32
+ .returns(@mock_client)
33
+ end
34
+
35
+ def mock_scope_with_environment(environment)
36
+ mock_scope = mock
37
+ mock_scope.stubs(:lookupvar).with('environment').returns(environment)
38
+ Hiera::Scope.new(mock_scope)
24
39
  end
25
40
 
26
41
  describe '#initialize' do
@@ -34,19 +49,59 @@ class Hiera
34
49
  it 'should set up a connection to AWS Secrets Manager' do
35
50
  Aws::SecretsManager::Client
36
51
  .expects(:new)
37
- .with(@region_object)
52
+ .with(region: @region_object[:region],
53
+ access_key_id: @credentials[:access_key_id],
54
+ secret_access_key: @credentials[:secret_access_key])
38
55
  Secrets_manager_backend.new
39
56
  end
57
+
58
+ context 'with bad config' do
59
+ after do
60
+ Secrets_manager_backend.new
61
+ end
62
+
63
+ it 'with empty config, should announce that it has no config' do
64
+ config_object = {}
65
+ Config.load(config_object)
66
+ Hiera
67
+ .expects(:debug)
68
+ .with('Warning! Config is empty. Starting in a bad state.')
69
+ end
70
+
71
+ it 'with no params, should announce that it is in a bad state' do
72
+ config_object = { secrets_manager: {} }
73
+ Config.load(config_object)
74
+ Hiera
75
+ .expects(:debug)
76
+ .with('Warning! Missing key(s) [:region, :access_key_id, :secret_access_key] in Config. Starting in a bad state.')
77
+ end
78
+
79
+ [:region, :access_key_id, :secret_access_key].each do |key|
80
+ it "debug should announce when key [#{key}] is missing in config" do
81
+ @config_object[:secrets_manager].delete(key)
82
+ Config.load(@config_object)
83
+ Hiera
84
+ .expects(:debug)
85
+ .with("Warning! Missing key(s) [:#{key}] in Config. Starting in a bad state.")
86
+ end
87
+ end
88
+ end
40
89
  end
41
90
 
42
91
  describe '#lookup' do
43
92
  before do
44
- @mock_client = mock('client')
45
- Aws::SecretsManager::Client
46
- .stubs(:new)
47
- .with(@region_object).returns(@mock_client)
48
93
  @backend = Secrets_manager_backend.new
49
- @scope = { 'environment' => 'env1' }
94
+ @scope = mock_scope_with_environment('env1')
95
+ end
96
+
97
+ it 'should announce if it is in a bad state' do
98
+ config_object = { secrets_manager: {} }
99
+ Config.load(config_object)
100
+ Hiera
101
+ .expects(:debug)
102
+ .with('Key lookup failed. AWS Secrets Manager backend is in a bad state.')
103
+ backend = Secrets_manager_backend.new
104
+ backend.lookup('some_secret', {}, nil, nil)
50
105
  end
51
106
 
52
107
  it 'should return a secret that exists' do
@@ -85,7 +140,8 @@ class Hiera
85
140
  end
86
141
 
87
142
  it 'falls back to provided scope environment when Hiera config does not include environment as a key / value pair' do
88
- scope = { 'environment' => 'some_env_not_in_config' }
143
+ scope = mock_scope_with_environment('some_env_not_in_config')
144
+
89
145
  prefixed_secret_name = 'some_env_not_in_config/secret_name'
90
146
 
91
147
  @mock_client
@@ -99,7 +155,8 @@ class Hiera
99
155
  incomplete_config = { secrets_manager: { region: @region_object[:region] } }
100
156
  Config.load(incomplete_config)
101
157
 
102
- scope = { 'environment' => 'some_env' }
158
+ scope = mock_scope_with_environment('some_env')
159
+
103
160
  prefixed_secret_name = 'some_env/secret_name'
104
161
 
105
162
  @mock_client
@@ -110,14 +167,32 @@ class Hiera
110
167
  end
111
168
 
112
169
  it 'does not use prefix if no environment is provided in scope' do
113
- scope = { 'no_environment_key' => 'some_value' }
170
+ scope = mock_scope_with_environment(nil)
171
+
114
172
  secret_name = 'secret_name'
115
173
 
116
174
  @mock_client
117
175
  .expects(:get_secret_value)
118
176
  .with(secret_id: secret_name)
119
177
  .returns('secret_string' => 'the_secret')
120
- @backend.lookup('secret_name', scope, nil, nil)
178
+
179
+ @backend.lookup(secret_name, scope, nil, nil)
180
+ end
181
+
182
+ %w[: ~ # \\].each do |character|
183
+ it "returns nil if key has illegal character [#{character}] (according to AWS)" do
184
+ @mock_client
185
+ .expects(:get_secret_value)
186
+ .never
187
+
188
+ secret_name = "secret#{character}name"
189
+
190
+ Hiera
191
+ .expects(:debug)
192
+ .with("#{secret_name} contains illegal characters. Skipping lookup.")
193
+
194
+ @backend.lookup(secret_name, @scope, nil, nil)
195
+ end
121
196
  end
122
197
  end
123
198
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiera-secrets-manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Unruly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-21 00:00:00.000000000 Z
11
+ date: 2018-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-secretsmanager