diff --git a/services/search-index-lambda/.gitignore b/services/search-index-lambda/.gitignore new file mode 100644 diff --git a/services/terraform/modules/shared/outputs.tf b/services/terraform/modules/shared/outputs.tf --- a/services/terraform/modules/shared/outputs.tf +++ b/services/terraform/modules/shared/outputs.tf @@ -4,6 +4,7 @@ aws_dynamodb_table.backup-service-backup, aws_dynamodb_table.reports-service-reports, aws_dynamodb_table.tunnelbroker-undelivered-messages, + aws_dynamodb_table.identity-users, ] } diff --git a/services/terraform/modules/shared/search_index_lambda.tf b/services/terraform/modules/shared/search_index_lambda.tf new file mode 100644 --- /dev/null +++ b/services/terraform/modules/shared/search_index_lambda.tf @@ -0,0 +1,61 @@ +variable iam_role_arn { + default = "arn:aws:iam::000000000000:role/lambda-role" +} + +variable lambda_zip_dir { + type = string + default = "../../search-index-lambda/target/lambda/search-index-lambda" +} + +resource "aws_lambda_function" "search_index_lambda" { + function_name = "search-index-lambda-function" + filename = "${var.lambda_zip_dir}/bootstrap.zip" + source_code_hash = filebase64sha256("${var.lambda_zip_dir}/bootstrap.zip") + handler = "bootstrap" + role = var.iam_role_arn + runtime = "provided.al2" + architectures = ["arm64"] + timeout = 300 + + vpc_config { + subnet_ids = var.subnet_ids + security_group_ids = [aws_security_group.search_index_lambda.id] + } + + environment { + variables = { + RUST_BACKTRACE = "1" + OPENSEARCH_ENDPOINT = aws_opensearch_domain.identity-search.endpoint + } + } + + tracing_config { + mode = "Active" + } +} + +resource "aws_lambda_event_source_mapping" "trigger" { + count = var.is_dev ? 0 : 1 + event_source_arn = aws_dynamodb_table.identity-users.stream_arn + function_name = aws_lambda_function.search_index_lambda.arn + starting_position = "LATEST" +} + +resource "aws_security_group" "search_index_lambda" { + name = "search_index_lambda_sg" + vpc_id = var.vpc_id + + egress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} + + +resource "aws_lambda_function_event_invoke_config" "example" { + function_name = aws_lambda_function.search_index_lambda.function_name + maximum_event_age_in_seconds = 60 + maximum_retry_attempts = 2 +} diff --git a/services/terraform/remote/aws_iam.tf b/services/terraform/remote/aws_iam.tf --- a/services/terraform/remote/aws_iam.tf +++ b/services/terraform/remote/aws_iam.tf @@ -196,6 +196,103 @@ } +data "aws_iam_policy_document" "assume_identity_search_role" { + statement { + effect = "Allow" + + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + + actions = ["sts:AssumeRole"] + } +} + +resource "aws_iam_role" "search_index_lambda_role" { + name = "search_index_lambda_role" + assume_role_policy = data.aws_iam_policy_document.assume_identity_search_role.json + + managed_policy_arns = [ + aws_iam_policy.manage_cloudwatch_logs.arn, + aws_iam_policy.opensearch_domain_access.arn, + aws_iam_policy.read_identity_users_stream.arn, + ] +} + +data "aws_iam_policy_document" "opensearch_domain_access" { + statement { + effect = "Allow" + + actions = [ + "es:ESHttpHead", + "es:ESHttpPost", + "es:ESHttpGet", + "es:ESHttpDelete", + "es:ESHttpPut", + ] + resources = ["*"] + } +} + +resource "aws_iam_policy" "opensearch_domain_access" { + name = "opensearch-domain-access" + path = "/" + description = "IAM policy for accessing opensearch domain" + policy = data.aws_iam_policy_document.opensearch_domain_access.json +} + +data "aws_iam_policy_document" "read_identity_users_stream" { + statement { + effect = "Allow" + + actions = [ + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:DescribeStream", + "dynamodb:ListStreams", + ] + resources = [ + module.shared.dynamodb_tables["identity-users"].arn, + module.shared.dynamodb_tables["identity-users"].stream_arn, + "${module.shared.dynamodb_tables["identity-users"].arn}/stream/*", + ] + } +} + +resource "aws_iam_policy" "read_identity_users_stream" { + name = "read-identity-users-stream" + path = "/" + description = "IAM policy for managing identity-users stream" + policy = data.aws_iam_policy_document.read_identity_users_stream.json +} + +data "aws_iam_policy_document" "manage_cloudwatch_logs" { + statement { + effect = "Allow" + + actions = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ] + + resources = ["arn:aws:logs:*:*:*"] + } +} + +resource "aws_iam_policy" "manage_cloudwatch_logs" { + name = "manage-cloudwatch-logs" + path = "/" + description = "IAM policy for managing cloudwatch logs" + policy = data.aws_iam_policy_document.manage_cloudwatch_logs.json +} + +resource "aws_iam_role_policy_attachment" "AWSLambdaVPCAccessExecutionRole" { + role = "${aws_iam_role.search_index_lambda_role.name}" + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" +} + data "aws_iam_policy_document" "identity-search" { statement { effect = "Allow" diff --git a/services/terraform/remote/main.tf b/services/terraform/remote/main.tf --- a/services/terraform/remote/main.tf +++ b/services/terraform/remote/main.tf @@ -53,6 +53,7 @@ bucket_name_suffix = local.s3_bucket_name_suffix vpc_id = aws_vpc.default.id + iam_role_arn = aws_iam_role.search_index_lambda_role.arn cidr_block = aws_vpc.default.cidr_block subnet_ids = [ aws_subnet.public_a.id,