Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions terraform/modules/service/data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ data "aws_ssm_parameter" "mtls_image_tag" {
count = var.enable_mtls_sidecar ? 1 : 0
name = "/cdap/${local.cdap_ssm_env}/nonsensitive/mtls-sidecar/image-tag"
}

data "aws_service_discovery_http_namespace" "service_discovery_namespace" {
name = "${var.platform.env}.${var.platform.app}.cmscloud.local"
}
19 changes: 12 additions & 7 deletions terraform/modules/service/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ resource "aws_iam_role_policy" "execution" {
policy = data.aws_iam_policy_document.execution[0].json
}


data "aws_iam_policy_document" "execution" {
count = var.execution_role_arn != null ? 0 : 1
statement {
Expand Down Expand Up @@ -77,7 +76,7 @@ data "aws_iam_policy_document" "execution" {
}

dynamic "statement" {
for_each = var.enable_ecs_service_connect ? [1] : []
for_each = (length(var.service_connect) > 0) ? [1] : []
content {
sid = "AllowPassServiceConnectRole"
actions = ["iam:PassRole"]
Expand All @@ -91,7 +90,7 @@ data "aws_iam_policy_document" "execution" {
#---------------------------

resource "aws_iam_role" "service_connect" {
count = var.enable_ecs_service_connect ? 1 : 0
count = (length(var.service_connect) > 0) ? 1 : 0
name = "${local.service_name_full}-service-connect"

assume_role_policy = jsonencode({
Expand All @@ -112,14 +111,14 @@ resource "aws_iam_role" "service_connect" {
}

resource "aws_iam_policy" "service_connect" {
count = var.enable_ecs_service_connect ? 1 : 0
count = (length(var.service_connect) > 0) ? 1 : 0
name = "${local.service_name_full}-service-connect"
description = "Base permissions for ECS Service Connect TLS lifecycle"
policy = data.aws_iam_policy_document.service_connect.json
}

resource "aws_iam_role_policy_attachment" "service_connect" {
count = var.enable_ecs_service_connect ? 1 : 0
count = (length(var.service_connect) > 0) ? 1 : 0
role = aws_iam_role.service_connect[0].name
policy_arn = aws_iam_policy.service_connect[0].arn
}
Expand All @@ -137,7 +136,7 @@ data "aws_iam_policy_document" "service_connect" {
}

dynamic "statement" {
for_each = var.enable_ecs_service_connect ? [1] : []
for_each = (length(var.service_connect) > 0) ? [1] : []
content {
sid = "AllowCertManagement"
actions = [
Expand All @@ -163,6 +162,7 @@ data "aws_iam_policy_document" "service_connect" {
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:UpdateSecret",
"secretsmanager:UpdateSecretVersionStage",
"secretsmanager:DeleteSecret",
"secretsmanager:PutSecretValue",
"secretsmanager:TagResource",
Expand Down Expand Up @@ -284,7 +284,6 @@ resource "aws_iam_policy" "ecs_exec" {
policy = data.aws_iam_policy_document.ecs_exec.json
}


data "aws_iam_policy_document" "ecs_exec" {
statement {
sid = "AllowECSExec"
Expand All @@ -297,3 +296,9 @@ data "aws_iam_policy_document" "ecs_exec" {
resources = ["*"]
}
}

resource "aws_iam_role_policy_attachment" "ecs_exec" {
count = var.enable_execute_command ? 1 : 0
role = aws_iam_role.task.name
policy_arn = aws_iam_policy.ecs_exec[0].arn
}
81 changes: 49 additions & 32 deletions terraform/modules/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ locals {

sc_port_name = try(
coalesce(
var.service_connect_port_name,
var.service_connect[0].port_name,
local.enable_mtls_sidecar ? "proxy" : try(
[for pm in coalesce(var.port_mappings, []) : pm.name if pm.name != null][0],
null
Expand Down Expand Up @@ -248,23 +248,27 @@ locals {
}
]

environment = [
{ name = "ECS_FARGATE", value = "true" },
{ name = "DD_APM_ENABLED", value = "true" },
{ name = "DD_APM_NON_LOCAL_TRAFFIC", value = "true" },
{ name = "DD_APM_RECEIVER_PORT", value = "8126" },
{ name = "DD_APM_TELEMETRY_ENABLED", value = "false" },
{ name = "DD_DATA_STREAMS_ENABLED", value = "false" },
{ name = "DD_DOGSTATSD_NON_LOCAL_TRAFFIC", value = "true" },
{ name = "DD_DOGSTATSD_PORT", value = "8125" }, # Default
{ name = "DD_ECS_TASK_COLLECTION_ENABLED", value = "true" },
{ name = "DD_ENV", value = var.platform.env },
{ name = "DD_LOGS_ENABLED", value = "false" }, # DD logging is currently not approved
{ name = "DD_PROCESS_AGENT_ENABLED", value = "true" },
{ name = "DD_SERVICE", value = local.service_name },
{ name = "DD_SITE", value = "ddog-gov.com" },
{ name = "DD_TAGS", value = "application:${var.platform.app}, service:${local.service_name}" },
]
environment = concat(
[
{ name = "ECS_FARGATE", value = "true" },
{ name = "DD_APM_ENABLED", value = "true" },
{ name = "DD_APM_NON_LOCAL_TRAFFIC", value = "true" },
{ name = "DD_APM_RECEIVER_PORT", value = "8126" },
{ name = "DD_APM_TELEMETRY_ENABLED", value = "false" },
{ name = "DD_DATA_STREAMS_ENABLED", value = "false" },
{ name = "DD_DOGSTATSD_NON_LOCAL_TRAFFIC", value = "true" },
{ name = "DD_DOGSTATSD_PORT", value = "8125" }, # Default
{ name = "DD_ECS_TASK_COLLECTION_ENABLED", value = "true" },
{ name = "DD_ENV", value = var.platform.env },
{ name = "DD_LOGS_ENABLED", value = "false" }, # DD logging is currently not approved
{ name = "DD_PROCESS_AGENT_ENABLED", value = "true" },
{ name = "DD_SERVICE", value = local.service_name },
{ name = "DD_SITE", value = "ddog-gov.com" },
{ name = "DD_TAGS", value = "application:${var.platform.app}, service:${local.service_name}" },
],
var.additional_dd_environment
)

secrets = [{ name = "DD_API_KEY", valueFrom = data.aws_ssm_parameter.datadog_api_key.name }]
}
}
Expand Down Expand Up @@ -433,26 +437,38 @@ resource "aws_ecs_service" "this" {
}
}

dynamic "service_connect_configuration" {
for_each = var.enable_ecs_service_connect ? [1] : []
content {
enabled = true
namespace = var.service_connect_namespace_arn
service_connect_configuration {
enabled = (length(var.service_connect) > 0) ? true : false
namespace = data.aws_service_discovery_http_namespace.service_discovery_namespace.arn

service {
discovery_name = local.service_name
port_name = local.sc_port_name
log_configuration {
log_driver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.app.name
"awslogs-stream-prefix" = "service-connect"
"awslogs-region" = "us-east-1"
}
}

access_log_configuration {
format = "TEXT"
include_query_parameters = "ENABLED"
}

dynamic "service" {
for_each = var.service_connect

content {
discovery_name = service.value.discovery_name
port_name = service.value.port_name

client_alias {
port = coalesce(
var.service_connect_client_port,
local.sc_port_name != null ? try(local.port_map[local.sc_port_name], null) : null
)
dns_name = local.service_name
dns_name = service.value.dns_name
port = service.value.port
}

tls {
kms_key = var.platform.kms_alias_primary.target_key_arn
kms_key = var.platform.kms_alias_primary["target_key_arn"]
role_arn = aws_iam_role.service_connect[0].arn

issuer_cert_authority {
Expand All @@ -462,6 +478,7 @@ resource "aws_ecs_service" "this" {
}
}
}

deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
deployment_maximum_percent = var.deployment_maximum_percent
health_check_grace_period_seconds = var.health_check_grace_period_seconds
Expand Down
27 changes: 1 addition & 26 deletions terraform/modules/service/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ output "listener_rule_arn" {

output "service_connect_role_arn" {
description = "ARN of the Service Connect IAM role (if Service Connect is enabled)."
value = var.enable_ecs_service_connect ? aws_iam_role.service_connect[0].arn : null
value = (length(var.service_connect) > 0) ? aws_iam_role.service_connect[0].arn : null
}

output "task_security_group_id" {
Expand All @@ -47,28 +47,3 @@ output "task_role_arn" {
description = "ARN of the ECS task role (module-managed or externally provided)."
value = aws_iam_role.task.arn
}

output "service_connect_port" {
description = "Port clients should use when calling this service via Service Connect."
value = var.enable_ecs_service_connect ? coalesce(
var.service_connect_client_port,
local.sc_port_name != null ? try(local.port_map[local.sc_port_name], null) : null
) : null
}

output "service_connect_name" {
description = "Short DNS name for this service within the Service Connect namespace. Other services call this service at http://<service_connect_name>:<service_connect_port>/."
value = var.enable_ecs_service_connect ? local.service_name : null
}

output "service_connect_endpoint" {
description = "Full Service Connect endpoint for this service (e.g. http://api:8080). Null if Service Connect is not enabled."
value = var.enable_ecs_service_connect ? format(
"http://%s:%d",
local.service_name,
coalesce(
var.service_connect_client_port,
local.sc_port_name != null ? try(local.port_map[local.sc_port_name], null) : null
)
) : null
}
53 changes: 18 additions & 35 deletions terraform/modules/service/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -119,41 +119,16 @@ variable "alb_security_group_id" {
# -------------------------------------------------------
# ECS Service Connect (optional)
# -------------------------------------------------------
variable "enable_ecs_service_connect" {
description = "Enables ECS Service Connect so other services in the namespace can reach this one."
type = bool
default = false
}

variable "service_connect_namespace_arn" {
type = string
default = null
description = <<-EOT
ARN of the Cloud Map HTTP namespace to use for ECS Service Connect.
When null, Service Connect will not be configured for this service.
EOT
}

variable "service_connect_port" {
type = number
default = null
description = "Optional. Defaults to the first containerPort in port_mappings. Override this for port remapping (e.g. expose on :80 while container listens on :8080)."
}

variable "service_connect_port_name" {
type = string
default = null
description = "Optional. Defaults to the first named port in port_mappings. Name of the port mapping to use for Service Connect."
}

variable "service_connect_client_port" {
type = number
default = null
description = <<-EOT
Override the port clients use to call this service via Service Connect.
Defaults to the containerPort of the named port mapping.
Use this for port remapping (e.g. container listens on 8080, clients call on 80 for easy calls by name without port).
EOT
variable "service_connect" {
default = []
description = "List of service connect discovery names and ports."
type = list(object({
discovery_name = string
dns_name = string
port = number
port_name = string
}))
}

variable "deployment_circuit_breaker" {
Expand Down Expand Up @@ -264,7 +239,6 @@ variable "load_balancers" {
default = null
}


#--------------------
# ALB Connection
#--------------------
Expand Down Expand Up @@ -514,3 +488,12 @@ variable "dd_version" {
type = string
default = "1.0.0"
}

variable "additional_dd_environment" {
default = []
description = "A list of additional environment variables to append to the default Datadog environment."
type = list(object({
name = string,
value = string
}))
}