tf-starter 1.0.0

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.
Files changed (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +421 -0
  3. package/bin/tf-starter.js +88 -0
  4. package/package.json +43 -0
  5. package/scripts/postinstall.js +105 -0
  6. package/setup.py +32 -0
  7. package/tf_starter/__init__.py +3 -0
  8. package/tf_starter/__main__.py +6 -0
  9. package/tf_starter/cli.py +379 -0
  10. package/tf_starter/generator.py +171 -0
  11. package/tf_starter/template_engine.py +80 -0
  12. package/tf_starter/templates/aws/environments/backend.tf.j2 +16 -0
  13. package/tf_starter/templates/aws/environments/main.tf.j2 +85 -0
  14. package/tf_starter/templates/aws/environments/terraform.tfvars.j2 +52 -0
  15. package/tf_starter/templates/aws/environments/variables.tf.j2 +127 -0
  16. package/tf_starter/templates/aws/github/terraform.yml.j2 +133 -0
  17. package/tf_starter/templates/aws/misc/Makefile.j2 +60 -0
  18. package/tf_starter/templates/aws/misc/README.md.j2 +445 -0
  19. package/tf_starter/templates/aws/misc/init.sh.j2 +110 -0
  20. package/tf_starter/templates/aws/misc/pre-commit-config.yaml.j2 +34 -0
  21. package/tf_starter/templates/aws/modules/apigateway/main.tf.j2 +224 -0
  22. package/tf_starter/templates/aws/modules/apigateway/outputs.tf.j2 +28 -0
  23. package/tf_starter/templates/aws/modules/apigateway/variables.tf.j2 +69 -0
  24. package/tf_starter/templates/aws/modules/compute/main.tf.j2 +245 -0
  25. package/tf_starter/templates/aws/modules/compute/outputs.tf.j2 +38 -0
  26. package/tf_starter/templates/aws/modules/compute/variables.tf.j2 +68 -0
  27. package/tf_starter/templates/aws/modules/database/main.tf.j2 +122 -0
  28. package/tf_starter/templates/aws/modules/database/outputs.tf.j2 +33 -0
  29. package/tf_starter/templates/aws/modules/database/variables.tf.j2 +63 -0
  30. package/tf_starter/templates/aws/modules/kubernetes/main.tf.j2 +167 -0
  31. package/tf_starter/templates/aws/modules/kubernetes/outputs.tf.j2 +33 -0
  32. package/tf_starter/templates/aws/modules/kubernetes/variables.tf.j2 +64 -0
  33. package/tf_starter/templates/aws/modules/lambda/main.tf.j2 +215 -0
  34. package/tf_starter/templates/aws/modules/lambda/outputs.tf.j2 +38 -0
  35. package/tf_starter/templates/aws/modules/lambda/variables.tf.j2 +88 -0
  36. package/tf_starter/templates/aws/modules/messaging/main.tf.j2 +85 -0
  37. package/tf_starter/templates/aws/modules/messaging/outputs.tf.j2 +28 -0
  38. package/tf_starter/templates/aws/modules/messaging/variables.tf.j2 +41 -0
  39. package/tf_starter/templates/aws/modules/monitoring/main.tf.j2 +155 -0
  40. package/tf_starter/templates/aws/modules/monitoring/outputs.tf.j2 +23 -0
  41. package/tf_starter/templates/aws/modules/monitoring/variables.tf.j2 +39 -0
  42. package/tf_starter/templates/aws/modules/network/main.tf.j2 +147 -0
  43. package/tf_starter/templates/aws/modules/network/outputs.tf.j2 +33 -0
  44. package/tf_starter/templates/aws/modules/network/variables.tf.j2 +52 -0
  45. package/tf_starter/templates/aws/modules/storage/main.tf.j2 +88 -0
  46. package/tf_starter/templates/aws/modules/storage/outputs.tf.j2 +23 -0
  47. package/tf_starter/templates/aws/modules/storage/variables.tf.j2 +25 -0
  48. package/tf_starter/templates/aws/root/backend.tf.j2 +19 -0
  49. package/tf_starter/templates/aws/root/main.tf.j2 +219 -0
  50. package/tf_starter/templates/aws/root/outputs.tf.j2 +134 -0
  51. package/tf_starter/templates/aws/root/providers.tf.j2 +24 -0
  52. package/tf_starter/templates/aws/root/variables.tf.j2 +300 -0
  53. package/tf_starter/templates/aws/root/versions.tf.j2 +26 -0
  54. package/tf_starter/templates/azure/environments/backend.tf.j2 +11 -0
  55. package/tf_starter/templates/azure/environments/main.tf.j2 +57 -0
  56. package/tf_starter/templates/azure/environments/terraform.tfvars.j2 +14 -0
  57. package/tf_starter/templates/azure/environments/variables.tf.j2 +30 -0
  58. package/tf_starter/templates/azure/github/terraform.yml.j2 +133 -0
  59. package/tf_starter/templates/azure/misc/Makefile.j2 +60 -0
  60. package/tf_starter/templates/azure/misc/README.md.j2 +426 -0
  61. package/tf_starter/templates/azure/misc/init.sh.j2 +110 -0
  62. package/tf_starter/templates/azure/misc/pre-commit-config.yaml.j2 +34 -0
  63. package/tf_starter/templates/azure/modules/apigateway/main.tf.j2 +125 -0
  64. package/tf_starter/templates/azure/modules/apigateway/outputs.tf.j2 +18 -0
  65. package/tf_starter/templates/azure/modules/apigateway/variables.tf.j2 +54 -0
  66. package/tf_starter/templates/azure/modules/compute/main.tf.j2 +114 -0
  67. package/tf_starter/templates/azure/modules/compute/outputs.tf.j2 +9 -0
  68. package/tf_starter/templates/azure/modules/compute/variables.tf.j2 +23 -0
  69. package/tf_starter/templates/azure/modules/database/main.tf.j2 +56 -0
  70. package/tf_starter/templates/azure/modules/database/outputs.tf.j2 +13 -0
  71. package/tf_starter/templates/azure/modules/database/variables.tf.j2 +38 -0
  72. package/tf_starter/templates/azure/modules/kubernetes/main.tf.j2 +50 -0
  73. package/tf_starter/templates/azure/modules/kubernetes/outputs.tf.j2 +19 -0
  74. package/tf_starter/templates/azure/modules/kubernetes/variables.tf.j2 +37 -0
  75. package/tf_starter/templates/azure/modules/lambda/main.tf.j2 +98 -0
  76. package/tf_starter/templates/azure/modules/lambda/outputs.tf.j2 +23 -0
  77. package/tf_starter/templates/azure/modules/lambda/variables.tf.j2 +53 -0
  78. package/tf_starter/templates/azure/modules/messaging/main.tf.j2 +29 -0
  79. package/tf_starter/templates/azure/modules/messaging/outputs.tf.j2 +14 -0
  80. package/tf_starter/templates/azure/modules/messaging/variables.tf.j2 +11 -0
  81. package/tf_starter/templates/azure/modules/monitoring/main.tf.j2 +31 -0
  82. package/tf_starter/templates/azure/modules/monitoring/outputs.tf.j2 +9 -0
  83. package/tf_starter/templates/azure/modules/monitoring/variables.tf.j2 +16 -0
  84. package/tf_starter/templates/azure/modules/network/main.tf.j2 +89 -0
  85. package/tf_starter/templates/azure/modules/network/outputs.tf.j2 +25 -0
  86. package/tf_starter/templates/azure/modules/network/variables.tf.j2 +25 -0
  87. package/tf_starter/templates/azure/modules/storage/main.tf.j2 +41 -0
  88. package/tf_starter/templates/azure/modules/storage/outputs.tf.j2 +17 -0
  89. package/tf_starter/templates/azure/modules/storage/variables.tf.j2 +16 -0
  90. package/tf_starter/templates/azure/root/backend.tf.j2 +11 -0
  91. package/tf_starter/templates/azure/root/main.tf.j2 +181 -0
  92. package/tf_starter/templates/azure/root/outputs.tf.j2 +45 -0
  93. package/tf_starter/templates/azure/root/providers.tf.j2 +18 -0
  94. package/tf_starter/templates/azure/root/variables.tf.j2 +114 -0
  95. package/tf_starter/templates/azure/root/versions.tf.j2 +16 -0
  96. package/tf_starter/templates/gcp/environments/backend.tf.j2 +9 -0
  97. package/tf_starter/templates/gcp/environments/main.tf.j2 +58 -0
  98. package/tf_starter/templates/gcp/environments/terraform.tfvars.j2 +12 -0
  99. package/tf_starter/templates/gcp/environments/variables.tf.j2 +21 -0
  100. package/tf_starter/templates/gcp/github/terraform.yml.j2 +133 -0
  101. package/tf_starter/templates/gcp/misc/Makefile.j2 +60 -0
  102. package/tf_starter/templates/gcp/misc/README.md.j2 +426 -0
  103. package/tf_starter/templates/gcp/misc/init.sh.j2 +110 -0
  104. package/tf_starter/templates/gcp/misc/pre-commit-config.yaml.j2 +34 -0
  105. package/tf_starter/templates/gcp/modules/apigateway/main.tf.j2 +67 -0
  106. package/tf_starter/templates/gcp/modules/apigateway/outputs.tf.j2 +18 -0
  107. package/tf_starter/templates/gcp/modules/apigateway/variables.tf.j2 +34 -0
  108. package/tf_starter/templates/gcp/modules/compute/main.tf.j2 +138 -0
  109. package/tf_starter/templates/gcp/modules/compute/outputs.tf.j2 +13 -0
  110. package/tf_starter/templates/gcp/modules/compute/variables.tf.j2 +33 -0
  111. package/tf_starter/templates/gcp/modules/database/main.tf.j2 +62 -0
  112. package/tf_starter/templates/gcp/modules/database/outputs.tf.j2 +13 -0
  113. package/tf_starter/templates/gcp/modules/database/variables.tf.j2 +29 -0
  114. package/tf_starter/templates/gcp/modules/kubernetes/main.tf.j2 +75 -0
  115. package/tf_starter/templates/gcp/modules/kubernetes/outputs.tf.j2 +14 -0
  116. package/tf_starter/templates/gcp/modules/kubernetes/variables.tf.j2 +38 -0
  117. package/tf_starter/templates/gcp/modules/lambda/main.tf.j2 +122 -0
  118. package/tf_starter/templates/gcp/modules/lambda/outputs.tf.j2 +18 -0
  119. package/tf_starter/templates/gcp/modules/lambda/variables.tf.j2 +77 -0
  120. package/tf_starter/templates/gcp/modules/messaging/main.tf.j2 +44 -0
  121. package/tf_starter/templates/gcp/modules/messaging/outputs.tf.j2 +13 -0
  122. package/tf_starter/templates/gcp/modules/messaging/variables.tf.j2 +20 -0
  123. package/tf_starter/templates/gcp/modules/monitoring/main.tf.j2 +44 -0
  124. package/tf_starter/templates/gcp/modules/monitoring/outputs.tf.j2 +9 -0
  125. package/tf_starter/templates/gcp/modules/monitoring/variables.tf.j2 +13 -0
  126. package/tf_starter/templates/gcp/modules/network/main.tf.j2 +103 -0
  127. package/tf_starter/templates/gcp/modules/network/outputs.tf.j2 +21 -0
  128. package/tf_starter/templates/gcp/modules/network/variables.tf.j2 +22 -0
  129. package/tf_starter/templates/gcp/modules/storage/main.tf.j2 +47 -0
  130. package/tf_starter/templates/gcp/modules/storage/outputs.tf.j2 +13 -0
  131. package/tf_starter/templates/gcp/modules/storage/variables.tf.j2 +16 -0
  132. package/tf_starter/templates/gcp/root/backend.tf.j2 +12 -0
  133. package/tf_starter/templates/gcp/root/main.tf.j2 +210 -0
  134. package/tf_starter/templates/gcp/root/outputs.tf.j2 +61 -0
  135. package/tf_starter/templates/gcp/root/providers.tf.j2 +18 -0
  136. package/tf_starter/templates/gcp/root/variables.tf.j2 +140 -0
  137. package/tf_starter/templates/gcp/root/versions.tf.j2 +23 -0
@@ -0,0 +1,38 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # LAMBDA MODULE — Outputs
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ output "function_name" {
6
+ description = "Name of the Lambda function"
7
+ value = aws_lambda_function.main.function_name
8
+ }
9
+
10
+ output "function_arn" {
11
+ description = "ARN of the Lambda function"
12
+ value = aws_lambda_function.main.arn
13
+ }
14
+
15
+ output "invoke_arn" {
16
+ description = "Invocation ARN of the Lambda function (for API Gateway)"
17
+ value = aws_lambda_function.main.invoke_arn
18
+ }
19
+
20
+ output "function_role_arn" {
21
+ description = "ARN of the Lambda execution IAM role"
22
+ value = aws_iam_role.lambda.arn
23
+ }
24
+
25
+ output "function_role_name" {
26
+ description = "Name of the Lambda execution IAM role"
27
+ value = aws_iam_role.lambda.name
28
+ }
29
+
30
+ output "alias_arn" {
31
+ description = "ARN of the live alias"
32
+ value = aws_lambda_alias.live.arn
33
+ }
34
+
35
+ output "log_group_name" {
36
+ description = "CloudWatch log group for the Lambda function"
37
+ value = aws_cloudwatch_log_group.lambda.name
38
+ }
@@ -0,0 +1,88 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # LAMBDA MODULE — Variables
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ variable "project_name" {
6
+ description = "Name of the project"
7
+ type = string
8
+ }
9
+
10
+ variable "environment" {
11
+ description = "Deployment environment"
12
+ type = string
13
+ }
14
+
15
+ variable "function_name" {
16
+ description = "Short name for the Lambda function (appended to project-env prefix)"
17
+ type = string
18
+ default = "app"
19
+ }
20
+
21
+ variable "runtime" {
22
+ description = "Lambda runtime identifier"
23
+ type = string
24
+ default = "python3.12"
25
+
26
+ validation {
27
+ condition = can(regex("^(python3\\.|nodejs|java|dotnet|ruby|provided)", var.runtime))
28
+ error_message = "Must be a valid Lambda runtime (e.g., python3.12, nodejs20.x)."
29
+ }
30
+ }
31
+
32
+ variable "handler" {
33
+ description = "Lambda function handler"
34
+ type = string
35
+ default = "index.handler"
36
+ }
37
+
38
+ variable "timeout" {
39
+ description = "Lambda function timeout in seconds"
40
+ type = number
41
+ default = 30
42
+
43
+ validation {
44
+ condition = var.timeout >= 1 && var.timeout <= 900
45
+ error_message = "Timeout must be between 1 and 900 seconds."
46
+ }
47
+ }
48
+
49
+ variable "memory_size" {
50
+ description = "Lambda function memory in MB"
51
+ type = number
52
+ default = 256
53
+
54
+ validation {
55
+ condition = var.memory_size >= 128 && var.memory_size <= 10240
56
+ error_message = "Memory must be between 128 and 10240 MB."
57
+ }
58
+ }
59
+
60
+ variable "environment_variables" {
61
+ description = "Additional environment variables for the Lambda function"
62
+ type = map(string)
63
+ default = {}
64
+ }
65
+
66
+ variable "deploy_in_vpc" {
67
+ description = "Deploy the Lambda function inside the VPC"
68
+ type = bool
69
+ default = false
70
+ }
71
+
72
+ variable "vpc_id" {
73
+ description = "VPC ID (required if deploy_in_vpc is true)"
74
+ type = string
75
+ default = ""
76
+ }
77
+
78
+ variable "private_subnet_ids" {
79
+ description = "Private subnet IDs (required if deploy_in_vpc is true)"
80
+ type = list(string)
81
+ default = []
82
+ }
83
+
84
+ variable "tags" {
85
+ description = "Common resource tags"
86
+ type = map(string)
87
+ default = {}
88
+ }
@@ -0,0 +1,85 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # MESSAGING MODULE — Amazon SQS
3
+ # Project: {{ project_name }}
4
+ # Generated by tf-starter
5
+ # ---------------------------------------------------------------------------------------------------------------------
6
+
7
+ locals {
8
+ name_prefix = "${var.project_name}-${var.environment}"
9
+ }
10
+
11
+ # ---------------------------------------------------------------------------------------------------------------------
12
+ # SQS QUEUE
13
+ # ---------------------------------------------------------------------------------------------------------------------
14
+
15
+ resource "aws_sqs_queue" "main" {
16
+ name = "${local.name_prefix}-queue"
17
+
18
+ message_retention_seconds = var.message_retention_seconds
19
+ visibility_timeout_seconds = var.visibility_timeout
20
+ receive_wait_time_seconds = 10 # Long polling
21
+
22
+ # Encryption at rest
23
+ sqs_managed_sse_enabled = true
24
+
25
+ tags = merge(var.tags, {
26
+ Name = "${local.name_prefix}-queue"
27
+ })
28
+ }
29
+
30
+ # ---------------------------------------------------------------------------------------------------------------------
31
+ # DEAD LETTER QUEUE
32
+ # ---------------------------------------------------------------------------------------------------------------------
33
+
34
+ resource "aws_sqs_queue" "dlq" {
35
+ name = "${local.name_prefix}-dlq"
36
+
37
+ message_retention_seconds = 1209600 # 14 days
38
+
39
+ sqs_managed_sse_enabled = true
40
+
41
+ tags = merge(var.tags, {
42
+ Name = "${local.name_prefix}-dlq"
43
+ })
44
+ }
45
+
46
+ resource "aws_sqs_queue_redrive_policy" "main" {
47
+ queue_url = aws_sqs_queue.main.id
48
+
49
+ redrive_policy = jsonencode({
50
+ deadLetterTargetArn = aws_sqs_queue.dlq.arn
51
+ maxReceiveCount = 3
52
+ })
53
+ }
54
+
55
+ resource "aws_sqs_queue_redrive_allow_policy" "dlq" {
56
+ queue_url = aws_sqs_queue.dlq.id
57
+
58
+ redrive_allow_policy = jsonencode({
59
+ redrivePermission = "byQueue"
60
+ sourceQueueArns = [aws_sqs_queue.main.arn]
61
+ })
62
+ }
63
+
64
+ # ---------------------------------------------------------------------------------------------------------------------
65
+ # SQS QUEUE POLICY — restrict access to same account
66
+ # ---------------------------------------------------------------------------------------------------------------------
67
+
68
+ data "aws_caller_identity" "current" {}
69
+
70
+ resource "aws_sqs_queue_policy" "main" {
71
+ queue_url = aws_sqs_queue.main.id
72
+
73
+ policy = jsonencode({
74
+ Version = "2012-10-17"
75
+ Statement = [
76
+ {
77
+ Sid = "AllowSameAccountAccess"
78
+ Effect = "Allow"
79
+ Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }
80
+ Action = "sqs:*"
81
+ Resource = aws_sqs_queue.main.arn
82
+ }
83
+ ]
84
+ })
85
+ }
@@ -0,0 +1,28 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # MESSAGING MODULE — Outputs
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ output "queue_url" {
6
+ description = "URL of the SQS queue"
7
+ value = aws_sqs_queue.main.url
8
+ }
9
+
10
+ output "queue_arn" {
11
+ description = "ARN of the SQS queue"
12
+ value = aws_sqs_queue.main.arn
13
+ }
14
+
15
+ output "queue_name" {
16
+ description = "Name of the SQS queue"
17
+ value = aws_sqs_queue.main.name
18
+ }
19
+
20
+ output "dlq_url" {
21
+ description = "URL of the dead-letter queue"
22
+ value = aws_sqs_queue.dlq.url
23
+ }
24
+
25
+ output "dlq_arn" {
26
+ description = "ARN of the dead-letter queue"
27
+ value = aws_sqs_queue.dlq.arn
28
+ }
@@ -0,0 +1,41 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # MESSAGING MODULE — Variables
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ variable "project_name" {
6
+ description = "Name of the project"
7
+ type = string
8
+ }
9
+
10
+ variable "environment" {
11
+ description = "Deployment environment"
12
+ type = string
13
+ }
14
+
15
+ variable "message_retention_seconds" {
16
+ description = "Number of seconds to retain messages"
17
+ type = number
18
+ default = 345600 # 4 days
19
+
20
+ validation {
21
+ condition = var.message_retention_seconds >= 60 && var.message_retention_seconds <= 1209600
22
+ error_message = "Retention must be between 60 and 1209600 seconds."
23
+ }
24
+ }
25
+
26
+ variable "visibility_timeout" {
27
+ description = "Visibility timeout in seconds"
28
+ type = number
29
+ default = 30
30
+
31
+ validation {
32
+ condition = var.visibility_timeout >= 0 && var.visibility_timeout <= 43200
33
+ error_message = "Visibility timeout must be between 0 and 43200 seconds."
34
+ }
35
+ }
36
+
37
+ variable "tags" {
38
+ description = "Common resource tags"
39
+ type = map(string)
40
+ default = {}
41
+ }
@@ -0,0 +1,155 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # MONITORING MODULE — CloudWatch Alarms, SNS Notifications
3
+ # Project: {{ project_name }}
4
+ # Generated by tf-starter
5
+ # ---------------------------------------------------------------------------------------------------------------------
6
+
7
+ locals {
8
+ name_prefix = "${var.project_name}-${var.environment}"
9
+ }
10
+
11
+ # ---------------------------------------------------------------------------------------------------------------------
12
+ # SNS TOPIC FOR ALARMS
13
+ # ---------------------------------------------------------------------------------------------------------------------
14
+
15
+ resource "aws_sns_topic" "alarms" {
16
+ name = "${local.name_prefix}-alarms"
17
+
18
+ tags = merge(var.tags, {
19
+ Name = "${local.name_prefix}-alarms"
20
+ })
21
+ }
22
+
23
+ resource "aws_sns_topic_subscription" "email" {
24
+ count = var.alarm_email != "" ? 1 : 0
25
+
26
+ topic_arn = aws_sns_topic.alarms.arn
27
+ protocol = "email"
28
+ endpoint = var.alarm_email
29
+
30
+ ### MUST EDIT THIS ###
31
+ # The email subscription must be confirmed manually via the confirmation email.
32
+ }
33
+
34
+ {% if "compute" in services %}
35
+ # ---------------------------------------------------------------------------------------------------------------------
36
+ # CLOUDWATCH ALARMS — COMPUTE (ASG)
37
+ # ---------------------------------------------------------------------------------------------------------------------
38
+
39
+ resource "aws_cloudwatch_metric_alarm" "high_cpu" {
40
+ alarm_name = "${local.name_prefix}-high-cpu"
41
+ comparison_operator = "GreaterThanThreshold"
42
+ evaluation_periods = 2
43
+ metric_name = "CPUUtilization"
44
+ namespace = "AWS/EC2"
45
+ period = 300
46
+ statistic = "Average"
47
+ threshold = 80
48
+ alarm_description = "CPU utilization exceeds 80% for 10 minutes"
49
+ alarm_actions = [aws_sns_topic.alarms.arn]
50
+ ok_actions = [aws_sns_topic.alarms.arn]
51
+
52
+ dimensions = {
53
+ AutoScalingGroupName = var.asg_name
54
+ }
55
+
56
+ tags = var.tags
57
+ }
58
+
59
+ resource "aws_cloudwatch_metric_alarm" "low_cpu" {
60
+ alarm_name = "${local.name_prefix}-low-cpu"
61
+ comparison_operator = "LessThanThreshold"
62
+ evaluation_periods = 2
63
+ metric_name = "CPUUtilization"
64
+ namespace = "AWS/EC2"
65
+ period = 300
66
+ statistic = "Average"
67
+ threshold = 20
68
+ alarm_description = "CPU utilization below 20% for 10 minutes (scale-down candidate)"
69
+ alarm_actions = [aws_sns_topic.alarms.arn]
70
+
71
+ dimensions = {
72
+ AutoScalingGroupName = var.asg_name
73
+ }
74
+
75
+ tags = var.tags
76
+ }
77
+ {% endif %}
78
+
79
+ {% if "database" in services %}
80
+ # ---------------------------------------------------------------------------------------------------------------------
81
+ # CLOUDWATCH ALARMS — DATABASE (RDS)
82
+ # ---------------------------------------------------------------------------------------------------------------------
83
+
84
+ resource "aws_cloudwatch_metric_alarm" "db_cpu" {
85
+ alarm_name = "${local.name_prefix}-db-high-cpu"
86
+ comparison_operator = "GreaterThanThreshold"
87
+ evaluation_periods = 2
88
+ metric_name = "CPUUtilization"
89
+ namespace = "AWS/RDS"
90
+ period = 300
91
+ statistic = "Average"
92
+ threshold = 80
93
+ alarm_description = "RDS CPU utilization exceeds 80% for 10 minutes"
94
+ alarm_actions = [aws_sns_topic.alarms.arn]
95
+ ok_actions = [aws_sns_topic.alarms.arn]
96
+
97
+ dimensions = {
98
+ DBInstanceIdentifier = var.db_instance_id
99
+ }
100
+
101
+ tags = var.tags
102
+ }
103
+
104
+ resource "aws_cloudwatch_metric_alarm" "db_free_storage" {
105
+ alarm_name = "${local.name_prefix}-db-low-storage"
106
+ comparison_operator = "LessThanThreshold"
107
+ evaluation_periods = 1
108
+ metric_name = "FreeStorageSpace"
109
+ namespace = "AWS/RDS"
110
+ period = 300
111
+ statistic = "Average"
112
+ threshold = 5368709120 # 5 GB in bytes
113
+ alarm_description = "RDS free storage below 5 GB"
114
+ alarm_actions = [aws_sns_topic.alarms.arn]
115
+ ok_actions = [aws_sns_topic.alarms.arn]
116
+
117
+ dimensions = {
118
+ DBInstanceIdentifier = var.db_instance_id
119
+ }
120
+
121
+ tags = var.tags
122
+ }
123
+
124
+ resource "aws_cloudwatch_metric_alarm" "db_connections" {
125
+ alarm_name = "${local.name_prefix}-db-high-connections"
126
+ comparison_operator = "GreaterThanThreshold"
127
+ evaluation_periods = 2
128
+ metric_name = "DatabaseConnections"
129
+ namespace = "AWS/RDS"
130
+ period = 300
131
+ statistic = "Average"
132
+ threshold = 100
133
+ alarm_description = "RDS connections exceed 100"
134
+ alarm_actions = [aws_sns_topic.alarms.arn]
135
+
136
+ dimensions = {
137
+ DBInstanceIdentifier = var.db_instance_id
138
+ }
139
+
140
+ tags = var.tags
141
+ }
142
+ {% endif %}
143
+
144
+ # ---------------------------------------------------------------------------------------------------------------------
145
+ # CLOUDWATCH LOG GROUP
146
+ # ---------------------------------------------------------------------------------------------------------------------
147
+
148
+ resource "aws_cloudwatch_log_group" "main" {
149
+ name = "/${var.project_name}/${var.environment}"
150
+ retention_in_days = var.environment == "prod" ? 90 : 30
151
+
152
+ tags = merge(var.tags, {
153
+ Name = "${local.name_prefix}-logs"
154
+ })
155
+ }
@@ -0,0 +1,23 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # MONITORING MODULE — Outputs
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ output "sns_topic_arn" {
6
+ description = "ARN of the SNS alarm topic"
7
+ value = aws_sns_topic.alarms.arn
8
+ }
9
+
10
+ output "sns_topic_name" {
11
+ description = "Name of the SNS alarm topic"
12
+ value = aws_sns_topic.alarms.name
13
+ }
14
+
15
+ output "log_group_name" {
16
+ description = "Name of the CloudWatch log group"
17
+ value = aws_cloudwatch_log_group.main.name
18
+ }
19
+
20
+ output "log_group_arn" {
21
+ description = "ARN of the CloudWatch log group"
22
+ value = aws_cloudwatch_log_group.main.arn
23
+ }
@@ -0,0 +1,39 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # MONITORING MODULE — Variables
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ variable "project_name" {
6
+ description = "Name of the project"
7
+ type = string
8
+ }
9
+
10
+ variable "environment" {
11
+ description = "Deployment environment"
12
+ type = string
13
+ }
14
+
15
+ variable "alarm_email" {
16
+ description = "Email address for alarm notifications"
17
+ type = string
18
+ default = ""
19
+ }
20
+
21
+ {% if "compute" in services %}
22
+ variable "asg_name" {
23
+ description = "Name of the Auto Scaling Group to monitor"
24
+ type = string
25
+ }
26
+ {% endif %}
27
+
28
+ {% if "database" in services %}
29
+ variable "db_instance_id" {
30
+ description = "ID of the RDS instance to monitor"
31
+ type = string
32
+ }
33
+ {% endif %}
34
+
35
+ variable "tags" {
36
+ description = "Common resource tags"
37
+ type = map(string)
38
+ default = {}
39
+ }
@@ -0,0 +1,147 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # NETWORK MODULE — VPC, Subnets, Internet Gateway, NAT Gateway
3
+ # Project: {{ project_name }}
4
+ # Generated by tf-starter
5
+ # ---------------------------------------------------------------------------------------------------------------------
6
+
7
+ locals {
8
+ name_prefix = "${var.project_name}-${var.environment}"
9
+ }
10
+
11
+ # ---------------------------------------------------------------------------------------------------------------------
12
+ # VPC
13
+ # ---------------------------------------------------------------------------------------------------------------------
14
+
15
+ resource "aws_vpc" "main" {
16
+ cidr_block = var.vpc_cidr
17
+ enable_dns_support = true
18
+ enable_dns_hostnames = true
19
+
20
+ tags = merge(var.tags, {
21
+ Name = "${local.name_prefix}-vpc"
22
+ })
23
+ }
24
+
25
+ # ---------------------------------------------------------------------------------------------------------------------
26
+ # INTERNET GATEWAY
27
+ # ---------------------------------------------------------------------------------------------------------------------
28
+
29
+ resource "aws_internet_gateway" "main" {
30
+ vpc_id = aws_vpc.main.id
31
+
32
+ tags = merge(var.tags, {
33
+ Name = "${local.name_prefix}-igw"
34
+ })
35
+ }
36
+
37
+ # ---------------------------------------------------------------------------------------------------------------------
38
+ # PUBLIC SUBNETS
39
+ # ---------------------------------------------------------------------------------------------------------------------
40
+
41
+ resource "aws_subnet" "public" {
42
+ count = length(var.public_subnet_cidrs)
43
+
44
+ vpc_id = aws_vpc.main.id
45
+ cidr_block = var.public_subnet_cidrs[count.index]
46
+ availability_zone = var.availability_zones[count.index]
47
+ map_public_ip_on_launch = true
48
+
49
+ tags = merge(var.tags, {
50
+ Name = "${local.name_prefix}-public-${var.availability_zones[count.index]}"
51
+ Tier = "public"
52
+ })
53
+ }
54
+
55
+ # ---------------------------------------------------------------------------------------------------------------------
56
+ # PRIVATE SUBNETS
57
+ # ---------------------------------------------------------------------------------------------------------------------
58
+
59
+ resource "aws_subnet" "private" {
60
+ count = length(var.private_subnet_cidrs)
61
+
62
+ vpc_id = aws_vpc.main.id
63
+ cidr_block = var.private_subnet_cidrs[count.index]
64
+ availability_zone = var.availability_zones[count.index]
65
+
66
+ tags = merge(var.tags, {
67
+ Name = "${local.name_prefix}-private-${var.availability_zones[count.index]}"
68
+ Tier = "private"
69
+ })
70
+ }
71
+
72
+ # ---------------------------------------------------------------------------------------------------------------------
73
+ # ELASTIC IP FOR NAT GATEWAY
74
+ # ---------------------------------------------------------------------------------------------------------------------
75
+
76
+ resource "aws_eip" "nat" {
77
+ domain = "vpc"
78
+
79
+ tags = merge(var.tags, {
80
+ Name = "${local.name_prefix}-nat-eip"
81
+ })
82
+
83
+ depends_on = [aws_internet_gateway.main]
84
+ }
85
+
86
+ # ---------------------------------------------------------------------------------------------------------------------
87
+ # NAT GATEWAY (single — for cost optimization; use one per AZ in production)
88
+ # ---------------------------------------------------------------------------------------------------------------------
89
+
90
+ resource "aws_nat_gateway" "main" {
91
+ allocation_id = aws_eip.nat.id
92
+ subnet_id = aws_subnet.public[0].id
93
+
94
+ tags = merge(var.tags, {
95
+ Name = "${local.name_prefix}-nat"
96
+ })
97
+
98
+ depends_on = [aws_internet_gateway.main]
99
+ }
100
+
101
+ # ---------------------------------------------------------------------------------------------------------------------
102
+ # ROUTE TABLES
103
+ # ---------------------------------------------------------------------------------------------------------------------
104
+
105
+ resource "aws_route_table" "public" {
106
+ vpc_id = aws_vpc.main.id
107
+
108
+ route {
109
+ cidr_block = "0.0.0.0/0"
110
+ gateway_id = aws_internet_gateway.main.id
111
+ }
112
+
113
+ tags = merge(var.tags, {
114
+ Name = "${local.name_prefix}-public-rt"
115
+ })
116
+ }
117
+
118
+ resource "aws_route_table" "private" {
119
+ vpc_id = aws_vpc.main.id
120
+
121
+ route {
122
+ cidr_block = "0.0.0.0/0"
123
+ nat_gateway_id = aws_nat_gateway.main.id
124
+ }
125
+
126
+ tags = merge(var.tags, {
127
+ Name = "${local.name_prefix}-private-rt"
128
+ })
129
+ }
130
+
131
+ # ---------------------------------------------------------------------------------------------------------------------
132
+ # ROUTE TABLE ASSOCIATIONS
133
+ # ---------------------------------------------------------------------------------------------------------------------
134
+
135
+ resource "aws_route_table_association" "public" {
136
+ count = length(aws_subnet.public)
137
+
138
+ subnet_id = aws_subnet.public[count.index].id
139
+ route_table_id = aws_route_table.public.id
140
+ }
141
+
142
+ resource "aws_route_table_association" "private" {
143
+ count = length(aws_subnet.private)
144
+
145
+ subnet_id = aws_subnet.private[count.index].id
146
+ route_table_id = aws_route_table.private.id
147
+ }
@@ -0,0 +1,33 @@
1
+ # ---------------------------------------------------------------------------------------------------------------------
2
+ # NETWORK MODULE — Outputs
3
+ # ---------------------------------------------------------------------------------------------------------------------
4
+
5
+ output "vpc_id" {
6
+ description = "ID of the VPC"
7
+ value = aws_vpc.main.id
8
+ }
9
+
10
+ output "vpc_cidr" {
11
+ description = "CIDR block of the VPC"
12
+ value = aws_vpc.main.cidr_block
13
+ }
14
+
15
+ output "public_subnet_ids" {
16
+ description = "IDs of the public subnets"
17
+ value = aws_subnet.public[*].id
18
+ }
19
+
20
+ output "private_subnet_ids" {
21
+ description = "IDs of the private subnets"
22
+ value = aws_subnet.private[*].id
23
+ }
24
+
25
+ output "internet_gateway_id" {
26
+ description = "ID of the Internet Gateway"
27
+ value = aws_internet_gateway.main.id
28
+ }
29
+
30
+ output "nat_gateway_id" {
31
+ description = "ID of the NAT Gateway"
32
+ value = aws_nat_gateway.main.id
33
+ }