@intentius/chant-lexicon-terraform 0.124.44 → 0.124.46
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.
- package/dist/__fixtures__/capabilities/chant.config.d.ts +26 -0
- package/dist/__fixtures__/capabilities/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/capabilities/chant.config.js +13 -0
- package/dist/__fixtures__/effective-topology/chant.config.d.ts +13 -0
- package/dist/__fixtures__/effective-topology/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/effective-topology/chant.config.js +9 -0
- package/dist/__fixtures__/kind-type/chant.config.d.ts +13 -0
- package/dist/__fixtures__/kind-type/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/kind-type/chant.config.js +9 -0
- package/dist/__fixtures__/search-roots/chant.config.d.ts +13 -0
- package/dist/__fixtures__/search-roots/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/search-roots/chant.config.js +9 -0
- package/dist/__fixtures__/sensitive-default/chant.config.d.ts +13 -0
- package/dist/__fixtures__/sensitive-default/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/sensitive-default/chant.config.js +9 -0
- package/dist/capabilities/adapter.d.ts +9 -0
- package/dist/capabilities/adapter.d.ts.map +1 -0
- package/dist/capabilities/adapter.js +25 -0
- package/dist/capabilities/mapping.json +166 -0
- package/dist/config.d.ts +52 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -0
- package/dist/describe-resources.d.ts +101 -8
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +395 -56
- package/dist/hcl/parse.d.ts +10 -0
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/parse.js +20 -2
- package/dist/hcl/redact.d.ts +26 -0
- package/dist/hcl/redact.d.ts.map +1 -0
- package/dist/hcl/redact.js +228 -0
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/activities/terraform.d.ts +109 -4
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +148 -7
- package/dist/plan-observation.d.ts +153 -0
- package/dist/plan-observation.d.ts.map +1 -0
- package/dist/plan-observation.js +354 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -0
- package/package.json +2 -2
- package/src/__fixtures__/ACCEPTANCE.md +53 -1
- package/src/__fixtures__/capabilities/catalog/main.tf +105 -0
- package/src/__fixtures__/capabilities/chant.config.ts +15 -0
- package/src/__fixtures__/capabilities/findings/main.tf +225 -0
- package/src/__fixtures__/capabilities/ledger/main.tf +265 -0
- package/src/__fixtures__/capabilities/package.json +1 -0
- package/src/__fixtures__/effective-topology/chant.config.ts +11 -0
- package/src/__fixtures__/effective-topology/net/main.tf +176 -0
- package/src/__fixtures__/effective-topology/package.json +6 -0
- package/src/__fixtures__/kind-type/app/main.tf +35 -0
- package/src/__fixtures__/kind-type/chant.config.ts +11 -0
- package/src/__fixtures__/kind-type/package.json +6 -0
- package/src/__fixtures__/live-plan-depth/README.md +59 -0
- package/src/__fixtures__/live-plan-depth/live-plan.json +110 -0
- package/src/__fixtures__/live-plan-depth/show-plan-sensitive.json +1 -0
- package/src/__fixtures__/live-plan-depth/show-plan.json +1 -0
- package/src/__fixtures__/plan-read/main.tf +46 -0
- package/src/__fixtures__/plan-read/next.tfvars +1 -0
- package/src/__fixtures__/plan-read-drift/README.md +33 -0
- package/src/__fixtures__/plan-read-drift/main.tf +63 -0
- package/src/__fixtures__/plan-read-drift/next.tfvars +1 -0
- package/src/__fixtures__/search-roots/chant.config.ts +11 -0
- package/src/__fixtures__/search-roots/net/main.tf +73 -0
- package/src/__fixtures__/search-roots/package.json +6 -0
- package/src/__fixtures__/sensitive-default/chant.config.ts +11 -0
- package/src/__fixtures__/sensitive-default/net/main.tf +38 -0
- package/src/__fixtures__/sensitive-default/package.json +6 -0
- package/src/__fixtures__/show-plan.json +663 -0
- package/src/capabilities/adapter.ts +32 -0
- package/src/capabilities/mapping.json +166 -0
- package/src/capabilities-workspace.e2e.test.ts +251 -0
- package/src/capabilities.test.ts +264 -0
- package/src/config.ts +26 -0
- package/src/describe-resources.live-plan.test.ts +302 -0
- package/src/describe-resources.live-root-unchanged.test.ts +126 -0
- package/src/describe-resources.plan.test.ts +437 -0
- package/src/describe-resources.ts +445 -52
- package/src/effective-topology.test.ts +134 -0
- package/src/hcl/parse.ts +30 -2
- package/src/hcl/redact.ts +181 -0
- package/src/live-plan-depth.acceptance.e2e.test.ts +193 -0
- package/src/op/activities/terraform.test.ts +118 -1
- package/src/op/activities/terraform.ts +213 -9
- package/src/plan-observation.ts +428 -0
- package/src/plan-read.acceptance.test.ts +184 -0
- package/src/plugin.ts +2 -0
- package/src/redact-ir.e2e.test.ts +79 -0
- package/src/redact.test.ts +111 -0
- package/src/search-build-roots.test.ts +125 -0
- package/src/search-count.test.ts +144 -0
- package/src/search-kind-type.test.ts +136 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# The -findings layer of choudoufu terralith-gen -scale 4 -findings (INTENTIUS/choudoufu#2199),
|
|
2
|
+
# copied from its bastion.tf, data.tf and network.tf, for behold#912 steps 4 and 6 (#4375).
|
|
3
|
+
resource "aws_vpc" "main" {
|
|
4
|
+
cidr_block = "10.42.0.0/16"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
resource "aws_subnet" "main" {
|
|
8
|
+
vpc_id = aws_vpc.main.id
|
|
9
|
+
cidr_block = "10.42.1.0/24"
|
|
10
|
+
availability_zone = "us-east-1a"
|
|
11
|
+
|
|
12
|
+
tags = {
|
|
13
|
+
Name = "tl-subnet"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
resource "aws_security_group" "ecs" {
|
|
18
|
+
name = "tl-ecs-sg"
|
|
19
|
+
description = "terralith-gen: shared security group for the container-service layer"
|
|
20
|
+
vpc_id = aws_vpc.main.id
|
|
21
|
+
|
|
22
|
+
egress {
|
|
23
|
+
from_port = 0
|
|
24
|
+
to_port = 0
|
|
25
|
+
protocol = "-1"
|
|
26
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
resource "aws_internet_gateway" "main" {
|
|
32
|
+
vpc_id = aws_vpc.main.id
|
|
33
|
+
|
|
34
|
+
tags = {
|
|
35
|
+
Name = "tl-igw"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
resource "aws_subnet" "public" {
|
|
40
|
+
vpc_id = aws_vpc.main.id
|
|
41
|
+
cidr_block = "10.42.2.0/24"
|
|
42
|
+
availability_zone = "us-east-1a"
|
|
43
|
+
map_public_ip_on_launch = true
|
|
44
|
+
|
|
45
|
+
tags = {
|
|
46
|
+
Name = "tl-public"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
resource "aws_route_table" "public" {
|
|
51
|
+
vpc_id = aws_vpc.main.id
|
|
52
|
+
|
|
53
|
+
route {
|
|
54
|
+
cidr_block = "0.0.0.0/0"
|
|
55
|
+
gateway_id = aws_internet_gateway.main.id
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
tags = {
|
|
59
|
+
Name = "tl-public"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
resource "aws_route_table_association" "public" {
|
|
64
|
+
subnet_id = aws_subnet.public.id
|
|
65
|
+
route_table_id = aws_route_table.public.id
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
resource "aws_security_group" "bastion" {
|
|
69
|
+
name = "tl-bastion-sg"
|
|
70
|
+
description = "terralith-gen: the bastion's security group"
|
|
71
|
+
vpc_id = aws_vpc.main.id
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
resource "aws_vpc_security_group_ingress_rule" "bastion_ssh" {
|
|
75
|
+
security_group_id = aws_security_group.bastion.id
|
|
76
|
+
description = "ssh from anywhere"
|
|
77
|
+
ip_protocol = "tcp"
|
|
78
|
+
from_port = 22
|
|
79
|
+
to_port = 22
|
|
80
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
resource "aws_launch_template" "bastion" {
|
|
84
|
+
name = "tl-bastion"
|
|
85
|
+
image_id = "ami-12345678"
|
|
86
|
+
instance_type = "t3.micro"
|
|
87
|
+
vpc_security_group_ids = [aws_security_group.bastion.id]
|
|
88
|
+
|
|
89
|
+
# By arn, not name: floci returns the profile by ARN only (issue #2199).
|
|
90
|
+
iam_instance_profile {
|
|
91
|
+
arn = aws_iam_instance_profile.app_data.arn
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
resource "aws_instance" "bastion" {
|
|
96
|
+
subnet_id = aws_subnet.public.id
|
|
97
|
+
|
|
98
|
+
launch_template {
|
|
99
|
+
id = aws_launch_template.bastion.id
|
|
100
|
+
version = "$Latest"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
tags = {
|
|
104
|
+
Name = "tl-bastion"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# floci does not return the aws:ec2launchtemplate:id tag the provider
|
|
108
|
+
# reads this block back from, so without this every plan replaces the
|
|
109
|
+
# instance (issue #2199).
|
|
110
|
+
lifecycle {
|
|
111
|
+
ignore_changes = [launch_template]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
resource "aws_subnet" "db_a" {
|
|
116
|
+
vpc_id = aws_vpc.main.id
|
|
117
|
+
cidr_block = "10.42.10.0/24"
|
|
118
|
+
availability_zone = "us-east-1a"
|
|
119
|
+
|
|
120
|
+
tags = {
|
|
121
|
+
Name = "tl-db-a"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
resource "aws_subnet" "db_b" {
|
|
126
|
+
vpc_id = aws_vpc.main.id
|
|
127
|
+
cidr_block = "10.42.11.0/24"
|
|
128
|
+
availability_zone = "us-east-1b"
|
|
129
|
+
|
|
130
|
+
tags = {
|
|
131
|
+
Name = "tl-db-b"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
resource "aws_db_subnet_group" "orders" {
|
|
136
|
+
name = "tl-orders"
|
|
137
|
+
subnet_ids = [aws_subnet.db_a.id, aws_subnet.db_b.id]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# storage_encrypted = true forces replacement; identifier and
|
|
141
|
+
# engine_version update in place on provider 6.59.0 (issue #2199).
|
|
142
|
+
resource "aws_db_instance" "orders" {
|
|
143
|
+
identifier = "tl-orders"
|
|
144
|
+
engine = "postgres"
|
|
145
|
+
engine_version = "16.3"
|
|
146
|
+
instance_class = "db.t3.micro"
|
|
147
|
+
allocated_storage = 20
|
|
148
|
+
db_name = "orders"
|
|
149
|
+
username = "orders_admin"
|
|
150
|
+
password = "emulator-only-not-a-secret"
|
|
151
|
+
db_subnet_group_name = aws_db_subnet_group.orders.name
|
|
152
|
+
storage_encrypted = false
|
|
153
|
+
skip_final_snapshot = true
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
resource "aws_dynamodb_table" "sessions" {
|
|
157
|
+
name = "tl-sessions"
|
|
158
|
+
billing_mode = "PAY_PER_REQUEST"
|
|
159
|
+
hash_key = "id"
|
|
160
|
+
|
|
161
|
+
attribute {
|
|
162
|
+
name = "id"
|
|
163
|
+
type = "S"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
resource "aws_iam_role" "app_data" {
|
|
168
|
+
name = "tl-app-data-role"
|
|
169
|
+
assume_role_policy = jsonencode({
|
|
170
|
+
Version = "2012-10-17"
|
|
171
|
+
Statement = [{
|
|
172
|
+
Effect = "Allow"
|
|
173
|
+
Action = "sts:AssumeRole"
|
|
174
|
+
Principal = { Service = "ec2.amazonaws.com" }
|
|
175
|
+
}]
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
resource "aws_iam_policy" "app_data" {
|
|
180
|
+
name = "tl-app-data"
|
|
181
|
+
policy = jsonencode({
|
|
182
|
+
Version = "2012-10-17"
|
|
183
|
+
Statement = [{
|
|
184
|
+
Effect = "Allow"
|
|
185
|
+
Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:DeleteItem"]
|
|
186
|
+
Resource = aws_dynamodb_table.sessions.arn
|
|
187
|
+
}]
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
resource "aws_iam_role_policy_attachment" "app_data" {
|
|
192
|
+
role = aws_iam_role.app_data.name
|
|
193
|
+
policy_arn = aws_iam_policy.app_data.arn
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
resource "aws_iam_instance_profile" "app_data" {
|
|
197
|
+
name = "tl-app-data"
|
|
198
|
+
role = aws_iam_role.app_data.name
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
# One of the eight team roles with dynamodb actions on Resource = "*" (iam.tf).
|
|
202
|
+
resource "aws_iam_role" "team_0002_role" {
|
|
203
|
+
name = "tl-team-0002-role"
|
|
204
|
+
assume_role_policy = jsonencode({
|
|
205
|
+
Version = "2012-10-17"
|
|
206
|
+
Statement = [{
|
|
207
|
+
Effect = "Allow"
|
|
208
|
+
Action = "sts:AssumeRole"
|
|
209
|
+
Principal = { Service = "lambda.amazonaws.com" }
|
|
210
|
+
}]
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
resource "aws_iam_role_policy" "team_0002_inline" {
|
|
215
|
+
name = "tl-team-0002-inline"
|
|
216
|
+
role = aws_iam_role.team_0002_role.name
|
|
217
|
+
policy = jsonencode({
|
|
218
|
+
Version = "2012-10-17"
|
|
219
|
+
Statement = [{
|
|
220
|
+
Effect = "Allow"
|
|
221
|
+
Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem"]
|
|
222
|
+
Resource = "*"
|
|
223
|
+
}]
|
|
224
|
+
})
|
|
225
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# "ledger": the Terraform form of the estate chant#4361 measured the rule language on (#4375).
|
|
2
|
+
terraform {
|
|
3
|
+
required_providers {
|
|
4
|
+
aws = { source = "hashicorp/aws", version = "~> 6.0" }
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
provider "aws" { region = "us-east-1" }
|
|
8
|
+
|
|
9
|
+
locals {
|
|
10
|
+
ami = "ami-0f3f13f145e66a0a3"
|
|
11
|
+
restricted = { "data-classification" = "restricted" }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# network
|
|
15
|
+
resource "aws_vpc" "vpc" { cidr_block = "10.0.0.0/16" }
|
|
16
|
+
resource "aws_subnet" "public" {
|
|
17
|
+
vpc_id = aws_vpc.vpc.id
|
|
18
|
+
cidr_block = "10.0.0.0/24"
|
|
19
|
+
}
|
|
20
|
+
resource "aws_subnet" "private" {
|
|
21
|
+
vpc_id = aws_vpc.vpc.id
|
|
22
|
+
cidr_block = "10.0.1.0/24"
|
|
23
|
+
}
|
|
24
|
+
resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.vpc.id }
|
|
25
|
+
resource "aws_route_table" "public" { vpc_id = aws_vpc.vpc.id }
|
|
26
|
+
resource "aws_route_table" "private" { vpc_id = aws_vpc.vpc.id }
|
|
27
|
+
resource "aws_route" "public_default" {
|
|
28
|
+
route_table_id = aws_route_table.public.id
|
|
29
|
+
destination_cidr_block = "0.0.0.0/0"
|
|
30
|
+
gateway_id = aws_internet_gateway.igw.id
|
|
31
|
+
}
|
|
32
|
+
resource "aws_route_table_association" "public" {
|
|
33
|
+
route_table_id = aws_route_table.public.id
|
|
34
|
+
subnet_id = aws_subnet.public.id
|
|
35
|
+
}
|
|
36
|
+
resource "aws_route_table_association" "private" {
|
|
37
|
+
route_table_id = aws_route_table.private.id
|
|
38
|
+
subnet_id = aws_subnet.private.id
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
resource "aws_security_group" "web" {
|
|
42
|
+
description = "web"
|
|
43
|
+
vpc_id = aws_vpc.vpc.id
|
|
44
|
+
ingress {
|
|
45
|
+
protocol = "tcp"
|
|
46
|
+
from_port = 443
|
|
47
|
+
to_port = 443
|
|
48
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
49
|
+
}
|
|
50
|
+
ingress {
|
|
51
|
+
protocol = "tcp"
|
|
52
|
+
from_port = 22
|
|
53
|
+
to_port = 22
|
|
54
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
resource "aws_security_group" "app" {
|
|
58
|
+
description = "app"
|
|
59
|
+
vpc_id = aws_vpc.vpc.id
|
|
60
|
+
}
|
|
61
|
+
resource "aws_vpc_security_group_ingress_rule" "app_from_web" {
|
|
62
|
+
security_group_id = aws_security_group.app.id
|
|
63
|
+
ip_protocol = "tcp"
|
|
64
|
+
from_port = 8080
|
|
65
|
+
to_port = 8080
|
|
66
|
+
referenced_security_group_id = aws_security_group.web.id
|
|
67
|
+
}
|
|
68
|
+
resource "aws_security_group" "db" {
|
|
69
|
+
description = "db"
|
|
70
|
+
vpc_id = aws_vpc.vpc.id
|
|
71
|
+
ingress {
|
|
72
|
+
protocol = "tcp"
|
|
73
|
+
from_port = 5432
|
|
74
|
+
to_port = 5432
|
|
75
|
+
security_groups = [aws_security_group.app.id]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# data
|
|
80
|
+
resource "aws_s3_bucket" "assets" {}
|
|
81
|
+
resource "aws_s3_bucket" "customer_data" { tags = local.restricted }
|
|
82
|
+
resource "aws_dynamodb_table" "orders" {
|
|
83
|
+
name = "orders"
|
|
84
|
+
hash_key = "id"
|
|
85
|
+
billing_mode = "PAY_PER_REQUEST"
|
|
86
|
+
attribute {
|
|
87
|
+
name = "id"
|
|
88
|
+
type = "S"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
resource "aws_secretsmanager_secret" "db" { name = "ledger-db" }
|
|
92
|
+
resource "aws_secretsmanager_secret_version" "db" {
|
|
93
|
+
secret_id = aws_secretsmanager_secret.db.id
|
|
94
|
+
secret_string = "generated-elsewhere"
|
|
95
|
+
}
|
|
96
|
+
resource "aws_db_instance" "customers" {
|
|
97
|
+
engine = "postgres"
|
|
98
|
+
instance_class = "db.t3.micro"
|
|
99
|
+
allocated_storage = 20
|
|
100
|
+
username = "ledger"
|
|
101
|
+
password = aws_secretsmanager_secret_version.db.secret_string
|
|
102
|
+
vpc_security_group_ids = [aws_security_group.db.id]
|
|
103
|
+
publicly_accessible = false
|
|
104
|
+
storage_encrypted = true
|
|
105
|
+
tags = { "data-classification" = "restricted" }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# identity
|
|
109
|
+
data "aws_iam_policy_document" "ec2_trust" {
|
|
110
|
+
statement {
|
|
111
|
+
actions = ["sts:AssumeRole"]
|
|
112
|
+
principals {
|
|
113
|
+
type = "Service"
|
|
114
|
+
identifiers = ["ec2.amazonaws.com"]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
resource "aws_iam_role" "web" { assume_role_policy = data.aws_iam_policy_document.ec2_trust.json }
|
|
119
|
+
resource "aws_iam_role" "deploy" {
|
|
120
|
+
assume_role_policy = jsonencode({
|
|
121
|
+
Version = "2012-10-17"
|
|
122
|
+
Statement = [{ Effect = "Allow", Principal = { AWS = aws_iam_role.web.arn }, Action = "sts:AssumeRole" }]
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
resource "aws_iam_role_policy" "web" {
|
|
126
|
+
name = "web"
|
|
127
|
+
role = aws_iam_role.web.id
|
|
128
|
+
policy = jsonencode({
|
|
129
|
+
Version = "2012-10-17"
|
|
130
|
+
Statement = [
|
|
131
|
+
{ Effect = "Allow", Action = "s3:GetObject", Resource = "${aws_s3_bucket.assets.arn}/*" },
|
|
132
|
+
{ Effect = "Allow", Action = "sts:AssumeRole", Resource = aws_iam_role.deploy.arn },
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
resource "aws_iam_policy" "deploy" {
|
|
137
|
+
name = "deploy"
|
|
138
|
+
policy = jsonencode({
|
|
139
|
+
Version = "2012-10-17"
|
|
140
|
+
Statement = [
|
|
141
|
+
{ Effect = "Allow", Action = "s3:*", Resource = [aws_s3_bucket.customer_data.arn, "${aws_s3_bucket.customer_data.arn}/*"] },
|
|
142
|
+
{ Effect = "Allow", Action = "secretsmanager:GetSecretValue", Resource = aws_secretsmanager_secret.db.arn },
|
|
143
|
+
]
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
resource "aws_iam_role_policy_attachment" "deploy" {
|
|
147
|
+
role = aws_iam_role.deploy.name
|
|
148
|
+
policy_arn = aws_iam_policy.deploy.arn
|
|
149
|
+
}
|
|
150
|
+
resource "aws_iam_role" "worker" {
|
|
151
|
+
assume_role_policy = data.aws_iam_policy_document.ec2_trust.json
|
|
152
|
+
inline_policy {
|
|
153
|
+
name = "worker"
|
|
154
|
+
policy = jsonencode({
|
|
155
|
+
Version = "2012-10-17"
|
|
156
|
+
Statement = [
|
|
157
|
+
{ Effect = "Allow", Action = "secretsmanager:GetSecretValue", Resource = aws_secretsmanager_secret.db.arn },
|
|
158
|
+
{ Effect = "Allow", Action = ["dynamodb:GetItem", "dynamodb:PutItem"], Resource = aws_dynamodb_table.orders.arn },
|
|
159
|
+
]
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
resource "aws_iam_role" "reporter" {
|
|
164
|
+
assume_role_policy = jsonencode({
|
|
165
|
+
Version = "2012-10-17"
|
|
166
|
+
Statement = [{ Effect = "Allow", Principal = { Service = "lambda.amazonaws.com" }, Action = "sts:AssumeRole" }]
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
resource "aws_iam_policy" "report_read" {
|
|
170
|
+
policy = jsonencode({
|
|
171
|
+
Version = "2012-10-17"
|
|
172
|
+
Statement = [
|
|
173
|
+
{ Effect = "Allow", Action = "s3:GetObject", Resource = "${aws_s3_bucket.customer_data.arn}/*" },
|
|
174
|
+
{ Effect = "Allow", Action = "logs:*", Resource = "*" },
|
|
175
|
+
]
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
resource "aws_iam_role_policy_attachment" "report_read" {
|
|
179
|
+
role = aws_iam_role.reporter.name
|
|
180
|
+
policy_arn = aws_iam_policy.report_read.arn
|
|
181
|
+
}
|
|
182
|
+
resource "aws_iam_role" "batch" {
|
|
183
|
+
assume_role_policy = jsonencode({
|
|
184
|
+
Version = "2012-10-17"
|
|
185
|
+
Statement = [{ Effect = "Allow", Principal = { Service = "lambda.amazonaws.com" }, Action = "sts:AssumeRole" }]
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
resource "aws_iam_role_policy" "batch" {
|
|
189
|
+
role = aws_iam_role.batch.id
|
|
190
|
+
policy = jsonencode({
|
|
191
|
+
Version = "2012-10-17"
|
|
192
|
+
Statement = [{ Effect = "Allow", Action = "sts:AssumeRole", Resource = "arn:aws:iam::123456789012:role/audit" }]
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
resource "aws_iam_role" "audit" {
|
|
196
|
+
name = "audit"
|
|
197
|
+
assume_role_policy = jsonencode({
|
|
198
|
+
Version = "2012-10-17"
|
|
199
|
+
Statement = [{ Effect = "Allow", Principal = { AWS = aws_iam_role.batch.arn }, Action = "sts:AssumeRole" }]
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
resource "aws_iam_role_policy" "audit" {
|
|
203
|
+
role = aws_iam_role.audit.id
|
|
204
|
+
policy = jsonencode({
|
|
205
|
+
Version = "2012-10-17"
|
|
206
|
+
Statement = [{ Effect = "Allow", Action = "dynamodb:Scan", Resource = aws_dynamodb_table.orders.arn }]
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
resource "aws_s3_bucket_policy" "assets" {
|
|
210
|
+
bucket = aws_s3_bucket.assets.id
|
|
211
|
+
policy = jsonencode({
|
|
212
|
+
Version = "2012-10-17"
|
|
213
|
+
Statement = [{ Effect = "Allow", Principal = { AWS = aws_iam_role.worker.arn }, Action = "s3:GetObject", Resource = "${aws_s3_bucket.assets.arn}/*" }]
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# compute
|
|
218
|
+
resource "aws_iam_instance_profile" "web" { role = aws_iam_role.web.name }
|
|
219
|
+
resource "aws_iam_instance_profile" "worker" { role = aws_iam_role.worker.name }
|
|
220
|
+
resource "aws_launch_template" "web" {
|
|
221
|
+
image_id = local.ami
|
|
222
|
+
instance_type = "t3.micro"
|
|
223
|
+
vpc_security_group_ids = [aws_security_group.web.id]
|
|
224
|
+
}
|
|
225
|
+
resource "aws_instance" "web" {
|
|
226
|
+
launch_template {
|
|
227
|
+
id = aws_launch_template.web.id
|
|
228
|
+
version = "1"
|
|
229
|
+
}
|
|
230
|
+
subnet_id = aws_subnet.public.id
|
|
231
|
+
iam_instance_profile = aws_iam_instance_profile.web.name
|
|
232
|
+
}
|
|
233
|
+
resource "aws_instance" "worker" {
|
|
234
|
+
ami = local.ami
|
|
235
|
+
instance_type = "t3.micro"
|
|
236
|
+
subnet_id = aws_subnet.private.id
|
|
237
|
+
vpc_security_group_ids = [aws_security_group.app.id]
|
|
238
|
+
iam_instance_profile = aws_iam_instance_profile.worker.name
|
|
239
|
+
}
|
|
240
|
+
# in a public subnet, but nothing on the internet is allowed in
|
|
241
|
+
resource "aws_instance" "admin_box" {
|
|
242
|
+
ami = local.ami
|
|
243
|
+
instance_type = "t3.micro"
|
|
244
|
+
subnet_id = aws_subnet.public.id
|
|
245
|
+
vpc_security_group_ids = [aws_security_group.app.id]
|
|
246
|
+
iam_instance_profile = aws_iam_instance_profile.worker.name
|
|
247
|
+
}
|
|
248
|
+
resource "aws_lambda_function" "reporter" {
|
|
249
|
+
function_name = "reporter"
|
|
250
|
+
runtime = "nodejs22.x"
|
|
251
|
+
handler = "index.handler"
|
|
252
|
+
role = aws_iam_role.reporter.arn
|
|
253
|
+
filename = "fn.zip"
|
|
254
|
+
}
|
|
255
|
+
resource "aws_lambda_function_url" "reporter" {
|
|
256
|
+
function_name = aws_lambda_function.reporter.function_name
|
|
257
|
+
authorization_type = "NONE"
|
|
258
|
+
}
|
|
259
|
+
resource "aws_lambda_function" "batch" {
|
|
260
|
+
function_name = "batch"
|
|
261
|
+
runtime = "nodejs22.x"
|
|
262
|
+
handler = "index.handler"
|
|
263
|
+
role = aws_iam_role.batch.arn
|
|
264
|
+
filename = "fn.zip"
|
|
265
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "chant-fixture-terraform-capabilities", "version": "0.0.0", "private": true, "type": "module" }
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# One VPC, three instances. Only `web` is internet-facing with SSH open to the
|
|
2
|
+
# world, and it gets its SSH rule through a launch template's security group.
|
|
3
|
+
# Every way of writing a route to an internet gateway and every way of writing
|
|
4
|
+
# an ingress rule appears exactly once, each on a path a test pins (chant #4362).
|
|
5
|
+
|
|
6
|
+
resource "aws_vpc" "main" {
|
|
7
|
+
cidr_block = "10.0.0.0/16"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
resource "aws_internet_gateway" "main" {
|
|
11
|
+
vpc_id = aws_vpc.main.id
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# --- Subnets and routing --------------------------------------------------
|
|
15
|
+
|
|
16
|
+
# public_a routes to the IGW through an INLINE `route` block.
|
|
17
|
+
resource "aws_subnet" "public_a" {
|
|
18
|
+
vpc_id = aws_vpc.main.id
|
|
19
|
+
cidr_block = "10.0.1.0/24"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
resource "aws_route_table" "public_inline" {
|
|
23
|
+
vpc_id = aws_vpc.main.id
|
|
24
|
+
|
|
25
|
+
route {
|
|
26
|
+
cidr_block = "0.0.0.0/0"
|
|
27
|
+
gateway_id = aws_internet_gateway.main.id
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resource "aws_route_table_association" "public_a" {
|
|
32
|
+
subnet_id = aws_subnet.public_a.id
|
|
33
|
+
route_table_id = aws_route_table.public_inline.id
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# public_b routes to the IGW through a separate `aws_route` resource.
|
|
37
|
+
resource "aws_subnet" "public_b" {
|
|
38
|
+
vpc_id = aws_vpc.main.id
|
|
39
|
+
cidr_block = "10.0.2.0/24"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
resource "aws_route_table" "public_separate" {
|
|
43
|
+
vpc_id = aws_vpc.main.id
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
resource "aws_route" "public_separate_default" {
|
|
47
|
+
route_table_id = aws_route_table.public_separate.id
|
|
48
|
+
destination_cidr_block = "0.0.0.0/0"
|
|
49
|
+
gateway_id = aws_internet_gateway.main.id
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
resource "aws_route_table_association" "public_b" {
|
|
53
|
+
subnet_id = aws_subnet.public_b.id
|
|
54
|
+
route_table_id = aws_route_table.public_separate.id
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# private's default route goes to a NAT gateway, which is not internet-facing.
|
|
58
|
+
resource "aws_subnet" "private" {
|
|
59
|
+
vpc_id = aws_vpc.main.id
|
|
60
|
+
cidr_block = "10.0.3.0/24"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
resource "aws_eip" "nat" {
|
|
64
|
+
domain = "vpc"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
resource "aws_nat_gateway" "main" {
|
|
68
|
+
allocation_id = aws_eip.nat.id
|
|
69
|
+
subnet_id = aws_subnet.public_a.id
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
resource "aws_route_table" "private" {
|
|
73
|
+
vpc_id = aws_vpc.main.id
|
|
74
|
+
|
|
75
|
+
route {
|
|
76
|
+
cidr_block = "0.0.0.0/0"
|
|
77
|
+
nat_gateway_id = aws_nat_gateway.main.id
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
resource "aws_route_table_association" "private" {
|
|
82
|
+
subnet_id = aws_subnet.private.id
|
|
83
|
+
route_table_id = aws_route_table.private.id
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# --- Security groups ------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
# web: SSH open to the world through an INLINE `ingress` block.
|
|
89
|
+
resource "aws_security_group" "web" {
|
|
90
|
+
vpc_id = aws_vpc.main.id
|
|
91
|
+
|
|
92
|
+
ingress {
|
|
93
|
+
protocol = "tcp"
|
|
94
|
+
from_port = 22
|
|
95
|
+
to_port = 22
|
|
96
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
egress {
|
|
100
|
+
protocol = "-1"
|
|
101
|
+
from_port = 0
|
|
102
|
+
to_port = 0
|
|
103
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# batch: HTTPS through an `aws_vpc_security_group_ingress_rule` resource.
|
|
108
|
+
resource "aws_security_group" "batch" {
|
|
109
|
+
vpc_id = aws_vpc.main.id
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
resource "aws_vpc_security_group_ingress_rule" "batch_https" {
|
|
113
|
+
security_group_id = aws_security_group.batch.id
|
|
114
|
+
ip_protocol = "tcp"
|
|
115
|
+
from_port = 443
|
|
116
|
+
to_port = 443
|
|
117
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# db: SSH open to the world through an `aws_security_group_rule` resource. The
|
|
121
|
+
# egress rule beside it is not ingress and must not be counted.
|
|
122
|
+
resource "aws_security_group" "db" {
|
|
123
|
+
vpc_id = aws_vpc.main.id
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
resource "aws_security_group_rule" "db_ssh" {
|
|
127
|
+
type = "ingress"
|
|
128
|
+
security_group_id = aws_security_group.db.id
|
|
129
|
+
protocol = "tcp"
|
|
130
|
+
from_port = 22
|
|
131
|
+
to_port = 22
|
|
132
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
resource "aws_security_group_rule" "db_egress" {
|
|
136
|
+
type = "egress"
|
|
137
|
+
security_group_id = aws_security_group.db.id
|
|
138
|
+
protocol = "-1"
|
|
139
|
+
from_port = 0
|
|
140
|
+
to_port = 0
|
|
141
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# --- Instances ------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
resource "aws_launch_template" "web" {
|
|
147
|
+
image_id = "ami-12345678"
|
|
148
|
+
instance_type = "t3.micro"
|
|
149
|
+
vpc_security_group_ids = [aws_security_group.web.id]
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# Public, SSH open to the world via the launch template's group. The one match.
|
|
153
|
+
resource "aws_instance" "web" {
|
|
154
|
+
subnet_id = aws_subnet.public_a.id
|
|
155
|
+
|
|
156
|
+
launch_template {
|
|
157
|
+
id = aws_launch_template.web.id
|
|
158
|
+
version = "$Latest"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Public (through the aws_route spelling), HTTPS only, group via `security_groups`.
|
|
163
|
+
resource "aws_instance" "batch" {
|
|
164
|
+
ami = "ami-12345678"
|
|
165
|
+
instance_type = "t3.micro"
|
|
166
|
+
subnet_id = aws_subnet.public_b.id
|
|
167
|
+
security_groups = [aws_security_group.batch.id]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# Private, SSH open to the world via `vpc_security_group_ids`. Not reachable.
|
|
171
|
+
resource "aws_instance" "db" {
|
|
172
|
+
ami = "ami-12345678"
|
|
173
|
+
instance_type = "t3.micro"
|
|
174
|
+
subnet_id = aws_subnet.private.id
|
|
175
|
+
vpc_security_group_ids = [aws_security_group.db.id]
|
|
176
|
+
}
|