fix(dash): Migrate to alb
[csit.git] / fdio.infra.terraform / terraform-aws-elastic-beanstalk-environment / main.tf
1 locals {
2   tags = {
3     "Name"        = "${var.application_name}"
4     "Environment" = "${var.application_name}"
5   }
6
7   # Settings for all loadbalancer types
8   generic_elb_settings = [
9     {
10       namespace = "aws:elasticbeanstalk:environment"
11       name      = "LoadBalancerType"
12       value     = var.environment_loadbalancer_type
13     }
14   ]
15
16   elb_settings = [
17     {
18       namespace = "aws:ec2:vpc"
19       name      = "ELBSubnets"
20       value     = join(",", [aws_subnet.subnet_a.id, aws_subnet.subnet_b.id])
21     },
22     {
23       namespace = "aws:elasticbeanstalk:environment:process:default"
24       name      = "Port"
25       value     = var.environment_process_default_port
26     },
27     {
28       namespace = "aws:elasticbeanstalk:environment:process:default"
29       name      = "Protocol"
30       value     = var.environment_loadbalancer_type == "network" ? "TCP" : "HTTP"
31     },
32     {
33       namespace = "aws:ec2:vpc"
34       name      = "ELBScheme"
35       value     = var.environment_type == "LoadBalanced" ? var.elb_scheme : ""
36     },
37     {
38       namespace = "aws:elasticbeanstalk:environment:process:default"
39       name      = "HealthCheckInterval"
40       value     = var.environment_process_default_healthcheck_interval
41     },
42     {
43       namespace = "aws:elasticbeanstalk:environment:process:default"
44       name      = "HealthyThresholdCount"
45       value     = var.environment_process_default_healthy_threshold_count
46     },
47     {
48       namespace = "aws:elasticbeanstalk:environment:process:default"
49       name      = "UnhealthyThresholdCount"
50       value     = var.environment_process_default_unhealthy_threshold_count
51     }
52   ]
53
54   generic_alb_settings = [
55     {
56       namespace = "aws:elbv2:loadbalancer"
57       name      = "SecurityGroups"
58       value     = join(",", sort(var.environment_loadbalancer_security_groups))
59     }
60   ]
61
62   alb_settings = [
63     {
64       namespace = "aws:elbv2:listener:default"
65       name      = "ListenerEnabled"
66       value     = var.default_listener_enabled || var.environment_loadbalancer_ssl_certificate_id == "" ? "true" : "false"
67     },
68     {
69       namespace = "aws:elbv2:loadbalancer"
70       name      = "ManagedSecurityGroup"
71       value     = var.environment_loadbalancer_managed_security_group
72     },
73     {
74       namespace = "aws:elbv2:listener:443"
75       name      = "ListenerEnabled"
76       value     = var.environment_loadbalancer_ssl_certificate_id == "" ? "false" : "true"
77     },
78     {
79       namespace = "aws:elbv2:listener:443"
80       name      = "Protocol"
81       value     = "HTTPS"
82     },
83     {
84       namespace = "aws:elbv2:listener:443"
85       name      = "SSLCertificateArns"
86       value     = var.environment_loadbalancer_ssl_certificate_id
87     },
88     {
89       namespace = "aws:elasticbeanstalk:environment:process:default"
90       name      = "HealthCheckPath"
91       value     = var.application_healthcheck_url
92     },
93     {
94       namespace = "aws:elasticbeanstalk:environment:process:default"
95       name      = "MatcherHTTPCode"
96       value     = join(",", sort(var.default_matcher_http_code))
97     },
98     {
99       namespace = "aws:elasticbeanstalk:environment:process:default"
100       name      = "HealthCheckTimeout"
101       value     = var.default_health_check_timeout
102     }
103   ]
104
105   nlb_settings = [
106     {
107       namespace = "aws:elbv2:listener:default"
108       name      = "ListenerEnabled"
109       value     = var.default_listener_enabled
110     }
111   ]
112
113   settings_nlb = var.environment_loadbalancer_type == "network" ? concat(local.nlb_settings, local.generic_elb_settings, local.elb_settings) : []
114   settings_alb = var.environment_loadbalancer_type == "application" ? concat(local.generic_alb_settings, local.alb_settings, local.generic_elb_settings, local.elb_settings) : []
115
116   # Full set of LoadBlanacer settings.
117   elb = var.environment_tier == "WebServer" ? concat(local.settings_nlb, local.settings_alb) : []
118 }
119
120 # Create elastic beanstalk VPC
121 resource "aws_vpc" "vpc" {
122   assign_generated_ipv6_cidr_block = true
123   cidr_block                       = var.vpc_cidr_block
124   enable_dns_hostnames             = var.vpc_enable_dns_hostnames
125   enable_dns_support               = var.vpc_enable_dns_support
126   instance_tenancy                 = var.vpc_instance_tenancy
127   tags                             = local.tags
128 }
129
130 # Create elastic beanstalk Subnets
131 resource "aws_subnet" "subnet_a" {
132   depends_on = [
133     aws_vpc.vpc
134   ]
135   availability_zone               = var.subnet_a_availability_zone
136   assign_ipv6_address_on_creation = true
137   cidr_block                      = var.subnet_a_cidr_block
138   ipv6_cidr_block                 = cidrsubnet(aws_vpc.vpc.ipv6_cidr_block, 8, 1)
139   map_public_ip_on_launch         = true
140   vpc_id                          = aws_vpc.vpc.id
141   tags                            = local.tags
142 }
143
144 resource "aws_subnet" "subnet_b" {
145   depends_on = [
146     aws_vpc.vpc
147   ]
148   availability_zone               = var.subnet_b_availability_zone
149   assign_ipv6_address_on_creation = true
150   cidr_block                      = var.subnet_b_cidr_block
151   ipv6_cidr_block                 = cidrsubnet(aws_vpc.vpc.ipv6_cidr_block, 8, 2)
152   map_public_ip_on_launch         = true
153   vpc_id                          = aws_vpc.vpc.id
154   tags                            = local.tags
155 }
156
157 resource "aws_internet_gateway" "internet_gateway" {
158   depends_on = [
159     aws_vpc.vpc
160   ]
161   vpc_id = aws_vpc.vpc.id
162   tags   = local.tags
163 }
164
165 resource "aws_route" "route" {
166   depends_on = [
167     aws_vpc.vpc,
168     aws_internet_gateway.internet_gateway
169   ]
170   destination_cidr_block = "0.0.0.0/0"
171   gateway_id             = aws_internet_gateway.internet_gateway.id
172   route_table_id         = aws_vpc.vpc.main_route_table_id
173 }
174
175 # Create elastic beanstalk IAM mapping
176 data "aws_iam_policy_document" "service" {
177   statement {
178     actions = [
179       "sts:AssumeRole"
180     ]
181     principals {
182       type        = "Service"
183       identifiers = ["elasticbeanstalk.amazonaws.com"]
184     }
185     effect = "Allow"
186   }
187 }
188
189 resource "aws_iam_role" "service" {
190   assume_role_policy = data.aws_iam_policy_document.service.json
191   name               = "${var.application_name}-eb-service"
192 }
193
194 resource "aws_iam_role_policy_attachment" "enhanced_health" {
195   policy_arn = "arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkEnhancedHealth"
196   role       = aws_iam_role.service.name
197 }
198
199 resource "aws_iam_role_policy_attachment" "service" {
200   policy_arn = "arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkService"
201   role       = aws_iam_role.service.name
202 }
203
204 data "aws_iam_policy_document" "ec2" {
205   statement {
206     actions = [
207       "sts:AssumeRole"
208     ]
209     principals {
210       type        = "Service"
211       identifiers = ["ec2.amazonaws.com"]
212     }
213     effect = "Allow"
214   }
215   statement {
216     actions = [
217       "sts:AssumeRole",
218     ]
219     principals {
220       type        = "Service"
221       identifiers = ["ssm.amazonaws.com"]
222     }
223     effect = "Allow"
224   }
225 }
226
227 resource "aws_iam_role" "ec2" {
228   assume_role_policy = data.aws_iam_policy_document.ec2.json
229   name               = "${var.application_name}-eb-ec2"
230 }
231
232 resource "aws_iam_instance_profile" "ec2_iam_instance_profile" {
233   name = "${var.application_name}-iam-instance-profile"
234   role = aws_iam_role.ec2.name
235 }
236
237 resource "aws_iam_role_policy_attachment" "multicontainer_docker" {
238   policy_arn = "arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker"
239   role       = aws_iam_role.ec2.name
240 }
241
242 resource "aws_iam_role_policy_attachment" "web_tier" {
243   policy_arn = "arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier"
244   role       = aws_iam_role.ec2.name
245 }
246
247 resource "aws_iam_role_policy_attachment" "worker_tier" {
248   policy_arn = "arn:aws:iam::aws:policy/AWSElasticBeanstalkWorkerTier"
249   role       = aws_iam_role.ec2.name
250 }
251
252 resource "aws_iam_role_policy_attachment" "ssm_automation" {
253   policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
254   role       = aws_iam_role.ec2.name
255 }
256
257 resource "aws_iam_role_policy_attachment" "ssm_ec2" {
258   policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
259   role       = aws_iam_role.ec2.name
260 }
261
262 resource "aws_iam_role_policy_attachment" "ecr_readonly" {
263   policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
264   role       = aws_iam_role.ec2.name
265 }
266
267 resource "aws_ssm_activation" "ec2" {
268   depends_on = [
269     aws_iam_role.ec2,
270     aws_iam_role_policy_attachment.ssm_ec2
271   ]
272   name               = "${var.application_name}-ec2-activation"
273   iam_role           = aws_iam_role.ec2.id
274   registration_limit = 3
275 }
276
277 data "aws_iam_policy_document" "default" {
278   statement {
279     actions = [
280       "elasticloadbalancing:DescribeInstanceHealth",
281       "elasticloadbalancing:DescribeLoadBalancers",
282       "elasticloadbalancing:DescribeTargetHealth",
283       "ec2:DescribeInstances",
284       "ec2:DescribeInstanceStatus",
285       "ec2:GetConsoleOutput",
286       "ec2:AssociateAddress",
287       "ec2:DescribeAddresses",
288       "ec2:DescribeSecurityGroups",
289       "sqs:GetQueueAttributes",
290       "sqs:GetQueueUrl",
291       "autoscaling:DescribeAutoScalingGroups",
292       "autoscaling:DescribeAutoScalingInstances",
293       "autoscaling:DescribeScalingActivities",
294       "autoscaling:DescribeNotificationConfigurations",
295     ]
296     resources = ["*"]
297     effect    = "Allow"
298   }
299
300   statement {
301     sid = "AllowOperations"
302     actions = [
303       "autoscaling:AttachInstances",
304       "autoscaling:CreateAutoScalingGroup",
305       "autoscaling:CreateLaunchConfiguration",
306       "autoscaling:DeleteLaunchConfiguration",
307       "autoscaling:DeleteAutoScalingGroup",
308       "autoscaling:DeleteScheduledAction",
309       "autoscaling:DescribeAccountLimits",
310       "autoscaling:DescribeAutoScalingGroups",
311       "autoscaling:DescribeAutoScalingInstances",
312       "autoscaling:DescribeLaunchConfigurations",
313       "autoscaling:DescribeLoadBalancers",
314       "autoscaling:DescribeNotificationConfigurations",
315       "autoscaling:DescribeScalingActivities",
316       "autoscaling:DescribeScheduledActions",
317       "autoscaling:DetachInstances",
318       "autoscaling:PutScheduledUpdateGroupAction",
319       "autoscaling:ResumeProcesses",
320       "autoscaling:SetDesiredCapacity",
321       "autoscaling:SetInstanceProtection",
322       "autoscaling:SuspendProcesses",
323       "autoscaling:TerminateInstanceInAutoScalingGroup",
324       "autoscaling:UpdateAutoScalingGroup",
325       "cloudwatch:PutMetricAlarm",
326       "ec2:AssociateAddress",
327       "ec2:AllocateAddress",
328       "ec2:AuthorizeSecurityGroupEgress",
329       "ec2:AuthorizeSecurityGroupIngress",
330       "ec2:CreateSecurityGroup",
331       "ec2:DeleteSecurityGroup",
332       "ec2:DescribeAccountAttributes",
333       "ec2:DescribeAddresses",
334       "ec2:DescribeImages",
335       "ec2:DescribeInstances",
336       "ec2:DescribeKeyPairs",
337       "ec2:DescribeSecurityGroups",
338       "ec2:DescribeSnapshots",
339       "ec2:DescribeSubnets",
340       "ec2:DescribeVpcs",
341       "ec2:DisassociateAddress",
342       "ec2:ReleaseAddress",
343       "ec2:RevokeSecurityGroupEgress",
344       "ec2:RevokeSecurityGroupIngress",
345       "ec2:TerminateInstances",
346       "ecs:CreateCluster",
347       "ecs:DeleteCluster",
348       "ecs:DescribeClusters",
349       "ecs:RegisterTaskDefinition",
350       "elasticbeanstalk:*",
351       "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
352       "elasticloadbalancing:ConfigureHealthCheck",
353       "elasticloadbalancing:CreateLoadBalancer",
354       "elasticloadbalancing:DeleteLoadBalancer",
355       "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
356       "elasticloadbalancing:DescribeInstanceHealth",
357       "elasticloadbalancing:DescribeLoadBalancers",
358       "elasticloadbalancing:DescribeTargetHealth",
359       "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
360       "elasticloadbalancing:DescribeTargetGroups",
361       "elasticloadbalancing:RegisterTargets",
362       "elasticloadbalancing:DeregisterTargets",
363       "iam:ListRoles",
364       "iam:PassRole",
365       "logs:CreateLogGroup",
366       "logs:PutRetentionPolicy",
367       "rds:DescribeDBEngineVersions",
368       "rds:DescribeDBInstances",
369       "rds:DescribeOrderableDBInstanceOptions",
370       "s3:GetObject",
371       "s3:GetObjectAcl",
372       "s3:ListBucket",
373       "sns:CreateTopic",
374       "sns:GetTopicAttributes",
375       "sns:ListSubscriptionsByTopic",
376       "sns:Subscribe",
377       "sqs:GetQueueAttributes",
378       "sqs:GetQueueUrl",
379       "codebuild:CreateProject",
380       "codebuild:DeleteProject",
381       "codebuild:BatchGetBuilds",
382       "codebuild:StartBuild",
383     ]
384     resources = ["*"]
385     effect    = "Allow"
386   }
387
388   statement {
389     sid = "AllowS3OperationsOnElasticBeanstalkBuckets"
390     actions = [
391       "s3:*"
392     ]
393     resources = [
394       "arn:aws:s3:::*"
395     ]
396     effect = "Allow"
397   }
398
399   statement {
400     sid = "AllowDeleteCloudwatchLogGroups"
401     actions = [
402       "logs:DeleteLogGroup"
403     ]
404     resources = [
405       "arn:aws:logs:*:*:log-group:/aws/elasticbeanstalk*"
406     ]
407     effect = "Allow"
408   }
409
410   statement {
411     sid = "AllowCloudformationOperationsOnElasticBeanstalkStacks"
412     actions = [
413       "cloudformation:*"
414     ]
415     resources = [
416       "arn:aws:cloudformation:*:*:stack/awseb-*",
417       "arn:aws:cloudformation:*:*:stack/eb-*"
418     ]
419     effect = "Allow"
420   }
421 }
422
423 resource "aws_iam_role_policy" "default" {
424   depends_on = [
425     aws_iam_role.ec2
426   ]
427   name   = "${var.application_name}-eb-default"
428   policy = data.aws_iam_policy_document.default.json
429   role   = aws_iam_role.ec2.id
430 }
431
432 # Create elastic beanstalk Environment
433 resource "aws_elastic_beanstalk_environment" "environment" {
434   depends_on = [
435     aws_vpc.vpc,
436     aws_subnet.subnet_a,
437     aws_subnet.subnet_b,
438     aws_ssm_activation.ec2
439   ]
440   application            = var.environment_application
441   description            = var.environment_description
442   name                   = var.environment_name
443   solution_stack_name    = var.environment_solution_stack_name
444   tier                   = var.environment_tier
445   wait_for_ready_timeout = var.environment_wait_for_ready_timeout
446   version_label          = var.environment_version_label
447   tags                   = local.tags
448
449   # aws:ec2:instances
450   setting {
451     namespace = "aws:ec2:instances"
452     name      = "InstanceTypes"
453     value     = var.instances_instance_types
454   }
455
456   # aws:ec2:vpc
457   setting {
458     namespace = "aws:ec2:vpc"
459     name      = "VPCId"
460     value     = aws_vpc.vpc.id
461   }
462
463   setting {
464     namespace = "aws:ec2:vpc"
465     name      = "Subnets"
466     value     = join(",", [aws_subnet.subnet_a.id, aws_subnet.subnet_b.id])
467   }
468
469   setting {
470     namespace = "aws:ec2:vpc"
471     name      = "AssociatePublicIpAddress"
472     value     = var.associate_public_ip_address
473   }
474
475   setting {
476     namespace = "aws:elasticbeanstalk:environment"
477     name      = "ServiceRole"
478     value     = aws_iam_role.service.name
479   }
480
481   # aws:autoscaling:launchconfiguration
482   setting {
483     namespace = "aws:autoscaling:launchconfiguration"
484     name      = "IamInstanceProfile"
485     value     = aws_iam_instance_profile.ec2_iam_instance_profile.name
486   }
487
488   setting {
489     namespace = "aws:autoscaling:launchconfiguration"
490     name      = "DisableIMDSv1"
491     value     = true
492   }
493
494   dynamic "setting" {
495     for_each = local.elb
496     content {
497       namespace = setting.value["namespace"]
498       name      = setting.value["name"]
499       value     = setting.value["value"]
500     }
501   }
502
503   # aws:autoscaling:updatepolicy:rollingupdate
504   setting {
505     namespace = "aws:autoscaling:updatepolicy:rollingupdate"
506     name      = "RollingUpdateEnabled"
507     value     = var.autoscaling_updatepolicy_rolling_update_enabled
508   }
509
510   setting {
511     namespace = "aws:autoscaling:updatepolicy:rollingupdate"
512     name      = "RollingUpdateType"
513     value     = var.autoscaling_updatepolicy_rolling_update_type
514   }
515
516   setting {
517     namespace = "aws:autoscaling:updatepolicy:rollingupdate"
518     name      = "MinInstancesInService"
519     value     = var.autoscaling_updatepolicy_min_instance_in_service
520   }
521
522   setting {
523     namespace = "aws:elasticbeanstalk:application"
524     name      = "Application Healthcheck URL"
525     value     = var.application_healthcheck_url
526   }
527
528   # aws:elasticbeanstalk:command
529   setting {
530     namespace = "aws:elasticbeanstalk:command"
531     name      = "DeploymentPolicy"
532     value     = var.command_deployment_policy
533   }
534
535   # aws:autoscaling:updatepolicy:rollingupdate
536   setting {
537     namespace = "aws:autoscaling:updatepolicy:rollingupdate"
538     name      = "MaxBatchSize"
539     value     = var.updatepolicy_max_batch_size
540   }
541
542   # aws:elasticbeanstalk:healthreporting:system
543   setting {
544     namespace = "aws:elasticbeanstalk:healthreporting:system"
545     name      = "SystemType"
546     value     = var.healthreporting_system_type
547   }
548
549   # aws:elasticbeanstalk:managedactions
550   setting {
551     namespace = "aws:elasticbeanstalk:managedactions"
552     name      = "ManagedActionsEnabled"
553     value     = var.managedactions_managed_actions_enabled ? "true" : "false"
554   }
555
556   setting {
557     namespace = "aws:elasticbeanstalk:managedactions"
558     name      = "PreferredStartTime"
559     value     = var.managedactions_preferred_start_time
560   }
561
562   # aws:elasticbeanstalk:managedactions:platformupdate
563   setting {
564     namespace = "aws:elasticbeanstalk:managedactions:platformupdate"
565     name      = "UpdateLevel"
566     value     = var.managedactions_platformupdate_update_level
567   }
568
569   setting {
570     namespace = "aws:elasticbeanstalk:managedactions:platformupdate"
571     name      = "InstanceRefreshEnabled"
572     value     = var.managedactions_platformupdate_instance_refresh_enabled
573   }
574
575   setting {
576     namespace = "aws:elasticbeanstalk:command"
577     name      = "IgnoreHealthCheck"
578     value     = var.command_ignore_health_check
579   }
580
581   # aws:autoscaling:asg
582   setting {
583     namespace = "aws:autoscaling:asg"
584     name      = "MinSize"
585     value     = var.autoscaling_asg_minsize
586   }
587   setting {
588     namespace = "aws:autoscaling:asg"
589     name      = "MaxSize"
590     value     = var.autoscaling_asg_maxsize
591   }
592
593   # aws:autoscaling:trigger
594   setting {
595     namespace = "aws:autoscaling:trigger"
596     name      = "MeasureName"
597     value     = var.autoscaling_trigger_measure_name
598   }
599
600   setting {
601     namespace = "aws:autoscaling:trigger"
602     name      = "Statistic"
603     value     = var.autoscaling_trigger_statistic
604   }
605
606   setting {
607     namespace = "aws:autoscaling:trigger"
608     name      = "Unit"
609     value     = var.autoscaling_trigger_unit
610   }
611
612   setting {
613     namespace = "aws:autoscaling:trigger"
614     name      = "LowerThreshold"
615     value     = var.autoscaling_trigger_lower_threshold
616   }
617
618   setting {
619     namespace = "aws:autoscaling:trigger"
620     name      = "LowerBreachScaleIncrement"
621     value     = var.autoscaling_trigger_lower_breach_scale_increment
622   }
623
624   setting {
625     namespace = "aws:autoscaling:trigger"
626     name      = "UpperThreshold"
627     value     = var.autoscaling_trigger_upper_threshold
628   }
629
630   setting {
631     namespace = "aws:autoscaling:trigger"
632     name      = "UpperBreachScaleIncrement"
633     value     = var.autoscaling_trigger_upper_breach_scale_increment
634   }
635
636   # aws:elasticbeanstalk:hostmanager
637   setting {
638     namespace = "aws:elasticbeanstalk:hostmanager"
639     name      = "LogPublicationControl"
640     value     = var.hostmanager_log_publication_control ? "true" : "false"
641   }
642
643   # aws:elasticbeanstalk:cloudwatch:logs
644   setting {
645     namespace = "aws:elasticbeanstalk:cloudwatch:logs"
646     name      = "StreamLogs"
647     value     = var.cloudwatch_logs_stream_logs ? "true" : "false"
648   }
649
650   setting {
651     namespace = "aws:elasticbeanstalk:cloudwatch:logs"
652     name      = "DeleteOnTerminate"
653     value     = var.cloudwatch_logs_delete_on_terminate ? "true" : "false"
654   }
655
656   setting {
657     namespace = "aws:elasticbeanstalk:cloudwatch:logs"
658     name      = "RetentionInDays"
659     value     = var.cloudwatch_logs_retention_in_days
660   }
661
662   # aws:elasticbeanstalk:cloudwatch:logs:health
663   setting {
664     namespace = "aws:elasticbeanstalk:cloudwatch:logs:health"
665     name      = "HealthStreamingEnabled"
666     value     = var.cloudwatch_logs_health_health_streaming_enabled ? "true" : "false"
667   }
668
669   setting {
670     namespace = "aws:elasticbeanstalk:cloudwatch:logs:health"
671     name      = "DeleteOnTerminate"
672     value     = var.cloudwatch_logs_health_delete_on_terminate ? "true" : "false"
673   }
674
675   setting {
676     namespace = "aws:elasticbeanstalk:cloudwatch:logs:health"
677     name      = "RetentionInDays"
678     value     = var.cloudwatch_logs_health_retention_in_days
679   }
680
681   # aws:elasticbeanstalk:application:environment
682   dynamic "setting" {
683     for_each = var.environment_variables
684     content {
685       namespace = "aws:elasticbeanstalk:application:environment"
686       name      = setting.key
687       value     = setting.value
688     }
689   }
690 }