@@ -14,6 +14,10 @@ locals {
1414 length (var. ami ) > 0 ? element (data. aws_ami . instance , 0 ). root_device_name : " /dev/xvda"
1515 )
1616
17+ # VPC and Subnet ID resolution - names take precedence over IDs
18+ vpc_id = length (var. vpc_name ) > 0 ? one (data. aws_vpc . selected [* ]. id ) : var. vpc_id
19+ subnet_ids = length (var. subnet_names ) > 0 ? values (data. aws_subnet . selected )[* ]. id : var. subnet_ids
20+
1721}
1822
1923resource "null_resource" "validate_instance_type" {
@@ -27,6 +31,34 @@ resource "null_resource" "validate_instance_type" {
2731 }
2832}
2933
34+ # Validation using terraform_data to halt execution if requirements aren't met
35+ resource "terraform_data" "vpc_subnet_validation" {
36+ lifecycle {
37+ precondition {
38+ condition = length (var. vpc_name ) > 0 || length (var. vpc_id ) > 0
39+ error_message = " Either vpc_name or vpc_id must be provided."
40+ }
41+
42+ precondition {
43+ condition = length (var. subnet_names ) > 0 || length (var. subnet_ids ) > 0
44+ error_message = " Either subnet_names or subnet_ids must be provided."
45+ }
46+ }
47+ }
48+
49+ # Warning checks for VPC and subnet configuration (non-blocking)
50+ check "vpc_subnet_warnings" {
51+ assert {
52+ condition = ! (length (var. vpc_name ) > 0 && length (var. vpc_id ) > 0 )
53+ error_message = " Both vpc_name and vpc_id are provided. When vpc_name is specified, vpc_id will be ignored."
54+ }
55+
56+ assert {
57+ condition = ! (length (var. subnet_names ) > 0 && length (var. subnet_ids ) > 0 )
58+ error_message = " Both subnet_names and subnet_ids are provided. When subnet_names are specified, subnet_ids will be ignored."
59+ }
60+ }
61+
3062module "role_label" {
3163 source = " cloudposse/label/null"
3264 version = " 0.25.0"
@@ -57,68 +89,6 @@ locals {
5789# # SSM AGENT ROLE ##
5890# ##################
5991
60- data "aws_iam_policy_document" "default" {
61-
62- statement {
63- effect = " Allow"
64- actions = [" sts:AssumeRole" ]
65-
66- principals {
67- type = " Service"
68- identifiers = [" ec2.amazonaws.com" ]
69- }
70- }
71- }
72-
73- data "aws_s3_bucket" "logs_bucket" {
74- count = var. session_logging_enabled ? 1 : 0
75- bucket = try (coalesce (var. session_logging_bucket_name , module. logs_bucket . bucket_id ), " " )
76- }
77-
78- # https://docs.aws.amazon.com/systems-manager/latest/userguide/getting-started-create-iam-instance-profile.html#create-iam-instance-profile-ssn-logging
79- data "aws_iam_policy_document" "session_logging" {
80- count = var. session_logging_enabled ? 1 : 0
81-
82- statement {
83- sid = " SSMAgentSessionAllowS3Logging"
84- effect = " Allow"
85- actions = [
86- " s3:PutObject"
87- ]
88- resources = [" ${ join (" " , data. aws_s3_bucket . logs_bucket . * . arn )} /*" ]
89- }
90-
91- statement {
92- sid = " SSMAgentSessionAllowCloudWatchLogging"
93- effect = " Allow"
94- actions = [
95- " logs:CreateLogStream" ,
96- " logs:PutLogEvents" ,
97- " logs:DescribeLogGroups" ,
98- " logs:DescribeLogStreams"
99- ]
100- resources = [" *" ]
101- }
102-
103- statement {
104- sid = " SSMAgentSessionAllowGetEncryptionConfig"
105- effect = " Allow"
106- actions = [
107- " s3:GetEncryptionConfiguration"
108- ]
109- resources = [" *" ]
110- }
111-
112- statement {
113- sid = " SSMAgentSessionAllowKMSDataKey"
114- effect = " Allow"
115- actions = [
116- " kms:GenerateDataKey"
117- ]
118- resources = [" *" ]
119- }
120- }
121-
12292resource "aws_iam_role" "default" {
12393 name = module. role_label . id
12494 assume_role_policy = data. aws_iam_policy_document . default . json
@@ -157,19 +127,21 @@ resource "aws_iam_instance_profile" "default" {
157127# ##################
158128
159129resource "aws_security_group" "default" {
160- vpc_id = var . vpc_id
130+ vpc_id = local . vpc_id
161131 name = module. this . id
162132 description = " Allow ALL egress from SSM Agent."
163133 tags = module. this . tags
164134}
165135
136+ # trivy:ignore:aws-vpc-no-public-egress-sgr SSM Agent requires broad egress to communicate with AWS services
166137resource "aws_security_group_rule" "allow_all_egress" {
167138 type = " egress"
168139 from_port = 0
169140 to_port = 0
170141 protocol = " -1"
171142 cidr_blocks = [" 0.0.0.0/0" ]
172143 ipv6_cidr_blocks = [" ::/0" ]
144+ description = " Allow all outbound traffic for SSM Agent communication with AWS services"
173145 security_group_id = aws_security_group. default . id
174146}
175147
@@ -246,21 +218,15 @@ DOC
246218
247219module "logs_bucket" {
248220 source = " cloudposse/s3-bucket/aws"
249- version = " 3.1.2 "
221+ version = " 4.10.0 "
250222
251223 enabled = local. logs_bucket_enabled
252224 context = module. logs_label . context
253225
254226 # Encryption / Security
255- acl = " private"
256- sse_algorithm = " aws:kms"
257- kms_master_key_arn = local. session_logging_kms_key_arn
258- allow_encrypted_uploads_only = false
259- force_destroy = true
260-
261- # Feature enablement
262- user_enabled = false
263- versioning_enabled = true
227+ sse_algorithm = " aws:kms"
228+ kms_master_key_arn = local. session_logging_kms_key_arn
229+ force_destroy = true
264230
265231 lifecycle_configuration_rules = [{
266232 enabled = true
@@ -385,7 +351,7 @@ resource "aws_autoscaling_group" "default" {
385351 # By default, we don't care to protect from scale in as we want to roll instances frequently
386352 protect_from_scale_in = var. protect_from_scale_in
387353
388- vpc_zone_identifier = var . subnet_ids
354+ vpc_zone_identifier = local . subnet_ids
389355
390356 default_cooldown = 180
391357 health_check_grace_period = 180
0 commit comments