ssm_utils 0.1.0
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 +7 -0
- data/exe/manage_ssm_params +5 -0
- data/lib/ssm_utils/get_params_command.rb +27 -0
- data/lib/ssm_utils/hash_walker.rb +71 -0
- data/lib/ssm_utils/manage_params_app.rb +57 -0
- data/lib/ssm_utils/put_params_command.rb +26 -0
- data/lib/ssm_utils/ssm_reader_driver.rb +75 -0
- data/lib/ssm_utils/ssm_writer_driver.rb +69 -0
- data/lib/ssm_utils/version.rb +3 -0
- data/lib/ssm_utils.rb +6 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8dcad91e6c48a3d501224e57692ae7d55d6f7871
|
4
|
+
data.tar.gz: 5706e830fbf3304a8fb1c2f0b5e9dea711a4f62c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff369cd39c2d9103250f8a1cb4c705027a0482846c4c5161e07fab08fccf88eb81d54e27ce5faa6f47de2b0e00e3b57bb275ca54ab06784f070f15f10d8a8599
|
7
|
+
data.tar.gz: bb98c3485d7732ff1871ab8678c888f69d4b1785f796cc1be9c33def553a0cce684fdc08d7fef1263d8f7cebad61708bca8c871103dedc599254e81433e02386
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'ssm_utils/ssm_reader_driver'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module SsmUtils
|
5
|
+
class GetParamsCommand
|
6
|
+
def initialize(options)
|
7
|
+
opt = {
|
8
|
+
decrypt: true,
|
9
|
+
ssm_root: '/',
|
10
|
+
}.merge(options)
|
11
|
+
|
12
|
+
raise ArgumentError.new("No file path specified") if !opt.key?(:file_out)
|
13
|
+
@file_out = opt[:file_out]
|
14
|
+
@decrypt = opt[:decrypt]
|
15
|
+
@ssm_root = opt[:ssm_root]
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
ssm = SsmUtils::SsmReaderDriver.new(decrypt: @decrypt, ssm_root: @ssm_root)
|
20
|
+
params = ssm.account_params
|
21
|
+
|
22
|
+
File.open(@file_out, 'w') do |f|
|
23
|
+
YAML.dump(params, f, line_width: -1)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SsmUtils
|
2
|
+
module HashWalker
|
3
|
+
|
4
|
+
class Walker
|
5
|
+
def initialize(hash, path_delim, block)
|
6
|
+
@hash = hash
|
7
|
+
@path_delim = path_delim
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def walk
|
12
|
+
walker(nil, @hash)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def walker(path, node)
|
19
|
+
if valid_value_hash? node
|
20
|
+
@block.yield(path, node)
|
21
|
+
elsif node.is_a? Hash
|
22
|
+
node.each do |key, value|
|
23
|
+
#nil path = "" + "" + {key}
|
24
|
+
#non-nill path = {path} + {path_delim} + {key}
|
25
|
+
walker("#{path}#{path.nil? ? "" : @path_delim}#{key}", value)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
@block.yield(path, node)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid_value_hash?(node)
|
33
|
+
return false unless node.is_a?(Hash) && node.has_key?('_value')
|
34
|
+
if node.has_key?('_type') && node['_type'] == 'SecureString'
|
35
|
+
return false unless node.has_key? '_key'
|
36
|
+
end
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# For a hash { 'a' => { 'b' => { 'c' => 'd' } } } this function will
|
42
|
+
# yield to the provided block ('a/b/c', 'd'). Furthermore, hashs containing
|
43
|
+
# the keys '_value' and '_type' will be interpreted as leaves and will not
|
44
|
+
# be walked into and instead yielded to the block.
|
45
|
+
def walk_hash(hash, path_delim, &block)
|
46
|
+
raise ArgumentError.new("Block required") unless block_given?
|
47
|
+
|
48
|
+
if !hash.is_a? Hash
|
49
|
+
raise ArgumentError.new("Cannot walk things that aren't hashes")
|
50
|
+
end
|
51
|
+
|
52
|
+
Walker.new(hash, path_delim.to_s, block).walk
|
53
|
+
hash
|
54
|
+
end
|
55
|
+
|
56
|
+
#Recursive safe-setting of keys
|
57
|
+
def dig_set(hash, key_list, value)
|
58
|
+
if !key_list.is_a? Array || key_list.length < 1
|
59
|
+
raise ArgumentError.new("Key list cannot be empty or a non-array")
|
60
|
+
elsif key_list.length == 1
|
61
|
+
hash[key_list[0]] = value
|
62
|
+
else
|
63
|
+
if hash[key_list[0]].nil?
|
64
|
+
hash[key_list[0]] = {}
|
65
|
+
end
|
66
|
+
dig_set(hash[key_list[0]], key_list[1..-1], value)
|
67
|
+
hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'commander'
|
2
|
+
require 'ssm_utils/hash_walker'
|
3
|
+
require 'ssm_utils/version'
|
4
|
+
require 'ssm_utils/get_params_command'
|
5
|
+
require 'ssm_utils/put_params_command'
|
6
|
+
|
7
|
+
module SsmUtils
|
8
|
+
class ManageParamsApp
|
9
|
+
include Commander::Methods
|
10
|
+
|
11
|
+
def run
|
12
|
+
program :name, 'Manage SSM Params'
|
13
|
+
program :version, SsmUtils::VERSION
|
14
|
+
program :description, 'Manages SSM parameters!'
|
15
|
+
program :help, 'Author', 'David Kolb <david.kolb@coxautoinc.com>'
|
16
|
+
|
17
|
+
command :get do |c|
|
18
|
+
c.syntax = 'manage_ssm_params get [OPTIONS]'
|
19
|
+
c.description = <<~EOF
|
20
|
+
Retrieves an entire tree of your SSM parameter store as a well
|
21
|
+
structured YAML document.
|
22
|
+
EOF
|
23
|
+
c.option '--file FILE', String, 'File to retrieve account to.'
|
24
|
+
c.option '--[no-]decrypt', 'Decrypt SecureStrings, default true'
|
25
|
+
c.option '--ssm_root PATH_ROOT', String,
|
26
|
+
"A path root to retrieve from, default is '/'"
|
27
|
+
c.when_called do |args, options|
|
28
|
+
options.default(decrypt: true, ssm_root: '/')
|
29
|
+
GetParamsCommand.new(
|
30
|
+
file_out: options.file,
|
31
|
+
decrypt: options.decrypt,
|
32
|
+
ssm_root: options.ssm_root
|
33
|
+
).execute
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
command :put do |c|
|
38
|
+
c.syntax = 'manage_ssm_params put [OPTIONS]'
|
39
|
+
c.description = <<~EOF
|
40
|
+
Writes the supplied YAML structure into SSM parameter store using
|
41
|
+
the reverse of the mappings used by get.
|
42
|
+
EOF
|
43
|
+
c.option '--file FILE', String, 'File to retrieve account to.'
|
44
|
+
c.option '--[no-]overwrite', 'Overwrite exitings strings, default true'
|
45
|
+
c.when_called do |args, options|
|
46
|
+
options.default(overwrite: true)
|
47
|
+
PutParamsCommand.new(
|
48
|
+
in_file: options.file,
|
49
|
+
overwrite: options.overwrite
|
50
|
+
).execute
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
run!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'aws-sdk-ssm'
|
3
|
+
require 'ssm_utils/ssm_writer_driver'
|
4
|
+
|
5
|
+
module SsmUtils
|
6
|
+
class PutParamsCommand
|
7
|
+
def initialize(options)
|
8
|
+
options = {
|
9
|
+
overwrite: false
|
10
|
+
}.merge(options)
|
11
|
+
|
12
|
+
raise ArgumentError.new("No input file") unless options.key? :in_file
|
13
|
+
|
14
|
+
@overwrite = options[:overwrite]
|
15
|
+
@in_file = options[:in_file]
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
parameters = YAML.load_file(@in_file)
|
20
|
+
SsmWriterDriver.new(
|
21
|
+
parameters: parameters,
|
22
|
+
overwrite: @overwrite
|
23
|
+
).write_parameters
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'aws-sdk-ssm'
|
2
|
+
require 'ssm_utils/hash_walker'
|
3
|
+
|
4
|
+
module SsmUtils
|
5
|
+
class SsmReaderDriver
|
6
|
+
include HashWalker
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
options = {
|
10
|
+
decrypt: true,
|
11
|
+
ssm_root: '/'
|
12
|
+
}.merge(options)
|
13
|
+
@ssm = Aws::SSM::Client.new()
|
14
|
+
@decrypt_flag = options[:decrypt]
|
15
|
+
@ssm_root = options[:ssm_root]
|
16
|
+
end
|
17
|
+
|
18
|
+
def raw_account_params
|
19
|
+
return @raw_params if @raw_params
|
20
|
+
|
21
|
+
params = []
|
22
|
+
|
23
|
+
@ssm.get_parameters_by_path(
|
24
|
+
path: @ssm_root,
|
25
|
+
recursive: 'true',
|
26
|
+
with_decryption: @decrypt_flag
|
27
|
+
).each do |r|
|
28
|
+
params += r.to_h[:parameters]
|
29
|
+
end
|
30
|
+
|
31
|
+
@raw_params = params
|
32
|
+
end
|
33
|
+
|
34
|
+
def account_params
|
35
|
+
params = {}
|
36
|
+
raw_account_params.each do |r|
|
37
|
+
if r[:type] == 'String'
|
38
|
+
value = r[:value]
|
39
|
+
elsif r[:type] == 'SecureString'
|
40
|
+
value = {
|
41
|
+
'_value' => r[:value],
|
42
|
+
'_type' => r[:type],
|
43
|
+
'_key' => encryption_key(r)
|
44
|
+
}
|
45
|
+
else
|
46
|
+
value = {
|
47
|
+
'_value' => r[:value],
|
48
|
+
'_type' => r[:type]
|
49
|
+
}
|
50
|
+
end
|
51
|
+
dig_set(params, key_list(r[:name]), value)
|
52
|
+
end
|
53
|
+
params
|
54
|
+
end
|
55
|
+
|
56
|
+
def encryption_key(param)
|
57
|
+
response = @ssm.get_parameter_history(name: param[:name])
|
58
|
+
matched_version = nil
|
59
|
+
|
60
|
+
# Apparently this is the idiomatic way to do/while. :-/
|
61
|
+
loop do
|
62
|
+
matched_version = response.parameters.find do |p|
|
63
|
+
p.version == param[:version]
|
64
|
+
end
|
65
|
+
response = response.next_page if response.next_page?
|
66
|
+
break unless matched_version.nil? && response.next_page?
|
67
|
+
end
|
68
|
+
matched_version.nil? ? nil : matched_version.key_id
|
69
|
+
end
|
70
|
+
|
71
|
+
def key_list(param_name)
|
72
|
+
param_name[0] == '/' ? param_name[1..-1].split('/') : param_name.split('/')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'aws-sdk-ssm'
|
2
|
+
require 'ssm_utils/hash_walker'
|
3
|
+
|
4
|
+
module SsmUtils
|
5
|
+
class SsmWriterDriver
|
6
|
+
include HashWalker
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
options = {
|
10
|
+
overwrite: false
|
11
|
+
}.merge(options)
|
12
|
+
|
13
|
+
raise ArgumentError('Missing parameters') unless options.key? :parameters
|
14
|
+
|
15
|
+
@parameters = options[:parameters]
|
16
|
+
@ssm = Aws::SSM::Client.new
|
17
|
+
@overwrite = options[:overwrite]
|
18
|
+
end
|
19
|
+
|
20
|
+
def write_parameters
|
21
|
+
ssm_requests.each do |request|
|
22
|
+
@ssm.put_parameter(request)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def ssm_requests
|
27
|
+
return @calls if @calls
|
28
|
+
|
29
|
+
@calls = []
|
30
|
+
|
31
|
+
walk_hash(@parameters, '/') { |path, value|
|
32
|
+
path = "/#{path}"
|
33
|
+
if value.is_a? Hash
|
34
|
+
@calls.push process_hash_value(path, value)
|
35
|
+
else
|
36
|
+
@calls.push process_literal_value(path,value)
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
@calls
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def process_literal_value(path, value)
|
46
|
+
{
|
47
|
+
name: path,
|
48
|
+
value: value.to_s,
|
49
|
+
type: "String",
|
50
|
+
overwrite: @overwrite
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_hash_value(path, value)
|
55
|
+
call = {
|
56
|
+
name: path,
|
57
|
+
value: value['_value'].to_s,
|
58
|
+
type: value['_type'],
|
59
|
+
overwrite: @overwrite
|
60
|
+
}
|
61
|
+
|
62
|
+
if value['_type'] == 'SecureString'
|
63
|
+
call[:key_id] = value['_key']
|
64
|
+
end
|
65
|
+
|
66
|
+
call
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ssm_utils.rb
ADDED
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssm_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Kolb
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.11.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.11.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: paint
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: commander
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: aws-sdk-ssm
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1'
|
111
|
+
description: Provides some CLI interfaces into the SSM parameter store with opinions.
|
112
|
+
email:
|
113
|
+
- david.kolb@krinchan.com
|
114
|
+
executables:
|
115
|
+
- manage_ssm_params
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- exe/manage_ssm_params
|
120
|
+
- lib/ssm_utils.rb
|
121
|
+
- lib/ssm_utils/get_params_command.rb
|
122
|
+
- lib/ssm_utils/hash_walker.rb
|
123
|
+
- lib/ssm_utils/manage_params_app.rb
|
124
|
+
- lib/ssm_utils/put_params_command.rb
|
125
|
+
- lib/ssm_utils/ssm_reader_driver.rb
|
126
|
+
- lib/ssm_utils/ssm_writer_driver.rb
|
127
|
+
- lib/ssm_utils/version.rb
|
128
|
+
homepage: https://github.com/ssm_utils
|
129
|
+
licenses:
|
130
|
+
- MIT
|
131
|
+
metadata: {}
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - "~>"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '2.3'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
requirements: []
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 2.6.14
|
149
|
+
signing_key:
|
150
|
+
specification_version: 4
|
151
|
+
summary: Utility scripts for managing SSM params
|
152
|
+
test_files: []
|