Skip to content

Commit 3d770e1

Browse files
committed
finalize protect-against-rds-instance-deletion
1 parent 029262b commit 3d770e1

File tree

8 files changed

+675
-8
lines changed

8 files changed

+675
-8
lines changed

governance/third-generation/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Each of these modules has several types of functions:
7272
* `resources`: a map consisting of resource changes (for tfplan/v2) or resources (for tfstate/v2) or blocks that violate a condition.
7373
* `messages`: a map of violation messages associated with the resource changes, resources, or blocks.
7474
Note that both the `resources` and `messages` collections are indexed by the address of the resources, so they will have the same order and length. The filter functions all call the `evaluate_attribute` function to evaluate attributes of resources even if nested deep within them. After calling a filter function and assigning the results to a variable like `violatingResources`, you can test if there are any violations with this condition: `length(violatingResources["messages"]) is 0`.
75-
* The `evaluate_attribute` function, which can evaluate the values of any attribute of any resource even if it is deeply nested inside the resource. It does this by calling itself recursively.
75+
* The `evaluate_attribute` function, which can evaluate the values of any attribute of any resource even if it is deeply nested inside the resource. It does this by calling itself recursively. The implementation in the tfplan-functions module will convert `rc` to `rc.change.after`. If you want it to examine previous values instead of planned values, pass it `rc.change.before` instead of `rc`.
7676
* The `to_string` function which can convert any Sentinel object to a string. It is used to build the messages in the `messages` collection returned by the filter functions.
7777
* The `print_violations` function which can be called after calling one of the filter function to print the violation messages. This would only be called if the `prtmsg` argument had been set to `false` when calling the filter function. This is sometimes desirable especially if processing blocks of resources since your policy can then print some other message that gives the address of the resource with block-level violations before printing them.
7878

governance/third-generation/aws/protect-against-rds-instance-deletion.sentinel

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
# This policy uses the Sentinel tfplan/v2 import to prevent deletion
22
# of RDS instances that have `deletion_protection` set to true.
3-
# Note that it is unusual in using `change.actions.before` instead of
4-
# `change.actions.after`.
3+
# Note that it calls the `filter_attribute_was_value()` function which passes
4+
# `rc.change.before` instead of `rc` to the `evaluate_attribute()` function
5+
# which converts `rc` to `rc.change.after`.
56

67
# Import common-functions/tfplan-functions/tfplan-functions.sentinel
78
# with alias "plan"
89
import "tfplan-functions" as plan
910

10-
# Get all RDS instances
11-
RDSInstancesBeingDeleted = plan.find_resources_being_destroyed("aws_db_instance")
11+
# Get all resources being destroyed
12+
resourcesBeingDestroyed = plan.find_resources_being_destroyed()
1213

14+
# Filter to RDS instances being destroyed
15+
RDSInstancesBeingDestroyed = filter resourcesBeingDestroyed as address, rc {
16+
rc.type is "aws_db_instance"
17+
}
1318

