Skip to content
Open
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
71 changes: 36 additions & 35 deletions tf/environments/dev/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -523,41 +523,38 @@ resource "aws_security_group_rule" "elasticache_sg_rule" {
#### OONI Probe service

# For accessing the s3 bucket
resource "aws_iam_role_policy" "ooniprobe_role" {
name = "${local.name}-task-role"
role = module.ooniapi_cluster.container_host_role.name

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "${aws_s3_bucket.ooniprobe_failed_reports.arn}/*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "${aws_s3_bucket.ooni_private_config_bucket.arn}/*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "${aws_s3_bucket.anoncred_manifests.arn}/*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "${aws_s3_bucket.anoncred_manifests.arn}/*"
}
]
}
EOF
# The S3 objects ooniprobe reads and writes: failed reports, its private
# config, and the anonymous credentials manifests
locals {
ooniprobe_s3_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = ""
Effect = "Allow"
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.ooniprobe_failed_reports.arn}/*"
},
{
Sid = ""
Effect = "Allow"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.ooni_private_config_bucket.arn}/*"
},
{
Sid = ""
Effect = "Allow"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.anoncred_manifests.arn}/*"
},
{
Sid = ""
Effect = "Allow"
Action = "s3:ListBucket"
Resource = "${aws_s3_bucket.anoncred_manifests.arn}/*"
},
]
})
}

module "ooniapi_ooniprobe_deployer" {
Expand All @@ -580,6 +577,8 @@ module "ooniapi_ooniprobe_deployer" {
module "ooniapi_ooniprobe" {
source = "../../modules/ooniapi_service"

task_role_policy = local.ooniprobe_s3_policy

task_memory = 256

# First run should be set on first run to bootstrap the task definition
Expand Down Expand Up @@ -641,6 +640,8 @@ module "ooniapi_ooniprobe" {
module "ooniapi_ooniprobe_legacy" {
source = "../../modules/ooniapi_service"

task_role_policy = local.ooniprobe_s3_policy

# First run should be set on first run to bootstrap the task definition
# first_run = true

Expand Down
71 changes: 36 additions & 35 deletions tf/environments/prod/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -836,41 +836,38 @@ resource "aws_security_group_rule" "elasticache_sg_rule" {
#### OONI Probe service

# For accessing the s3 bucket
resource "aws_iam_role_policy" "ooniprobe_role" {
name = "${local.name}-task-role"
role = module.ooniapi_cluster.container_host_role.name

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "${aws_s3_bucket.ooniprobe_failed_reports.arn}/*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "${aws_s3_bucket.ooni_private_config_bucket.arn}/*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "${aws_s3_bucket.anoncred_manifests.arn}/*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "${aws_s3_bucket.anoncred_manifests.arn}/*"
}
]
}
EOF
# The S3 objects ooniprobe reads and writes: failed reports, its private
# config, and the anonymous credentials manifests
locals {
ooniprobe_s3_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = ""
Effect = "Allow"
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.ooniprobe_failed_reports.arn}/*"
},
{
Sid = ""
Effect = "Allow"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.ooni_private_config_bucket.arn}/*"
},
{
Sid = ""
Effect = "Allow"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.anoncred_manifests.arn}/*"
},
{
Sid = ""
Effect = "Allow"
Action = "s3:ListBucket"
Resource = "${aws_s3_bucket.anoncred_manifests.arn}/*"
},
]
})
}

module "ooniapi_ooniprobe_deployer" {
Expand All @@ -893,6 +890,8 @@ module "ooniapi_ooniprobe_deployer" {
module "ooniapi_ooniprobe" {
source = "../../modules/ooniapi_service"

task_role_policy = local.ooniprobe_s3_policy

# First run should be set on first run to bootstrap the task definition
#first_run = true

Expand Down Expand Up @@ -955,6 +954,8 @@ module "ooniapi_ooniprobe" {
module "ooniapi_ooniprobe_legacy" {
source = "../../modules/ooniapi_service"

task_role_policy = local.ooniprobe_s3_policy

# First run should be set on first run to bootstrap the task definition
# first_run = true

Expand Down
10 changes: 10 additions & 0 deletions tf/modules/ecs_cluster/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,16 @@ resource "aws_launch_template" "container_host" {
name = aws_iam_instance_profile.container_host.name
}

# The instance credentials are for the host: the ECS agent and docker's
# log driver. Requiring IMDSv2 with a hop limit of 1 keeps them from the
# containers, which are a hop further away on the bridge network; tasks
# get credentials from their task role instead.
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
}

network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
Expand Down
15 changes: 0 additions & 15 deletions tf/modules/ecs_cluster/templates/profile_policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,6 @@
"Action": ["logs:*", "cloudwatch:GenerateQuery"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetResourcePolicy",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "secretsmanager:ListSecrets",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
Expand Down
11 changes: 9 additions & 2 deletions tf/modules/ooni_docker_build/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ data "aws_caller_identity" "current" {}

locals {
account_id = data.aws_caller_identity.current.account_id
env_label = var.environment == "prod" ? "latest" : "dev"
# the only secret the builds read (buildspec.yml DOCKERHUB_SECRET_ID), to
# log in to Docker Hub
dockerhub_secret_name = "oonidevops/dockerhub/access_token"
env_label = var.environment == "prod" ? "latest" : "dev"
}

resource "aws_iam_policy" "codebuild" {
Expand Down Expand Up @@ -63,6 +66,11 @@ resource "aws_iam_policy" "codebuild" {
"arn:aws:codebuild:${var.aws_region}:${local.account_id}:report-group/oonidkr-${var.service_name}-*"
]
},
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:${var.aws_region}:${local.account_id}:secret:${local.dockerhub_secret_name}-??????"
},
{
"Effect": "Allow",
"Action": "codestar-connections:UseConnection",
Expand Down Expand Up @@ -93,7 +101,6 @@ POLICY
managed_policy_arns = [
aws_iam_policy.codebuild.arn,
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess",
"arn:aws:iam::aws:policy/SecretsManagerReadWrite"
]
max_session_duration = "3600"
name = "codebuild-oonidkr-${var.service_name}"
Expand Down
70 changes: 69 additions & 1 deletion tf/modules/ooniapi_service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,78 @@ resource "aws_iam_role" "ooniapi_service_task" {
EOF
}

locals {
# The execution role only needs to read the secrets ECS injects into this
# task (task_secrets): every value is an SSM parameter or a Secrets
# Manager secret ARN.
task_secret_arns_secretsmanager = [for arn in values(var.task_secrets) : arn if startswith(arn, "arn:aws:secretsmanager:")]
task_secret_arns_ssm = [for arn in values(var.task_secrets) : arn if startswith(arn, "arn:aws:ssm:")]
task_secret_statements = concat(
length(local.task_secret_arns_secretsmanager) == 0 ? [] : [{
Effect = "Allow"
Action = ["secretsmanager:GetSecretValue"]
Resource = local.task_secret_arns_secretsmanager
}],
length(local.task_secret_arns_ssm) == 0 ? [] : [{
Effect = "Allow"
Action = ["ssm:GetParameters"]
Resource = local.task_secret_arns_ssm
}],
)
}

resource "aws_iam_role_policy" "ooniapi_service_task" {
name = "${local.name}-task-role"
role = aws_iam_role.ooniapi_service_task.name

policy = templatefile("${path.module}/templates/profile_policy.json", {})
policy = jsonencode({
Version = "2012-10-17"
Statement = concat([
{
Sid = "ecsInstanceRole"
Effect = "Allow"
Action = ["ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:Submit*", "ecs:StartTelemetrySession"]
Resource = ["*"]
},
{
Sid = "CloudWatchLogsFullAccess"
Effect = "Allow"
Action = ["logs:*", "cloudwatch:GenerateQuery"]
Resource = "*"
},
{
Effect = "Allow"
Action = ["ec2:Describe*", "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:DeregisterTargets", "elasticloadbalancing:Describe*", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "elasticloadbalancing:RegisterTargets"]
Resource = "*"
},
], local.task_secret_statements)
})
}

# The role the service's own code gets credentials from, for the AWS calls
# it makes. The execution role above is only used by ECS, to start the task.
resource "aws_iam_role" "ooniapi_service_app" {
count = var.task_role_policy == null ? 0 : 1

name = "${local.name}-app-role"
tags = var.tags

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}

resource "aws_iam_role_policy" "ooniapi_service_app" {
count = var.task_role_policy == null ? 0 : 1

name = "${local.name}-app-role"
role = aws_iam_role.ooniapi_service_app[0].name
policy = var.task_role_policy
}

resource "aws_cloudwatch_log_group" "ooniapi_service" {
Expand Down Expand Up @@ -91,6 +158,7 @@ resource "aws_ecs_task_definition" "ooniapi_service" {
}
])
execution_role_arn = aws_iam_role.ooniapi_service_task.arn
task_role_arn = var.task_role_policy == null ? null : aws_iam_role.ooniapi_service_app[0].arn
tags = var.tags
track_latest = true
}
Expand Down
Loading
Loading