hasher-matcher-actioner/terraform/indexer/main.tf (179 lines of code) (raw):

# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved # First define the Indexing Schedule resource "aws_cloudwatch_event_rule" "indexing_trigger" { name = "${var.prefix}-RecurringIndexBuild" description = "Rebuild Index on a regular cadence" schedule_expression = "rate(${var.indexer_frequency})" role_arn = aws_iam_role.indexing_trigger.arn } resource "aws_iam_role" "indexing_trigger" { name_prefix = "${var.prefix}_indexing_trigger" assume_role_policy = data.aws_iam_policy_document.indexing_trigger_assume_role.json tags = merge( var.additional_tags, { Name = "FetcherLambdaTriggerRole" } ) } data "aws_iam_policy_document" "indexing_trigger_assume_role" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["events.amazonaws.com"] } } } ## Define a policy document to asign to the role data "aws_iam_policy_document" "indexing_trigger" { statement { actions = ["lambda:InvokeFunction"] resources = [aws_lambda_function.indexer.arn] effect = "Allow" condition { test = "ArnLike" variable = "AWS:SourceArn" values = [aws_cloudwatch_event_rule.indexing_trigger.arn] } } } ## Create a permission policy from policy document resource "aws_iam_policy" "indexing_trigger" { name_prefix = "${var.prefix}_indexing_trigger_role_policy" description = "Permissions for Indexing Schedule" policy = data.aws_iam_policy_document.indexing_trigger.json } ## Attach a permission policy to the indexing trigger role resource "aws_iam_role_policy_attachment" "indexing_trigger" { role = aws_iam_role.indexing_trigger.name policy_arn = aws_iam_policy.indexing_trigger.arn } ## Connect rule to function invocation resource "aws_cloudwatch_event_target" "indexer" { arn = aws_lambda_function.indexer.arn rule = aws_cloudwatch_event_rule.indexing_trigger.name } # Then define the Indexing Function / Lambda etc. data "aws_iam_policy_document" "lambda_assume_role" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } } } resource "aws_lambda_function" "indexer" { function_name = "${var.prefix}_indexer" package_type = "Image" role = aws_iam_role.indexer.arn image_uri = var.lambda_docker_info.uri image_config { command = [var.lambda_docker_info.commands.indexer] } timeout = 300 memory_size = 512 environment { variables = { THREAT_EXCHANGE_DATA_BUCKET_NAME = var.threat_exchange_data.bucket_name THREAT_EXCHANGE_DATA_FOLDER = var.threat_exchange_data.data_folder INDEXES_BUCKET_NAME = var.index_data_storage.bucket_name MEASURE_PERFORMANCE = var.measure_performance ? "True" : "False" HMA_CONFIG_TABLE = var.config_table.name BANKS_TABLE = var.banks_datastore.name } } tags = merge( var.additional_tags, { Name = "IndexerFunction" } ) } resource "aws_lambda_permission" "allow_cloudwatch" { statement_id = "${var.prefix}AllowExecutionFromCloudWatch" action = "lambda:InvokeFunction" function_name = aws_lambda_function.indexer.function_name principal = "events.amazonaws.com" source_arn = aws_cloudwatch_event_rule.indexing_trigger.arn } resource "aws_cloudwatch_log_group" "indexer" { name = "/aws/lambda/${aws_lambda_function.indexer.function_name}" retention_in_days = var.log_retention_in_days tags = merge( var.additional_tags, { Name = "IndexerLambdaLogGroup" } ) } resource "aws_iam_role" "indexer" { name_prefix = "${var.prefix}_indexer" assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json tags = merge( var.additional_tags, { Name = "IndexerLambdaRole" } ) } data "aws_iam_policy_document" "indexer" { statement { effect = "Allow" actions = [ "s3:GetObject", ] resources = [ "arn:aws:s3:::${var.threat_exchange_data.bucket_name}/${var.threat_exchange_data.data_folder}*", ] } statement { effect = "Allow" actions = [ "s3:ListBucket" ] resources = [ "arn:aws:s3:::${var.threat_exchange_data.bucket_name}", ] } statement { effect = "Allow" actions = ["s3:PutObject"] resources = ["arn:aws:s3:::${var.index_data_storage.bucket_name}/index/*"] } statement { effect = "Allow" actions = ["dynamodb:GetItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:PutItem", "dynamodb:UpdateItem"] resources = ["${var.banks_datastore.arn}*"] } statement { effect = "Allow" actions = [ "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ] resources = ["${aws_cloudwatch_log_group.indexer.arn}:*"] } statement { effect = "Allow" actions = ["cloudwatch:PutMetricData"] resources = ["*"] } } resource "aws_iam_policy" "indexer" { name_prefix = "${var.prefix}_indexer_role_policy" description = "Permissions for Indexer Lambda" policy = data.aws_iam_policy_document.indexer.json } resource "aws_iam_role_policy_attachment" "indexer" { role = aws_iam_role.indexer.name policy_arn = aws_iam_policy.indexer.arn } resource "null_resource" "provide_sample_pdq_data_holidays" { # To force-update on existing deployment, taint and apply terraform again # $ terraform taint module.indexer.null_resource.provide_sample_pdq_data_holidays # $ terraform apply # To get a sensible privacy group value, we reverse engineer the filename split at # hmalib.common.s3_adapters.ThreatExchangeS3Adapter._parse_file at line 118 depends_on = [ aws_lambda_function.indexer ] provisioner "local-exec" { environment = { PRIVACY_GROUP = "inria-holidays-test" } command = "aws s3 cp ../sample_data/holidays-jpg1-pdq-hashes.csv s3://${var.threat_exchange_data.bucket_name}/${var.threat_exchange_data.data_folder}$PRIVACY_GROUP.hash_pdq.te" } }