1419
# Filter to RDS instances with violations
1520
# Warnings will be printed for all violations since the last parameter is true
16-
violatingRDSInstances = plan.filter_attribute_was_value(RDSInstancesBeingDeleted,
21+
violatingRDSInstances = plan.filter_attribute_was_value(RDSInstancesBeingDestroyed,
1722
"deletion_protection", true, false)
1823

1924
if length(violatingRDSInstances["messages"]) > 0 {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module "tfplan-functions" {
2+
source = "../../../common-functions/tfplan-functions/tfplan-functions.sentinel"
3+
}
4+
5+
mock "tfplan/v2" {
6+
module {
7+
source = "mock-tfplan-fail.sentinel"
8+
}
9+
}
10+
11+
test {
12+
rules = {
13+
main = false
14+
}
15+
}
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
terraform_version = "0.13.6"
2+
3+
planned_values = {
4+
"outputs": {},
5+
"resources": {},
6+
}
7+
8+
variables = {}
9+
10+
resource_changes = {
11+
"aws_db_instance.default": {
12+
"address": "aws_db_instance.default",
13+
"change": {
14+
"actions": [
15+
"delete",
16+
],
17+
"after": null,
18+
"after_unknown": {},
19+
"before": {
20+
"address": "terraform-20210224200525302700000001.cjm7z941xa9c.us-east-1.rds.amazonaws.com",
21+
"allocated_storage": 10,
22+
"allow_major_version_upgrade": null,
23+
"apply_immediately": null,
24+
"arn": "arn:aws:rds:us-east-1:711129375688:db:terraform-20210224200525302700000001",
25+
"auto_minor_version_upgrade": true,
26+
"availability_zone": "us-east-1c",
27+
"backup_retention_period": 0,
28+
"backup_window": "06:57-07:27",
29+
"ca_cert_identifier": "rds-ca-2019",
30+
"character_set_name": null,
31+
"copy_tags_to_snapshot": false,
32+
"db_subnet_group_name": "default",
33+
"delete_automated_backups": true,
34+
"deletion_protection": true,
35+
"domain": "",
36+
"domain_iam_role_name": "",
37+
"enabled_cloudwatch_logs_exports": [],
38+
"endpoint": "terraform-20210224200525302700000001.cjm7z941xa9c.us-east-1.rds.amazonaws.com:3306",
39+
"engine": "mysql",
40+
"engine_version": "5.7.26",
41+
"final_snapshot_identifier": null,
42+
"hosted_zone_id": "Z2R2ITUGPM61AM",
43+
"iam_database_authentication_enabled": false,
44+
"id": "terraform-20210224200525302700000001",
45+
"identifier": "terraform-20210224200525302700000001",
46+
"identifier_prefix": null,
47+
"instance_class": "db.t3.micro",
48+
"iops": 0,
49+
"kms_key_id": "",
50+
"latest_restorable_time": "0001-01-01T00:00:00Z",
51+
"license_model": "general-public-license",
52+
"maintenance_window": "sat:03:23-sat:03:53",
53+
"max_allocated_storage": 0,
54+
"monitoring_interval": 0,
55+
"monitoring_role_arn": "",
56+
"multi_az": false,
57+
"name": "mydb",
58+
"option_group_name": "default:mysql-5-7",
59+
"parameter_group_name": "default.mysql5.7",
60+
"password": "foobarbaz",
61+
"performance_insights_enabled": false,
62+
"performance_insights_kms_key_id": "",
63+
"performance_insights_retention_period": 0,
64+
"port": 3306,
65+
"publicly_accessible": false,
66+
"replicas": [],
67+
"replicate_source_db": "",
68+
"resource_id": "db-FQBMWQWOZZJIQQI6U7T74XITAM",
69+
"restore_to_point_in_time": [],
70+
"s3_import": [],
71+
"security_group_names": [],
72+
"skip_final_snapshot": true,
73+
"snapshot_identifier": null,
74+
"status": "available",
75+
"storage_encrypted": false,
76+
"storage_type": "gp2",
77+
"tags": {},
78+
"timeouts": null,
79+
"timezone": "",
80+
"username": "foo",
81+
"vpc_security_group_ids": [
82+
"sg-d6ecdbf4",
83+
],
84+
},
85+
},
86+
"deposed": "",
87+
"index": null,
88+
"mode": "managed",
89+
"module_address": "",
90+
"name": "default",
91+
"provider_name": "registry.terraform.io/hashicorp/aws",
92+
"type": "aws_db_instance",
93+
},
94+
}
95+
96+
output_changes = {}
97+
98+
raw = {
99+
"configuration": {
100+
"root_module": {
101+
"resources": [
102+
{
103+
"address": "aws_db_instance.default",
104+
"expressions": {
105+
"allocated_storage": {
106+
"constant_value": 10,
107+
},
108+
"deletion_protection": {
109+
"constant_value": true,
110+
},
111+
"engine": {
112+
"constant_value": "mysql",
113+
},
114+
"engine_version": {
115+
"constant_value": "5.7",
116+
},
117+
"instance_class": {
118+
"constant_value": "db.t3.micro",
119+
},
120+
"name": {
121+
"constant_value": "mydb",
122+
},
123+
"parameter_group_name": {
124+
"constant_value": "default.mysql5.7",
125+
},
126+
"password": {
127+
"constant_value": "foobarbaz",
128+
},
129+
"skip_final_snapshot": {
130+
"constant_value": true,
131+
},
132+
"username": {
133+
"constant_value": "foo",
134+
},
135+
},
136+
"mode": "managed",
137+
"name": "default",
138+
"provider_config_key": "aws",
139+
"schema_version": 1,
140+
"type": "aws_db_instance",
141+
},
142+
],
143+
},
144+
},
145+
"format_version": "0.1",
146+
"planned_values": {
147+
"root_module": {},
148+
},
149+
"prior_state": {
150+
"format_version": "0.1",
151+
"terraform_version": "0.13.6",
152+
"values": {
153+
"root_module": {
154+
"resources": [
155+
{
156+
"address": "aws_db_instance.default",
157+
"mode": "managed",
158+
"name": "default",
159+
"provider_name": "registry.terraform.io/hashicorp/aws",
160+
"schema_version": 1,
161+
"type": "aws_db_instance",
162+
"values": {
163+
"address": "terraform-20210224200525302700000001.cjm7z941xa9c.us-east-1.rds.amazonaws.com",
164+
"allocated_storage": 10,
165+
"allow_major_version_upgrade": null,
166+
"apply_immediately": null,
167+
"arn": "arn:aws:rds:us-east-1:711129375688:db:terraform-20210224200525302700000001",
168+
"auto_minor_version_upgrade": true,
169+
"availability_zone": "us-east-1c",
170+
"backup_retention_period": 0,
171+
"backup_window": "06:57-07:27",
172+
"ca_cert_identifier": "rds-ca-2019",
173+
"character_set_name": null,
174+
"copy_tags_to_snapshot": false,
175+
"db_subnet_group_name": "default",
176+
"delete_automated_backups": true,
177+
"deletion_protection": true,
178+
"domain": "",
179+
"domain_iam_role_name": "",
180+
"enabled_cloudwatch_logs_exports": [],
181+
"endpoint": "terraform-20210224200525302700000001.cjm7z941xa9c.us-east-1.rds.amazonaws.com:3306",
182+
"engine": "mysql",
183+
"engine_version": "5.7.26",
184+
"final_snapshot_identifier": null,
185+
"hosted_zone_id": "Z2R2ITUGPM61AM",
186+
"iam_database_authentication_enabled": false,
187+
"id": "terraform-20210224200525302700000001",
188+
"identifier": "terraform-20210224200525302700000001",
189+
"identifier_prefix": null,
190+
"instance_class": "db.t3.micro",
191+
"iops": 0,
192+
"kms_key_id": "",
193+
"latest_restorable_time": "0001-01-01T00:00:00Z",
194+
"license_model": "general-public-license",
195+
"maintenance_window": "sat:03:23-sat:03:53",
196+
"max_allocated_storage": 0,
197+
"monitoring_interval": 0,
198+
"monitoring_role_arn": "",
199+
"multi_az": false,
200+
"name": "mydb",
201+
"option_group_name": "default:mysql-5-7",
202+
"parameter_group_name": "default.mysql5.7",
203+
"password": "foobarbaz",
204+
"performance_insights_enabled": false,
205+
"performance_insights_kms_key_id": "",
206+
"performance_insights_retention_period": 0,
207+
"port": 3306,
208+
"publicly_accessible": false,
209+
"replicas": [],
210+
"replicate_source_db": "",
211+
"resource_id": "db-FQBMWQWOZZJIQQI6U7T74XITAM",
212+
"restore_to_point_in_time": [],
213+
"s3_import": [],
214+
"security_group_names": [],
215+
"skip_final_snapshot": true,
216+
"snapshot_identifier": null,
217+
"status": "available",
218+
"storage_encrypted": false,
219+
"storage_type": "gp2",
220+
"tags": {},
221+
"timeouts": null,
222+
"timezone": "",
223+
"username": "foo",
224+
"vpc_security_group_ids": [
225+
"sg-d6ecdbf4",
226+
],
227+
},
228+
},
229+
],
230+
},
231+
},
232+
},
233+
"resource_changes": [
234+
{
235+
"address": "aws_db_instance.default",
236+
"change": {
237+
"actions": [
238+
"delete",
239+
],
240+
"after_unknown": {},
241+
"before": {
242+
"address": "terraform-20210224200525302700000001.cjm7z941xa9c.us-east-1.rds.amazonaws.com",
243+
"allocated_storage": 10,
244+
"allow_major_version_upgrade": null,
245+
"apply_immediately": null,
246+
"arn": "arn:aws:rds:us-east-1:711129375688:db:terraform-20210224200525302700000001",
247+
"auto_minor_version_upgrade": true,
248+
"availability_zone": "us-east-1c",
249+
"backup_retention_period": 0,
250+
"backup_window": "06:57-07:27",
251+
"ca_cert_identifier": "rds-ca-2019",
252+
"character_set_name": null,
253+
"copy_tags_to_snapshot": false,
254+
"db_subnet_group_name": "default",
255+
"delete_automated_backups": true,
256+
"deletion_protection": true,
257+
"domain": "",
258+
"domain_iam_role_name": "",
259+
"enabled_cloudwatch_logs_exports": [],
260+
"endpoint": "terraform-20210224200525302700000001.cjm7z941xa9c.us-east-1.rds.amazonaws.com:3306",
261+
"engine": "mysql",
262+
"engine_version": "5.7.26",
263+
"final_snapshot_identifier": null,
264+
"hosted_zone_id": "Z2R2ITUGPM61AM",
265+
"iam_database_authentication_enabled": false,
266+
"id": "terraform-20210224200525302700000001",
267+
"identifier": "terraform-20210224200525302700000001",
268+
"identifier_prefix": null,
269+
"instance_class": "db.t3.micro",
270+
"iops": 0,
271+
"kms_key_id": "",
272+
"latest_restorable_time": "0001-01-01T00:00:00Z",
273+
"license_model": "general-public-license",
274+
"maintenance_window": "sat:03:23-sat:03:53",
275+
"max_allocated_storage": 0,
276+
"monitoring_interval": 0,
277+
"monitoring_role_arn": "",
278+
"multi_az": false,
279+
"name": "mydb",
280+
"option_group_name": "default:mysql-5-7",
281+
"parameter_group_name": "default.mysql5.7",
282+
"password": "foobarbaz",
283+
"performance_insights_enabled": false,
284+
"performance_insights_kms_key_id": "",
285+
"performance_insights_retention_period": 0,
286+
"port": 3306,
287+
"publicly_accessible": false,
288+
"replicas": [],
289+
"replicate_source_db": "",
290+
"resource_id": "db-FQBMWQWOZZJIQQI6U7T74XITAM",
291+
"restore_to_point_in_time": [],
292+
"s3_import": [],
293+
"security_group_names": [],
294+
"skip_final_snapshot": true,
295+
"snapshot_identifier": null,
296+
"status": "available",
297+
"storage_encrypted": false,
298+
"storage_type": "gp2",
299+
"tags": {},
300+
"timeouts": null,
301+
"timezone": "",
302+
"username": "foo",
303+
"vpc_security_group_ids": [
304+
"sg-d6ecdbf4",
305+
],
306+
},
307+
},
308+
"mode": "managed",
309+
"name": "default",
310+
"provider_name": "registry.terraform.io/hashicorp/aws",
311+
"type": "aws_db_instance",
312+
},
313+
],
314+
"terraform_version": "0.13.6",
315+
}

0 commit comments

Comments
 (0)