diff --git a/README.md b/README.md index 3242a97..5e66d71 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_cloudfront_origin_access_control.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_control) | resource | | [aws_cloudwatch_event_rule.ecs_cluster_infrastructure_ecs_asg_diff_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | | [aws_cloudwatch_event_rule.ecs_cluster_infrastructure_pending_task_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | +| [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | | [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_service_ecr_scan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | | [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | | [aws_cloudwatch_event_rule.infrastructure_rds_s3_backups_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | @@ -68,6 +69,7 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_cloudwatch_event_target.ecr_scan_event_target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | | [aws_cloudwatch_event_target.ecs_cluster_infrastructure_ecs_asg_diff_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | | [aws_cloudwatch_event_target.ecs_cluster_infrastructure_pending_task_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | +| [aws_cloudwatch_event_target.infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | | [aws_cloudwatch_event_target.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | | [aws_cloudwatch_event_target.infrastructure_rds_s3_backups_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | | [aws_cloudwatch_event_target.infrastructure_rds_s3_backups_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | @@ -81,6 +83,7 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_cloudwatch_metric_alarm.infrastructure_ecs_cluster_asg_cpu](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource | | [aws_cloudwatch_metric_alarm.infrastructure_ecs_cluster_ecs_asg_diff](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource | | [aws_cloudwatch_metric_alarm.infrastructure_ecs_cluster_pending_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource | +| [aws_codebuild_project.infrastructure_ecs_cluster_logspout_image_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource | | [aws_codebuild_project.infrastructure_ecs_cluster_service_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource | | [aws_codebuild_project.infrastructure_rds_s3_backups_image_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource | | [aws_codedeploy_app.infrastructure_ecs_cluster_service_blue_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codedeploy_app) | resource | @@ -92,11 +95,14 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_db_parameter_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_parameter_group) | resource | | [aws_db_subnet_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_subnet_group) | resource | | [aws_default_network_acl.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_network_acl) | resource | +| [aws_ecr_repository.infrastructure_ecs_cluster_logspout](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecr_repository.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecr_repository.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecs_cluster.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource | | [aws_ecs_cluster.infrastrucutre_rds_tooling](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource | +| [aws_ecs_service.infrastructure_ecs_cluster_logspout](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource | | [aws_ecs_service.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource | +| [aws_ecs_task_definition.infrastructure_ecs_cluster_logspout](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource | | [aws_ecs_task_definition.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource | | [aws_ecs_task_definition.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource | | [aws_ecs_task_definition.infrastructure_rds_s3_backups_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource | @@ -138,6 +144,9 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.infrastructure_ecs_cluster_pass_role_ssm_dhmc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.infrastructure_ecs_cluster_service_blue_green_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | @@ -178,6 +187,7 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_iam_role.ecs_cluster_infrastructure_pending_task_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.infrastructure_ecs_cluster_logspout_image_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.infrastructure_ecs_cluster_service_blue_green_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.infrastructure_ecs_cluster_service_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.infrastructure_ecs_cluster_service_codepipeline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | @@ -208,6 +218,9 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_pass_role_ssm_dhmc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_blue_green_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | @@ -368,6 +381,7 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_https_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_logspout_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_nfs_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_ingress_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | @@ -399,6 +413,7 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_wafv2_web_acl.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource | | [random_password.infrastructure_ecs_cluster_service_cloudfront_bypass_protection_secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | | [random_password.infrastructure_rds_root](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [terraform_data.infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource | | [terraform_data.infrastructure_ecs_cluster_service_blue_green_create_codedeploy_deployment](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource | | [terraform_data.infrastructure_ecs_cluster_service_env_file](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource | | [terraform_data.infrastructure_rds_s3_backups_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource | @@ -483,6 +498,8 @@ This project creates and manages resources within an AWS account for infrastruct | [infrastructure\_ecs\_cluster\_services\_alb\_enable\_global\_accelerator](#input\_infrastructure\_ecs\_cluster\_services\_alb\_enable\_global\_accelerator) | Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution. | `bool` | n/a | yes | | [infrastructure\_ecs\_cluster\_services\_alb\_ip\_allow\_list](#input\_infrastructure\_ecs\_cluster\_services\_alb\_ip\_allow\_list) | IP allow list for ingress traffic to the infrastructure ECS cluster services ALB | `list(string)` | n/a | yes | | [infrastructure\_ecs\_cluster\_services\_alb\_logs\_retention](#input\_infrastructure\_ecs\_cluster\_services\_alb\_logs\_retention) | Retention in days for the infrasrtucture ecs cluster ALB logs | `number` | n/a | yes | +| [infrastructure\_ecs\_cluster\_syslog\_endpoint](#input\_infrastructure\_ecs\_cluster\_syslog\_endpoint) | ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234' | `string` | n/a | yes | +| [infrastructure\_ecs\_cluster\_syslog\_permitted\_peer](#input\_infrastructure\_ecs\_cluster\_syslog\_permitted\_peer) | Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com') | `string` | n/a | yes | | [infrastructure\_ecs\_cluster\_termination\_timeout](#input\_infrastructure\_ecs\_cluster\_termination\_timeout) | The timeout for the terminiation lifecycle hook | `number` | n/a | yes | | [infrastructure\_ecs\_cluster\_wafs](#input\_infrastructure\_ecs\_cluster\_wafs) | Map of WAF ACLs to craete, which can be used with service CloudFront distributions |
map(object({
ipv4_deny_list = optional(list(string), null)
ipv4_allow_list = optional(list(string), null)
ipv6_deny_list = optional(list(string), null)
ipv6_allow_list = optional(list(string), null)
aws_managed_rules = optional(list(object({
name = string
action = string
exclude_rules = optional(list(string), null)
excluded_path_patterns = optional(list(string), null)
})), null)
}))
| n/a | yes | | [infrastructure\_elasticache](#input\_infrastructure\_elasticache) | Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set."
{
elasticache-name = {
type: Choose either `cluster` or `serverless`
engine: ElastiCache engine (Only `redis` is currently supported)
engine\_version: ElastiCache Engine version (For serverless, Specify the major version only)
parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })
cluster\_node\_type: ElastiCache Cluster node type
cluster\_node\_count: ElastiCache Cluster node count
serverless\_max\_storage: Serverless maximum storage
serverless\_max\_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)
snapshot\_retention\_limit: Snapshot retention limit
}
} |
map(object({
type = optional(string, null)
engine = optional(string, null)
engine_version = optional(string, null)
parameters = optional(map(string), null)
cluster_node_type = optional(string, null)
cluster_node_count = optional(number, null)
serverless_max_storage = optional(string, null)
serverless_max_ecpu = optional(number, null)
snapshot_retention_limit = optional(number, null)
}))
| n/a | yes | diff --git a/buildspecs/dalmatian-logspout.yml b/buildspecs/dalmatian-logspout.yml new file mode 100644 index 0000000..85a2d70 --- /dev/null +++ b/buildspecs/dalmatian-logspout.yml @@ -0,0 +1,24 @@ +version: 0.2 + +phases: + pre_build: + commands: + - echo "Build started on $(date)" + - echo "Logging in to Amazon ECR..." + - aws ecr get-login-password --region "$AWS_DEFAULT_REGION" | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com" + - | + if [ -n "$DOCKERHUB_USERNAME" ] && [ -n "DOCKERHUB_TOKEN" ]; + then + echo "Logging into Dockerhub ..."; + echo "$DOCKERHUB_TOKEN" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin; + fi; + - echo "Pulling Logspout docker image ..." + - docker pull gliderlabs/logspout:v3.2.14 + build: + commands: + - echo "Adding ECR repo tag..." + - docker tag gliderlabs/logspout:v3.2.14 "$REPOSITORY_URI:latest" + post_build: + commands: + - echo "Pushing the Docker image..." + - docker push "$REPOSITORY_URI:latest" diff --git a/container-definitions/app.json.tpl b/container-definitions/app.json.tpl index 828323b..9a8c608 100644 --- a/container-definitions/app.json.tpl +++ b/container-definitions/app.json.tpl @@ -1,7 +1,5 @@ [ { - "essential": true, - "memoryReservation": 16, "image": "${image}", "name": "${container_name}", %{ if cloudwatch_log_group != "" } @@ -52,6 +50,13 @@ %{ if linux_parameters != "{}" } "linuxParameters": ${linux_parameters}, %{ endif } - "entrypoint": ${entrypoint} + %{if entrypoint != "[]"} + "entrypoint": ${entrypoint}, + %{ endif } + %{if command != "[]"} + "command": ${command}, + %{ endif } + "memoryReservation": 16, + "essential": true } ] diff --git a/ec2-userdata/ecs-instance.tpl b/ec2-userdata/ecs-instance.tpl index ff17e1e..186273c 100644 --- a/ec2-userdata/ecs-instance.tpl +++ b/ec2-userdata/ecs-instance.tpl @@ -34,6 +34,25 @@ fi sudo yum install -y \ jq \ rsync +%{~ if syslog_endpoint != "" } +# Configure Syslog +sudo yum install -y \ + rsyslog-gnutls + +{ + echo "\$DefaultNetstreamDriverCAFile /etc/ssl/certs/ca-bundle.crt" + echo "\$ActionSendStreamDriver gtls # use gtls netstream driver" + echo "\$ActionSendStreamDriverMode 1 # require TLS" + echo "\$ActionSendStreamDriverAuthMode x509/name # authenticate by hostname" +%{~ if syslog_permitted_peer != ""} + echo "\$ActionSendStreamDriverPermittedPeer ${syslog_permitted_peer}" +%{~ endif } + echo "*.* @@${syslog_endpoint}" +} > /etc/rsyslog.d/syslog-remote.conf + +service rsyslog restart +%{ endif } + %{~ if efs_id != ""} # EFS sudo mkdir -p /mnt/efs diff --git a/ecs-cluster-infrastructure-logspout-ecr.tf b/ecs-cluster-infrastructure-logspout-ecr.tf new file mode 100644 index 0000000..0467db2 --- /dev/null +++ b/ecs-cluster-infrastructure-logspout-ecr.tf @@ -0,0 +1,17 @@ +resource "aws_ecr_repository" "infrastructure_ecs_cluster_logspout" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + name = "${local.resource_prefix}-ecs-cluster-logspout" + + #tfsec:ignore:aws-ecr-enforce-immutable-repository + image_tag_mutability = "MUTABLE" + + encryption_configuration { + encryption_type = local.infrastructure_kms_encryption ? "KMS" : "AES256" + kms_key = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null + } + + image_scanning_configuration { + scan_on_push = true + } +} diff --git a/ecs-cluster-infrastructure-logspout-image-codebuild.tf b/ecs-cluster-infrastructure-logspout-image-codebuild.tf new file mode 100644 index 0000000..5b9ec3e --- /dev/null +++ b/ecs-cluster-infrastructure-logspout-image-codebuild.tf @@ -0,0 +1,146 @@ +resource "aws_iam_role" "infrastructure_ecs_cluster_logspout_image_codebuild" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + name = "${local.resource_prefix}-${substr(sha512("ecs-cluster-logspout-image-codebuild"), 0, 6)}" + description = "${local.resource_prefix}-ecs-cluster-logspout-image-codebuild" + assume_role_policy = templatefile( + "${path.root}/policies/assume-roles/service-principle-standard.json.tpl", + { services = jsonencode(["codebuild.amazonaws.com", "events.amazonaws.com"]) } + ) +} + +resource "aws_iam_policy" "infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + name = "${local.resource_prefix}-${substr(sha512("ecs-cluster-logspout-image-codebuild-cloudwatch-rw"), 0, 6)}" + description = "${local.resource_prefix}-ecs-cluster-logspout-image-codebuild-cloudwatch-rw" + policy = templatefile("${path.root}/policies/cloudwatch-logs-rw.json.tpl", {}) +} + +resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + role = aws_iam_role.infrastructure_ecs_cluster_logspout_image_codebuild[0].name + policy_arn = aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw[0].arn +} + +resource "aws_iam_policy" "infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + name = "${local.resource_prefix}-${substr(sha512("ecs-cluster-logspout-image-codebuild-allow-builds"), 0, 6)}" + description = "${local.resource_prefix}-ecs-cluster-logspout-image-codebuild-allow-builds" + policy = templatefile("${path.root}/policies/codebuild-allow-builds.json.tpl", {}) +} + +resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + role = aws_iam_role.infrastructure_ecs_cluster_logspout_image_codebuild[0].name + policy_arn = aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds[0].arn +} + +resource "aws_iam_policy" "infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + name = "${local.resource_prefix}-${substr(sha512("ecs-cluster-logspout-image-codebuild-ecr-push"), 0, 6)}" + description = "${local.resource_prefix}-ecs-cluster-logspout-image-codebuild-ecr-push" + policy = templatefile( + "${path.root}/policies/ecr-push.json.tpl", + { ecr_repository_arn = aws_ecr_repository.infrastructure_ecs_cluster_logspout[0].arn } + ) +} + +resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + role = aws_iam_role.infrastructure_ecs_cluster_logspout_image_codebuild[0].name + policy_arn = aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push[0].arn +} + +resource "aws_codebuild_project" "infrastructure_ecs_cluster_logspout_image_build" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + name = "${local.resource_prefix}-ecs-cluster-logspout-image-build" + description = "${local.resource_prefix} ECS Cluster Logspout Image Build" + build_timeout = "20" + service_role = aws_iam_role.infrastructure_ecs_cluster_logspout_image_codebuild[0].arn + + artifacts { + type = "NO_ARTIFACTS" + } + + environment { + compute_type = "BUILD_GENERAL1_SMALL" + image = "aws/codebuild/standard:7.0" + type = "LINUX_CONTAINER" + privileged_mode = true + + environment_variable { + name = "AWS_ACCOUNT_ID" + value = local.aws_account_id + } + + environment_variable { + name = "REPOSITORY_URI" + value = aws_ecr_repository.infrastructure_ecs_cluster_logspout[0].repository_url + } + + environment_variable { + name = "DOCKERHUB_USERNAME" + value = local.infrastructure_dockerhub_username + } + + environment_variable { + name = "DOCKERHUB_TOKEN" + value = local.infrastructure_dockerhub_token + } + } + + source { + type = "NO_SOURCE" + buildspec = templatefile("${path.root}/buildspecs/dalmatian-logspout.yml", {}) + } + + depends_on = [ + aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw, + aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds, + aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push, + ] +} + +resource "terraform_data" "infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild" { + count = local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + triggers_replace = [ + md5(templatefile("${path.root}/buildspecs/dalmatian-logspout.yml", {})), + ] + + provisioner "local-exec" { + interpreter = ["/bin/bash", "-c"] + command = < 0 ? each.value["cidr_blocks"] : null security_group_id = aws_security_group.infrastructure_ecs_cluster_container_instances[0].id } + +resource "aws_security_group_rule" "infrastructure_ecs_cluster_container_instances_egress_logspout_tcp" { + count = local.enable_infrastructure_ecs_cluster && local.infrastrucutre_ecs_cluster_logspout_enabled ? 1 : 0 + + description = "Allow Logspout tcp outbound" + type = "egress" + from_port = local.infrastructure_ecs_cluster_syslog_port + to_port = local.infrastructure_ecs_cluster_syslog_port + protocol = "tcp" + # tfsec:ignore:aws-ec2-no-public-egress-sgr + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.infrastructure_ecs_cluster_container_instances[0].id +} diff --git a/ecs-cluster-infrastructure-service-scheduled-task.tf b/ecs-cluster-infrastructure-service-scheduled-task.tf index 814d9bf..e6d712e 100644 --- a/ecs-cluster-infrastructure-service-scheduled-task.tf +++ b/ecs-cluster-infrastructure-service-scheduled-task.tf @@ -20,6 +20,7 @@ resource "aws_ecs_task_definition" "infrastructure_ecs_cluster_service_scheduled container_name = each.value["container_name"] image = aws_ecr_repository.infrastructure_ecs_cluster_service[each.value["container_name"]].repository_url entrypoint = each.value["entrypoint"] != null ? jsonencode(each.value["entrypoint"]) : "[]" + command = jsonencode([]) environment_file_s3 = "${aws_s3_bucket.infrastructure_ecs_cluster_service_environment_files[0].arn}/${each.value["container_name"]}.env" environment = jsonencode([]) secrets = jsonencode([]) diff --git a/ecs-cluster-infrastructure-service.tf b/ecs-cluster-infrastructure-service.tf index 91db4e4..a08574c 100644 --- a/ecs-cluster-infrastructure-service.tf +++ b/ecs-cluster-infrastructure-service.tf @@ -222,6 +222,7 @@ resource "aws_ecs_task_definition" "infrastructure_ecs_cluster_service" { container_name = each.key image = aws_ecr_repository.infrastructure_ecs_cluster_service[each.key].repository_url entrypoint = each.value["container_entrypoint"] != null ? jsonencode(each.value["container_entrypoint"]) : "[]" + command = jsonencode([]) environment_file_s3 = "${aws_s3_bucket.infrastructure_ecs_cluster_service_environment_files[0].arn}/${each.key}.env" environment = jsonencode([]) secrets = jsonencode([]) diff --git a/locals.tf b/locals.tf index d4b3ea6..6871134 100644 --- a/locals.tf +++ b/locals.tf @@ -175,6 +175,10 @@ locals { infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs infrastructure_ecs_cluster_enable_ssm_dhmc = local.enable_infrastructure_ecs_cluster ? data.external.ssm_dhmc_setting[0].result.setting_value != "$None" : false + infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint + infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != "" ? split(":", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null + infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer + infrastrucutre_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && local.infrastructure_ecs_cluster_syslog_endpoint != "" infrastructure_ecs_cluster_user_data = base64encode( templatefile("ec2-userdata/ecs-instance.tpl", { docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name, @@ -185,9 +189,11 @@ locals { efs_id = local.enable_infrastructure_ecs_cluster_efs && ( local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : "", - region = local.aws_region, - efs_dirs = join(" ", local.ecs_cluster_efs_directories), - log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode + region = local.aws_region, + efs_dirs = join(" ", local.ecs_cluster_efs_directories), + syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint + syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer + log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode }) ) diff --git a/rds-infrastructure-s3-backups-task-definition.tf b/rds-infrastructure-s3-backups-task-definition.tf index c1e02d0..6b80ebe 100644 --- a/rds-infrastructure-s3-backups-task-definition.tf +++ b/rds-infrastructure-s3-backups-task-definition.tf @@ -140,6 +140,7 @@ resource "aws_ecs_task_definition" "infrastructure_rds_s3_backups_scheduled_task s3_bucket_name = aws_s3_bucket.infrastructure_rds_s3_backups[0].bucket } )]) + command = jsonencode([]) environment_file_s3 = "" environment = jsonencode([ { diff --git a/variables.tf b/variables.tf index 7168968..039add4 100644 --- a/variables.tf +++ b/variables.tf @@ -423,6 +423,16 @@ variable "infrastructure_ecs_cluster_enable_execute_command_logging" { type = bool } +variable "infrastructure_ecs_cluster_syslog_endpoint" { + description = "ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'" + type = string +} + +variable "infrastructure_ecs_cluster_syslog_permitted_peer" { + description = "Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')" + type = string +} + variable "infrastructure_ecs_cluster_wafs" { description = "Map of WAF ACLs to craete, which can be used with service CloudFront distributions" type = map(object({