Skip to content

Commit 8c2ca76

Browse files
jamengualcloudpossebotaknysh
authored
Adding SSM patch support (#103)
* Adding SSM patch support * Auto Format * remove uneeded change * remove uneeded change * Auto Format * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Update variables.tf Co-authored-by: Andriy Knysh <[email protected]> * Auto Format * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Adding SSM patch support * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Auto Format * Fixinf var name * Fixinf var name * Fixing variable name for count * Fixing variable name for count and adding label module + attribute * Auto Format * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Update main.tf Co-authored-by: Andriy Knysh <[email protected]> * Minor fixes Co-authored-by: cloudpossebot <[email protected]> Co-authored-by: Andriy Knysh <[email protected]>
1 parent f251bf5 commit 8c2ca76

File tree

5 files changed

+348
-3
lines changed

5 files changed

+348
-3
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ Available targets:
215215

216216
| Name | Source | Version |
217217
|------|--------|---------|
218+
| <a name="module_label_ssm_patch_s3_log_policy"></a> [label\_ssm\_patch\_s3\_log\_policy](#module\_label\_ssm\_patch\_s3\_log\_policy) | cloudposse/label/null | 0.24.1 |
218219
| <a name="module_security_group"></a> [security\_group](#module\_security\_group) | cloudposse/security-group/aws | 0.3.1 |
219220
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.24.1 |
220221

@@ -227,7 +228,10 @@ Available targets:
227228
| [aws_eip.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
228229
| [aws_eip.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
229230
| [aws_iam_instance_profile.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
231+
| [aws_iam_policy.ssm_patch_s3_log_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
230232
| [aws_iam_role.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
233+
| [aws_iam_role_policy_attachment.ssm_core](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
234+
| [aws_iam_role_policy_attachment.ssm_s3_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
231235
| [aws_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
232236
| [aws_network_interface.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface) | resource |
233237
| [aws_network_interface_attachment.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface_attachment) | resource |
@@ -239,6 +243,7 @@ Available targets:
239243
| [aws_caller_identity.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
240244
| [aws_iam_instance_profile.given](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_instance_profile) | data source |
241245
| [aws_iam_policy_document.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
246+
| [aws_iam_policy_document.ssm_patch_s3_log_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
242247
| [aws_partition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
243248
| [aws_region.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
244249
| [aws_subnet.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
@@ -306,6 +311,9 @@ Available targets:
306311
| <a name="input_security_groups"></a> [security\_groups](#input\_security\_groups) | A list of Security Group IDs to associate with EC2 instance. | `list(string)` | `[]` | no |
307312
| <a name="input_source_dest_check"></a> [source\_dest\_check](#input\_source\_dest\_check) | Controls if traffic is routed to the instance when the destination address does not match the instance. Used for NAT or VPNs | `bool` | `true` | no |
308313
| <a name="input_ssh_key_pair"></a> [ssh\_key\_pair](#input\_ssh\_key\_pair) | SSH key pair to be provisioned on the instance | `string` | n/a | yes |
314+
| <a name="input_ssm_patch_manager_enabled"></a> [ssm\_patch\_manager\_enabled](#input\_ssm\_patch\_manager\_enabled) | Whether to enable SSM Patch manager | `bool` | `false` | no |
315+
| <a name="input_ssm_patch_manager_iam_policy"></a> [ssm\_patch\_manager\_iam\_policy](#input\_ssm\_patch\_manager\_iam\_policy) | IAM policy to allow Patch manager to manage the instance | `string` | `null` | no |
316+
| <a name="input_ssm_patch_manager_s3_log_bucket"></a> [ssm\_patch\_manager\_s3\_log\_bucket](#input\_ssm\_patch\_manager\_s3\_log\_bucket) | The name of the s3 bucket to export the patch log to | `string` | `null` | no |
309317
| <a name="input_stage"></a> [stage](#input\_stage) | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
310318
| <a name="input_statistic_level"></a> [statistic\_level](#input\_statistic\_level) | The statistic to apply to the alarm's associated metric. Allowed values are: SampleCount, Average, Sum, Minimum, Maximum | `string` | `"Maximum"` | no |
311319
| <a name="input_subnet"></a> [subnet](#input\_subnet) | VPC Subnet ID the instance is launched in | `string` | n/a | yes |

docs/terraform.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
| Name | Source | Version |
2020
|------|--------|---------|
21+
| <a name="module_label_ssm_patch_s3_log_policy"></a> [label\_ssm\_patch\_s3\_log\_policy](#module\_label\_ssm\_patch\_s3\_log\_policy) | cloudposse/label/null | 0.24.1 |
2122
| <a name="module_security_group"></a> [security\_group](#module\_security\_group) | cloudposse/security-group/aws | 0.3.1 |
2223
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.24.1 |
2324

@@ -30,7 +31,10 @@
3031
| [aws_eip.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
3132
| [aws_eip.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
3233
| [aws_iam_instance_profile.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
34+
| [aws_iam_policy.ssm_patch_s3_log_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
3335
| [aws_iam_role.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
36+
| [aws_iam_role_policy_attachment.ssm_core](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
37+
| [aws_iam_role_policy_attachment.ssm_s3_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
3438
| [aws_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
3539
| [aws_network_interface.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface) | resource |
3640
| [aws_network_interface_attachment.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface_attachment) | resource |
@@ -42,6 +46,7 @@
4246
| [aws_caller_identity.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
4347
| [aws_iam_instance_profile.given](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_instance_profile) | data source |
4448
| [aws_iam_policy_document.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
49+
| [aws_iam_policy_document.ssm_patch_s3_log_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
4550
| [aws_partition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
4651
| [aws_region.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
4752
| [aws_subnet.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
@@ -109,6 +114,9 @@
109114
| <a name="input_security_groups"></a> [security\_groups](#input\_security\_groups) | A list of Security Group IDs to associate with EC2 instance. | `list(string)` | `[]` | no |
110115
| <a name="input_source_dest_check"></a> [source\_dest\_check](#input\_source\_dest\_check) | Controls if traffic is routed to the instance when the destination address does not match the instance. Used for NAT or VPNs | `bool` | `true` | no |
111116
| <a name="input_ssh_key_pair"></a> [ssh\_key\_pair](#input\_ssh\_key\_pair) | SSH key pair to be provisioned on the instance | `string` | n/a | yes |
117+
| <a name="input_ssm_patch_manager_enabled"></a> [ssm\_patch\_manager\_enabled](#input\_ssm\_patch\_manager\_enabled) | Whether to enable SSM Patch manager | `bool` | `false` | no |
118+
| <a name="input_ssm_patch_manager_iam_policy"></a> [ssm\_patch\_manager\_iam\_policy](#input\_ssm\_patch\_manager\_iam\_policy) | IAM policy to allow Patch manager to manage the instance | `string` | `null` | no |
119+
| <a name="input_ssm_patch_manager_s3_log_bucket"></a> [ssm\_patch\_manager\_s3\_log\_bucket](#input\_ssm\_patch\_manager\_s3\_log\_bucket) | The name of the s3 bucket to export the patch log to | `string` | `null` | no |
112120
| <a name="input_stage"></a> [stage](#input\_stage) | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
113121
| <a name="input_statistic_level"></a> [statistic\_level](#input\_statistic\_level) | The statistic to apply to the alarm's associated metric. Allowed values are: SampleCount, Average, Sum, Minimum, Maximum | `string` | `"Maximum"` | no |
114122
| <a name="input_subnet"></a> [subnet](#input\_subnet) | VPC Subnet ID the instance is launched in | `string` | n/a | yes |

main.tf

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
locals {
2-
instance_count = module.this.enabled ? 1 : 0
2+
enabled = module.this.enabled
3+
instance_count = local.enabled ? 1 : 0
34
volume_count = var.ebs_volume_count > 0 && local.instance_count > 0 ? var.ebs_volume_count : 0
45
# create an instance profile if the instance is enabled and we aren't given one to use
56
instance_profile_count = module.this.enabled ? (length(var.instance_profile) > 0 ? 0 : 1) : 0
@@ -19,6 +20,8 @@ locals {
1920
var.associate_public_ip_address && var.assign_eip_address && module.this.enabled ?
2021
local.eip_public_dns : join("", aws_instance.default.*.public_dns)
2122
)
23+
ssm_path_log_bucket_enabled = local.enabled && var.ssm_patch_manager_enabled && var.ssm_patch_manager_s3_log_bucket != "" && var.ssm_patch_manager_s3_log_bucket != null
24+
ssm_policy = var.ssm_patch_manager_iam_policy == null || var.ssm_patch_manager_iam_policy == "" ? "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" : var.ssm_patch_manager_iam_policy
2225
}
2326

2427
data "aws_caller_identity" "default" {
@@ -51,6 +54,39 @@ data "aws_iam_policy_document" "default" {
5154
}
5255
}
5356

57+
module "label_ssm_patch_s3_log_policy" {
58+
source = "cloudposse/label/null"
59+
version = "0.24.1"
60+
61+
attributes = ["ssm-patch-s3-logs"]
62+
context = module.this.context
63+
}
64+
65+
data "aws_iam_policy_document" "ssm_patch_s3_log_policy" {
66+
count = local.ssm_path_log_bucket_enabled ? 1 : 0
67+
statement {
68+
sid = "AllowAccessToPathLogBucket"
69+
actions = [
70+
"s3:GetObject",
71+
"s3:PutObject",
72+
"s3:PutObjectAcl",
73+
"s3:GetEncryptionConfiguration",
74+
]
75+
resources = [
76+
"arn:aws:s3:::${var.ssm_patch_manager_s3_log_bucket}/*",
77+
"arn:aws:s3:::${var.ssm_patch_manager_s3_log_bucket}",
78+
]
79+
}
80+
}
81+
82+
resource "aws_iam_policy" "ssm_patch_s3_log_policy" {
83+
count = local.ssm_path_log_bucket_enabled ? 1 : 0
84+
name = module.label_ssm_patch_s3_log_policy.id
85+
path = "/"
86+
description = "Policy to allow the local SSM agent on the instance to write the log output to the defined bucket"
87+
policy = data.aws_iam_policy_document.ssm_patch_s3_log_policy[0].json
88+
}
89+
5490
data "aws_ami" "default" {
5591
count = var.ami == "" ? 1 : 0
5692
most_recent = "true"
@@ -79,14 +115,14 @@ data "aws_ami" "info" {
79115

80116
# https://github.com/hashicorp/terraform-guides/tree/master/infrastructure-as-code/terraform-0.13-examples/module-depends-on
81117
resource "null_resource" "instance_profile_dependency" {
82-
count = module.this.enabled && length(var.instance_profile) > 0 ? 1 : 0
118+
count = local.enabled && length(var.instance_profile) > 0 ? 1 : 0
83119
triggers = {
84120
dependency_id = var.instance_profile
85121
}
86122
}
87123

88124
data "aws_iam_instance_profile" "given" {
89-
count = module.this.enabled && length(var.instance_profile) > 0 ? 1 : 0
125+
count = local.enabled && length(var.instance_profile) > 0 ? 1 : 0
90126
name = var.instance_profile
91127
depends_on = [null_resource.instance_profile_dependency]
92128
}
@@ -106,6 +142,19 @@ resource "aws_iam_role" "default" {
106142
tags = module.this.tags
107143
}
108144

145+
resource "aws_iam_role_policy_attachment" "ssm_core" {
146+
count = local.enabled ? local.instance_profile_count : 0
147+
role = aws_iam_role.default[count.index]
148+
policy_arn = local.ssm_policy
149+
}
150+
151+
resource "aws_iam_role_policy_attachment" "ssm_s3_policy" {
152+
count = local.enabled && local.ssm_path_log_bucket_enabled ? local.instance_profile_count : 0
153+
role = aws_iam_role.default[count.index]
154+
policy_arn = aws_iam_policy.ssm_patch_s3_log_policy[0].arn
155+
}
156+
157+
109158
resource "aws_instance" "default" {
110159
#bridgecrew:skip=BC_AWS_GENERAL_31: Skipping `Ensure Instance Metadata Service Version 1 is not enabled` check until BridgeCrew supports conditional evaluation. See https://github.com/bridgecrewio/checkov/issues/793
111160
#bridgecrew:skip=BC_AWS_NETWORKING_47: Skiping `Ensure AWS EC2 instance is configured with VPC` because it is incorrectly flagging that this instance does not belong to a VPC even though subnet_id is configured.

0 commit comments

Comments
 (0)