Skip to content

Commit

Permalink
Adding SSM patch support (#103)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Jun 24, 2021
1 parent f251bf5 commit 8c2ca76
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 3 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ Available targets:

| Name | Source | Version |
|------|--------|---------|
| <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 |
| <a name="module_security_group"></a> [security\_group](#module\_security\_group) | cloudposse/security-group/aws | 0.3.1 |
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.24.1 |

Expand All @@ -227,7 +228,10 @@ Available targets:
| [aws_eip.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_eip.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_iam_instance_profile.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
| [aws_iam_policy.ssm_patch_s3_log_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_role.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.ssm_core](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.ssm_s3_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
| [aws_network_interface.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface) | resource |
| [aws_network_interface_attachment.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface_attachment) | resource |
Expand All @@ -239,6 +243,7 @@ Available targets:
| [aws_caller_identity.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_instance_profile.given](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_instance_profile) | data source |
| [aws_iam_policy_document.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [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 |
| [aws_partition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_region.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [aws_subnet.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
Expand Down Expand Up @@ -306,6 +311,9 @@ Available targets:
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_stage"></a> [stage](#input\_stage) | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| <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 |
| <a name="input_subnet"></a> [subnet](#input\_subnet) | VPC Subnet ID the instance is launched in | `string` | n/a | yes |
Expand Down
8 changes: 8 additions & 0 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

| Name | Source | Version |
|------|--------|---------|
| <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 |
| <a name="module_security_group"></a> [security\_group](#module\_security\_group) | cloudposse/security-group/aws | 0.3.1 |
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.24.1 |

Expand All @@ -30,7 +31,10 @@
| [aws_eip.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_eip.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_iam_instance_profile.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
| [aws_iam_policy.ssm_patch_s3_log_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_role.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.ssm_core](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.ssm_s3_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
| [aws_network_interface.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface) | resource |
| [aws_network_interface_attachment.additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface_attachment) | resource |
Expand All @@ -42,6 +46,7 @@
| [aws_caller_identity.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_instance_profile.given](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_instance_profile) | data source |
| [aws_iam_policy_document.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [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 |
| [aws_partition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_region.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [aws_subnet.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
Expand Down Expand Up @@ -109,6 +114,9 @@
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_stage"></a> [stage](#input\_stage) | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| <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 |
| <a name="input_subnet"></a> [subnet](#input\_subnet) | VPC Subnet ID the instance is launched in | `string` | n/a | yes |
Expand Down
55 changes: 52 additions & 3 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
locals {
instance_count = module.this.enabled ? 1 : 0
enabled = module.this.enabled
instance_count = local.enabled ? 1 : 0
volume_count = var.ebs_volume_count > 0 && local.instance_count > 0 ? var.ebs_volume_count : 0
# create an instance profile if the instance is enabled and we aren't given one to use
instance_profile_count = module.this.enabled ? (length(var.instance_profile) > 0 ? 0 : 1) : 0
Expand All @@ -19,6 +20,8 @@ locals {
var.associate_public_ip_address && var.assign_eip_address && module.this.enabled ?
local.eip_public_dns : join("", aws_instance.default.*.public_dns)
)
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
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
}

data "aws_caller_identity" "default" {
Expand Down Expand Up @@ -51,6 +54,39 @@ data "aws_iam_policy_document" "default" {
}
}

module "label_ssm_patch_s3_log_policy" {
source = "cloudposse/label/null"
version = "0.24.1"

attributes = ["ssm-patch-s3-logs"]
context = module.this.context
}

data "aws_iam_policy_document" "ssm_patch_s3_log_policy" {
count = local.ssm_path_log_bucket_enabled ? 1 : 0
statement {
sid = "AllowAccessToPathLogBucket"
actions = [
"s3:GetObject",
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetEncryptionConfiguration",
]
resources = [
"arn:aws:s3:::${var.ssm_patch_manager_s3_log_bucket}/*",
"arn:aws:s3:::${var.ssm_patch_manager_s3_log_bucket}",
]
}
}

resource "aws_iam_policy" "ssm_patch_s3_log_policy" {
count = local.ssm_path_log_bucket_enabled ? 1 : 0
name = module.label_ssm_patch_s3_log_policy.id
path = "/"
description = "Policy to allow the local SSM agent on the instance to write the log output to the defined bucket"
policy = data.aws_iam_policy_document.ssm_patch_s3_log_policy[0].json
}

data "aws_ami" "default" {
count = var.ami == "" ? 1 : 0
most_recent = "true"
Expand Down Expand Up @@ -79,14 +115,14 @@ data "aws_ami" "info" {

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

data "aws_iam_instance_profile" "given" {
count = module.this.enabled && length(var.instance_profile) > 0 ? 1 : 0
count = local.enabled && length(var.instance_profile) > 0 ? 1 : 0
name = var.instance_profile
depends_on = [null_resource.instance_profile_dependency]
}
Expand All @@ -106,6 +142,19 @@ resource "aws_iam_role" "default" {
tags = module.this.tags
}

resource "aws_iam_role_policy_attachment" "ssm_core" {
count = local.enabled ? local.instance_profile_count : 0
role = aws_iam_role.default[count.index]
policy_arn = local.ssm_policy
}

resource "aws_iam_role_policy_attachment" "ssm_s3_policy" {
count = local.enabled && local.ssm_path_log_bucket_enabled ? local.instance_profile_count : 0
role = aws_iam_role.default[count.index]
policy_arn = aws_iam_policy.ssm_patch_s3_log_policy[0].arn
}


resource "aws_instance" "default" {
#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
#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.
Expand Down
Loading

0 comments on commit 8c2ca76

Please sign in to comment.