tfctl 0.2.0 → 1.2.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 +4 -4
- data/.rubocop.yml +8 -4
- data/.travis.yml +13 -12
- data/CHANGELOG.adoc +22 -0
- data/README.adoc +67 -31
- data/bin/tfctl +11 -6
- data/docs/configuration.adoc +59 -13
- data/docs/control_tower.adoc +75 -37
- data/docs/creating_a_profile.adoc +32 -10
- data/docs/iam_permissions.adoc +23 -3
- data/docs/project_layout.adoc +32 -6
- data/examples/control_tower/{conf/example.yaml → tfctl.yaml} +31 -23
- data/lib/tfctl.rb +4 -3
- data/lib/tfctl/aws_org.rb +17 -15
- data/lib/tfctl/config.rb +1 -2
- data/lib/tfctl/error.rb +9 -0
- data/lib/tfctl/executor.rb +9 -5
- data/lib/tfctl/schema.rb +80 -0
- data/lib/tfctl/version.rb +1 -1
- data/tfctl.gemspec +7 -4
- metadata +28 -14
data/docs/control_tower.adoc
CHANGED
@@ -1,17 +1,37 @@
|
|
1
|
-
:
|
2
|
-
|
3
|
-
|
1
|
+
// Settings:
|
2
|
+
:idprefix:
|
3
|
+
:idseparator: -
|
4
|
+
ifndef::env-github[:icons: font]
|
5
|
+
ifdef::env-github,env-browser[]
|
6
|
+
:toc: macro
|
7
|
+
:toclevels: 1
|
8
|
+
endif::[]
|
9
|
+
ifdef::env-github[]
|
10
|
+
:branch: master
|
11
|
+
:status:
|
12
|
+
:outfilesuffix: .adoc
|
13
|
+
:!toc-title:
|
14
|
+
:caution-caption: :fire:
|
15
|
+
:important-caption: :exclamation:
|
16
|
+
:note-caption: :paperclip:
|
17
|
+
:tip-caption: :bulb:
|
18
|
+
:warning-caption: :warning:
|
19
|
+
endif::[]
|
20
|
+
|
21
|
+
= Control Tower integration guide
|
4
22
|
|
5
23
|
This guide will help you integrate Terraform with AWS Control Tower using the
|
6
24
|
tfctl wrapper. This involves setting up resources for remote state tracking,
|
7
25
|
necessary IAM roles and a tfctl project.
|
8
26
|
|
9
|
-
|
27
|
+
toc::[]
|
28
|
+
|
29
|
+
== Overview
|
10
30
|
|
11
31
|
For state tracking we're going to create a dedicated `shared-services` account
|
12
32
|
under a `mgmt` organization unit. We'll use S3 for state storage and DynamoDB
|
13
33
|
for locking. `TerraformState` IAM role will be created for cross account
|
14
|
-
access to state resources from the primary account.
|
34
|
+
access to state resources from the primary AWS account.
|
15
35
|
|
16
36
|
In the primary account we'll create a `TfctlOrgAccess` role. It gives tfctl
|
17
37
|
read only access to AWS Organizations which is used to discover accounts and
|
@@ -26,16 +46,17 @@ account factory and can be assumed from the primary account.
|
|
26
46
|
We're going to create a `live` and `test` organization units in Control Tower
|
27
47
|
and provision a couple of accounts for testing.
|
28
48
|
|
29
|
-
|
49
|
+
== Prerequisites
|
30
50
|
|
31
51
|
Before starting you'll need:
|
32
52
|
|
33
|
-
*
|
34
|
-
*
|
35
|
-
*
|
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.
|
36
57
|
* Terraform 0.12 or higher.
|
37
58
|
|
38
|
-
|
59
|
+
== Configure Control Tower
|
39
60
|
|
40
61
|
Create the following organization units in Control Tower:
|
41
62
|
|
@@ -52,30 +73,35 @@ Then provision accounts:
|
|
52
73
|
NOTE: Control Tower accounts need to be provisioned one at a time. It takes
|
53
74
|
approximately 20 mins to provision one.
|
54
75
|
|
55
|
-
|
76
|
+
== Install tfctl
|
56
77
|
|
78
|
+
[source,shell]
|
57
79
|
----
|
58
80
|
git clone git@github.com:scalefactory/tfctl.git
|
59
81
|
cd tfctl/ && sudo make install
|
60
82
|
----
|
61
83
|
|
62
|
-
|
84
|
+
== Set up AWS resources
|
63
85
|
|
64
86
|
It's assumed you have configured AWS CLI access to the primary account.
|
65
87
|
|
66
88
|
We'll use CloudFormation templates in `examples/bootstrap/`.
|
67
89
|
|
68
|
-
First export configuration using environment variables making sure to change to
|
69
|
-
values to suit your
|
90
|
+
First export configuration using environment variables, making sure to change to
|
91
|
+
values to suit your setup:
|
70
92
|
|
93
|
+
[source,shell]
|
71
94
|
----
|
72
|
-
|
73
|
-
export
|
95
|
+
# Change these to match your setup
|
96
|
+
export PRIMARY_ACCOUNT_ID=123456789012
|
97
|
+
export SHARED_SERVICES_ACCOUNT_ID=345678901234
|
74
98
|
export STATE_BUCKET_NAME='example-terraform-state'
|
99
|
+
export AWS_REGION=eu-west-1
|
75
100
|
----
|
76
101
|
|
77
102
|
Create the remote state resources stack set:
|
78
103
|
|
104
|
+
[source,shell]
|
79
105
|
----
|
80
106
|
cd examples/bootstrap/
|
81
107
|
|
@@ -87,31 +113,34 @@ aws cloudformation create-stack-set \
|
|
87
113
|
--execution-role-name AWSControlTowerExecution \
|
88
114
|
--administration-role-arn arn:aws:iam::${PRIMARY_ACCOUNT_ID}:role/service-role/AWSControlTowerStackSetRole \
|
89
115
|
--parameters ParameterKey=PrimaryAccountId,ParameterValue=${PRIMARY_ACCOUNT_ID} \
|
90
|
-
ParameterKey=TerraformStateBucket,ParameterValue
|
116
|
+
ParameterKey=TerraformStateBucket,ParameterValue="${STATE_BUCKET_NAME}"
|
91
117
|
----
|
92
118
|
|
93
|
-
Create a stack set instance in
|
119
|
+
Create a stack set instance in your shared services account:
|
94
120
|
|
121
|
+
[source,shell]
|
95
122
|
----
|
96
123
|
aws cloudformation create-stack-instances \
|
97
124
|
--stack-set-name TerraformState \
|
98
125
|
--accounts ${SHARED_SERVICES_ACCOUNT_ID} \
|
99
|
-
--regions
|
126
|
+
--regions ${AWS_REGION}
|
100
127
|
----
|
101
128
|
|
102
129
|
Check status:
|
103
130
|
|
131
|
+
[source,shell]
|
104
132
|
----
|
105
133
|
aws cloudformation describe-stack-instance \
|
106
134
|
--stack-set-name TerraformState \
|
107
135
|
--stack-instance-account ${SHARED_SERVICES_ACCOUNT_ID} \
|
108
|
-
--stack-instance-region
|
136
|
+
--stack-instance-region ${AWS_REGION}
|
109
137
|
----
|
110
138
|
|
111
139
|
NOTE: Initial status will be `OUTDATED`, it should change to `CURRENT` once deployed.
|
112
140
|
|
113
|
-
Deploy `TfctlOrgAccess` IAM role stack:
|
141
|
+
Deploy the `TfctlOrgAccess` IAM role stack:
|
114
142
|
|
143
|
+
[source,shell]
|
115
144
|
----
|
116
145
|
aws cloudformation create-stack \
|
117
146
|
--stack-name TfctlOrgAccess \
|
@@ -122,70 +151,79 @@ aws cloudformation create-stack \
|
|
122
151
|
|
123
152
|
Check status:
|
124
153
|
|
154
|
+
[source,shell]
|
125
155
|
----
|
126
156
|
aws cloudformation describe-stacks --stack-name TfctlOrgAccess
|
127
157
|
----
|
128
158
|
|
129
159
|
NOTE: Successful status should read: `CREATE_COMPLETE`.
|
130
160
|
|
131
|
-
|
161
|
+
== Configure tfctl
|
132
162
|
|
133
163
|
Copy the example project directory `examples/control_tower` somewhere convenient
|
134
|
-
and edit `
|
164
|
+
and edit `tfctl.yaml`.
|
135
165
|
|
136
166
|
You need to modify the following parameters:
|
137
167
|
|
138
168
|
* `tf_state_bucket` - set to `$STATE_BUCKET_NAME`
|
139
169
|
* `tf_state_role_arn` - set shared services account ID
|
140
170
|
* `tfctl_role_arn` - set primary account ID
|
141
|
-
* `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.
|
142
172
|
|
143
173
|
TIP: You should keep your project directory under version control.
|
144
174
|
|
145
|
-
|
175
|
+
== Deploy example tfctl profile
|
146
176
|
|
147
177
|
The example profile will create an S3 bucket in accounts under `test`, `live`
|
148
178
|
and `mgmt` OUs.
|
149
179
|
|
150
180
|
NOTE: Run tfctl commands from the root of you project directory.
|
151
181
|
|
152
|
-
First dump the configuration to verify everything works:
|
182
|
+
First, dump the configuration to verify everything works:
|
153
183
|
|
184
|
+
[source,shell]
|
154
185
|
----
|
155
|
-
tfctl -
|
186
|
+
tfctl -s
|
156
187
|
----
|
157
188
|
|
158
|
-
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,
|
159
190
|
merged configuration data. It should contain a list of discovered accounts and
|
160
191
|
their configuration.
|
161
192
|
|
162
|
-
Initialise
|
193
|
+
Initialise Terraform for all discovered accounts:
|
163
194
|
|
195
|
+
[source,shell]
|
164
196
|
----
|
165
|
-
tfctl
|
197
|
+
tfctl --all -- init
|
166
198
|
----
|
167
199
|
|
168
200
|
Tfctl will run Terraform against all accounts in parallel.
|
169
201
|
|
170
|
-
|
202
|
+
`plan` the Terraform:
|
171
203
|
|
204
|
+
[source,shell]
|
172
205
|
----
|
173
|
-
tfctl
|
206
|
+
tfctl --all -- plan
|
174
207
|
----
|
175
208
|
|
176
|
-
and apply:
|
209
|
+
and `apply` it:
|
177
210
|
|
211
|
+
[source,shell]
|
178
212
|
----
|
179
|
-
tfctl
|
213
|
+
tfctl --all -- apply
|
180
214
|
----
|
181
215
|
|
182
|
-
To destroy created resources run:
|
183
216
|
|
217
|
+
== Clean up
|
218
|
+
|
219
|
+
To destroy created resources, run:
|
220
|
+
|
221
|
+
[source,shell]
|
184
222
|
----
|
185
|
-
tfctl
|
223
|
+
tfctl --all -- destroy -auto-approve
|
186
224
|
----
|
187
225
|
|
188
|
-
That's it! You can now execute
|
226
|
+
That's it! You can now execute Terraform across your Control Tower estate.
|
189
227
|
|
190
228
|
TIP: Your project directory should be under version control excluding the
|
191
229
|
`.tfctl` directory which is automatically generated.
|
@@ -1,9 +1,31 @@
|
|
1
|
-
|
1
|
+
// Settings:
|
2
|
+
:idprefix:
|
3
|
+
:idseparator: -
|
4
|
+
ifndef::env-github[:icons: font]
|
5
|
+
ifdef::env-github,env-browser[]
|
6
|
+
:toc: macro
|
7
|
+
:toclevels: 1
|
8
|
+
endif::[]
|
9
|
+
ifdef::env-github[]
|
10
|
+
:branch: master
|
11
|
+
:status:
|
12
|
+
:outfilesuffix: .adoc
|
13
|
+
:!toc-title:
|
14
|
+
:caution-caption: :fire:
|
15
|
+
:important-caption: :exclamation:
|
16
|
+
:note-caption: :paperclip:
|
17
|
+
:tip-caption: :bulb:
|
18
|
+
:warning-caption: :warning:
|
19
|
+
endif::[]
|
20
|
+
|
21
|
+
= Creating and deploying a tfctl profile
|
2
22
|
|
3
23
|
This guide will show you how to create a tfctl profile, declare some resources
|
4
24
|
in it and deploy it to to a group of accounts in an organization unit.
|
5
25
|
|
6
|
-
|
26
|
+
toc::[]
|
27
|
+
|
28
|
+
== Create a new profile
|
7
29
|
|
8
30
|
In your tfctl project directory create a new profile:
|
9
31
|
|
@@ -59,7 +81,7 @@ profile. Tfctl configuration can be accessed using this variable. This It
|
|
59
81
|
includes an array of all discovered accounts as well their parameters from
|
60
82
|
tfctl config file.
|
61
83
|
|
62
|
-
TIP: You can run `tfctl -
|
84
|
+
TIP: You can run `tfctl -s` to show the config data in
|
63
85
|
yaml format. This exact data is available in the `config` variable in your
|
64
86
|
profile.
|
65
87
|
|
@@ -87,7 +109,7 @@ resource "aws_s3_bucket" "example" {
|
|
87
109
|
This will create an S3 bucket with a name containing the current account name
|
88
110
|
(which will vary depending on which account it's deployed to).
|
89
111
|
|
90
|
-
|
112
|
+
== Assign profile to accounts
|
91
113
|
|
92
114
|
Before you can deploy the new profile you need to tell `tfctl` which accounts
|
93
115
|
to deploy it to.
|
@@ -102,7 +124,7 @@ You have few options here:
|
|
102
124
|
For the sake of this example we're going to deploy our bucket to all accounts
|
103
125
|
in `test` OU.
|
104
126
|
|
105
|
-
In tfctl
|
127
|
+
In `tfctl.yaml` add the profile to the `test` OU:
|
106
128
|
|
107
129
|
[source, yaml]
|
108
130
|
----
|
@@ -113,13 +135,13 @@ organization_units:
|
|
113
135
|
----
|
114
136
|
|
115
137
|
|
116
|
-
|
138
|
+
== Plan
|
117
139
|
|
118
140
|
To see what would happen when the change is applied run:
|
119
141
|
|
120
142
|
----
|
121
|
-
tfctl -
|
122
|
-
tfctl -
|
143
|
+
tfctl -o test -- init
|
144
|
+
tfctl -o test -- plan
|
123
145
|
----
|
124
146
|
|
125
147
|
This will run `terraform init` to initialise terraform and then `terraform
|
@@ -161,9 +183,9 @@ what went wrong.
|
|
161
183
|
tfctl will generate a plan file automatically and use it with `apply` in the
|
162
184
|
next step.
|
163
185
|
|
164
|
-
|
186
|
+
== Apply
|
165
187
|
|
166
188
|
Once you're happy with the plan, apply it.
|
167
189
|
----
|
168
|
-
tfctl -
|
190
|
+
tfctl -o test -- apply
|
169
191
|
----
|
data/docs/iam_permissions.adoc
CHANGED
@@ -1,6 +1,26 @@
|
|
1
|
-
|
1
|
+
// Settings:
|
2
|
+
:idprefix:
|
3
|
+
:idseparator: -
|
4
|
+
ifndef::env-github[:icons: font]
|
5
|
+
ifdef::env-github,env-browser[]
|
6
|
+
:toc: macro
|
7
|
+
:toclevels: 1
|
8
|
+
endif::[]
|
9
|
+
ifdef::env-github[]
|
10
|
+
:branch: master
|
11
|
+
:status:
|
12
|
+
:outfilesuffix: .adoc
|
13
|
+
:!toc-title:
|
14
|
+
:caution-caption: :fire:
|
15
|
+
:important-caption: :exclamation:
|
16
|
+
:note-caption: :paperclip:
|
17
|
+
:tip-caption: :bulb:
|
18
|
+
:warning-caption: :warning:
|
19
|
+
endif::[]
|
2
20
|
|
3
|
-
|
21
|
+
= IAM roles
|
22
|
+
|
23
|
+
`tfctl` usually requires three IAM roles to be configured:
|
4
24
|
|
5
25
|
* `TfctlRole` - read only access to AWS Organizations set up in the primary account.
|
6
26
|
* `TerraformStateRole` - access to remote state resources (S3, DynamoDB) in the
|
@@ -8,7 +28,7 @@ Tfctl usually requires three IAM roles to be configured:
|
|
8
28
|
* `TerraformExecutionRole` - configured in all spoke accounts and used for executing Terraform.
|
9
29
|
|
10
30
|
The user executing tfctl needs permission to assume all three roles cross
|
11
|
-
account.
|
31
|
+
account. Once these are configured, tfctl automatically assumes roles for you.
|
12
32
|
|
13
33
|
It's possible to configure different Terraform execution roles in different
|
14
34
|
spoke accounts based on OU or account names. This can be used to restrict
|
data/docs/project_layout.adoc
CHANGED
@@ -1,10 +1,29 @@
|
|
1
|
-
|
1
|
+
// Settings:
|
2
|
+
:idprefix:
|
3
|
+
:idseparator: -
|
4
|
+
ifndef::env-github[:icons: font]
|
5
|
+
ifdef::env-github,env-browser[]
|
6
|
+
:toc: macro
|
7
|
+
:toclevels: 1
|
8
|
+
endif::[]
|
9
|
+
ifdef::env-github[]
|
10
|
+
:branch: master
|
11
|
+
:status:
|
12
|
+
:outfilesuffix: .adoc
|
13
|
+
:!toc-title:
|
14
|
+
:caution-caption: :fire:
|
15
|
+
:important-caption: :exclamation:
|
16
|
+
:note-caption: :paperclip:
|
17
|
+
:tip-caption: :bulb:
|
18
|
+
:warning-caption: :warning:
|
19
|
+
endif::[]
|
20
|
+
|
21
|
+
= Project layout
|
2
22
|
|
3
23
|
Example project structure
|
4
24
|
----
|
5
25
|
project_dir/
|
6
|
-
├── conf
|
7
|
-
│ └── example.yaml
|
26
|
+
├── tfctl.conf
|
8
27
|
├── modules
|
9
28
|
│ └── s3-bucket
|
10
29
|
│ ├── main.tf
|
@@ -16,7 +35,9 @@ project_dir/
|
|
16
35
|
└── variables.tf
|
17
36
|
----
|
18
37
|
|
19
|
-
|
38
|
+
toc::[]
|
39
|
+
|
40
|
+
== tfctl configuration file
|
20
41
|
|
21
42
|
Assigns Terraform profiles and configuration to accounts based on:
|
22
43
|
|
@@ -29,7 +50,12 @@ The configuration data is exposed to terraform via a profile `config` variable.
|
|
29
50
|
It also defines Terraform and tfctl configuration such as state tracking and
|
30
51
|
what IAM roles to use.
|
31
52
|
|
32
|
-
|
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`
|
33
59
|
|
34
60
|
Profiles are re-usable collections of resources which can be applied to
|
35
61
|
accounts. They are implemented just like usual modules but provide an
|
@@ -38,6 +64,6 @@ other data sources). Profiles often compose multiple modules and provide
|
|
38
64
|
configuration data to them. This approach makes it possible to re-use standard
|
39
65
|
modules (e.g. Terraform module registry).
|
40
66
|
|
41
|
-
|
67
|
+
== `modules`
|
42
68
|
|
43
69
|
Standard Terraform modules.
|
@@ -12,8 +12,6 @@
|
|
12
12
|
# Terraform configuration
|
13
13
|
#
|
14
14
|
|
15
|
-
# State management
|
16
|
-
|
17
15
|
tf_state_bucket: 'CHANGEME'
|
18
16
|
tf_state_dynamodb_table: 'terraform-lock'
|
19
17
|
tf_state_region: 'eu-west-1'
|
@@ -26,47 +24,57 @@ aws_provider_version: '>= 2.14'
|
|
26
24
|
tfctl_role_arn: 'arn:aws:iam::PRIMARY_ACCOUNT_ID:role/TfctlRole'
|
27
25
|
|
28
26
|
#
|
29
|
-
#
|
27
|
+
# Data
|
28
|
+
#
|
29
|
+
# Here you can add arbitrary data which will be accessible from Terraform
|
30
|
+
# profiles. Data can also be defined per account in the organization sections
|
31
|
+
# below.
|
30
32
|
#
|
33
|
+
# data:
|
34
|
+
# my_parameter: some_value
|
31
35
|
|
36
|
+
#
|
37
|
+
# Organization configuration
|
38
|
+
#
|
39
|
+
# Assign resources and data to accounts based on the organization structure.
|
40
|
+
#
|
32
41
|
# IMPORTANT: Removing a Terraform profile here will remove all of it's
|
33
|
-
# associated resources
|
34
|
-
|
35
|
-
# Name of the primary account.
|
36
|
-
primary_account: CHANGEME
|
42
|
+
# associated resources during next apply!
|
37
43
|
|
38
|
-
# Configuration to apply
|
44
|
+
# Configuration to apply to all accounts
|
39
45
|
organization_root:
|
40
|
-
|
41
46
|
# Role assumed by Terraform for execution in each account
|
42
47
|
tf_execution_role: 'AWSControlTowerExecution'
|
43
48
|
region: 'eu-west-1'
|
44
|
-
|
45
|
-
|
46
|
-
|
49
|
+
data:
|
50
|
+
# Bucket name used by example profile it will be prefixed with the target
|
51
|
+
# account number for uniqueness across accounts.
|
52
|
+
example_bucket_name: 'tfctl-example-bucket'
|
47
53
|
# Assign example-profile to all accounts in managed OUs
|
48
54
|
profiles:
|
49
55
|
- example-profile
|
50
56
|
|
51
57
|
# Configuration to apply to accounts in Organization Units
|
52
|
-
#
|
58
|
+
# OU's not listed here will be ignored.
|
53
59
|
organization_units:
|
54
|
-
# Uncomment if you want to include Core OU accounts
|
55
|
-
# Core: {}
|
60
|
+
# Core: {} # Uncomment if you want to include Core OU accounts
|
56
61
|
live: {}
|
57
62
|
test: {}
|
58
63
|
mgmt:
|
59
|
-
|
60
|
-
|
64
|
+
data:
|
65
|
+
# Override the example bucket name in mgmt OU accounts
|
66
|
+
example_bucket_name: 'tfctl-ou-override-example'
|
61
67
|
|
62
68
|
# Configuration to apply to individual accounts
|
63
69
|
account_overrides:
|
64
70
|
test-example1:
|
65
|
-
|
66
|
-
|
71
|
+
data:
|
72
|
+
# Override the bucket name in a specific account
|
73
|
+
example_bucket_name: 'tfctl-account-override-example'
|
67
74
|
|
68
75
|
|
69
|
-
# Exclude individual accounts from Terraform runs
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
76
|
+
# Exclude individual accounts from Terraform runs
|
77
|
+
#
|
78
|
+
# exclude_accounts:
|
79
|
+
# - Audit
|
80
|
+
# - 'Log archive'
|