stack_master 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/stack_master.rb +2 -0
- data/lib/stack_master/cli.rb +4 -2
- data/lib/stack_master/commands/apply.rb +2 -14
- data/lib/stack_master/commands/status.rb +1 -1
- data/lib/stack_master/identity.rb +25 -4
- data/lib/stack_master/parameter_validator.rb +36 -0
- data/lib/stack_master/role_assumer.rb +1 -0
- data/lib/stack_master/stack.rb +0 -6
- data/lib/stack_master/validator.rb +13 -5
- data/lib/stack_master/version.rb +1 -1
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 676259d50dc1b2634f669f98625e3203f57d39eb77d6e6bf55f0e3b13318174b
|
4
|
+
data.tar.gz: f759222c480eed85f359c9b6f713f865664f156078a065bd4ad16fcd2db47417
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 482ccf3ecd0511921404744dd8f081f6f1c17c954918bc8fef5e5d6b2bf4ddebafd74d942c22b858062abb9e38fa238031d0fb310c8a5dbd02482833b6119641
|
7
|
+
data.tar.gz: f9fdaf391a317ccaa1cad9e527b8bd4b529c7446b6bc13335a31fc8fde7504878f6f9183959742710e9a5b637ad3a783b302f2955f7ed6c2b67ba2876ef6fb62
|
data/README.md
CHANGED
@@ -625,7 +625,7 @@ stacks:
|
|
625
625
|
|
626
626
|
## Allowed accounts
|
627
627
|
|
628
|
-
The AWS account the command is executing in can be restricted to a specific list of allowed accounts. This is useful in reducing the possibility of applying non-production changes in a production account. Each stack definition can specify the `allowed_accounts` property with an array of AWS account IDs the stack is allowed to work with.
|
628
|
+
The AWS account the command is executing in can be restricted to a specific list of allowed accounts. This is useful in reducing the possibility of applying non-production changes in a production account. Each stack definition can specify the `allowed_accounts` property with an array of AWS account IDs or aliases the stack is allowed to work with.
|
629
629
|
|
630
630
|
This is an opt-in feature which is enabled by specifying at least one account to allow.
|
631
631
|
|
@@ -644,7 +644,7 @@ stacks:
|
|
644
644
|
template: myapp_db.rb
|
645
645
|
allowed_accounts: # only allow these accounts (overrides the stack defaults)
|
646
646
|
- '1234567890'
|
647
|
-
-
|
647
|
+
- my-account-alias
|
648
648
|
tags:
|
649
649
|
purpose: back-end
|
650
650
|
myapp-web:
|
@@ -659,7 +659,7 @@ stacks:
|
|
659
659
|
purpose: back-end
|
660
660
|
```
|
661
661
|
|
662
|
-
In the cases where you want to bypass the account check, there is StackMaster flag `--skip-account-check` that can be used.
|
662
|
+
In the cases where you want to bypass the account check, there is the StackMaster flag `--skip-account-check` that can be used.
|
663
663
|
|
664
664
|
## Commands
|
665
665
|
|
data/lib/stack_master.rb
CHANGED
@@ -7,6 +7,7 @@ require 'aws-sdk-ecr'
|
|
7
7
|
require 'aws-sdk-s3'
|
8
8
|
require 'aws-sdk-sns'
|
9
9
|
require 'aws-sdk-ssm'
|
10
|
+
require 'aws-sdk-iam'
|
10
11
|
require 'colorize'
|
11
12
|
require 'active_support/core_ext/hash/keys'
|
12
13
|
require 'active_support/core_ext/object/blank'
|
@@ -45,6 +46,7 @@ module StackMaster
|
|
45
46
|
|
46
47
|
autoload :StackDiffer, 'stack_master/stack_differ'
|
47
48
|
autoload :Validator, 'stack_master/validator'
|
49
|
+
autoload :ParameterValidator, 'stack_master/parameter_validator'
|
48
50
|
|
49
51
|
require 'stack_master/template_compilers/sparkle_formation'
|
50
52
|
require 'stack_master/template_compilers/json'
|
data/lib/stack_master/cli.rb
CHANGED
@@ -262,13 +262,15 @@ module StackMaster
|
|
262
262
|
if running_in_allowed_account?(allowed_accounts)
|
263
263
|
block.call
|
264
264
|
else
|
265
|
-
|
265
|
+
account_text = "'#{identity.account}'"
|
266
|
+
account_text << " (#{identity.account_aliases.join(', ')})" if identity.account_aliases.any?
|
267
|
+
StackMaster.stdout.puts "Account #{account_text} is not an allowed account. Allowed accounts are #{allowed_accounts}."
|
266
268
|
false
|
267
269
|
end
|
268
270
|
end
|
269
271
|
|
270
272
|
def running_in_allowed_account?(allowed_accounts)
|
271
|
-
StackMaster.skip_account_check? || identity.
|
273
|
+
StackMaster.skip_account_check? || identity.running_in_account?(allowed_accounts)
|
272
274
|
end
|
273
275
|
|
274
276
|
def identity
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
1
|
module StackMaster
|
4
2
|
module Commands
|
5
3
|
class Apply
|
@@ -205,18 +203,8 @@ module StackMaster
|
|
205
203
|
end
|
206
204
|
|
207
205
|
def ensure_valid_parameters!
|
208
|
-
|
209
|
-
|
210
|
-
Empty/blank parameters detected, ensure values exist for those parameters.
|
211
|
-
Parameters will be read from the following locations:
|
212
|
-
MESSAGE
|
213
|
-
base_dir = Pathname.new(@stack_definition.base_dir)
|
214
|
-
@stack_definition.parameter_file_globs.each do |glob|
|
215
|
-
parameter_file = Pathname.new(glob).relative_path_from(base_dir)
|
216
|
-
message << " - #{parameter_file}\n"
|
217
|
-
end
|
218
|
-
failed!(message)
|
219
|
-
end
|
206
|
+
pv = ParameterValidator.new(stack: @proposed_stack, stack_definition: @stack_definition)
|
207
|
+
failed!(pv.error_message) if pv.missing_parameters?
|
220
208
|
end
|
221
209
|
|
222
210
|
def ensure_valid_template_body_size!
|
@@ -44,7 +44,7 @@ module StackMaster
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def running_in_allowed_account?(allowed_accounts)
|
47
|
-
StackMaster.skip_account_check? || identity.
|
47
|
+
StackMaster.skip_account_check? || identity.running_in_account?(allowed_accounts)
|
48
48
|
end
|
49
49
|
|
50
50
|
def identity
|
@@ -1,16 +1,25 @@
|
|
1
1
|
module StackMaster
|
2
2
|
class Identity
|
3
|
-
|
4
|
-
|
3
|
+
MissingIamPermissionsError = Class.new(StandardError)
|
4
|
+
|
5
|
+
def running_in_account?(accounts)
|
6
|
+
accounts.nil? ||
|
7
|
+
accounts.empty? ||
|
8
|
+
contains_account_id?(accounts) ||
|
9
|
+
contains_account_alias?(accounts)
|
5
10
|
end
|
6
11
|
|
7
12
|
def account
|
8
13
|
@account ||= sts.get_caller_identity.account
|
9
14
|
end
|
10
15
|
|
11
|
-
|
16
|
+
def account_aliases
|
17
|
+
@aliases ||= iam.list_account_aliases.account_aliases
|
18
|
+
rescue Aws::IAM::Errors::AccessDenied
|
19
|
+
raise MissingIamPermissionsError, 'Failed to retrieve account aliases. Missing required IAM permission: iam:ListAccountAliases'
|
20
|
+
end
|
12
21
|
|
13
|
-
|
22
|
+
private
|
14
23
|
|
15
24
|
def region
|
16
25
|
@region ||= ENV['AWS_REGION'] || Aws.config[:region] || Aws.shared_config.region || 'us-east-1'
|
@@ -19,5 +28,17 @@ module StackMaster
|
|
19
28
|
def sts
|
20
29
|
@sts ||= Aws::STS::Client.new(region: region)
|
21
30
|
end
|
31
|
+
|
32
|
+
def iam
|
33
|
+
@iam ||= Aws::IAM::Client.new(region: region)
|
34
|
+
end
|
35
|
+
|
36
|
+
def contains_account_id?(ids)
|
37
|
+
ids.include?(account)
|
38
|
+
end
|
39
|
+
|
40
|
+
def contains_account_alias?(aliases)
|
41
|
+
account_aliases.any? { |account_alias| aliases.include?(account_alias) }
|
42
|
+
end
|
22
43
|
end
|
23
44
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module StackMaster
|
4
|
+
class ParameterValidator
|
5
|
+
def initialize(stack:, stack_definition:)
|
6
|
+
@stack = stack
|
7
|
+
@stack_definition = stack_definition
|
8
|
+
end
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
return nil unless missing_parameters?
|
12
|
+
message = "Empty/blank parameters detected. Please provide values for these parameters:"
|
13
|
+
missing_parameters.each do |parameter_name|
|
14
|
+
message << "\n - #{parameter_name}"
|
15
|
+
end
|
16
|
+
message << "\nParameters will be read from files matching the following globs:"
|
17
|
+
base_dir = Pathname.new(@stack_definition.base_dir)
|
18
|
+
@stack_definition.parameter_file_globs.each do |glob|
|
19
|
+
parameter_file = Pathname.new(glob).relative_path_from(base_dir)
|
20
|
+
message << "\n - #{parameter_file}"
|
21
|
+
end
|
22
|
+
message
|
23
|
+
end
|
24
|
+
|
25
|
+
def missing_parameters?
|
26
|
+
missing_parameters.any?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def missing_parameters
|
32
|
+
@missing_parameters ||=
|
33
|
+
@stack.parameters_with_defaults.select { |_key, value| value.nil? }.keys
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -45,6 +45,7 @@ module StackMaster
|
|
45
45
|
credentials_key = "#{account}:#{role}"
|
46
46
|
@credentials.fetch(credentials_key) do
|
47
47
|
@credentials[credentials_key] = Aws::AssumeRoleCredentials.new(
|
48
|
+
region: StackMaster.cloud_formation_driver.region,
|
48
49
|
role_arn: "arn:aws:iam::#{account}:role/#{role}",
|
49
50
|
role_session_name: "stack-master-role-assumer"
|
50
51
|
)
|
data/lib/stack_master/stack.rb
CHANGED
@@ -27,12 +27,6 @@ module StackMaster
|
|
27
27
|
template_default_parameters.merge(parameters)
|
28
28
|
end
|
29
29
|
|
30
|
-
def missing_parameters?
|
31
|
-
parameters_with_defaults.any? do |key, value|
|
32
|
-
value == nil
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
30
|
def self.find(region, stack_name)
|
37
31
|
cf = StackMaster.cloud_formation_driver
|
38
32
|
cf_stack = cf.describe_stacks(stack_name: stack_name).stacks.first
|
@@ -10,12 +10,12 @@ module StackMaster
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def perform
|
13
|
-
parameter_hash = ParameterLoader.load(@stack_definition.parameter_files)
|
14
|
-
compile_time_parameters = ParameterResolver.resolve(@config, @stack_definition, parameter_hash[:compile_time_parameters])
|
15
|
-
|
16
13
|
StackMaster.stdout.print "#{@stack_definition.stack_name}: "
|
17
|
-
|
18
|
-
|
14
|
+
if parameter_validator.missing_parameters?
|
15
|
+
StackMaster.stdout.puts "invalid\n#{parameter_validator.error_message}"
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
cf.validate_template(template_body: TemplateUtils.maybe_compressed_template_body(stack.template_body))
|
19
19
|
StackMaster.stdout.puts "valid"
|
20
20
|
true
|
21
21
|
rescue Aws::CloudFormation::Errors::ValidationError => e
|
@@ -28,5 +28,13 @@ module StackMaster
|
|
28
28
|
def cf
|
29
29
|
@cf ||= StackMaster.cloud_formation_driver
|
30
30
|
end
|
31
|
+
|
32
|
+
def stack
|
33
|
+
@stack ||= Stack.generate(@stack_definition, @config)
|
34
|
+
end
|
35
|
+
|
36
|
+
def parameter_validator
|
37
|
+
@parameter_validator ||= ParameterValidator.new(stack: stack, stack_definition: @stack_definition)
|
38
|
+
end
|
31
39
|
end
|
32
40
|
end
|
data/lib/stack_master/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stack_master
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Hodgkiss
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-03
|
12
|
+
date: 2020-04-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -255,6 +255,20 @@ dependencies:
|
|
255
255
|
- - "~>"
|
256
256
|
- !ruby/object:Gem::Version
|
257
257
|
version: '1'
|
258
|
+
- !ruby/object:Gem::Dependency
|
259
|
+
name: aws-sdk-iam
|
260
|
+
requirement: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - "~>"
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '1'
|
265
|
+
type: :runtime
|
266
|
+
prerelease: false
|
267
|
+
version_requirements: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - "~>"
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '1'
|
258
272
|
- !ruby/object:Gem::Dependency
|
259
273
|
name: diffy
|
260
274
|
requirement: !ruby/object:Gem::Requirement
|
@@ -472,6 +486,7 @@ files:
|
|
472
486
|
- lib/stack_master/parameter_resolvers/security_group.rb
|
473
487
|
- lib/stack_master/parameter_resolvers/sns_topic_name.rb
|
474
488
|
- lib/stack_master/parameter_resolvers/stack_output.rb
|
489
|
+
- lib/stack_master/parameter_validator.rb
|
475
490
|
- lib/stack_master/prompter.rb
|
476
491
|
- lib/stack_master/resolver_array.rb
|
477
492
|
- lib/stack_master/role_assumer.rb
|
@@ -523,8 +538,8 @@ licenses:
|
|
523
538
|
metadata:
|
524
539
|
bug_tracker_uri: https://github.com/envato/stack_master/issues
|
525
540
|
changelog_uri: https://github.com/envato/stack_master/blob/master/CHANGELOG.md
|
526
|
-
documentation_uri: https://www.rubydoc.info/gems/stack_master/2.
|
527
|
-
source_code_uri: https://github.com/envato/stack_master/tree/v2.
|
541
|
+
documentation_uri: https://www.rubydoc.info/gems/stack_master/2.4.0
|
542
|
+
source_code_uri: https://github.com/envato/stack_master/tree/v2.4.0
|
528
543
|
post_install_message:
|
529
544
|
rdoc_options: []
|
530
545
|
require_paths:
|