tfctl 1.0.0 → 1.3.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 +4 -4
- data/.bundle/config +3 -0
- data/.github/dependabot.yml +7 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +9 -4
- data/.travis.yml +13 -12
- data/CHANGELOG.adoc +29 -0
- data/Makefile +4 -3
- data/README.adoc +61 -29
- data/RELEASING.adoc +13 -0
- data/bin/tfctl +6 -9
- data/docs/configuration.adoc +18 -8
- data/docs/control_tower.adoc +45 -27
- data/docs/creating_a_profile.adoc +5 -5
- data/docs/iam_permissions.adoc +2 -2
- data/docs/project_layout.adoc +8 -4
- data/examples/control_tower/profiles/example-profile/main.tf +1 -1
- data/examples/control_tower/profiles/example-profile/variables.tf +1 -1
- data/examples/control_tower/{conf/example.yaml → tfctl.yaml} +2 -2
- data/lib/hash.rb +2 -1
- data/lib/tfctl.rb +8 -8
- data/lib/tfctl/aws_org.rb +18 -16
- data/lib/tfctl/config.rb +5 -4
- data/lib/tfctl/executor.rb +1 -1
- data/lib/tfctl/generator.rb +12 -10
- data/lib/tfctl/logger.rb +1 -1
- data/lib/tfctl/schema.rb +3 -3
- data/lib/tfctl/version.rb +1 -1
- data/tfctl.gemspec +9 -6
- metadata +38 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5fe79c7d1c05d536eabd439037d74996bf35af1b72e359e34a0f52f32067fecf
|
|
4
|
+
data.tar.gz: 67c20fd6e27f58ce119e9c050923c80499b0054991716515f41dbbd2c4156336
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 693f29d4f7ddea34dfe9dbb747cf976452bdc8ff423bf63d41bc2f77f2ae05fb58ddb8b6d9a2d4c1f151749899a325b7326384e5e4128eda076d51c7c54bd8ca
|
|
7
|
+
data.tar.gz: a71acfa057e8a80923b7ec9c48ab2654af1fd6d73e4fa0259949d3bded769773dd3127590475266586fe48e3f5549a7f8725c111429a6ceb850389bb7fc63c01
|
data/.bundle/config
ADDED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
AllCops:
|
|
3
|
-
TargetRubyVersion: 2.
|
|
3
|
+
TargetRubyVersion: 2.5
|
|
4
4
|
DisplayCopNames: true
|
|
5
|
+
NewCops: enable
|
|
5
6
|
|
|
6
7
|
Layout/IndentationWidth:
|
|
7
8
|
Width: 4
|
|
8
9
|
|
|
9
|
-
Layout/
|
|
10
|
+
Layout/HeredocIndentation:
|
|
10
11
|
Enabled: false
|
|
11
12
|
|
|
12
13
|
Layout/EmptyLines:
|
|
@@ -15,7 +16,7 @@ Layout/EmptyLines:
|
|
|
15
16
|
Layout/EmptyLinesAroundMethodBody:
|
|
16
17
|
Enabled: false
|
|
17
18
|
|
|
18
|
-
Layout/
|
|
19
|
+
Layout/HashAlignment:
|
|
19
20
|
EnforcedHashRocketStyle:
|
|
20
21
|
- table
|
|
21
22
|
EnforcedColonStyle:
|
|
@@ -45,7 +46,7 @@ Metrics/BlockLength:
|
|
|
45
46
|
Metrics/MethodLength:
|
|
46
47
|
Enabled: false
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
Layout/LineLength:
|
|
49
50
|
Max: 140
|
|
50
51
|
|
|
51
52
|
Metrics/AbcSize:
|
|
@@ -77,3 +78,7 @@ Style/TrailingCommaInHashLiteral:
|
|
|
77
78
|
|
|
78
79
|
Style/RedundantReturn:
|
|
79
80
|
Enabled: false
|
|
81
|
+
|
|
82
|
+
# don't break older Rubies just because of style
|
|
83
|
+
Style/RedundantBegin:
|
|
84
|
+
Enabled: false
|
data/.travis.yml
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
rvm:
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
- 2.5
|
|
3
|
+
- 2.6
|
|
4
|
+
- 2.7
|
|
4
5
|
os: linux
|
|
5
6
|
language: ruby
|
|
6
7
|
script: make test
|
|
7
8
|
jobs:
|
|
8
9
|
include:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
- stage: Gem release
|
|
11
|
+
rvm: 2.6
|
|
12
|
+
deploy:
|
|
13
|
+
provider: rubygems
|
|
14
|
+
api_key:
|
|
15
|
+
secure: LAVcdER+LtQ2TSUrVOY7Be1BC7GXJRD0QBt386vRM5Nld5QaD9Ow9gtN6FprzkzloI4R8BkPWqZbAT6YjC+C0AFB5HK6iPwD2bLsiF9w3ccDD+yrW99RHxiErpmYMun2PqZv0WkJ/pkEplPCKMRFv7SM7W9DMRlU7dsXc1v6IVyIb5u3A04jErS2jXXKY0ijlCDJYVo8zzYL6yUmUcXhc//3CIVnu2Miu6Qr8h7e6jMXNUWfMkwEXsFP9id4TsCz7hRY+39PkiBAknHTN5UqjjJiEOknZnHeTBcVPvi2h2xv+fFLSzVTxlxaRsVoMCShQp5D12qzhQObRJsRVQFs8Yyg9IYMyPdxssFYyUZFaAy5taWDm57uM3HTHylm/Dq3LmXTgGNxWUUkf2oh1g7R6cYZpBUQwiEPzhZQ7CoBQbGUAJmH9ZU9m+cr8kuAOUipd6BNEDvn/fIH4WJsRCNP72JGX16JBpuICvpkuNhskZT91xFlYk1pTXHOxNpbTcxUTgMHhrTqspeRXPmf6DiYGvjMb2S6kaoGqCIRIcwl0TGKuMsOMqR9SqF8gubkqHMVbSl1E7mwBn4ke8/7IGoMkWOGwUpVxqVOLBHi6zSR09RTVSbKl4oiFV3ZwmVPSxDncq54MptyJ2WCZ7dD6ht2l+VA8iGwYeIoqOpwGWxyuNI=
|
|
16
|
+
gem: tfctl
|
|
17
|
+
on:
|
|
18
|
+
tags: true
|
|
19
|
+
repo: scalefactory/tfctl
|
data/CHANGELOG.adoc
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
= Changelog
|
|
2
2
|
|
|
3
|
+
== 1.3.0
|
|
4
|
+
|
|
5
|
+
* feat: support new Terraform provider syntax
|
|
6
|
+
|
|
7
|
+
BREAKING CHANGE: The minimum supported Terraform version has been bumped to
|
|
8
|
+
0.12.29. If you are running an older version of Terraform you will need to
|
|
9
|
+
update to the latest Terraform in 0.12.x series before updating tfctl. Once
|
|
10
|
+
tfctl is updated you can upgrade Terraform to further versions.
|
|
11
|
+
|
|
12
|
+
== 1.2.2
|
|
13
|
+
* chore: reverted PR #11 - not necessary and introduced regression. See PR #13 for details.
|
|
14
|
+
|
|
15
|
+
== 1.2.1
|
|
16
|
+
* chore: added required Ruby version to Gemspec.
|
|
17
|
+
|
|
18
|
+
== 1.2.0
|
|
19
|
+
|
|
20
|
+
* feat: pass TF_ environment variables to terraform (PR #11).
|
|
21
|
+
|
|
22
|
+
== 1.1.1
|
|
23
|
+
|
|
24
|
+
* fix: handle empty response from Organizations API containing children (thanks @grothja)
|
|
25
|
+
* chore: stopped testing on EOL Rubies 2.3 and 2.4 (but should still currently work)
|
|
26
|
+
* chore: dependencies minimum version bump
|
|
27
|
+
|
|
28
|
+
== 1.1.0
|
|
29
|
+
|
|
30
|
+
* feat: look for configuration in `tfctl.yaml` by default.
|
|
31
|
+
|
|
3
32
|
== 1.0.0
|
|
4
33
|
|
|
5
34
|
* feat(config): JSON schema config validation
|
data/Makefile
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
vendor:
|
|
4
4
|
$(info => Installing Ruby dependencies)
|
|
5
|
-
@bundle install
|
|
5
|
+
@bundle install
|
|
6
|
+
@bundle binstubs --all --path vendor/bin
|
|
6
7
|
|
|
7
8
|
test: vendor rubocop spec
|
|
8
9
|
|
|
@@ -10,11 +11,11 @@ guard: vendor
|
|
|
10
11
|
$(info => Starting guard)
|
|
11
12
|
@bundle exec guard
|
|
12
13
|
|
|
13
|
-
rubocop:
|
|
14
|
+
rubocop: vendor
|
|
14
15
|
$(info => Running rubocop)
|
|
15
16
|
@vendor/bin/rubocop
|
|
16
17
|
|
|
17
|
-
spec:
|
|
18
|
+
spec: vendor
|
|
18
19
|
$(info => Running spec tests)
|
|
19
20
|
@vendor/bin/rspec
|
|
20
21
|
|
data/README.adoc
CHANGED
|
@@ -28,19 +28,37 @@ toc::[]
|
|
|
28
28
|
|
|
29
29
|
== Overview
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
`tfctl` is a small Terraform wrapper for working with multi-account AWS
|
|
32
32
|
infrastructures where new accounts may be created dynamically and on-demand.
|
|
33
33
|
|
|
34
|
-
It discovers accounts by reading the AWS Organizations API and can assign
|
|
34
|
+
It discovers accounts by reading the AWS Organizations API, and can assign
|
|
35
35
|
Terraform resources to multiple accounts based on the organization hierarchy.
|
|
36
36
|
Resources can be assigned globally, based on organization unit or to individual
|
|
37
|
-
accounts. It supports
|
|
37
|
+
accounts. It supports hierarchies of nested Organizational Units (OUs),
|
|
38
|
+
and helps keep your Terraform DRY.
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
The Scale Factory originally created tfctl to integrate Terraform with
|
|
40
41
|
https://aws.amazon.com/solutions/aws-landing-zone/[AWS Landing Zone] and
|
|
41
42
|
https://aws.amazon.com/controltower/[Control Tower] but should work with most
|
|
42
43
|
other ways of managing accounts in AWS Organizations.
|
|
43
44
|
|
|
45
|
+
== Project status
|
|
46
|
+
|
|
47
|
+
`tfctl` is an open source project published by The Scale Factory.
|
|
48
|
+
|
|
49
|
+
We currently consider this project to be maintained but we don't actively
|
|
50
|
+
develop new features. We keep it security patched and ready for use in
|
|
51
|
+
production environments.
|
|
52
|
+
|
|
53
|
+
We’ll take a look at any issues or PRs you open and get back to you as soon as
|
|
54
|
+
we can. We don’t offer any formal SLA, but we’ll be checking on this project
|
|
55
|
+
periodically.
|
|
56
|
+
|
|
57
|
+
If your issue is urgent, you can flag it as such, and we’ll attempt to triage
|
|
58
|
+
appropriately, but we have paying customers who also have demands on our time.
|
|
59
|
+
If your business depends on this project and you have an urgent problem, then
|
|
60
|
+
you can talk to our sales team about paying us to support you.
|
|
61
|
+
|
|
44
62
|
== Features
|
|
45
63
|
|
|
46
64
|
* Discovers AWS accounts automatically.
|
|
@@ -56,8 +74,8 @@ other ways of managing accounts in AWS Organizations.
|
|
|
56
74
|
|
|
57
75
|
== Requirements
|
|
58
76
|
|
|
59
|
-
* Terraform >= 0.12
|
|
60
|
-
* Ruby >= 2.
|
|
77
|
+
* Terraform >= 0.12.29
|
|
78
|
+
* Ruby >= 2.5
|
|
61
79
|
* Accounts managed in AWS Organizations (by Landing Zone, Control Tower, some
|
|
62
80
|
other means)
|
|
63
81
|
|
|
@@ -65,17 +83,19 @@ other ways of managing accounts in AWS Organizations.
|
|
|
65
83
|
|
|
66
84
|
To install the latest release from RubyGems run:
|
|
67
85
|
|
|
86
|
+
[source,shell]
|
|
68
87
|
----
|
|
69
88
|
gem install tfctl
|
|
70
89
|
----
|
|
71
90
|
|
|
72
|
-
Alternatively you can build and install from this repo with:
|
|
91
|
+
Alternatively, you can build and install from this repo with:
|
|
73
92
|
|
|
93
|
+
[source,shell]
|
|
74
94
|
----
|
|
75
95
|
make install
|
|
76
96
|
----
|
|
77
97
|
|
|
78
|
-
==
|
|
98
|
+
== Documentation
|
|
79
99
|
|
|
80
100
|
* https://github.com/scalefactory/tfctl/tree/master/docs/control_tower.adoc[Control Tower quick start guide]
|
|
81
101
|
* https://github.com/scalefactory/tfctl/tree/master/docs/project_layout.adoc[Project layout]
|
|
@@ -85,23 +105,25 @@ make install
|
|
|
85
105
|
|
|
86
106
|
== Running tfctl
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
Terraform configuration in `.tfctl
|
|
108
|
+
You should run `tfctl` from the root of your project directory. It will generate
|
|
109
|
+
Terraform configuration in `.tfctl/` (add this to your `.gitignore`).
|
|
90
110
|
|
|
91
111
|
Anatomy of a tfctl command:
|
|
92
112
|
|
|
113
|
+
[source,shell]
|
|
93
114
|
----
|
|
94
115
|
tfctl -c CONFIG_FILE TARGET_OPTIONS -- TERRAFORM_COMMAND
|
|
95
116
|
----
|
|
96
117
|
|
|
97
|
-
* `-c` specifies which tfctl config file to use (
|
|
118
|
+
* `-c` specifies which tfctl config file to use (defaults to `tfctl.yaml` in
|
|
119
|
+
current working directory if not set)
|
|
98
120
|
* `TARGET_OPTIONS` specifies which accounts to target. This could be an individual
|
|
99
121
|
account, a group of accounts in an organizational unit or all accounts.
|
|
100
122
|
* `TERRAFORM_COMMAND` will be passed to `terraform` along with any
|
|
101
123
|
options. See https://www.terraform.io/docs/commands/index.html[Terraform
|
|
102
124
|
commands] for details.
|
|
103
125
|
|
|
104
|
-
NOTE: You must have your AWS credentials configured before
|
|
126
|
+
NOTE: You must have your AWS credentials configured before you run `tfctl`, or run
|
|
105
127
|
it using an AWS credentials helper such as
|
|
106
128
|
https://github.com/99designs/aws-vault[aws-vault].
|
|
107
129
|
|
|
@@ -109,68 +131,78 @@ https://github.com/99designs/aws-vault[aws-vault].
|
|
|
109
131
|
|
|
110
132
|
Show help:
|
|
111
133
|
|
|
134
|
+
[source,shell]
|
|
112
135
|
----
|
|
113
136
|
tfctl -h
|
|
114
137
|
----
|
|
115
138
|
|
|
116
139
|
Show merged configuration:
|
|
117
140
|
|
|
141
|
+
[source,shell]
|
|
118
142
|
----
|
|
119
|
-
tfctl -
|
|
143
|
+
tfctl -s
|
|
120
144
|
----
|
|
121
145
|
|
|
122
146
|
List all discovered accounts:
|
|
123
147
|
|
|
148
|
+
[source,shell]
|
|
124
149
|
----
|
|
125
|
-
tfctl
|
|
150
|
+
tfctl --all -l
|
|
126
151
|
----
|
|
127
152
|
|
|
128
153
|
TIP: This can be narrowed down using targeting options and is a good way to
|
|
129
154
|
test what accounts match.
|
|
130
155
|
|
|
131
|
-
Run
|
|
156
|
+
Run `terraform init` across all accounts:
|
|
132
157
|
|
|
158
|
+
[source,shell]
|
|
133
159
|
----
|
|
134
|
-
tfctl
|
|
160
|
+
tfctl --all -- init
|
|
135
161
|
----
|
|
136
162
|
|
|
137
|
-
|
|
163
|
+
Plan Terraform across all accounts in the `test` OU:
|
|
138
164
|
|
|
165
|
+
[source,shell]
|
|
139
166
|
----
|
|
140
|
-
tfctl -
|
|
167
|
+
tfctl -o test -- plan
|
|
141
168
|
----
|
|
142
169
|
|
|
143
|
-
|
|
170
|
+
Plan Terraform in `live` accounts, assuming that `live` is a child OU in multiple
|
|
144
171
|
organization units:
|
|
145
172
|
|
|
173
|
+
[source,shell]
|
|
146
174
|
----
|
|
147
|
-
tfctl -
|
|
175
|
+
tfctl -o '.*/live' -- plan
|
|
148
176
|
----
|
|
149
177
|
|
|
150
|
-
Run plan
|
|
178
|
+
Run a plan for an individual account:
|
|
151
179
|
|
|
180
|
+
[source,shell]
|
|
152
181
|
----
|
|
153
|
-
tfctl -
|
|
182
|
+
tfctl -a example-account - plan
|
|
154
183
|
----
|
|
155
184
|
|
|
156
|
-
|
|
185
|
+
Apply Terraform changes across all accounts:
|
|
157
186
|
|
|
187
|
+
[source,shell]
|
|
158
188
|
----
|
|
159
|
-
tfctl
|
|
189
|
+
tfctl --all -- apply
|
|
160
190
|
----
|
|
161
191
|
|
|
162
|
-
|
|
192
|
+
Destroy Terraform-managed resources in all the `test` OU accounts:
|
|
163
193
|
|
|
194
|
+
[source,shell]
|
|
164
195
|
----
|
|
165
|
-
tfctl -
|
|
196
|
+
tfctl -o test -- destroy -auto-approve
|
|
166
197
|
----
|
|
167
198
|
|
|
168
199
|
Don't buffer the output:
|
|
169
200
|
|
|
201
|
+
[source,shell]
|
|
170
202
|
----
|
|
171
|
-
tfctl -
|
|
203
|
+
tfctl -a example-account -u -- plan
|
|
172
204
|
----
|
|
173
205
|
|
|
174
206
|
This will show output in real time. Usually output is buffered and displayed
|
|
175
|
-
after Terraform command finishes to make it more readable when running
|
|
176
|
-
multiple accounts in parallel.
|
|
207
|
+
after the Terraform command finishes, to make it more readable when running
|
|
208
|
+
across multiple accounts in parallel.
|
data/RELEASING.adoc
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
= Releasing
|
|
2
|
+
|
|
3
|
+
This document is aimed at `tfctl` maintainers and describes the process of
|
|
4
|
+
releasing a new gem version.
|
|
5
|
+
|
|
6
|
+
== Process
|
|
7
|
+
|
|
8
|
+
* Smoke test in SF test accounts: https://github.com/scalefactory/tfctl-test
|
|
9
|
+
* Bump version in `lib/tfctl/version.rb`
|
|
10
|
+
* Update `CHANGELOG.adoc`
|
|
11
|
+
* Commit
|
|
12
|
+
* Create a new GitHub release and version tag using format: vX.X.X
|
|
13
|
+
* TravisCI will build and release the gem automatically: https://travis-ci.org/github/scalefactory/tfctl
|
data/bin/tfctl
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
if File.directory?(File.dirname(__FILE__)
|
|
4
|
+
if File.directory?("#{File.dirname(__FILE__)}/../vendor")
|
|
5
5
|
require 'bundler/setup'
|
|
6
6
|
end
|
|
7
7
|
require 'optparse'
|
|
@@ -22,7 +22,7 @@ options = {
|
|
|
22
22
|
ou: nil,
|
|
23
23
|
all: nil,
|
|
24
24
|
show_config: false,
|
|
25
|
-
config_file:
|
|
25
|
+
config_file: 'tfctl.yaml',
|
|
26
26
|
unbuffered: false,
|
|
27
27
|
debug: false,
|
|
28
28
|
use_cache: false,
|
|
@@ -68,10 +68,6 @@ begin
|
|
|
68
68
|
|
|
69
69
|
# Validate CLI arguments
|
|
70
70
|
|
|
71
|
-
if options[:config_file].nil?
|
|
72
|
-
raise OptionParser::MissingArgument, '--config-file'
|
|
73
|
-
end
|
|
74
|
-
|
|
75
71
|
unless File.exist? options[:config_file]
|
|
76
72
|
raise OptionParser::InvalidOption,
|
|
77
73
|
"Config file not found in: #{options[:config_file]}"
|
|
@@ -85,8 +81,8 @@ begin
|
|
|
85
81
|
targetting_opts = %i[account ou all]
|
|
86
82
|
targets_set = []
|
|
87
83
|
options.each do |k, v|
|
|
88
|
-
if targetting_opts.include?(k)
|
|
89
|
-
targets_set << k.to_s
|
|
84
|
+
if targetting_opts.include?(k) and !v.nil?
|
|
85
|
+
targets_set << k.to_s
|
|
90
86
|
end
|
|
91
87
|
end
|
|
92
88
|
if targets_set.length > 1
|
|
@@ -104,7 +100,7 @@ end
|
|
|
104
100
|
|
|
105
101
|
|
|
106
102
|
|
|
107
|
-
#
|
|
103
|
+
# Execute terraform in target accounts
|
|
108
104
|
def run_account(config, account, options, tf_argv, log)
|
|
109
105
|
|
|
110
106
|
# Skip excluded accounts
|
|
@@ -145,6 +141,7 @@ begin
|
|
|
145
141
|
log.info 'tfctl running'
|
|
146
142
|
|
|
147
143
|
config_name = File.basename(options[:config_file]).chomp('.yaml')
|
|
144
|
+
config_name = 'default' if config_name == 'tfctl'
|
|
148
145
|
log.info "Using config: #{config_name}"
|
|
149
146
|
|
|
150
147
|
log.info 'Working out AWS account topology'
|
data/docs/configuration.adoc
CHANGED
|
@@ -24,8 +24,8 @@ toc::[]
|
|
|
24
24
|
|
|
25
25
|
== Overview
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
it with configuration specified in
|
|
27
|
+
`tfctl` retrieves initial account configuration from AWS Organizations and merges
|
|
28
|
+
it with configuration specified in YAML format (`tfctl.yaml` by default).
|
|
29
29
|
|
|
30
30
|
The configuration is merged in the following order:
|
|
31
31
|
|
|
@@ -68,9 +68,9 @@ organization_units:
|
|
|
68
68
|
|
|
69
69
|
This will result in all three profiles deployed to accounts in `team` OU.
|
|
70
70
|
|
|
71
|
-
TIP: You can display the fully merged configuration by running `tfctl -
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
TIP: You can display the fully merged configuration by running `tfctl -s`.
|
|
72
|
+
It's safe to run as it doesn't make any changes to AWS resources. It's a good
|
|
73
|
+
way to test your configuration.
|
|
74
74
|
|
|
75
75
|
== Defining arbitrary data
|
|
76
76
|
|
|
@@ -83,7 +83,17 @@ above.
|
|
|
83
83
|
|
|
84
84
|
== Handling secrets
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
CAUTION: Do not commit secrets into your Terraform or tfctl configuration.
|
|
87
|
+
|
|
88
|
+
Instead, use AWS Secrets Manager and retrieve secrets in Terraform profiles using
|
|
89
|
+
the
|
|
88
90
|
https://www.terraform.io/docs/providers/aws/d/secretsmanager_secret.html[secrets
|
|
89
|
-
manager data source]
|
|
91
|
+
manager data source].
|
|
92
|
+
|
|
93
|
+
== Configuration Schema
|
|
94
|
+
|
|
95
|
+
The configuration file is validated using https://json-schema.org/[JSON Schema].
|
|
96
|
+
|
|
97
|
+
The schema is defined in
|
|
98
|
+
https://github.com/scalefactory/tfctl/blob/master/lib/tfctl/schema.rb[lib/tfctl/schema.rb]
|
|
99
|
+
and is a good place to look up all available options.
|
data/docs/control_tower.adoc
CHANGED
|
@@ -31,7 +31,7 @@ toc::[]
|
|
|
31
31
|
For state tracking we're going to create a dedicated `shared-services` account
|
|
32
32
|
under a `mgmt` organization unit. We'll use S3 for state storage and DynamoDB
|
|
33
33
|
for locking. `TerraformState` IAM role will be created for cross account
|
|
34
|
-
access to state resources from the primary account.
|
|
34
|
+
access to state resources from the primary AWS account.
|
|
35
35
|
|
|
36
36
|
In the primary account we'll create a `TfctlOrgAccess` role. It gives tfctl
|
|
37
37
|
read only access to AWS Organizations which is used to discover accounts and
|
|
@@ -50,9 +50,10 @@ and provision a couple of accounts for testing.
|
|
|
50
50
|
|
|
51
51
|
Before starting you'll need:
|
|
52
52
|
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
53
|
+
* An AWS account that is part of an Organization.
|
|
54
|
+
* Control Tower set up in your primary AWS account.
|
|
55
|
+
* A user with `AdministratorAccess` privileges in your primary AWS account.
|
|
56
|
+
* AWS CLI tools installed on your local machine.
|
|
56
57
|
* Terraform 0.12 or higher.
|
|
57
58
|
|
|
58
59
|
== Configure Control Tower
|
|
@@ -74,6 +75,7 @@ approximately 20 mins to provision one.
|
|
|
74
75
|
|
|
75
76
|
== Install tfctl
|
|
76
77
|
|
|
78
|
+
[source,shell]
|
|
77
79
|
----
|
|
78
80
|
git clone git@github.com:scalefactory/tfctl.git
|
|
79
81
|
cd tfctl/ && sudo make install
|
|
@@ -85,17 +87,21 @@ It's assumed you have configured AWS CLI access to the primary account.
|
|
|
85
87
|
|
|
86
88
|
We'll use CloudFormation templates in `examples/bootstrap/`.
|
|
87
89
|
|
|
88
|
-
First export configuration using environment variables making sure to change to
|
|
89
|
-
values to suit your
|
|
90
|
+
First export configuration using environment variables, making sure to change to
|
|
91
|
+
values to suit your setup:
|
|
90
92
|
|
|
93
|
+
[source,shell]
|
|
91
94
|
----
|
|
92
|
-
|
|
93
|
-
export
|
|
95
|
+
# Change these to match your setup
|
|
96
|
+
export PRIMARY_ACCOUNT_ID=123456789012
|
|
97
|
+
export SHARED_SERVICES_ACCOUNT_ID=345678901234
|
|
94
98
|
export STATE_BUCKET_NAME='example-terraform-state'
|
|
99
|
+
export AWS_REGION=eu-west-1
|
|
95
100
|
----
|
|
96
101
|
|
|
97
102
|
Create the remote state resources stack set:
|
|
98
103
|
|
|
104
|
+
[source,shell]
|
|
99
105
|
----
|
|
100
106
|
cd examples/bootstrap/
|
|
101
107
|
|
|
@@ -107,31 +113,34 @@ aws cloudformation create-stack-set \
|
|
|
107
113
|
--execution-role-name AWSControlTowerExecution \
|
|
108
114
|
--administration-role-arn arn:aws:iam::${PRIMARY_ACCOUNT_ID}:role/service-role/AWSControlTowerStackSetRole \
|
|
109
115
|
--parameters ParameterKey=PrimaryAccountId,ParameterValue=${PRIMARY_ACCOUNT_ID} \
|
|
110
|
-
ParameterKey=TerraformStateBucket,ParameterValue
|
|
116
|
+
ParameterKey=TerraformStateBucket,ParameterValue="${STATE_BUCKET_NAME}"
|
|
111
117
|
----
|
|
112
118
|
|
|
113
|
-
Create a stack set instance in
|
|
119
|
+
Create a stack set instance in your shared services account:
|
|
114
120
|
|
|
121
|
+
[source,shell]
|
|
115
122
|
----
|
|
116
123
|
aws cloudformation create-stack-instances \
|
|
117
124
|
--stack-set-name TerraformState \
|
|
118
125
|
--accounts ${SHARED_SERVICES_ACCOUNT_ID} \
|
|
119
|
-
--regions
|
|
126
|
+
--regions ${AWS_REGION}
|
|
120
127
|
----
|
|
121
128
|
|
|
122
129
|
Check status:
|
|
123
130
|
|
|
131
|
+
[source,shell]
|
|
124
132
|
----
|
|
125
133
|
aws cloudformation describe-stack-instance \
|
|
126
134
|
--stack-set-name TerraformState \
|
|
127
135
|
--stack-instance-account ${SHARED_SERVICES_ACCOUNT_ID} \
|
|
128
|
-
--stack-instance-region
|
|
136
|
+
--stack-instance-region ${AWS_REGION}
|
|
129
137
|
----
|
|
130
138
|
|
|
131
139
|
NOTE: Initial status will be `OUTDATED`, it should change to `CURRENT` once deployed.
|
|
132
140
|
|
|
133
|
-
Deploy `TfctlOrgAccess` IAM role stack:
|
|
141
|
+
Deploy the `TfctlOrgAccess` IAM role stack:
|
|
134
142
|
|
|
143
|
+
[source,shell]
|
|
135
144
|
----
|
|
136
145
|
aws cloudformation create-stack \
|
|
137
146
|
--stack-name TfctlOrgAccess \
|
|
@@ -142,6 +151,7 @@ aws cloudformation create-stack \
|
|
|
142
151
|
|
|
143
152
|
Check status:
|
|
144
153
|
|
|
154
|
+
[source,shell]
|
|
145
155
|
----
|
|
146
156
|
aws cloudformation describe-stacks --stack-name TfctlOrgAccess
|
|
147
157
|
----
|
|
@@ -151,14 +161,14 @@ NOTE: Successful status should read: `CREATE_COMPLETE`.
|
|
|
151
161
|
== Configure tfctl
|
|
152
162
|
|
|
153
163
|
Copy the example project directory `examples/control_tower` somewhere convenient
|
|
154
|
-
and edit `
|
|
164
|
+
and edit `tfctl.yaml`.
|
|
155
165
|
|
|
156
166
|
You need to modify the following parameters:
|
|
157
167
|
|
|
158
168
|
* `tf_state_bucket` - set to `$STATE_BUCKET_NAME`
|
|
159
169
|
* `tf_state_role_arn` - set shared services account ID
|
|
160
170
|
* `tfctl_role_arn` - set primary account ID
|
|
161
|
-
* `primary_account` - set the primary account name. You can find it
|
|
171
|
+
* `primary_account` - set the primary account name. You can find it through AWS Organizations in the console.
|
|
162
172
|
|
|
163
173
|
TIP: You should keep your project directory under version control.
|
|
164
174
|
|
|
@@ -169,43 +179,51 @@ and `mgmt` OUs.
|
|
|
169
179
|
|
|
170
180
|
NOTE: Run tfctl commands from the root of you project directory.
|
|
171
181
|
|
|
172
|
-
First dump the configuration to verify everything works:
|
|
182
|
+
First, dump the configuration to verify everything works:
|
|
173
183
|
|
|
184
|
+
[source,shell]
|
|
174
185
|
----
|
|
175
|
-
tfctl -
|
|
186
|
+
tfctl -s
|
|
176
187
|
----
|
|
177
188
|
|
|
178
|
-
This will not make any changes but will print out
|
|
189
|
+
This will not make any changes but will print out YAML containing the final,
|
|
179
190
|
merged configuration data. It should contain a list of discovered accounts and
|
|
180
191
|
their configuration.
|
|
181
192
|
|
|
182
|
-
Initialise
|
|
193
|
+
Initialise Terraform for all discovered accounts:
|
|
183
194
|
|
|
195
|
+
[source,shell]
|
|
184
196
|
----
|
|
185
|
-
tfctl
|
|
197
|
+
tfctl --all -- init
|
|
186
198
|
----
|
|
187
199
|
|
|
188
200
|
Tfctl will run Terraform against all accounts in parallel.
|
|
189
201
|
|
|
190
|
-
|
|
202
|
+
`plan` the Terraform:
|
|
191
203
|
|
|
204
|
+
[source,shell]
|
|
192
205
|
----
|
|
193
|
-
tfctl
|
|
206
|
+
tfctl --all -- plan
|
|
194
207
|
----
|
|
195
208
|
|
|
196
|
-
and apply:
|
|
209
|
+
and `apply` it:
|
|
197
210
|
|
|
211
|
+
[source,shell]
|
|
198
212
|
----
|
|
199
|
-
tfctl
|
|
213
|
+
tfctl --all -- apply
|
|
200
214
|
----
|
|
201
215
|
|
|
202
|
-
To destroy created resources run:
|
|
203
216
|
|
|
217
|
+
== Clean up
|
|
218
|
+
|
|
219
|
+
To destroy created resources, run:
|
|
220
|
+
|
|
221
|
+
[source,shell]
|
|
204
222
|
----
|
|
205
|
-
tfctl
|
|
223
|
+
tfctl --all -- destroy -auto-approve
|
|
206
224
|
----
|
|
207
225
|
|
|
208
|
-
That's it! You can now execute
|
|
226
|
+
That's it! You can now execute Terraform across your Control Tower estate.
|
|
209
227
|
|
|
210
228
|
TIP: Your project directory should be under version control excluding the
|
|
211
229
|
`.tfctl` directory which is automatically generated.
|
|
@@ -81,7 +81,7 @@ profile. Tfctl configuration can be accessed using this variable. This It
|
|
|
81
81
|
includes an array of all discovered accounts as well their parameters from
|
|
82
82
|
tfctl config file.
|
|
83
83
|
|
|
84
|
-
TIP: You can run `tfctl -
|
|
84
|
+
TIP: You can run `tfctl -s` to show the config data in
|
|
85
85
|
yaml format. This exact data is available in the `config` variable in your
|
|
86
86
|
profile.
|
|
87
87
|
|
|
@@ -124,7 +124,7 @@ You have few options here:
|
|
|
124
124
|
For the sake of this example we're going to deploy our bucket to all accounts
|
|
125
125
|
in `test` OU.
|
|
126
126
|
|
|
127
|
-
In tfctl
|
|
127
|
+
In `tfctl.yaml` add the profile to the `test` OU:
|
|
128
128
|
|
|
129
129
|
[source, yaml]
|
|
130
130
|
----
|
|
@@ -140,8 +140,8 @@ organization_units:
|
|
|
140
140
|
To see what would happen when the change is applied run:
|
|
141
141
|
|
|
142
142
|
----
|
|
143
|
-
tfctl -
|
|
144
|
-
tfctl -
|
|
143
|
+
tfctl -o test -- init
|
|
144
|
+
tfctl -o test -- plan
|
|
145
145
|
----
|
|
146
146
|
|
|
147
147
|
This will run `terraform init` to initialise terraform and then `terraform
|
|
@@ -187,5 +187,5 @@ next step.
|
|
|
187
187
|
|
|
188
188
|
Once you're happy with the plan, apply it.
|
|
189
189
|
----
|
|
190
|
-
tfctl -
|
|
190
|
+
tfctl -o test -- apply
|
|
191
191
|
----
|
data/docs/iam_permissions.adoc
CHANGED
|
@@ -20,7 +20,7 @@ endif::[]
|
|
|
20
20
|
|
|
21
21
|
= IAM roles
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
`tfctl` usually requires three IAM roles to be configured:
|
|
24
24
|
|
|
25
25
|
* `TfctlRole` - read only access to AWS Organizations set up in the primary account.
|
|
26
26
|
* `TerraformStateRole` - access to remote state resources (S3, DynamoDB) in the
|
|
@@ -28,7 +28,7 @@ Tfctl usually requires three IAM roles to be configured:
|
|
|
28
28
|
* `TerraformExecutionRole` - configured in all spoke accounts and used for executing Terraform.
|
|
29
29
|
|
|
30
30
|
The user executing tfctl needs permission to assume all three roles cross
|
|
31
|
-
account.
|
|
31
|
+
account. Once these are configured, tfctl automatically assumes roles for you.
|
|
32
32
|
|
|
33
33
|
It's possible to configure different Terraform execution roles in different
|
|
34
34
|
spoke accounts based on OU or account names. This can be used to restrict
|
data/docs/project_layout.adoc
CHANGED
|
@@ -23,8 +23,7 @@ endif::[]
|
|
|
23
23
|
Example project structure
|
|
24
24
|
----
|
|
25
25
|
project_dir/
|
|
26
|
-
├── conf
|
|
27
|
-
│ └── example.yaml
|
|
26
|
+
├── tfctl.conf
|
|
28
27
|
├── modules
|
|
29
28
|
│ └── s3-bucket
|
|
30
29
|
│ ├── main.tf
|
|
@@ -51,7 +50,12 @@ The configuration data is exposed to terraform via a profile `config` variable.
|
|
|
51
50
|
It also defines Terraform and tfctl configuration such as state tracking and
|
|
52
51
|
what IAM roles to use.
|
|
53
52
|
|
|
54
|
-
|
|
53
|
+
By default, tfctl will use `tfctl.yaml` in its current working directory. You
|
|
54
|
+
can specify a different file using `-c`. Multiple configurations are supported
|
|
55
|
+
in the same project directory and generated data will be stored separately for
|
|
56
|
+
each config file in `.tfctl/`.
|
|
57
|
+
|
|
58
|
+
== `profiles`
|
|
55
59
|
|
|
56
60
|
Profiles are re-usable collections of resources which can be applied to
|
|
57
61
|
accounts. They are implemented just like usual modules but provide an
|
|
@@ -60,6 +64,6 @@ other data sources). Profiles often compose multiple modules and provide
|
|
|
60
64
|
configuration data to them. This approach makes it possible to re-use standard
|
|
61
65
|
modules (e.g. Terraform module registry).
|
|
62
66
|
|
|
63
|
-
== modules
|
|
67
|
+
== `modules`
|
|
64
68
|
|
|
65
69
|
Standard Terraform modules.
|
|
@@ -7,6 +7,6 @@ variable "config" {
|
|
|
7
7
|
locals {
|
|
8
8
|
config = jsondecode(var.config)
|
|
9
9
|
account_id = "${data.aws_caller_identity.current.account_id}"
|
|
10
|
-
# get
|
|
10
|
+
# get account configuration from tfctl config
|
|
11
11
|
account = [ for account in local.config["accounts"]: account if account["id"] == local.account_id ][0]
|
|
12
12
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# create final configuration used by tfctl. You can view the merged
|
|
6
6
|
# configuration by running:
|
|
7
7
|
#
|
|
8
|
-
# tfctl -c conf/
|
|
8
|
+
# tfctl -c conf/tfctl.yaml -s
|
|
9
9
|
#
|
|
10
10
|
|
|
11
11
|
#
|
|
@@ -17,7 +17,7 @@ tf_state_dynamodb_table: 'terraform-lock'
|
|
|
17
17
|
tf_state_region: 'eu-west-1'
|
|
18
18
|
# Role for accessing state resources
|
|
19
19
|
tf_state_role_arn: 'arn:aws:iam::SHARED_SERVICES_ACCOUNT_ID:role/TerraformStateRole'
|
|
20
|
-
tf_required_version: '>= 0.12.
|
|
20
|
+
tf_required_version: '>= 0.12.29'
|
|
21
21
|
aws_provider_version: '>= 2.14'
|
|
22
22
|
# Role used by tfctl to retrieve data from AWS Organizations
|
|
23
23
|
# Has to be set up in the primary org account
|
data/lib/hash.rb
CHANGED
|
@@ -18,13 +18,14 @@ class Hash
|
|
|
18
18
|
merge(second.to_h, &merger)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# Copied from ruby 2.6 Psych for 2.3 compatibility.
|
|
22
21
|
def symbolize_names!(result = self)
|
|
23
22
|
case result
|
|
24
23
|
when Hash
|
|
24
|
+
# rubocop:disable Style/HashEachMethods
|
|
25
25
|
result.keys.each do |key|
|
|
26
26
|
result[key.to_sym] = symbolize_names!(result.delete(key))
|
|
27
27
|
end
|
|
28
|
+
# rubocop:enable Style/HashEachMethods
|
|
28
29
|
when Array
|
|
29
30
|
result.map! { |r| symbolize_names!(r) }
|
|
30
31
|
end
|
data/lib/tfctl.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'tfctl/aws_org
|
|
4
|
-
require_relative 'tfctl/config
|
|
5
|
-
require_relative 'tfctl/error
|
|
6
|
-
require_relative 'tfctl/executor
|
|
7
|
-
require_relative 'tfctl/generator
|
|
8
|
-
require_relative 'tfctl/logger
|
|
9
|
-
require_relative 'tfctl/schema
|
|
10
|
-
require_relative 'tfctl/version
|
|
3
|
+
require_relative 'tfctl/aws_org'
|
|
4
|
+
require_relative 'tfctl/config'
|
|
5
|
+
require_relative 'tfctl/error'
|
|
6
|
+
require_relative 'tfctl/executor'
|
|
7
|
+
require_relative 'tfctl/generator'
|
|
8
|
+
require_relative 'tfctl/logger'
|
|
9
|
+
require_relative 'tfctl/schema'
|
|
10
|
+
require_relative 'tfctl/version'
|
data/lib/tfctl/aws_org.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'error
|
|
3
|
+
require_relative 'error'
|
|
4
4
|
require 'aws-sdk-organizations'
|
|
5
5
|
|
|
6
6
|
module Tfctl
|
|
@@ -71,23 +71,25 @@ module Tfctl
|
|
|
71
71
|
@aws_org_client.list_children(
|
|
72
72
|
child_type: 'ORGANIZATIONAL_UNIT',
|
|
73
73
|
parent_id: parent_id,
|
|
74
|
-
).
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
74
|
+
).each do |resp|
|
|
75
|
+
resp.children.each do |child|
|
|
76
|
+
|
|
77
|
+
begin
|
|
78
|
+
ou = @aws_org_client.describe_organizational_unit(
|
|
79
|
+
organizational_unit_id: child.id,
|
|
80
|
+
).organizational_unit
|
|
81
|
+
rescue Aws::Organizations::Errors::TooManyRequestsException
|
|
82
|
+
# FIXME: - use logger
|
|
83
|
+
puts 'AWS Organizations: too many requests. Retrying in 5 secs.'
|
|
84
|
+
sleep 5
|
|
85
|
+
retries += 1
|
|
86
|
+
retry if retries < 10
|
|
87
|
+
end
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
ou_name = parent_name == :root ? ou.name.to_sym : "#{parent_name}/#{ou.name}".to_sym
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
output[ou_name] = ou.id
|
|
92
|
+
end
|
|
91
93
|
end
|
|
92
94
|
output
|
|
93
95
|
end
|
data/lib/tfctl/config.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../hash
|
|
4
|
-
require_relative 'error
|
|
3
|
+
require_relative '../hash'
|
|
4
|
+
require_relative 'error'
|
|
5
5
|
require 'yaml'
|
|
6
6
|
require 'json'
|
|
7
7
|
|
|
@@ -48,7 +48,7 @@ module Tfctl
|
|
|
48
48
|
@config.to_json
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
# Filters accounts by account property
|
|
51
|
+
# Filters accounts by an account property
|
|
52
52
|
def find_accounts(property_name, property_value)
|
|
53
53
|
output =[]
|
|
54
54
|
@config[:accounts].each do |account|
|
|
@@ -88,7 +88,6 @@ module Tfctl
|
|
|
88
88
|
|
|
89
89
|
# Retrieves AWS Organizations data and merges it with data from yaml config.
|
|
90
90
|
def load_config(config_name, yaml_config, aws_org_config)
|
|
91
|
-
|
|
92
91
|
# AWS Organizations data
|
|
93
92
|
config = aws_org_config
|
|
94
93
|
# Merge organization sections from yaml file
|
|
@@ -122,7 +121,9 @@ module Tfctl
|
|
|
122
121
|
return config unless config.key?(:exclude_accounts)
|
|
123
122
|
|
|
124
123
|
config[:accounts].each_with_index do |account, idx|
|
|
124
|
+
# rubocop:disable Style/IfWithBooleanLiteralBranches
|
|
125
125
|
config[:accounts][idx][:excluded] = config[:exclude_accounts].include?(account[:name]) ? true : false
|
|
126
|
+
# rubocop:enable Style/IfWithBooleanLiteralBranches
|
|
126
127
|
end
|
|
127
128
|
|
|
128
129
|
config
|
data/lib/tfctl/executor.rb
CHANGED
data/lib/tfctl/generator.rb
CHANGED
|
@@ -10,21 +10,27 @@ module Tfctl
|
|
|
10
10
|
|
|
11
11
|
def write_json_block(path, block)
|
|
12
12
|
File.open(path, 'w') do |f|
|
|
13
|
-
f.write(JSON.pretty_generate(block)
|
|
13
|
+
f.write("#{JSON.pretty_generate(block)}\n")
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def make(account:, config:)
|
|
18
18
|
target_dir = "#{PROJECT_ROOT}/.tfctl/#{config[:config_name]}/#{account[:name]}"
|
|
19
|
-
tf_version = config.fetch(:tf_required_version, '>= 0.12.
|
|
19
|
+
tf_version = config.fetch(:tf_required_version, '>= 0.12.29')
|
|
20
20
|
aws_provider_version = config.fetch(:aws_provider_version, '>= 2.14')
|
|
21
21
|
|
|
22
22
|
FileUtils.mkdir_p target_dir
|
|
23
23
|
|
|
24
24
|
terraform_block = {
|
|
25
25
|
'terraform' => {
|
|
26
|
-
'required_version'
|
|
27
|
-
'
|
|
26
|
+
'required_version' => tf_version,
|
|
27
|
+
'required_providers' => {
|
|
28
|
+
'aws' => {
|
|
29
|
+
'source' => 'hashicorp/aws',
|
|
30
|
+
'version' => aws_provider_version,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
'backend' => {
|
|
28
34
|
's3' => {
|
|
29
35
|
'bucket' => config[:tf_state_bucket],
|
|
30
36
|
'key' => "#{account[:name]}/tfstate",
|
|
@@ -41,7 +47,6 @@ module Tfctl
|
|
|
41
47
|
provider_block = {
|
|
42
48
|
'provider' => {
|
|
43
49
|
'aws' => {
|
|
44
|
-
'version' => aws_provider_version,
|
|
45
50
|
'region' => account[:region],
|
|
46
51
|
'assume_role' => {
|
|
47
52
|
'role_arn' => "arn:aws:iam::#{account[:id]}:role/#{account[:tf_execution_role]}",
|
|
@@ -71,11 +76,8 @@ module Tfctl
|
|
|
71
76
|
profile_block = {
|
|
72
77
|
'module' => {
|
|
73
78
|
profile => {
|
|
74
|
-
'source'
|
|
75
|
-
'config'
|
|
76
|
-
'providers' => {
|
|
77
|
-
'aws' => 'aws',
|
|
78
|
-
},
|
|
79
|
+
'source' => "../../../profiles/#{profile}",
|
|
80
|
+
'config' => '${var.config}',
|
|
79
81
|
},
|
|
80
82
|
},
|
|
81
83
|
}
|
data/lib/tfctl/logger.rb
CHANGED
data/lib/tfctl/schema.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'json_schemer'
|
|
4
|
-
require_relative 'error
|
|
4
|
+
require_relative 'error'
|
|
5
5
|
|
|
6
6
|
# Config validator using JSON schema
|
|
7
7
|
|
|
@@ -29,7 +29,7 @@ module Tfctl
|
|
|
29
29
|
def main_schema
|
|
30
30
|
iam_arn_pattern = 'arn:aws:iam:[a-z\-0-9]*:[0-9]{12}:[a-zA-Z\/+@=.,]*'
|
|
31
31
|
|
|
32
|
-
# rubocop:disable Layout/
|
|
32
|
+
# rubocop:disable Layout/HashAlignment
|
|
33
33
|
{
|
|
34
34
|
'type' => 'object',
|
|
35
35
|
'properties' => {
|
|
@@ -61,7 +61,7 @@ module Tfctl
|
|
|
61
61
|
],
|
|
62
62
|
'additionalProperties' => false,
|
|
63
63
|
}
|
|
64
|
-
# rubocop:enable Layout/
|
|
64
|
+
# rubocop:enable Layout/HashAlignment
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def org_schema
|
data/lib/tfctl/version.rb
CHANGED
data/tfctl.gemspec
CHANGED
|
@@ -23,14 +23,17 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
24
24
|
spec.require_paths = ['lib']
|
|
25
25
|
|
|
26
|
+
spec.required_ruby_version = '>= 2.5.0'
|
|
27
|
+
|
|
26
28
|
# Think when adding new dependencies. Is it really necessary?
|
|
27
29
|
# "The things you own end up owning you" etc.
|
|
28
|
-
spec.add_dependency 'aws-sdk-organizations', '~> 1.
|
|
30
|
+
spec.add_dependency 'aws-sdk-organizations', '~> 1.40'
|
|
29
31
|
spec.add_dependency 'json_schemer', '~> 0.2'
|
|
30
|
-
spec.add_dependency 'parallel', '~> 1.
|
|
31
|
-
spec.add_dependency 'terminal-table', '
|
|
32
|
+
spec.add_dependency 'parallel', '~> 1.19'
|
|
33
|
+
spec.add_dependency 'terminal-table', '>= 1.8', '< 4.0'
|
|
32
34
|
|
|
33
|
-
spec.add_development_dependency 'guard-rspec',
|
|
34
|
-
spec.add_development_dependency 'rspec',
|
|
35
|
-
spec.add_development_dependency 'rubocop',
|
|
35
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
|
36
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
|
37
|
+
spec.add_development_dependency 'rubocop', '~> 1.3'
|
|
38
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.2'
|
|
36
39
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tfctl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Wasilczuk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-05-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-organizations
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
19
|
+
version: '1.40'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '1.
|
|
26
|
+
version: '1.40'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: json_schemer
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,28 +44,34 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '1.
|
|
47
|
+
version: '1.19'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '1.
|
|
54
|
+
version: '1.19'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: terminal-table
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '1.8'
|
|
62
|
+
- - "<"
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '4.0'
|
|
62
65
|
type: :runtime
|
|
63
66
|
prerelease: false
|
|
64
67
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
68
|
requirements:
|
|
66
|
-
- - "
|
|
69
|
+
- - ">="
|
|
67
70
|
- !ruby/object:Gem::Version
|
|
68
71
|
version: '1.8'
|
|
72
|
+
- - "<"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '4.0'
|
|
69
75
|
- !ruby/object:Gem::Dependency
|
|
70
76
|
name: guard-rspec
|
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -86,28 +92,42 @@ dependencies:
|
|
|
86
92
|
requirements:
|
|
87
93
|
- - "~>"
|
|
88
94
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '3.
|
|
95
|
+
version: '3.9'
|
|
90
96
|
type: :development
|
|
91
97
|
prerelease: false
|
|
92
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
99
|
requirements:
|
|
94
100
|
- - "~>"
|
|
95
101
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '3.
|
|
102
|
+
version: '3.9'
|
|
97
103
|
- !ruby/object:Gem::Dependency
|
|
98
104
|
name: rubocop
|
|
99
105
|
requirement: !ruby/object:Gem::Requirement
|
|
100
106
|
requirements:
|
|
101
107
|
- - "~>"
|
|
102
108
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
109
|
+
version: '1.3'
|
|
110
|
+
type: :development
|
|
111
|
+
prerelease: false
|
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '1.3'
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: rubocop-rspec
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '2.2'
|
|
104
124
|
type: :development
|
|
105
125
|
prerelease: false
|
|
106
126
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
127
|
requirements:
|
|
108
128
|
- - "~>"
|
|
109
129
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
130
|
+
version: '2.2'
|
|
111
131
|
description:
|
|
112
132
|
email:
|
|
113
133
|
- akw@scalefactory.com
|
|
@@ -116,6 +136,8 @@ executables:
|
|
|
116
136
|
extensions: []
|
|
117
137
|
extra_rdoc_files: []
|
|
118
138
|
files:
|
|
139
|
+
- ".bundle/config"
|
|
140
|
+
- ".github/dependabot.yml"
|
|
119
141
|
- ".gitignore"
|
|
120
142
|
- ".rspec"
|
|
121
143
|
- ".rubocop.yml"
|
|
@@ -126,6 +148,7 @@ files:
|
|
|
126
148
|
- LICENSE
|
|
127
149
|
- Makefile
|
|
128
150
|
- README.adoc
|
|
151
|
+
- RELEASING.adoc
|
|
129
152
|
- bin/tfctl
|
|
130
153
|
- docs/configuration.adoc
|
|
131
154
|
- docs/control_tower.adoc
|
|
@@ -135,12 +158,12 @@ files:
|
|
|
135
158
|
- examples/bootstrap/terraform-exec-role.template
|
|
136
159
|
- examples/bootstrap/terraform-state.template
|
|
137
160
|
- examples/bootstrap/tfctl-org-access.template
|
|
138
|
-
- examples/control_tower/conf/example.yaml
|
|
139
161
|
- examples/control_tower/modules/s3-bucket/main.tf
|
|
140
162
|
- examples/control_tower/modules/s3-bucket/variables.tf
|
|
141
163
|
- examples/control_tower/profiles/example-profile/data.tf
|
|
142
164
|
- examples/control_tower/profiles/example-profile/main.tf
|
|
143
165
|
- examples/control_tower/profiles/example-profile/variables.tf
|
|
166
|
+
- examples/control_tower/tfctl.yaml
|
|
144
167
|
- lib/hash.rb
|
|
145
168
|
- lib/tfctl.rb
|
|
146
169
|
- lib/tfctl/aws_org.rb
|
|
@@ -164,15 +187,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
164
187
|
requirements:
|
|
165
188
|
- - ">="
|
|
166
189
|
- !ruby/object:Gem::Version
|
|
167
|
-
version:
|
|
190
|
+
version: 2.5.0
|
|
168
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
192
|
requirements:
|
|
170
193
|
- - ">="
|
|
171
194
|
- !ruby/object:Gem::Version
|
|
172
195
|
version: '0'
|
|
173
196
|
requirements: []
|
|
174
|
-
|
|
175
|
-
rubygems_version: 2.7.7
|
|
197
|
+
rubygems_version: 3.0.8
|
|
176
198
|
signing_key:
|
|
177
199
|
specification_version: 4
|
|
178
200
|
summary: Terraform wrapper for managing multi-account AWS infrastructures
|