Created
May 8, 2023 17:32
-
-
Save gunzip/4f322c577151f7ea40e9d13efa5a1260 to your computer and use it in GitHub Desktop.
pdv tokenizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
terraform { | |
required_version = ">= 1.0.0" | |
backend "s3" {} | |
required_providers { | |
aws = { | |
source = "hashicorp/aws" | |
version = "= 4.63.0" | |
configuration_aliases = [aws.alternate] | |
} | |
} | |
} | |
provider "aws" { | |
region = var.aws_region | |
default_tags { | |
tags = var.tags | |
} | |
} | |
provider "aws" { | |
alias = "eu-central-1" | |
region = "eu-central-1" | |
default_tags { | |
tags = var.tags | |
} | |
} | |
locals { | |
project = format("%s-%s", var.app_name, var.env_short) | |
} | |
data "aws_caller_identity" "current" {}locals { | |
task_tokenizer_name = format("%s-task-tokenizer", local.project) | |
service_tokenizer_name = format("%s-service-tokenizer", local.project) | |
api_key_list = { for k in var.tokenizer_plans : k.key_name => k } | |
additional_keys = flatten([for k in var.tokenizer_plans : | |
[for a in k.additional_keys : | |
{ | |
"key" : a | |
"plan" : k.key_name | |
}] | |
]) | |
tokenizer_api_name = format("%s-tokenizer-api", local.project) | |
tokenizer_stage_name = "v1" | |
list_tokenizer_key_to_name = concat( | |
[for n in var.tokenizer_plans : "'${aws_api_gateway_api_key.main[n.key_name].id}':'${n.key_name}'"], | |
[for n in local.additional_keys : "'${aws_api_gateway_api_key.additional[n.key].id}':'${n.plan}'"] | |
) | |
tokenizer_log_group_name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.tokenizer.id}/${local.tokenizer_stage_name}" | |
tokenizer_api_plan_ids = merge( | |
{ for k in keys(local.api_key_list) : k => aws_api_gateway_usage_plan.tokenizer[k].id }, | |
{ for k in local.additional_keys : k.key => aws_api_gateway_usage_plan.tokenizer[k.plan].id }, | |
) | |
}module "vpc" { | |
source = "terraform-aws-modules/vpc/aws" | |
version = "3.14.0" | |
name = format("%s-vpc", local.project) | |
cidr = var.vpc_cidr | |
azs = var.azs | |
private_subnets = var.vpc_private_subnets_cidr | |
private_subnet_suffix = "private" | |
public_subnets = var.vpc_public_subnets_cidr | |
public_subnet_suffix = "public" | |
intra_subnets = var.vpc_internal_subnets_cidr | |
enable_nat_gateway = var.enable_nat_gateway | |
enable_dns_hostnames = true | |
enable_dns_support = true | |
} | |
data "aws_iam_policy_document" "generic_endpoint_policy" { | |
statement { | |
effect = "Deny" | |
actions = ["*"] | |
resources = ["*"] | |
principals { | |
type = "*" | |
identifiers = ["*"] | |
} | |
condition { | |
test = "StringNotEquals" | |
variable = "aws:SourceVpc" | |
values = [module.vpc.vpc_id] | |
} | |
} | |
} | |
data "aws_iam_policy_document" "dynamodb_endpoint_policy" { | |
statement { | |
effect = "Deny" | |
actions = ["dynamodb:*"] | |
resources = ["*"] | |
principals { | |
type = "*" | |
identifiers = ["*"] | |
} | |
condition { | |
test = "StringNotEquals" | |
variable = "aws:sourceVpce" | |
values = [module.vpc.vpc_id] | |
} | |
} | |
} | |
data "aws_security_group" "default" { | |
name = "default" | |
vpc_id = module.vpc.vpc_id | |
} | |
resource "aws_security_group" "vpc_tls" { | |
name_prefix = format("%s_vpc_tls_sg", local.project) | |
description = "Allow TLS inbound traffic" | |
vpc_id = module.vpc.vpc_id | |
ingress { | |
description = "TLS from VPC" | |
from_port = 443 | |
to_port = 443 | |
protocol = "tcp" | |
cidr_blocks = [module.vpc.vpc_cidr_block] | |
} | |
tags = { Name = format("%s_vpc_tls_sg", local.project) } | |
} | |
module "vpc_endpoints" { | |
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" | |
vpc_id = module.vpc.vpc_id | |
security_group_ids = [data.aws_security_group.default.id] | |
endpoints = { | |
s3 = { | |
service = "s3" | |
service_type = "Gateway" | |
route_table_ids = flatten([module.vpc.intra_route_table_ids, module.vpc.private_route_table_ids, module.vpc.public_route_table_ids]) | |
tags = { Name = "s3-vpc-endpoint" } | |
}, | |
logs = { | |
service = "logs" | |
private_dns_enabled = true | |
subnet_ids = module.vpc.private_subnets | |
#policy = data.aws_iam_policy_document.generic_endpoint_policy.json | |
security_group_ids = [aws_security_group.vpc_tls.id] | |
tags = { Name = "logs-endpoint" } | |
}, | |
ecr_api = { | |
service = "ecr.api" | |
private_dns_enabled = true | |
subnet_ids = module.vpc.private_subnets | |
#policy = data.aws_iam_policy_document.generic_endpoint_policy.json | |
security_group_ids = [aws_security_group.vpc_tls.id] | |
tags = { Name = "ecr.api-endpoint" } | |
}, | |
ecr_dkr = { | |
service = "ecr.dkr" | |
private_dns_enabled = true | |
subnet_ids = module.vpc.private_subnets | |
#policy = data.aws_iam_policy_document.generic_endpoint_policy.json | |
security_group_ids = [aws_security_group.vpc_tls.id] | |
tags = { Name = "ecr.dkr-endpoint" } | |
}, | |
dynamodb = { | |
service = "dynamodb" | |
service_type = "Gateway" | |
route_table_ids = flatten([module.vpc.intra_route_table_ids, module.vpc.private_route_table_ids, module.vpc.public_route_table_ids]) | |
# policy = data.aws_iam_policy_document.dynamodb_endpoint_policy.json | |
tags = { Name = "dynamodb-vpc-endpoint" } | |
}, | |
/* | |
ecs = { | |
service = "ecs" | |
private_dns_enabled = true | |
subnet_ids = module.vpc.private_subnets | |
tags = merge({ Name = "ecs-endpoint" }, var.tags) | |
}, | |
ecs_telemetry = { | |
service = "ecs-telemetry" | |
private_dns_enabled = true | |
subnet_ids = module.vpc.private_subnets | |
tags = merge({ Name = "ecs-telemetry-endpoint" }, var.tags) | |
}, | |
kms = { | |
service = "kms" | |
private_dns_enabled = true | |
subnet_ids = module.vpc.private_subnets | |
security_group_ids = [aws_security_group.vpc_tls.id] | |
tags = merge({ Name = "kms-endpoint" }, var.tags) | |
}, | |
*/ | |
} | |
} | |
data "aws_route_tables" "accepter" { | |
vpc_id = module.vpc.vpc_id | |
} | |
resource "aws_route" "accepter" { | |
count = var.vpc_peering != null ? length(data.aws_route_tables.accepter.ids) : 0 | |
route_table_id = data.aws_route_tables.accepter.ids[count.index] | |
destination_cidr_block = var.vpc_peering.owner_cidr_block | |
vpc_peering_connection_id = var.vpc_peering.owner_connection_id | |
} | |
locals { | |
repositories = [ | |
format("%s-ecr", local.project, ), # todo rename into tokenizer | |
] | |
} | |
resource "aws_ecr_repository" "main" { | |
count = length(local.repositories) | |
name = local.repositories[count.index] | |
image_scanning_configuration { | |
scan_on_push = false | |
} | |
tags = { "Name" : local.repositories[count.index] } | |
} | |
resource "aws_ecr_lifecycle_policy" "main" { | |
count = length(local.repositories) | |
repository = aws_ecr_repository.main[count.index].name | |
policy = jsonencode({ | |
rules = [{ | |
rulePriority = 1 | |
description = format("Keeps last %s images", var.ecr_keep_nr_images) | |
action = { | |
type = "expire" | |
} | |
selection = { | |
tagStatus = "any" | |
countType = "imageCountMoreThan" | |
countNumber = var.ecr_keep_nr_images | |
} | |
}] | |
}) | |
}data "aws_iam_policy_document" "ecs_tasks_assume_role_policy" { | |
statement { | |
actions = ["sts:AssumeRole"] | |
principals { | |
type = "Service" | |
identifiers = ["ecs-tasks.amazonaws.com"] | |
} | |
} | |
} | |
resource "aws_iam_role" "ecs_execution_task" { | |
name = format("%s-execution-task-role", local.project) | |
assume_role_policy = data.aws_iam_policy_document.ecs_tasks_assume_role_policy.json | |
tags = { Name = format("%s-execution-task-role", local.project) } | |
} | |
resource "aws_iam_role_policy_attachment" "ecsTaskExecutionRole_policy" { | |
role = aws_iam_role.ecs_execution_task.name | |
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" | |
} | |
# policy to allow execute command. | |
resource "aws_iam_policy" "execute_command_policy" { | |
count = var.ecs_enable_execute_command ? 1 : 0 | |
name = "PagoPaECSExecuteCommand" | |
description = "Policy to allow ecs execute command." | |
policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Action": [ | |
"ssmmessages:CreateControlChannel", | |
"ssmmessages:CreateDataChannel", | |
"ssmmessages:OpenControlChannel", | |
"ssmmessages:OpenDataChannel" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
] | |
} | |
EOF | |
} | |
resource "aws_iam_role_policy_attachment" "ecs_execute_command_policy" { | |
count = var.ecs_enable_execute_command ? 1 : 0 | |
role = aws_iam_role.ecs_execution_task.name | |
policy_arn = aws_iam_policy.execute_command_policy[0].arn | |
} | |
## policy to allow ecs to read and write in dynamodb | |
resource "aws_iam_policy" "dynamodb_rw" { | |
name = "PagoPaECSReadWriteDynamoDB" | |
description = "Policy to allow ecs tasks to read and write in dynamodb table" | |
policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Action": [ | |
"dynamodb:PutItem", | |
"dynamodb:DeleteItem", | |
"dynamodb:GetItem", | |
"dynamodb:Query", | |
"dynamodb:UpdateItem", | |
"dynamodb:GetRecords" | |
], | |
"Effect": "Allow", | |
"Resource": [ | |
"${module.dynamodb_table_token.dynamodb_table_arn}", | |
"${module.dynamodb_table_token.dynamodb_table_arn}/index/${local.dynamo_gsi_token_name}" | |
] | |
} | |
] | |
} | |
EOF | |
} | |
resource "aws_iam_role_policy_attachment" "ecs_dynamodb_rw" { | |
role = aws_iam_role.ecs_execution_task.name | |
policy_arn = aws_iam_policy.dynamodb_rw.arn | |
} | |
## Allow ecs tasks to encrypt and decrypt KMS key | |
resource "aws_iam_policy" "ecs_allow_kms" { | |
name = "PagoPaAllowECSKMS" | |
description = "Policy to allow ECS tasks to encrypt and decrypt data at rest in DynamoDB." | |
policy = templatefile( | |
"./iam_policies/allow-kms-encrypt-decrypt.json.tpl", | |
{ | |
account_id = data.aws_caller_identity.current.account_id | |
} | |
) | |
} | |
resource "aws_iam_role_policy_attachment" "ecs_allow_kms" { | |
role = aws_iam_role.ecs_execution_task.name | |
policy_arn = aws_iam_policy.ecs_allow_kms.arn | |
} | |
## Allow fargate task to query cloud hsm | |
## This action does not support resource-level permissions. Policies granting access must specify "*" ## in the resource element. | |
resource "aws_iam_policy" "ecs_allow_hsm" { | |
count = var.create_cloudhsm ? 1 : 0 | |
name = "PagoPaAllowECSHSM" | |
description = "Policy to allow ECS tasks query cloud hsm." | |
policy = templatefile( | |
"./iam_policies/allow-hsm.tpl.json", {} | |
) | |
} | |
resource "aws_iam_role_policy_attachment" "ecs_allow_hsm" { | |
count = var.create_cloudhsm ? 1 : 0 | |
role = aws_iam_role.ecs_execution_task.name | |
policy_arn = aws_iam_policy.ecs_allow_hsm[0].arn | |
} | |
## IAM Group Developer | |
resource "aws_iam_group" "developers" { | |
name = "Developers" | |
} | |
data "aws_iam_policy" "power_user" { | |
name = "PowerUserAccess" | |
} | |
### Deny access to secret devops | |
data "aws_secretsmanager_secret" "devops" { | |
name = "devops" | |
} | |
resource "aws_iam_policy" "deny_secrets_devops" { | |
name = "PagoPaDenyAccessSecretsDevops" | |
description = "Deny access to devops secrets." | |
policy = templatefile( | |
"./iam_policies/deny-access-secret-devops.json.tpl", | |
{ | |
secret_arn = data.aws_secretsmanager_secret.devops.arn | |
} | |
) | |
} | |
resource "aws_iam_group_policy_attachment" "power_user" { | |
count = var.env_short == "u" ? 1 : 0 | |
group = aws_iam_group.developers.name | |
policy_arn = data.aws_iam_policy.power_user.arn | |
} | |
resource "aws_iam_group_policy_attachment" "deny_secrets_devops" { | |
count = var.env_short == "u" ? 1 : 0 | |
group = aws_iam_group.developers.name | |
policy_arn = aws_iam_policy.deny_secrets_devops.arn | |
} | |
resource "aws_iam_policy" "deploy_ecs" { | |
name = "PagoPaECSDeploy" | |
description = "Policy to allow deploy on ECS." | |
policy = templatefile( | |
"./iam_policies/deploy-ecs.json.tpl", | |
{ | |
account_id = data.aws_caller_identity.current.account_id | |
execute_task_role_arn = aws_iam_role.ecs_execution_task.arn | |
} | |
) | |
} | |
data "aws_iam_policy" "ec2_ecr_full_access" { | |
name = "AmazonEC2ContainerRegistryFullAccess" | |
} | |
## Deploy with github action | |
resource "aws_iam_role" "githubecsdeploy" { | |
name = "GitHubDeployECS" | |
description = "Role to assume to create the infrastructure." | |
assume_role_policy = jsonencode({ | |
Version = "2012-10-17" | |
Statement = [ | |
{ | |
Effect = "Allow", | |
Principal = { | |
"Federated" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com" | |
}, | |
Action = "sts:AssumeRoleWithWebIdentity", | |
Condition = { | |
StringLike = { | |
"token.actions.githubusercontent.com:sub" : [ | |
"repo:${var.github_tokenizer_repo}:*" | |
] | |
}, | |
"ForAllValues:StringEquals" = { | |
"token.actions.githubusercontent.com:iss" : "https://token.actions.githubusercontent.com", | |
"token.actions.githubusercontent.com:aud" : "sts.amazonaws.com" | |
} | |
} | |
} | |
] | |
}) | |
} | |
resource "aws_iam_role_policy_attachment" "deploy_ecs" { | |
role = aws_iam_role.githubecsdeploy.name | |
policy_arn = aws_iam_policy.deploy_ecs.arn | |
} | |
resource "aws_iam_role_policy_attachment" "deploy_ec2_ecr_full_access" { | |
role = aws_iam_role.githubecsdeploy.name | |
policy_arn = data.aws_iam_policy.ec2_ecr_full_access.arn | |
}# Cluster | |
resource "aws_ecs_cluster" "ecs_cluster" { | |
name = format("%s-ecs-cluster", local.project) | |
tags = { Name = format("%s-ecs", local.project) } | |
setting { | |
name = "containerInsights" | |
value = var.enable_container_insights ? "enabled" : "diabled" | |
} | |
} | |
locals { | |
service_ids = [ | |
join("/", ["service", aws_ecs_cluster.ecs_cluster.name, aws_ecs_service.tokenizer.name, ]), | |
] | |
} | |
## Autoscaling | |
resource "aws_appautoscaling_target" "ecs_target" { | |
count = length(local.service_ids) | |
max_capacity = var.ecs_autoscaling.max_capacity | |
min_capacity = var.ecs_autoscaling.min_capacity | |
resource_id = local.service_ids[count.index] | |
scalable_dimension = "ecs:service:DesiredCount" | |
service_namespace = "ecs" | |
} | |
resource "aws_appautoscaling_policy" "ecs_policy_memory" { | |
count = length(local.service_ids) | |
name = format("%s-memory-autoscaling", element(split("/", local.service_ids[count.index]), 2)) | |
policy_type = "TargetTrackingScaling" | |
resource_id = aws_appautoscaling_target.ecs_target[count.index].resource_id | |
scalable_dimension = aws_appautoscaling_target.ecs_target[count.index].scalable_dimension | |
service_namespace = aws_appautoscaling_target.ecs_target[count.index].service_namespace | |
target_tracking_scaling_policy_configuration { | |
scale_in_cooldown = var.ecs_autoscaling.scale_in_cooldown | |
scale_out_cooldown = var.ecs_autoscaling.scale_out_cooldown | |
predefined_metric_specification { | |
predefined_metric_type = "ECSServiceAverageMemoryUtilization" | |
} | |
target_value = 80 | |
} | |
} | |
resource "aws_appautoscaling_policy" "ecs_policy_cpu" { | |
count = length(local.service_ids) | |
name = format("%s-cpu-autoscaling", element(split("/", local.service_ids[count.index]), 2)) | |
policy_type = "TargetTrackingScaling" | |
resource_id = aws_appautoscaling_target.ecs_target[count.index].resource_id | |
scalable_dimension = aws_appautoscaling_target.ecs_target[count.index].scalable_dimension | |
service_namespace = aws_appautoscaling_target.ecs_target[count.index].service_namespace | |
target_tracking_scaling_policy_configuration { | |
scale_in_cooldown = var.ecs_autoscaling.scale_in_cooldown | |
scale_out_cooldown = var.ecs_autoscaling.scale_out_cooldown | |
predefined_metric_specification { | |
predefined_metric_type = "ECSServiceAverageCPUUtilization" | |
} | |
target_value = 80 | |
} | |
}resource "aws_cloudwatch_log_group" "ecs_tokenizer" { | |
name = format("ecs/%s", local.task_tokenizer_name) | |
retention_in_days = var.ecs_logs_retention_days | |
tags = { | |
Name = local.task_tokenizer_name | |
} | |
} | |
resource "aws_ecs_task_definition" "tokenizer" { | |
family = local.task_tokenizer_name | |
container_definitions = <<DEFINITION | |
[ | |
{ | |
"name": "${local.project}-container", | |
"image": "${aws_ecr_repository.main[0].repository_url}:latest", | |
"entryPoint": [], | |
"essential": true, | |
"logConfiguration": { | |
"logDriver": "awslogs", | |
"options": { | |
"awslogs-group": "${aws_cloudwatch_log_group.ecs_tokenizer.id}", | |
"awslogs-region": "${var.aws_region}", | |
"awslogs-stream-prefix": "${local.project}" | |
} | |
}, | |
"portMappings": [ | |
{ | |
"containerPort": ${var.container_port_tokenizer}, | |
"hostPort": ${var.container_port_tokenizer} | |
} | |
], | |
"environment": [ | |
{ | |
"name": "AWS_REGION", | |
"value": "${var.aws_region}" | |
}, | |
{ | |
"name": "APP_SERVER_PORT", | |
"value": "${var.container_port_tokenizer}" | |
}, | |
{ | |
"name": "APP_LOG_LEVEL", | |
"value": "${var.ms_tokenizer_log_level}" | |
}, | |
{ | |
"name": "REST_CLIENT_LOGGER_LEVEL", | |
"value": "${var.ms_tokenizer_rest_client_log_level}" | |
}, | |
{ | |
"name": "ENABLE_CONFIDENTIAL_FILTER", | |
"value": "${var.ms_tokenizer_enable_confidential_filter}" | |
}, | |
{ | |
"name": "ENABLE_SINGLE_LINE_STACK_TRACE_LOGGING", | |
"value": "${var.ms_tokenizer_enable_single_line_stack_trace_logging}" | |
} | |
], | |
"cpu": 256, | |
"memory": 512, | |
"networkMode": "awsvpc" | |
} | |
] | |
DEFINITION | |
requires_compatibilities = ["FARGATE"] | |
network_mode = "awsvpc" | |
memory = "512" | |
cpu = "256" | |
execution_role_arn = aws_iam_role.ecs_execution_task.arn | |
task_role_arn = aws_iam_role.ecs_execution_task.arn | |
tags = { Name = format("%s-ecs-td", local.project) } | |
} | |
data "aws_ecs_task_definition" "tokenizer" { | |
task_definition = aws_ecs_task_definition.tokenizer.family | |
} | |
# Service | |
resource "aws_ecs_service" "tokenizer" { | |
name = local.service_tokenizer_name | |
cluster = aws_ecs_cluster.ecs_cluster.id | |
task_definition = format("%s:%s", | |
aws_ecs_task_definition.tokenizer.family, | |
max(aws_ecs_task_definition.tokenizer.revision, data.aws_ecs_task_definition.tokenizer.revision) | |
) | |
launch_type = "FARGATE" | |
scheduling_strategy = "REPLICA" | |
desired_count = var.replica_count | |
force_new_deployment = true | |
enable_execute_command = var.ecs_enable_execute_command | |
network_configuration { | |
subnets = module.vpc.private_subnets | |
assign_public_ip = false | |
security_groups = [ | |
# NLB | |
aws_security_group.nsg_task.id | |
] | |
} | |
load_balancer { | |
target_group_arn = module.nlb.target_group_arns[0] | |
container_name = format("%s-container", local.project) | |
container_port = var.container_port_tokenizer | |
} | |
depends_on = [module.nlb] | |
tags = { Name : local.service_tokenizer_name } | |
} | |
resource "aws_cloudwatch_metric_alarm" "cpu_utilization_high" { | |
count = length(local.service_ids) | |
alarm_name = format("%s-CPU-Utilization-High-%s", split("/", local.service_ids[count.index])[2], | |
var.ecs_as_threshold.cpu_max) | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = "1" | |
metric_name = "CPUUtilization" | |
namespace = "AWS/ECS" | |
period = "60" | |
statistic = "Average" | |
threshold = var.ecs_as_threshold.cpu_max | |
dimensions = { | |
ClusterName = aws_ecs_cluster.ecs_cluster.name | |
ServiceName = split("/", local.service_ids[count.index])[2] | |
} | |
alarm_actions = [ | |
aws_appautoscaling_policy.app_up[count.index].arn, | |
aws_sns_topic.alarms.arn, | |
] | |
} | |
resource "aws_cloudwatch_metric_alarm" "cpu_utilization_low" { | |
count = length(local.service_ids) | |
alarm_name = format("%s-CPU-Utilization-Low-%s", split("/", local.service_ids[count.index])[2], | |
var.ecs_as_threshold.cpu_min) | |
comparison_operator = "LessThanThreshold" | |
evaluation_periods = "1" | |
metric_name = "CPUUtilization" | |
namespace = "AWS/ECS" | |
period = "60" | |
statistic = "Average" | |
threshold = var.ecs_as_threshold.cpu_min | |
dimensions = { | |
ClusterName = aws_ecs_cluster.ecs_cluster.name | |
ServiceName = split("/", local.service_ids[count.index])[2] | |
} | |
alarm_actions = [ | |
aws_appautoscaling_policy.app_down[count.index].arn, | |
] | |
} | |
# Alarm | |
resource "aws_cloudwatch_metric_alarm" "mem_utilization_high" { | |
count = length(local.service_ids) | |
alarm_name = format("%s-Mem-Utilization-High-%s", split("/", local.service_ids[count.index])[2], | |
var.ecs_as_threshold.mem_max) | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = "1" | |
metric_name = "MemoryUtilization" | |
namespace = "AWS/ECS" | |
period = "60" | |
statistic = "Average" | |
threshold = var.ecs_as_threshold.mem_max | |
dimensions = { | |
ClusterName = aws_ecs_cluster.ecs_cluster.name | |
ServiceName = split("/", local.service_ids[count.index])[2] | |
} | |
alarm_actions = [ | |
#aws_appautoscaling_policy.app_up[count.index].arn, | |
aws_sns_topic.alarms.arn, | |
] | |
} | |
resource "aws_appautoscaling_policy" "app_up" { | |
count = length(local.service_ids) | |
name = format("%s-scale-up", aws_ecs_cluster.ecs_cluster.name) | |
service_namespace = aws_appautoscaling_target.ecs_target[count.index].service_namespace | |
resource_id = aws_appautoscaling_target.ecs_target[count.index].resource_id | |
scalable_dimension = aws_appautoscaling_target.ecs_target[count.index].scalable_dimension | |
step_scaling_policy_configuration { | |
adjustment_type = "ChangeInCapacity" | |
cooldown = 60 | |
metric_aggregation_type = "Average" | |
step_adjustment { | |
metric_interval_lower_bound = 0 | |
scaling_adjustment = 1 | |
} | |
} | |
} | |
resource "aws_appautoscaling_policy" "app_down" { | |
count = length(local.service_ids) | |
name = format("%s-scale-down", aws_ecs_cluster.ecs_cluster.name) | |
service_namespace = aws_appautoscaling_target.ecs_target[count.index].service_namespace | |
resource_id = aws_appautoscaling_target.ecs_target[count.index].resource_id | |
scalable_dimension = aws_appautoscaling_target.ecs_target[count.index].scalable_dimension | |
step_scaling_policy_configuration { | |
adjustment_type = "ChangeInCapacity" | |
cooldown = 300 | |
metric_aggregation_type = "Average" | |
step_adjustment { | |
metric_interval_upper_bound = 0 | |
scaling_adjustment = -1 | |
} | |
} | |
} | |
resource "aws_kms_key" "dynamo_db" { | |
description = "Kms dynamo db encryption key." | |
customer_master_key_spec = "SYMMETRIC_DEFAULT" | |
tags = { Name = format("%s-dynamo-table-key", local.project) } | |
} | |
resource "aws_kms_alias" "dynamo_db" { | |
name = format("alias/%s-dynamo-table", local.project) | |
target_key_id = aws_kms_key.dynamo_db.id | |
} | |
resource "aws_kms_key" "dynamo_db_replica" { | |
provider = aws.eu-central-1 | |
count = var.env_short == "p" ? 1 : 0 | |
description = "Kms dynamo db encryption key." | |
customer_master_key_spec = "SYMMETRIC_DEFAULT" | |
tags = { Name = format("%s-dynamo-table-key", local.project) } | |
} | |
resource "aws_kms_alias" "dynamo_db_replica" { | |
provider = aws.eu-central-1 | |
count = var.env_short == "p" ? 1 : 0 | |
name = format("alias/%s-dynamo-table", local.project) | |
target_key_id = aws_kms_key.dynamo_db_replica[0].id | |
}locals { | |
apigw_custom_domain = join(".", ["api", keys(var.public_dns_zones)[0]]) | |
} | |
resource "aws_acm_certificate" "main" { | |
count = var.apigw_custom_domain_create ? 1 : 0 | |
domain_name = local.apigw_custom_domain | |
validation_method = "DNS" | |
lifecycle { | |
create_before_destroy = true | |
} | |
} | |
resource "aws_route53_record" "cert_validation" { | |
for_each = var.apigw_custom_domain_create ? { | |
for dvo in aws_acm_certificate.main[0].domain_validation_options : dvo.domain_name => { | |
name = dvo.resource_record_name | |
record = dvo.resource_record_value | |
type = dvo.resource_record_type | |
} | |
} : {} | |
allow_overwrite = true | |
name = each.value.name | |
records = [each.value.record] | |
ttl = 3600 # 1h | |
type = each.value.type | |
zone_id = module.dn_zone.route53_zone_zone_id[keys(var.public_dns_zones)[0]] | |
} | |
locals { | |
# Token | |
dynamodb_table_token = "Token" | |
dynamo_gsi_token_name = keys(var.table_token_autoscling_indexes)[0] | |
} | |
# Table Token | |
module "dynamodb_table_token" { | |
source = "terraform-aws-modules/dynamodb-table/aws" | |
name = local.dynamodb_table_token | |
hash_key = "PK" | |
range_key = "SK" | |
stream_enabled = var.table_token_stream_enabled | |
stream_view_type = var.table_token_stream_enabled ? "NEW_IMAGE" : null | |
point_in_time_recovery_enabled = var.dynamodb_point_in_time_recovery_enabled | |
billing_mode = "PROVISIONED" | |
autoscaling_enabled = true | |
read_capacity = var.table_token_read_capacity | |
write_capacity = var.table_token_write_capacity | |
attributes = [ | |
{ | |
name = "PK" | |
type = "S" | |
}, | |
{ | |
name = "SK" | |
type = "S" | |
}, | |
{ | |
name = "token" | |
type = "S" | |
}, | |
] | |
global_secondary_indexes = [ | |
{ | |
name = local.dynamo_gsi_token_name | |
hash_key = "token" | |
projection_type = "ALL" | |
write_capacity = var.table_token_autoscling_indexes[local.dynamo_gsi_token_name]["write_min_capacity"] | |
read_capacity = var.table_token_autoscling_indexes[local.dynamo_gsi_token_name]["read_min_capacity"] | |
} | |
] | |
server_side_encryption_enabled = true | |
server_side_encryption_kms_key_arn = aws_kms_alias.dynamo_db.target_key_arn | |
autoscaling_read = var.table_token_autoscaling_read | |
autoscaling_write = var.table_token_autoscaling_write | |
autoscaling_indexes = var.table_token_autoscling_indexes | |
replica_regions = var.dynamodb_region_replication_enable ? [{ | |
region_name = "eu-central-1" | |
kms_key_arn = aws_kms_alias.dynamo_db_replica[0].target_key_arn | |
}] : [] | |
tags = { Name = local.dynamodb_table_token } | |
}resource "aws_iam_role" "pipe" { | |
count = var.create_event_bridge_pipe ? 1 : 0 | |
name = "pipe-tokens-role" | |
assume_role_policy = jsonencode({ | |
Version = "2012-10-17" | |
Statement = { | |
Effect = "Allow" | |
Action = "sts:AssumeRole" | |
Principal = { | |
Service = "pipes.amazonaws.com" | |
} | |
Condition = { | |
StringEquals = { | |
"aws:SourceAccount" = data.aws_caller_identity.current.account_id | |
} | |
} | |
} | |
}) | |
} | |
resource "aws_iam_role_policy" "source" { | |
count = var.create_event_bridge_pipe ? 1 : 0 | |
name = "AllowPipeConsumeStream" | |
role = aws_iam_role.pipe[0].id | |
policy = jsonencode({ | |
Version = "2012-10-17" | |
Statement = [ | |
{ | |
Effect = "Allow" | |
Action = [ | |
"dynamodb:GetRecords", | |
"dynamodb:GetShardIterator", | |
"dynamodb:DescribeStream", | |
"dynamodb:ListStreams" | |
], | |
Resource = [ | |
module.dynamodb_table_token.dynamodb_table_stream_arn | |
] | |
}, | |
{ | |
Effect = "Allow" | |
Action = [ | |
"kms:Decrypt", | |
"kms:Encrypt", | |
], | |
Resource = [ | |
aws_kms_alias.dynamo_db.target_key_arn | |
] | |
}, | |
] | |
}) | |
} | |
resource "aws_sqs_queue" "target" { | |
count = var.create_event_bridge_pipe ? 1 : 0 | |
name = format("queue-%s-tokens", var.env_short) | |
} | |
resource "aws_iam_role_policy" "target" { | |
count = var.create_event_bridge_pipe ? 1 : 0 | |
name = "AllowPipeWriteSQS" | |
role = aws_iam_role.pipe[0].id | |
policy = jsonencode({ | |
Version = "2012-10-17" | |
Statement = [ | |
{ | |
Effect = "Allow" | |
Action = [ | |
"sqs:SendMessage", | |
], | |
Resource = [ | |
aws_sqs_queue.target[0].arn, | |
] | |
}, | |
] | |
}) | |
} | |
resource "aws_pipes_pipe" "token" { | |
count = var.create_event_bridge_pipe ? 1 : 0 | |
depends_on = [aws_iam_role_policy.source, aws_iam_role_policy.target] | |
name = format("pipe-%s-tokens", var.env_short) | |
role_arn = aws_iam_role.pipe[0].arn | |
source = module.dynamodb_table_token.dynamodb_table_stream_arn | |
target = aws_sqs_queue.target[0].arn | |
source_parameters { | |
filter_criteria { | |
filter { | |
pattern = jsonencode({ | |
dynamodb = { | |
Keys = { | |
SK = { | |
S = [ | |
{ | |
anything-but = "GLOBAL" | |
}, | |
] | |
} | |
} | |
} | |
}) | |
} | |
} | |
} | |
target_parameters {} | |
} | |
# https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html | |
module "metric_alarms" { | |
count = length(var.dynamodb_alarms) | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarm" | |
version = "~> 3.0" | |
actions_enabled = var.dynamodb_alarms[count.index].actions_enabled | |
alarm_name = var.dynamodb_alarms[count.index].alarm_name | |
alarm_description = var.dynamodb_alarms[count.index].alarm_description | |
comparison_operator = var.dynamodb_alarms[count.index].comparison_operator | |
evaluation_periods = var.dynamodb_alarms[count.index].evaluation_periods | |
threshold = var.dynamodb_alarms[count.index].threshold | |
period = var.dynamodb_alarms[count.index].period | |
unit = var.dynamodb_alarms[count.index].unit | |
datapoints_to_alarm = var.dynamodb_alarms[count.index].datapoints_to_alarm | |
namespace = var.dynamodb_alarms[count.index].namespace | |
metric_name = var.dynamodb_alarms[count.index].metric_name | |
statistic = var.dynamodb_alarms[count.index].statistic | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
module "dynamo_successful_request_latency" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarm" | |
version = "~> 3.0" | |
alarm_name = "dynamodb-successful-request-latency" | |
alarm_description = "Dynamodb successful request latency" | |
comparison_operator = "LessThanLowerOrGreaterThanUpperThreshold" | |
evaluation_periods = 2 | |
threshold_metric_id = "ad1" | |
metric_query = [ | |
{ | |
id = "m1" | |
return_data = true | |
metric = [{ | |
dimensions = null | |
metric_name = "SuccessfulRequestLatency" | |
namespace = "AWS/DynamoDB" | |
period = 300 | |
stat = "Maximum" | |
unit = "Percent" | |
}, | |
] | |
}, { | |
expression = "ANOMALY_DETECTION_BAND(m1, 2)" | |
id = "ad1" | |
label = "SuccessfulRequestLatency" | |
return_data = true | |
}, | |
] | |
} | |
## Read capacity units | |
module "dynamodb_read_capacity_units_limit_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
alarm_name = "dynamodb-read-capacity-units-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when read capacity reaches 80% of provisioned read capacity" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = var.table_token_read_capacity - (var.table_token_read_capacity * 0.2) | |
period = 60 | |
namespace = "AWS/DynamoDB" | |
metric_name = "ConsumedReadCapacityUnits" | |
statistic = "Average" | |
dimensions = { | |
"token" = { | |
TableName = local.dynamodb_table_token | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
## Write capacity units | |
module "dynamodb_write_capacity_units_limit_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
alarm_name = "dynamodb-write-capacity-units-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when write capacity reaches 80% of provisioned read capacity" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = var.table_token_write_capacity - (var.table_token_write_capacity * 0.2) | |
period = 60 | |
namespace = "AWS/DynamoDB" | |
metric_name = "ConsumedWriteCapacityUnits" | |
statistic = "Average" | |
dimensions = { | |
"token" = { | |
TableName = local.dynamodb_table_token | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
### Global secondary index read capacity. | |
module "gsi_index_read_capacity_units_limit_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
alarm_name = "read-capacity-units-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when read capacity reaches 80% of provisioned read capacity" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = var.table_token_autoscling_indexes[local.dynamo_gsi_token_name]["read_max_capacity"] - (var.table_token_autoscling_indexes[local.dynamo_gsi_token_name]["read_max_capacity"] * 0.2) | |
period = 60 | |
namespace = "AWS/DynamoDB" | |
metric_name = "ConsumedReadCapacityUnits" | |
statistic = "Average" | |
dimensions = { | |
"gsi_index" = { | |
GlobalSecondaryIndexName = local.dynamo_gsi_token_name | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
### Global secondary write read capacity. | |
module "gsi_index_write_capacity_units_limit_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
alarm_name = "write-capacity-units-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when read capacity reaches 80% of provisioned read capacity" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = var.table_token_autoscling_indexes[local.dynamo_gsi_token_name]["write_max_capacity"] - (var.table_token_autoscling_indexes[local.dynamo_gsi_token_name]["write_max_capacity"] * 0.2) | |
period = 60 | |
namespace = "AWS/DynamoDB" | |
metric_name = "ConsumedWriteCapacityUnits" | |
statistic = "Average" | |
dimensions = { | |
"gsi_index" = { | |
GlobalSecondaryIndexName = local.dynamo_gsi_token_name | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
#ExceedingThroughput | |
module "dynamodb_request_exceeding_throughput_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
alarm_name = "dynamodb-exceeding-throughput-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when my requests are exceeding provisioned throughput quotas of a table." | |
comparison_operator = "GreaterThanThreshold" | |
evaluation_periods = 1 | |
threshold = 0 | |
period = 300 | |
unit = "Count" | |
namespace = "AWS/DynamoDB" | |
metric_name = "ThrottledRequests" | |
statistic = "Sum" | |
dimensions = { | |
"token-getitem" = { | |
TableName = local.dynamodb_table_token | |
Operation = "GetItem" | |
}, | |
"token-query" = { | |
TableName = local.dynamodb_table_token | |
Operation = "Query" | |
}, | |
"token-putitem" = { | |
TableName = local.dynamodb_table_token | |
Operation = "PutItem" | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
}resource "aws_cloudhsm_v2_cluster" "main" { | |
count = var.create_cloudhsm ? 1 : 0 | |
hsm_type = "hsm1.medium" | |
subnet_ids = module.vpc.private_subnets | |
tags = { "Name" : format("%s-cloudhsm", local.project) } | |
} | |
resource "aws_cloudhsm_v2_hsm" "hsm1" { | |
count = var.create_cloudhsm ? 1 : 0 | |
subnet_id = module.vpc.private_subnets[0] | |
cluster_id = aws_cloudhsm_v2_cluster.main[0].id | |
} | |
resource "aws_security_group_rule" "task_hsm" { | |
count = var.create_cloudhsm ? 1 : 0 | |
description = "Only allow connections from fargate tasks nsg ${count.index}" | |
type = "ingress" | |
from_port = 2223 | |
to_port = 2225 | |
protocol = "tcp" | |
# security group assigned to fargate tasks. | |
source_security_group_id = aws_security_group.nsg_task.id | |
security_group_id = aws_cloudhsm_v2_cluster.main[0].security_group_id | |
} | |
data "aws_network_interface" "hsm" { | |
count = var.create_cloudhsm ? 1 : 0 | |
id = aws_cloudhsm_v2_hsm.hsm1[0].hsm_eni_id | |
}module "dn_zone" { | |
source = "terraform-aws-modules/route53/aws//modules/zones" | |
version = "~> 2.0" | |
zones = var.public_dns_zones | |
} | |
resource "aws_route53_record" "uat" { | |
count = var.env_short == "p" ? 1 : 0 | |
allow_overwrite = true | |
name = "uat" | |
ttl = var.dns_record_ttl | |
type = "NS" | |
zone_id = module.dn_zone.route53_zone_zone_id[keys(var.public_dns_zones)[0]] | |
records = [ | |
"ns-1471.awsdns-55.org", | |
"ns-90.awsdns-11.com", | |
"ns-962.awsdns-56.net", | |
"ns-1970.awsdns-54.co.uk", | |
] | |
} | |
resource "aws_api_gateway_domain_name" "main" { | |
count = var.apigw_custom_domain_create ? 1 : 0 | |
domain_name = local.apigw_custom_domain | |
regional_certificate_arn = aws_acm_certificate.main[0].arn | |
endpoint_configuration { | |
types = ["REGIONAL"] | |
} | |
security_policy = "TLS_1_2" | |
} | |
resource "aws_route53_record" "main" { | |
count = var.apigw_custom_domain_create ? 1 : 0 | |
zone_id = module.dn_zone.route53_zone_zone_id[keys(var.public_dns_zones)[0]] | |
name = aws_api_gateway_domain_name.main[0].domain_name | |
type = "A" | |
# ttl = var.dns_record_ttl | |
alias { | |
name = aws_api_gateway_domain_name.main[0].regional_domain_name | |
zone_id = aws_api_gateway_domain_name.main[0].regional_zone_id | |
evaluate_target_health = true | |
} | |
}locals { | |
apigw_name = format("%s-apigw-vpc-lik", local.project) | |
webacl_name = format("%s-webacl", local.project) | |
} | |
resource "aws_api_gateway_vpc_link" "apigw" { | |
name = local.apigw_name | |
description = "allows public API Gateway for ${local.apigw_name} to talk to private NLB" | |
target_arns = [module.nlb.lb_arn] | |
tags = { Name = local.apigw_name } | |
} | |
## API Gateway cloud watch logs | |
resource "aws_api_gateway_account" "main" { | |
cloudwatch_role_arn = aws_iam_role.apigw.arn | |
} | |
resource "aws_iam_role" "apigw" { | |
name = "api_gateway_cloudwatch_global" | |
assume_role_policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Sid": "AssumeRole", | |
"Effect": "Allow", | |
"Principal": { | |
"Service": "apigateway.amazonaws.com" | |
}, | |
"Action": "sts:AssumeRole" | |
} | |
] | |
} | |
EOF | |
} | |
resource "aws_iam_role_policy" "cloudwatch" { | |
name = "default" | |
role = aws_iam_role.apigw.id | |
policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Effect": "Allow", | |
"Action": [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:DescribeLogGroups", | |
"logs:DescribeLogStreams", | |
"logs:PutLogEvents", | |
"logs:GetLogEvents", | |
"logs:FilterLogEvents" | |
], | |
"Resource": "*" | |
} | |
] | |
} | |
EOF | |
} | |
# Create API Gateway Role | |
resource "aws_iam_role" "s3_api_gateyway_role" { | |
name = "s3-api-gateyway-role" | |
# Create Trust Policy for API Gateway | |
assume_role_policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Sid": "", | |
"Effect": "Allow", | |
"Principal": { | |
"Service": "apigateway.amazonaws.com" | |
}, | |
"Action": "sts:AssumeRole" | |
} | |
] | |
} | |
EOF | |
} | |
data "aws_iam_policy" "s3_full_access" { | |
name = "AmazonS3ReadOnlyAccess" | |
} | |
resource "aws_iam_role_policy_attachment" "s3_policy_attach" { | |
role = aws_iam_role.s3_api_gateyway_role.name | |
policy_arn = data.aws_iam_policy.s3_full_access.arn | |
}resource "aws_api_gateway_api_key" "main" { | |
for_each = local.api_key_list | |
name = each.key | |
} | |
# Temporary change to allow interop to share selfcare namespace. | |
resource "aws_api_gateway_api_key" "additional" { | |
for_each = { for k in local.additional_keys : k.key => k } | |
name = each.key | |
}resource "aws_api_gateway_rest_api" "tokenizer" { | |
name = local.tokenizer_api_name | |
api_key_source = "HEADER" | |
body = templatefile("./api/ms_tokenizer/api-docs.json.tftpl", | |
{ | |
uri = format("http://%s", module.nlb.lb_dns_name), | |
connection_id = aws_api_gateway_vpc_link.apigw.id | |
request_template = chomp(templatefile("./api/request_template.tftpl", | |
{ | |
list_key_to_name = join(",", local.list_tokenizer_key_to_name) | |
})) | |
responses = file("./api/ms_tokenizer/status_code_mapping.tpl.json") | |
responses_only_token = file("./api/ms_tokenizer/status_code_mapping_only_token.tpl.json") | |
} | |
) | |
endpoint_configuration { | |
types = ["REGIONAL"] | |
} | |
tags = { Name = local.tokenizer_api_name } | |
} | |
resource "aws_api_gateway_deployment" "tokenizer" { | |
rest_api_id = aws_api_gateway_rest_api.tokenizer.id | |
# stage_name = local.tokenizer_stage_name | |
triggers = { | |
redeployment = sha1(jsonencode(aws_api_gateway_rest_api.tokenizer.body)) | |
} | |
lifecycle { | |
create_before_destroy = true | |
} | |
} | |
resource "aws_cloudwatch_log_group" "tokenizer" { | |
name = local.tokenizer_log_group_name | |
retention_in_days = var.apigw_execution_logs_retention | |
tags = { Name = local.tokenizer_api_name } | |
} | |
resource "aws_api_gateway_stage" "tokenizer" { | |
deployment_id = aws_api_gateway_deployment.tokenizer.id | |
rest_api_id = aws_api_gateway_rest_api.tokenizer.id | |
stage_name = local.tokenizer_stage_name | |
cache_cluster_size = 0.5 #why is this needed ? | |
documentation_version = aws_api_gateway_documentation_version.main.version | |
dynamic "access_log_settings" { | |
for_each = var.apigw_access_logs_enable ? ["dymmy"] : [] | |
content { | |
destination_arn = aws_cloudwatch_log_group.tokenizer.arn | |
#todo: find a better way to represent this log format. | |
format = "{ \"requestId\":\"$context.requestId\", \"extendedRequestId\":\"$context.extendedRequestId\", \"ip\": \"$context.identity.sourceIp\", \"caller\":\"$context.identity.caller\", \"user\":\"$context.identity.user\", \"requestTime\":\"$context.requestTime\", \"httpMethod\":\"$context.httpMethod\", \"resourcePath\":\"$context.resourcePath\", \"status\":\"$context.status\", \"protocol\":\"$context.protocol\", \"responseLength\":\"$context.responseLength\"}" | |
} | |
} | |
} | |
resource "aws_api_gateway_method_settings" "tokenizer" { | |
rest_api_id = aws_api_gateway_rest_api.tokenizer.id | |
stage_name = local.tokenizer_stage_name | |
method_path = "*/*" | |
settings { | |
# Enable CloudWatch logging and metrics | |
metrics_enabled = true | |
data_trace_enabled = var.apigw_data_trace_enabled | |
logging_level = "ERROR" | |
#todo. | |
# Limit the rate of calls to prevent abuse and unwanted charges | |
#throttling_rate_limit = 100 | |
#throttling_burst_limit = 50 | |
} | |
} | |
resource "aws_api_gateway_usage_plan" "tokenizer" { | |
for_each = local.api_key_list | |
name = format("%s-api-plan-%s", local.project, lower(each.key)) | |
description = "Usage plan for tokenizer apis" | |
api_stages { | |
api_id = aws_api_gateway_rest_api.tokenizer.id | |
stage = aws_api_gateway_stage.tokenizer.stage_name | |
dynamic "throttle" { | |
for_each = each.value.method_throttle | |
content { | |
path = throttle.value.path | |
burst_limit = throttle.value.burst_limit | |
rate_limit = throttle.value.rate_limit | |
} | |
} | |
} | |
/* | |
quota_settings { | |
limit = 20 | |
offset = 2 | |
period = "WEEK" | |
} | |
*/ | |
#TODO: tune this settings | |
throttle_settings { | |
burst_limit = each.value.burst_limit | |
rate_limit = each.value.rate_limit | |
} | |
} | |
resource "aws_api_gateway_usage_plan_key" "tokenizer" { | |
for_each = local.api_key_list | |
key_id = aws_api_gateway_api_key.main[each.key].id | |
key_type = "API_KEY" | |
usage_plan_id = aws_api_gateway_usage_plan.tokenizer[each.key].id | |
} | |
resource "aws_api_gateway_usage_plan_key" "tokenizer_additional" { | |
for_each = { for k in local.additional_keys : k.key => k } | |
key_id = aws_api_gateway_api_key.additional[each.key].id | |
key_type = "API_KEY" | |
usage_plan_id = aws_api_gateway_usage_plan.tokenizer[each.value.plan].id | |
depends_on = [ | |
aws_api_gateway_api_key.additional | |
] | |
} | |
## Mapping api tokenizer with apigw custom domain. | |
resource "aws_apigatewayv2_api_mapping" "tokenizer" { | |
count = var.apigw_custom_domain_create ? 1 : 0 | |
api_id = aws_api_gateway_rest_api.tokenizer.id | |
stage = aws_api_gateway_stage.tokenizer.stage_name | |
domain_name = aws_api_gateway_domain_name.main[0].domain_name | |
api_mapping_key = format("tokenizer/%s", aws_api_gateway_stage.tokenizer.stage_name) | |
} | |
## WAF association | |
resource "aws_wafv2_web_acl_association" "tokenizer" { | |
web_acl_arn = aws_wafv2_web_acl.main.arn | |
resource_arn = "arn:aws:apigateway:${var.aws_region}::/restapis/${aws_api_gateway_rest_api.tokenizer.id}/stages/${aws_api_gateway_stage.tokenizer.stage_name}" | |
} | |
/* | |
//The API Gateway endpoint | |
output "api_gateway_endpoint" { | |
value = format("https://", aws_api_gateway_domain_name.main.domain_name) | |
} | |
*/ | |
output "tokenizerinvoke_url" { | |
value = aws_api_gateway_deployment.tokenizer.invoke_url | |
} | |
## Alarms | |
### 4xx | |
module "api_tokenizer_4xx_error_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_name = "high-4xx-rate-" | |
alarm_description = "Api tokenizer error rate has exceeded 5%" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 2 | |
threshold = 200 | |
period = 300 | |
unit = "Count" | |
datapoints_to_alarm = 1 | |
namespace = "AWS/ApiGateway" | |
metric_name = "4XXError" | |
statistic = "Sum" | |
dimensions = { | |
"${local.tokenizer_api_name}" = { | |
ApiName = local.tokenizer_api_name | |
Stage = local.tokenizer_stage_name | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
### 5xx | |
module "api_tokenizer_5xx_error_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_name = "high-5xx-rate-" | |
alarm_description = "Api tokenizer error rate has exceeded 5%" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 20 | |
threshold = 5 | |
period = 300 | |
unit = "Count" | |
datapoints_to_alarm = 2 | |
namespace = "AWS/ApiGateway" | |
metric_name = "5XXError" | |
statistic = "Sum" | |
dimensions = { | |
"${local.tokenizer_api_name}" = { | |
ApiName = local.tokenizer_api_name | |
Stage = local.tokenizer_stage_name | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
} | |
### throttling (exceeded throttle limit) | |
module "log_filter_throttle_limit_tokenizer" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/log-metric-filter" | |
version = "~> 3.0" | |
name = format("%s-metric-throttle-rate-limit", local.tokenizer_api_name) | |
log_group_name = local.tokenizer_log_group_name | |
pattern = "exceeded throttle limit" | |
metric_transformation_namespace = "ErrorCount" | |
metric_transformation_name = format("%s-namespace", local.tokenizer_api_name) | |
depends_on = [ | |
aws_cloudwatch_log_group.tokenizer | |
] | |
} | |
module "api_tokenizer_throttle_limit_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarm" | |
version = "~> 3.0" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_name = format("high-rate-limit-throttle-%s", local.tokenizer_api_name) | |
alarm_description = "Throttle rate limit too high." | |
comparison_operator = "GreaterThanThreshold" | |
datapoints_to_alarm = 1 | |
evaluation_periods = 2 | |
threshold = 20 | |
period = 300 | |
#unit = "Count" | |
namespace = "ErrorCount" | |
metric_name = format("%s-namespace", local.tokenizer_api_name) | |
statistic = "Sum" | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
depends_on = [ | |
module.log_filter_throttle_limit_tokenizer | |
] | |
} | |
locals { | |
latency_threshold = 2000 | |
} | |
module "api_tokenizer_low_latency_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_name = "low-latency-" | |
alarm_description = format("The Api responds in more than %s ms.", local.latency_threshold) | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = local.latency_threshold | |
period = 300 | |
unit = "Count" | |
datapoints_to_alarm = 1 | |
namespace = "AWS/ApiGateway" | |
metric_name = "Latency" | |
statistic = "Maximum" | |
dimensions = { | |
"${local.tokenizer_api_name}" = { | |
ApiName = local.tokenizer_api_name | |
Stage = local.tokenizer_stage_name | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
}resource "aws_api_gateway_documentation_version" "main" { | |
# assign the deployment creation date as a version. | |
version = formatdate("YYYYMMDDHHmmss", aws_api_gateway_deployment.tokenizer.created_date) | |
rest_api_id = aws_api_gateway_rest_api.tokenizer.id | |
description = format("Documentation api %s", aws_api_gateway_rest_api.tokenizer.id) | |
lifecycle { | |
create_before_destroy = true | |
} | |
} | |
# export api | |
## open api | |
data "aws_api_gateway_export" "tokenizer" { | |
rest_api_id = aws_api_gateway_stage.tokenizer.rest_api_id | |
stage_name = aws_api_gateway_stage.tokenizer.stage_name | |
export_type = "oas30" | |
} | |
resource "aws_s3_object" "openapi_tokenizer" { | |
key = "openapi.json" | |
bucket = aws_s3_bucket.openapidocs.bucket | |
content = data.aws_api_gateway_export.tokenizer.body | |
content_encoding = "utf-8" | |
content_type = "application/json" | |
} | |
resource "aws_api_gateway_rest_api" "openapi_tokenizer" { | |
name = format("%s-openapi", local.project) | |
description = "Openapi tokenizer documentation." | |
} | |
resource "aws_api_gateway_resource" "folder" { | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
parent_id = aws_api_gateway_rest_api.openapi_tokenizer.root_resource_id | |
path_part = "{folder}" | |
} | |
resource "aws_api_gateway_resource" "item" { | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
parent_id = aws_api_gateway_resource.folder.id | |
path_part = "{item}" | |
} | |
resource "aws_api_gateway_method" "get_item" { | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
resource_id = aws_api_gateway_resource.item.id | |
http_method = "GET" | |
authorization = "NONE" | |
request_parameters = { | |
"method.request.path.folder" = true | |
"method.request.path.item" = true | |
} | |
} | |
resource "aws_api_gateway_integration" "openapi_tokenizer_integration" { | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
resource_id = aws_api_gateway_resource.item.id | |
http_method = aws_api_gateway_method.get_item.http_method | |
integration_http_method = "GET" | |
type = "AWS" | |
uri = format("arn:aws:apigateway:%s:s3:path/{bucket}/{object}", var.aws_region) | |
credentials = aws_iam_role.s3_api_gateyway_role.arn | |
request_parameters = { | |
"integration.request.path.bucket" = "method.request.path.folder" | |
"integration.request.path.object" = "method.request.path.item" | |
} | |
} | |
resource "aws_api_gateway_method_response" "openapi_tokenizer_response_200" { | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
resource_id = aws_api_gateway_resource.item.id | |
http_method = aws_api_gateway_method.get_item.http_method | |
status_code = "200" | |
response_models = { | |
"application/json" = "Empty" | |
} | |
} | |
resource "aws_api_gateway_integration_response" "openapi_tokenizer_integration_200" { | |
depends_on = [aws_api_gateway_integration.openapi_tokenizer_integration] | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
resource_id = aws_api_gateway_resource.item.id | |
http_method = aws_api_gateway_method.get_item.http_method | |
status_code = aws_api_gateway_method_response.openapi_tokenizer_response_200.status_code | |
} | |
resource "aws_api_gateway_deployment" "openapi_tokenizer" { | |
depends_on = [aws_api_gateway_integration.openapi_tokenizer_integration] | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
} | |
resource "aws_api_gateway_stage" "openapi_tokenizer" { | |
deployment_id = aws_api_gateway_deployment.openapi_tokenizer.id | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
stage_name = "v1" | |
cache_cluster_size = 0.5 | |
} | |
resource "aws_api_gateway_method_settings" "openapi_tokenizer" { | |
rest_api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
stage_name = aws_api_gateway_stage.openapi_tokenizer.stage_name | |
method_path = "*/*" | |
settings { | |
caching_enabled = true | |
throttling_rate_limit = 10 | |
throttling_burst_limit = 2 | |
} | |
} | |
## Mapping openapi with custom domain . | |
resource "aws_apigatewayv2_api_mapping" "openapi_tokrnizer" { | |
count = var.apigw_custom_domain_create ? 1 : 0 | |
api_id = aws_api_gateway_rest_api.openapi_tokenizer.id | |
stage = aws_api_gateway_stage.openapi_tokenizer.stage_name | |
domain_name = aws_api_gateway_domain_name.main[0].domain_name | |
api_mapping_key = "docs" | |
}## Firewall regional web acl | |
resource "aws_wafv2_web_acl" "main" { | |
name = format("%s-webacl", local.project) | |
description = "Api gateway WAF." | |
scope = "REGIONAL" | |
visibility_config { | |
cloudwatch_metrics_enabled = var.web_acl_visibility_config.cloudwatch_metrics_enabled | |
metric_name = local.webacl_name | |
sampled_requests_enabled = var.web_acl_visibility_config.sampled_requests_enabled | |
} | |
default_action { | |
allow {} | |
} | |
rule { | |
name = "IpReputationList" | |
priority = 1 | |
override_action { | |
count {} | |
} | |
statement { | |
managed_rule_group_statement { | |
name = "AWSManagedRulesAmazonIpReputationList" | |
vendor_name = "AWS" | |
} | |
} | |
visibility_config { | |
cloudwatch_metrics_enabled = var.web_acl_visibility_config.cloudwatch_metrics_enabled | |
metric_name = "IpReputationList" | |
sampled_requests_enabled = var.web_acl_visibility_config.sampled_requests_enabled | |
} | |
} | |
rule { | |
name = "CommonRuleSet" | |
priority = 2 | |
override_action { | |
count {} | |
} | |
statement { | |
managed_rule_group_statement { | |
name = "AWSManagedRulesCommonRuleSet" | |
vendor_name = "AWS" | |
} | |
} | |
visibility_config { | |
cloudwatch_metrics_enabled = var.web_acl_visibility_config.cloudwatch_metrics_enabled | |
metric_name = "CommonRuleSet" | |
sampled_requests_enabled = var.web_acl_visibility_config.sampled_requests_enabled | |
} | |
} | |
rule { | |
name = "KnownBadInputsRuleSet" | |
priority = 3 | |
override_action { | |
count {} | |
} | |
statement { | |
managed_rule_group_statement { | |
name = "AWSManagedRulesKnownBadInputsRuleSet" | |
vendor_name = "AWS" | |
} | |
} | |
visibility_config { | |
cloudwatch_metrics_enabled = var.web_acl_visibility_config.cloudwatch_metrics_enabled | |
metric_name = "KnownBadInputsRuleSet" | |
sampled_requests_enabled = var.web_acl_visibility_config.sampled_requests_enabled | |
} | |
} | |
rule { | |
name = "SQLiRuleSet" | |
priority = 4 | |
override_action { | |
count {} | |
} | |
statement { | |
managed_rule_group_statement { | |
name = "AWSManagedRulesSQLiRuleSet" | |
vendor_name = "AWS" | |
} | |
} | |
visibility_config { | |
cloudwatch_metrics_enabled = var.web_acl_visibility_config.cloudwatch_metrics_enabled | |
metric_name = "SQLiRuleSet" | |
sampled_requests_enabled = var.web_acl_visibility_config.sampled_requests_enabled | |
} | |
} | |
tags = { Name = format("%s-webacl", local.project) } | |
} | |
## Alarm | |
module "webacl_count_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
count = var.web_acl_visibility_config.cloudwatch_metrics_enabled ? 1 : 0 | |
alarm_name = "waf-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when webacl count greater than 10" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = 10 | |
period = 60 | |
unit = "Count" | |
namespace = "AWS/WAFV2" | |
metric_name = "CountedRequests" | |
statistic = "Sum" | |
dimensions = { | |
"webacl" = { | |
WebACL = aws_wafv2_web_acl.main.name | |
Ragion = var.aws_region | |
Rule = aws_wafv2_web_acl.main.name | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
}resource "aws_security_group" "nsg_task" { | |
name = format("%s-task-nlb", local.project) | |
description = "Limit connections from internal resources while allowing ${local.project}-task to connect to all external resources" | |
vpc_id = module.vpc.vpc_id | |
tags = { Name = format("%s-task-nlb", local.project) } | |
} | |
# Rules for the TASK (Targets the LB's IPs) | |
locals { | |
# list of container port in use. | |
container_ports = [ | |
var.container_port_tokenizer, | |
] | |
} | |
resource "aws_security_group_rule" "nsg_task_ingress_rule" { | |
count = length(local.container_ports) | |
description = "Only allow connections from the NLB ${count.index}" | |
type = "ingress" | |
from_port = local.container_ports[count.index] | |
to_port = local.container_ports[count.index] | |
protocol = "tcp" | |
cidr_blocks = formatlist( | |
"%s/32", | |
flatten(data.aws_network_interface.nlb.*.private_ips), | |
) | |
security_group_id = aws_security_group.nsg_task.id | |
} | |
resource "aws_security_group_rule" "nsg_task_egress_rule" { | |
description = "Allows task to establish connections to all resources" | |
type = "egress" | |
from_port = "0" | |
to_port = "0" | |
protocol = "-1" | |
cidr_blocks = ["0.0.0.0/0"] | |
security_group_id = aws_security_group.nsg_task.id | |
} | |
# lookup the ENIs associated with the NLB | |
data "aws_network_interface" "nlb" { | |
count = length(module.vpc.private_subnets) | |
filter { | |
name = "description" | |
values = ["ELB ${module.nlb.lb_arn_suffix}"] | |
} | |
filter { | |
name = "subnet-id" | |
values = [element(module.vpc.private_subnets, count.index)] | |
} | |
} | |
module "nlb" { | |
source = "terraform-aws-modules/alb/aws" | |
name = format("%s-nlb", local.project) | |
load_balancer_type = "network" | |
vpc_id = module.vpc.vpc_id | |
subnets = module.vpc.private_subnets | |
enable_cross_zone_load_balancing = "true" | |
internal = true | |
http_tcp_listeners = [ | |
{ | |
port = 80 | |
protocol = "TCP" | |
target_group_index = 0 | |
}, | |
] | |
target_groups = [ | |
{ | |
# service tokenizer | |
name = format("%s-tokenizer", local.project) | |
backend_protocol = "TCP" | |
backend_port = 80 | |
#port = 80 | |
target_type = "ip" | |
#preserve_client_ip = true | |
deregistration_delay = 30 | |
vpc_id = module.vpc.vpc_id | |
health_check = { | |
enabled = true | |
healthy_threshold = 3 | |
interval = 10 | |
timeout = 6 | |
unhealthy_threshold = 3 | |
matcher = "200-399" | |
path = "/actuator/health" | |
} | |
}, | |
] | |
tags = { Name : format("%s-nlb", local.project) } | |
}module "nlb_unhealthy_unhealthy_targets_alarm" { | |
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarms-by-multiple-dimensions" | |
version = "~> 3.0" | |
count = length(module.nlb.target_group_names) | |
alarm_name = "nlb-unhealthy-unhealthy-" | |
actions_enabled = var.env_short == "p" ? true : false | |
alarm_description = "Alarm when an unhealthy count is greater than one in the target" | |
comparison_operator = "GreaterThanOrEqualToThreshold" | |
evaluation_periods = 1 | |
threshold = 1 | |
period = 60 | |
unit = "Count" | |
namespace = "AWS/NetworkELB" | |
metric_name = "UnHealthyHostCount" | |
statistic = "Sum" | |
dimensions = { | |
"${module.nlb.target_group_names[count.index]}" = { | |
TargetGroup = module.nlb.target_group_names[count.index] | |
LoadBalacer = module.nlb.lb_arn_suffix | |
}, | |
} | |
alarm_actions = [aws_sns_topic.alarms.arn] | |
}# ApiGw throttling | |
resource "aws_cloudwatch_query_definition" "apigw_429" { | |
name = "ApiGateway/429" | |
log_group_names = [ | |
local.tokenizer_log_group_name | |
] | |
query_string = file("./cloudwatch-query/apigw-429.sql") | |
} | |
resource "aws_cloudwatch_query_definition" "apigw_count_rate_limit" { | |
name = "ApiGateway/Count Rate Limit" | |
log_group_names = [ | |
local.tokenizer_log_group_name | |
] | |
query_string = file("./cloudwatch-query/count-api-rate-limit.sql") | |
} | |
## ECS | |
resource "aws_cloudwatch_query_definition" "ecs_log_level_error" { | |
name = "ECS/Errors" | |
log_group_names = [ | |
aws_cloudwatch_log_group.ecs_tokenizer.name, | |
] | |
query_string = file("./cloudwatch-query/log-level-error.sql") | |
} | |
resource "aws_cloudwatch_query_definition" "ecs_exception" { | |
name = "ECS/Exceptions" | |
log_group_names = [ | |
aws_cloudwatch_log_group.ecs_tokenizer.name, | |
] | |
query_string = file("./cloudwatch-query/log-with-exception.sql") | |
} | |
resource "aws_cloudwatch_query_definition" "ecs_provisioned_throughput_exception" { | |
name = "ECS/Count Provisioned Throughput" | |
log_group_names = [ | |
aws_cloudwatch_log_group.ecs_tokenizer.name, | |
] | |
query_string = file("./cloudwatch-query/count-provisioned-throughput-exceeded.sql") | |
} | |
resource "aws_cloudwatch_query_definition" "ecs_log_by_traceid" { | |
name = "ECS/Log by traceid" | |
log_group_names = [ | |
aws_cloudwatch_log_group.ecs_tokenizer.name, | |
] | |
query_string = file("./cloudwatch-query/log-by-traceid.sql") | |
}resource "aws_cloudwatch_dashboard" "main" { | |
dashboard_name = "MS-Tokenizer" | |
dashboard_body = templatefile("${path.module}/dashboards/main.tpl.json", | |
{ | |
aws_region = var.aws_region | |
tokenizer_api_name = aws_api_gateway_rest_api.tokenizer.name | |
nlb_arn_suffix = module.nlb.lb_arn_suffix | |
nlb_target_arn_suffix = module.nlb.target_group_arn_suffixes[0] | |
ecs_tokenizer_service = aws_ecs_service.tokenizer.name | |
ecs_cluster_name = aws_ecs_cluster.ecs_cluster.name | |
waf_web_acl = aws_wafv2_web_acl.main.name | |
tokenizer_api_plan_ids = local.tokenizer_api_plan_ids | |
tokenizer_api_id = aws_api_gateway_rest_api.tokenizer.id | |
tokenizer_api_state_name = aws_api_gateway_stage.tokenizer.stage_name | |
} | |
) | |
}module "sentinel" { | |
count = var.enable_sentinel_logs ? 1 : 0 | |
source = "git::https://github.com/pagopa/terraform-aws-sentinel.git?ref=v1.0.1" | |
account_id = data.aws_caller_identity.current.account_id | |
queue_name = format("%s-sentinel-queue", local.project) | |
trail_name = format("%s-sentinel-trail", local.project) | |
sentinel_bucket_name = format("%s-sentinel-logs", local.project) | |
expiration_days = 3 | |
sentinel_workspace_id = var.sentinel_workspace_id | |
}locals { | |
openapidocs_bucket_name = format("%s%sapis", var.app_name, var.env_short) | |
} | |
# S3 bucket for website. | |
resource "aws_s3_bucket" "openapidocs" { | |
bucket = local.openapidocs_bucket_name | |
force_destroy = true | |
} | |
resource "aws_s3_bucket_acl" "openapidocs" { | |
bucket = aws_s3_bucket.openapidocs.id | |
acl = "private" | |
} | |
resource "aws_s3_bucket_policy" "openapidocs" { | |
bucket = aws_s3_bucket.openapidocs.id | |
policy = templatefile("./templates/s3_policy.tpl.json", { | |
bucket_name = local.openapidocs_bucket_name | |
account_id = data.aws_caller_identity.current.id | |
}) | |
}data "aws_secretsmanager_secret" "email_operation" { | |
name = "operation/alerts" | |
} | |
data "aws_secretsmanager_secret_version" "email_operation_lt" { | |
secret_id = data.aws_secretsmanager_secret.email_operation.id | |
} | |
resource "aws_sns_topic" "alarms" { | |
name = format("%s-alarms", local.project) | |
display_name = "Alarms" | |
} | |
resource "aws_sns_topic_subscription" "alarms_email" { | |
endpoint = jsondecode(data.aws_secretsmanager_secret_version.email_operation_lt.secret_string)["email"] | |
endpoint_auto_confirms = true | |
protocol = "email" | |
topic_arn = aws_sns_topic.alarms.arn | |
}moved { | |
from = aws_api_gateway_api_key.main["INTEROP-DEV"] | |
to = aws_api_gateway_api_key.additional["INTEROP-DEV"] | |
} | |
moved { | |
from = aws_api_gateway_api_key.main["INTEROP-UAT"] | |
to = aws_api_gateway_api_key.additional["INTEROP-UAT"] | |
} | |
moved { | |
from = aws_api_gateway_api_key.main["INTEROP"] | |
to = aws_api_gateway_api_key.additional["INTEROP"] | |
}variable "aws_region" { | |
type = string | |
description = "AWS region to create resources. Default Milan" | |
default = "eu-south-1" | |
} | |
variable "app_name" { | |
type = string | |
default = "tokenizer" | |
description = "App name. Tokenizer" | |
} | |
variable "environment" { | |
type = string | |
default = "dev" | |
description = "Environment" | |
} | |
variable "env_short" { | |
type = string | |
default = "d" | |
description = "Evnironment short." | |
} | |
variable "vpc_cidr" { | |
type = string | |
default = "10.1.0.0/16" | |
description = "VPC cidr." | |
} | |
variable "azs" { | |
type = list(string) | |
description = "Availability zones" | |
default = ["eu-south-1a", "eu-south-1b", "eu-south-1c"] | |
} | |
variable "vpc_private_subnets_cidr" { | |
type = list(string) | |
description = "Private subnets list of cidr." | |
default = ["10.1.1.0/24", "10.1.2.0/24", "10.1.3.0/24"] | |
} | |
variable "vpc_public_subnets_cidr" { | |
type = list(string) | |
description = "Private subnets list of cidr." | |
default = ["10.1.101.0/24", "10.1.102.0/24", "10.1.103.0/24"] | |
} | |
variable "vpc_internal_subnets_cidr" { | |
type = list(string) | |
description = "Internal subnets list of cidr. Mainly for private endpoints" | |
default = ["10.1.201.0/24", "10.1.202.0/24", "10.1.203.0/24"] | |
} | |
variable "enable_nat_gateway" { | |
type = bool | |
description = "Enable/Create nat gateway" | |
default = false | |
} | |
### VPC Peering | |
variable "vpc_peering" { | |
type = object({ | |
owner_connection_id = string | |
owner_cidr_block = string | |
}) | |
default = null | |
description = "Vpc peering configuration" | |
} | |
## Public Dns zones | |
variable "public_dns_zones" { | |
type = map(any) | |
description = "Route53 Hosted Zone" | |
} | |
variable "dns_record_ttl" { | |
type = number | |
description = "Dns record ttl (in sec)" | |
default = 86400 # 24 hours | |
} | |
## Api Gateway | |
variable "apigw_custom_domain_create" { | |
type = bool | |
description = "Create apigw Custom Domain with its tls certificate" | |
default = false | |
} | |
variable "apigw_access_logs_enable" { | |
type = bool | |
description = "Enable api gateway access logs" | |
default = false | |
} | |
variable "apigw_data_trace_enabled" { | |
type = bool | |
description = "Specifies whether data trace logging is enabled. It effects the log entries pushed to Amazon CloudWatch Logs." | |
default = false | |
} | |
variable "apigw_execution_logs_retention" { | |
type = number | |
default = 7 | |
description = "Api gateway exection logs retention (days)" | |
} | |
## Web acl config | |
variable "web_acl_visibility_config" { | |
type = object({ | |
cloudwatch_metrics_enabled = bool | |
sampled_requests_enabled = bool | |
}) | |
default = { | |
cloudwatch_metrics_enabled = false | |
sampled_requests_enabled = false | |
} | |
description = "Cloudwatch metric eneble for web acl rules." | |
} | |
## ECR | |
variable "ecr_keep_nr_images" { | |
type = number | |
description = "Number of images to keep." | |
default = 10 | |
} | |
## ECS | |
variable "ecs_logs_retention_days" { | |
type = number | |
description = "Specifies the number of days you want to retain log events in the specified log group." | |
default = 7 | |
} | |
variable "ecs_enable_execute_command" { | |
type = bool | |
description = "Specifies whether to enable Amazon ECS Exec for the tasks within the service." | |
default = false | |
} | |
variable "container_port_tokenizer" { | |
type = number | |
description = "Container port tokenizer" | |
default = 8080 | |
} | |
variable "replica_count" { | |
type = number | |
description = "Number of task replica" | |
default = 1 | |
} | |
variable "ecs_autoscaling" { | |
type = object({ | |
max_capacity = number | |
min_capacity = number | |
scale_in_cooldown = number | |
scale_out_cooldown = number | |
}) | |
default = { | |
max_capacity = 3 | |
min_capacity = 1 | |
scale_in_cooldown = 180 | |
scale_out_cooldown = 40 | |
} | |
description = "ECS Service autoscaling." | |
} | |
variable "ecs_as_threshold" { | |
type = object({ | |
cpu_min = number | |
cpu_max = number | |
mem_min = number | |
mem_max = number | |
}) | |
default = { | |
cpu_max = 80 | |
cpu_min = 20 | |
mem_max = 80 | |
mem_min = 60 | |
} | |
description = "ECS Tasks autoscaling settings." | |
} | |
variable "ms_tokenizer_log_level" { | |
type = string | |
default = "DEBUG" | |
description = "Log level micro service tokenizer" | |
} | |
variable "ms_tokenizer_rest_client_log_level" { | |
type = string | |
default = "FULL" | |
description = "Rest client log level micro service tokenizer" | |
} | |
variable "ms_tokenizer_enable_confidential_filter" { | |
type = bool | |
default = false | |
description = "Enable a filter to avoid logging confidential data" | |
} | |
variable "ms_tokenizer_enable_single_line_stack_trace_logging" { | |
type = bool | |
default = false | |
description = "Enable logging stack trace in a single line" | |
} | |
variable "enable_container_insights" { | |
type = bool | |
description = "Enable container insight in ECS cluster" | |
default = false | |
} | |
# Dynamodb | |
variable "dynamodb_region_replication_enable" { | |
type = bool | |
description = "Enable dyamodb deplicaton in a secondary region." | |
default = false | |
} | |
variable "dynamodb_point_in_time_recovery_enabled" { | |
type = bool | |
description = "Enable dynamodb point in time recovery" | |
default = false | |
} | |
## Table Token | |
variable "table_token_read_capacity" { | |
type = number | |
description = "Table token read capacity." | |
} | |
variable "table_token_write_capacity" { | |
type = number | |
description = "Table token read capacity." | |
} | |
variable "table_token_autoscaling_read" { | |
type = object({ | |
scale_in_cooldown = number | |
scale_out_cooldown = number | |
target_value = number | |
max_capacity = number | |
}) | |
description = "Read autoscaling settings table token." | |
} | |
variable "table_token_autoscaling_write" { | |
type = object({ | |
scale_in_cooldown = number | |
scale_out_cooldown = number | |
target_value = number | |
max_capacity = number | |
}) | |
description = "Write autoscaling settings table token." | |
} | |
variable "table_token_stream_enabled" { | |
type = bool | |
description = "Enable Streams" | |
default = false | |
} | |
# Event bridge | |
variable "create_event_bridge_pipe" { | |
type = bool | |
description = "Create event bridge pipe." | |
default = false | |
} | |
// We assume every plan has its own api key | |
variable "tokenizer_plans" { | |
type = list(object({ | |
key_name = string | |
burst_limit = number | |
rate_limit = number | |
additional_keys = list(string) | |
method_throttle = list(object({ | |
path = string | |
burst_limit = number | |
rate_limit = number | |
})) | |
})) | |
description = "Usage plan with its api key and rate limit." | |
} | |
variable "table_token_autoscling_indexes" { | |
type = any | |
description = "Autoscaling gsi configurations" | |
} | |
variable "create_cloudhsm" { | |
type = bool | |
description = "Create cloudhsm cluster to enctypt dynamodb tables" | |
default = false | |
} | |
## Alarms | |
variable "dynamodb_alarms" { | |
type = list( | |
object({ | |
actions_enabled = bool | |
alarm_name = string | |
alarm_description = string | |
comparison_operator = string | |
evaluation_periods = number | |
datapoints_to_alarm = number | |
threshold = number | |
period = number | |
unit = string | |
namespace = string | |
metric_name = string | |
statistic = string | |
})) | |
} | |
# Sentinel integration | |
variable "enable_sentinel_logs" { | |
type = bool | |
default = false | |
description = "Create all resources required to sento logs to azure sentinel." | |
} | |
variable "sentinel_servcie_account_id" { | |
type = string | |
description = "Microsoft Sentinel's service account ID for AWS." | |
default = "197857026523" | |
} | |
variable "sentinel_workspace_id" { | |
type = string | |
description = "Sentinel workspece id" | |
default = null | |
} | |
variable "github_tokenizer_repo" { | |
type = string | |
description = "Github repository allowed to run action for ECS deploy." | |
default = "pagopa/pdv-ms-tokenizer" | |
} | |
variable "tags" { | |
type = map(any) | |
default = { | |
CreatedBy = "Terraform" | |
} | |
} | |
output "vpc_cidr" { | |
value = module.vpc.vpc_cidr_block | |
} | |
## ecs | |
output "ecs_definition_task_arn" { | |
value = data.aws_ecs_task_definition.tokenizer.arn | |
} | |
output "ecs_definition_task_revision" { | |
value = data.aws_ecs_task_definition.tokenizer.revision | |
} | |
output "ecs_task_definition_tokenizer_arn" { | |
value = data.aws_ecs_task_definition.tokenizer.arn | |
} | |
output "ecs_task_definition_tokenizer_revision" { | |
value = data.aws_ecs_task_definition.tokenizer.revision | |
} | |
## dynamodb | |
output "dynamodb_table_token_arn" { | |
value = module.dynamodb_table_token.dynamodb_table_arn | |
} | |
output "dynamodb_table_token_id" { | |
value = module.dynamodb_table_token.dynamodb_table_id | |
} | |
output "dynamodb_table_token_stream_arn" { | |
value = var.table_token_stream_enabled ? module.dynamodb_table_token.dynamodb_table_stream_arn : null | |
} | |
# Dns | |
output "public_dns_zone_name" { | |
value = module.dn_zone.route53_zone_name | |
} | |
output "public_dns_servers" { | |
value = module.dn_zone.route53_zone_name_servers | |
} | |
# NLB | |
output "nlb_hostname" { | |
value = module.nlb.lb_dns_name | |
} | |
# API Gateway | |
output "api_gateway_endpoint" { | |
value = var.apigw_custom_domain_create ? format("https://%s", aws_api_gateway_domain_name.main[0].domain_name) : "" | |
} | |
output "openapi_endpoint" { | |
value = var.apigw_custom_domain_create ? format("https://%s/docs/%s/%s", | |
aws_api_gateway_domain_name.main[0].domain_name, | |
aws_s3_bucket.openapidocs.id, | |
aws_s3_object.openapi_tokenizer.key, ) : "" | |
} | |
output "tokenizer_api_keys" { | |
value = { for k in keys(local.api_key_list) : k => aws_api_gateway_usage_plan_key.tokenizer[k].value } | |
sensitive = true | |
} | |
output "tokenizer_api_ids" { | |
value = local.tokenizer_api_plan_ids | |
} | |
# cloud hsm | |
output "cloudhsm_cluster_id" { | |
value = try(aws_cloudhsm_v2_cluster.main[0].id, null) | |
} | |
output "cloudhsm_cluster_certificates" { | |
value = try(aws_cloudhsm_v2_cluster.main[0].cluster_certificates, null) | |
sensitive = true | |
} | |
output "cloudhsm_hsm_id" { | |
value = try(aws_cloudhsm_v2_hsm.hsm1[0].hsm_id, null) | |
} | |
output "clouthsm_hsm_eni_ip" { | |
value = try(data.aws_network_interface.hsm[0].private_ip, null) | |
} | |
# sentinel | |
output "sentinel_role_arn" { | |
value = try(module.sentinel[0].sentinel_role_arn, null) | |
} | |
output "sentinel_queue_url" { | |
value = try(module.sentinel[0].sentinel_queue_url, null) | |
} | |
# github action role. | |
output "github_ecs_deploy_role_arn" { | |
value = aws_iam_role.githubecsdeploy.arn | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment