1+ # Define the directory containing the Docker image and calculate its SHA-256 hash for triggering redeployments
12locals {
2- lambda_dir = abspath (" ${ path . root } /../backend" )
3- source_path = local. lambda_dir
4- path_include = [" **" ]
5- path_exclude = [" **/__pycache__/**" ]
6- files_include = setunion ([for f in local . path_include : fileset (local. source_path , f)]... )
7- files_exclude = setunion ([for f in local . path_exclude : fileset (local. source_path , f)]... )
8- files = sort (setsubtract (local. files_include , local. files_exclude ))
9-
10- dir_sha = sha1 (join (" " , [for f in local . files : filesha1 (" ${ local . source_path } /${ f } " )]))
3+ shared_dir = abspath (" ${ path . root } /../shared" )
4+ id_sync_lambda_dir = abspath (" ${ path . root } /../id_sync" )
5+
6+ # Get files from both directories
7+ shared_files = fileset (local. shared_dir , " **" )
8+ id_sync_lambda_files = fileset (local. id_sync_lambda_dir , " **" )
9+
10+ # Calculate SHA for both directories
11+ shared_dir_sha = sha1 (join (" " , [for f in local . shared_files : filesha1 (" ${ local . shared_dir } /${ f } " )]))
12+ id_sync_lambda_dir_sha = sha1 (join (" " , [for f in local . id_sync_lambda_files : filesha1 (" ${ local . id_sync_lambda_dir } /${ f } " )]))
13+
1114}
1215
13- resource "aws_ecr_repository" "operation_lambda_repository " {
16+ resource "aws_ecr_repository" "id_sync_lambda_repository " {
1417 image_scanning_configuration {
1518 scan_on_push = true
1619 }
17- name = " ${ local . prefix } -operation-lambda -repo"
20+ name = " ${ local . short_prefix } -id-sync -repo"
1821 force_delete = local. is_temp
1922}
2023
21- # resource "docker_image" "lambda_function_docker" {
22- module "docker_image " {
23- source = " terraform-aws-modules/lambda/aws//modules/docker-build"
24- version = " 8.0.1"
25-
24+ # Module for building and pushing Docker image to ECR
25+ module "id_sync_docker_image " {
26+ source = " terraform-aws-modules/lambda/aws//modules/docker-build"
27+ version = " 8.0.1"
28+ docker_file_path = " ./id_sync/Dockerfile "
2629 create_ecr_repo = false
27- ecr_repo = " ${ local . prefix } -operation-lambda-repo"
28- docker_file_path = " lambda.Dockerfile"
30+ ecr_repo = aws_ecr_repository. id_sync_lambda_repository . name
2931 ecr_repo_lifecycle_policy = jsonencode ({
3032 " rules" : [
3133 {
@@ -45,46 +47,278 @@ module "docker_image" {
4547
4648 platform = " linux/amd64"
4749 use_image_tag = false
48- source_path = local . lambda_dir
50+ source_path = abspath ( " ${ path . root } /.. " )
4951 triggers = {
50- dir_sha = local.dir_sha
52+ dir_sha = local.id_sync_lambda_dir_sha
5153 }
5254}
5355
5456# Define the lambdaECRImageRetreival policy
55- resource "aws_ecr_repository_policy" "operation_lambda_ECRImageRetreival_policy " {
56- repository = aws_ecr_repository. operation_lambda_repository . name
57+ resource "aws_ecr_repository_policy" "id_sync_lambda_ECRImageRetreival_policy " {
58+ repository = aws_ecr_repository. id_sync_lambda_repository . name
5759
5860 policy = jsonencode ({
5961 Version = " 2012-10-17"
6062 Statement = [
6163 {
62- " Sid" : " LambdaECRImageRetrievalPolicy" ,
63- " Effect" : " Allow" ,
64- " Principal" : {
65- " Service" : " lambda.amazonaws.com"
64+ Sid : " LambdaECRImageRetrievalPolicy" ,
65+ Effect : " Allow" ,
66+ Principal : {
67+ Service : " lambda.amazonaws.com"
6668 },
67- " Action" : [
69+ Action : [
6870 " ecr:BatchGetImage" ,
6971 " ecr:DeleteRepositoryPolicy" ,
7072 " ecr:GetDownloadUrlForLayer" ,
7173 " ecr:GetRepositoryPolicy" ,
7274 " ecr:SetRepositoryPolicy"
7375 ],
74- " Condition" : {
75- " StringLike" : {
76- " aws:sourceArn" : [
77- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _get_status" ,
78- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _not_found" ,
79- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _search_imms" ,
80- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _get_imms" ,
81- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _delete_imms" ,
82- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _create_imms" ,
83- " arn:aws:lambda:eu-west-2:${ var . immunisation_account_id } :function:${ local . short_prefix } _update_imms"
84- ]
76+ Condition : {
77+ StringLike : {
78+ " aws:sourceArn" : aws_lambda_function.id_sync_lambda.arn
8579 }
8680 }
8781 }
8882 ]
8983 })
9084}
85+
86+ # IAM Role for Lambda
87+ resource "aws_iam_role" "id_sync_lambda_exec_role" {
88+ name = " ${ local . short_prefix } -id-sync-lambda-exec-role"
89+ assume_role_policy = jsonencode ({
90+ Version = " 2012-10-17" ,
91+ Statement = [{
92+ Effect = " Allow" ,
93+ Sid = " " ,
94+ Principal = {
95+ Service = " lambda.amazonaws.com"
96+ },
97+ Action = " sts:AssumeRole"
98+ }]
99+ })
100+ }
101+
102+ # Policy for Lambda execution role
103+ resource "aws_iam_policy" "id_sync_lambda_exec_policy" {
104+ name = " ${ local . short_prefix } -id-sync-lambda-exec-policy"
105+ policy = jsonencode ({
106+ Version = " 2012-10-17" ,
107+ Statement = [
108+ {
109+ Effect = " Allow"
110+ Action = [
111+ " logs:CreateLogGroup" ,
112+ " logs:CreateLogStream" ,
113+ " logs:PutLogEvents"
114+ ]
115+ Resource = " arn:aws:logs:${ var . aws_region } :${ var . immunisation_account_id } :log-group:/aws/lambda/${ local . short_prefix } -id_sync_lambda:*"
116+ },
117+ {
118+ Effect = " Allow"
119+ Action = [
120+ " s3:GetObject" ,
121+ " s3:ListBucket" ,
122+ " s3:PutObject" ,
123+ " s3:CopyObject" ,
124+ " s3:DeleteObject"
125+ ]
126+ Resource = [
127+ aws_s3_bucket.batch_data_source_bucket.arn,
128+ " ${ aws_s3_bucket . batch_data_source_bucket . arn } /*"
129+ ]
130+ },
131+ {
132+ Effect = " Allow"
133+ Action = [
134+ " s3:GetObject" ,
135+ " s3:PutObject" ,
136+ " s3:ListBucket"
137+ ]
138+ Resource = [
139+ aws_s3_bucket.batch_data_destination_bucket.arn,
140+ " ${ aws_s3_bucket . batch_data_destination_bucket . arn } /*"
141+ ]
142+ },
143+ {
144+ Effect = " Allow" ,
145+ Action = [
146+ " ec2:CreateNetworkInterface" ,
147+ " ec2:DescribeNetworkInterfaces" ,
148+ " ec2:DeleteNetworkInterface"
149+ ],
150+ Resource = " *"
151+ },
152+ {
153+ Effect = " Allow"
154+ Action = [
155+ " s3:GetObject" ,
156+ " s3:PutObject" ,
157+ " s3:ListBucket"
158+ ]
159+ Resource = [
160+ local.config_bucket_arn,
161+ " ${ local . config_bucket_arn } /*"
162+ ]
163+ },
164+ {
165+ Effect = " Allow" ,
166+ Action = [
167+ " firehose:PutRecord" ,
168+ " firehose:PutRecordBatch"
169+ ],
170+ Resource = " arn:aws:firehose:*:*:deliverystream/${ module . splunk . firehose_stream_name } "
171+ },
172+ {
173+ Effect = " Allow"
174+ Action = " lambda:InvokeFunction"
175+ Resource = [
176+ " arn:aws:lambda:${ var . aws_region } :${ var . immunisation_account_id } :function:imms-${ var . sub_environment } -id_sync_lambda" ,
177+ ]
178+ },
179+ # NEW
180+ # NB anomaly: do we want this in "id_sync_lambda_sqs_access_policy"?
181+ {
182+ Effect = " Allow" ,
183+ Action = [
184+ " sqs:ReceiveMessage" ,
185+ " sqs:DeleteMessage" ,
186+ " sqs:GetQueueAttributes"
187+ ],
188+ Resource = " arn:aws:sqs:eu-west-2:${ var . immunisation_account_id } :${ local . short_prefix } -id-sync-queue"
189+ },
190+ # NB anomaly: in redis_sync this appears in "redis_sync_lambda_kms_access_policy"
191+ {
192+ Effect = " Allow" ,
193+ Action = [
194+ " kms:Decrypt" ,
195+ " kms:GenerateDataKey"
196+ ],
197+ Resource = data.aws_kms_key.existing_id_sync_sqs_encryption_key.arn
198+ }
199+ ]
200+ })
201+ }
202+
203+ resource "aws_iam_policy" "id_sync_lambda_kms_access_policy" {
204+ name = " ${ local . short_prefix } -id-sync-lambda-kms-policy"
205+ description = " Allow Lambda to decrypt environment variables"
206+
207+ policy = jsonencode ({
208+ Version = " 2012-10-17"
209+ Statement = [
210+ {
211+ Effect = " Allow"
212+ Action = [
213+ " kms:Decrypt"
214+ ]
215+ Resource = data.aws_kms_key.existing_lambda_encryption_key.arn
216+ },
217+ {
218+ Effect = " Allow"
219+ Action = [
220+ " kms:Encrypt" ,
221+ " kms:Decrypt" ,
222+ " kms:GenerateDataKey*"
223+ ]
224+ Resource = [
225+ data.aws_kms_key.existing_s3_encryption_key.arn,
226+ ]
227+ }
228+ ]
229+ })
230+ }
231+
232+ # Attach the execution policy to the Lambda role
233+ resource "aws_iam_role_policy_attachment" "id_sync_lambda_exec_policy_attachment" {
234+ role = aws_iam_role. id_sync_lambda_exec_role . name
235+ policy_arn = aws_iam_policy. id_sync_lambda_exec_policy . arn
236+ }
237+
238+ # Attach the kms policy to the Lambda role
239+ resource "aws_iam_role_policy_attachment" "id_sync_lambda_kms_policy_attachment" {
240+ role = aws_iam_role. id_sync_lambda_exec_role . name
241+ policy_arn = aws_iam_policy. id_sync_lambda_kms_access_policy . arn
242+ }
243+
244+ data "aws_iam_policy_document" "id_sync_policy_document" {
245+ source_policy_documents = [
246+ templatefile (" ${ local . policy_path } /dynamodb.json" , {
247+ " dynamodb_table_name" : aws_dynamodb_table.delta- dynamodb- table.name
248+ }),
249+ templatefile (" ${ local . policy_path } /dynamodb_stream.json" , {
250+ " dynamodb_table_name" : aws_dynamodb_table.events- dynamodb- table.name
251+ }),
252+ templatefile (" ${ local . policy_path } /secret_manager.json" , {
253+ " account_id" : data.aws_caller_identity.current.account_id,
254+ " pds_environment" : var.pds_environment
255+ })
256+ ]
257+ }
258+
259+ resource "aws_iam_policy" "id_sync_lambda_dynamodb_access_policy" {
260+ name = " ${ local . short_prefix } -id-sync-lambda-dynamodb-access-policy"
261+ description = " Allow Lambda to access DynamoDB"
262+ policy = data. aws_iam_policy_document . id_sync_policy_document . json
263+ }
264+
265+ # Attach the dynamodb policy to the Lambda role
266+ resource "aws_iam_role_policy_attachment" "id_sync_lambda_dynamodb_policy_attachment" {
267+ role = aws_iam_role. id_sync_lambda_exec_role . name
268+ policy_arn = aws_iam_policy. id_sync_lambda_dynamodb_access_policy . arn
269+ }
270+
271+ # Lambda Function with Security Group and VPC.
272+ resource "aws_lambda_function" "id_sync_lambda" {
273+ function_name = " ${ local . short_prefix } -id_sync_lambda"
274+ role = aws_iam_role. id_sync_lambda_exec_role . arn
275+ package_type = " Image"
276+ image_uri = module. id_sync_docker_image . image_uri
277+ architectures = [" x86_64" ]
278+ timeout = 360
279+
280+ vpc_config {
281+ subnet_ids = local. private_subnet_ids
282+ security_group_ids = [data . aws_security_group . existing_securitygroup . id ]
283+ }
284+
285+ environment {
286+ variables = {
287+ CONFIG_BUCKET_NAME = local.config_bucket_name
288+ REDIS_HOST = data.aws_elasticache_cluster.existing_redis.cache_nodes[0 ].address
289+ REDIS_PORT = data.aws_elasticache_cluster.existing_redis.cache_nodes[0 ].port
290+ ID_SYNC_PROC_LAMBDA_NAME = " imms-${ var . sub_environment } -id_sync_lambda"
291+ # NEW
292+ DELTA_TABLE_NAME = aws_dynamodb_table.delta- dynamodb- table.name
293+ IEDS_TABLE_NAME = aws_dynamodb_table.events- dynamodb- table.name
294+ PDS_ENV = var.pds_environment
295+ SPLUNK_FIREHOSE_NAME = module.splunk.firehose_stream_name
296+ }
297+ }
298+ kms_key_arn = data. aws_kms_key . existing_lambda_encryption_key . arn
299+
300+ depends_on = [
301+ aws_cloudwatch_log_group . id_sync_log_group ,
302+ aws_iam_policy . id_sync_lambda_exec_policy
303+ ]
304+ }
305+
306+ resource "aws_cloudwatch_log_group" "id_sync_log_group" {
307+ name = " /aws/lambda/${ local . short_prefix } -id_sync_lambda"
308+ retention_in_days = 30
309+ }
310+
311+ # delete config_lambda_notification / new_s3_invoke_permission - not required; duplicate
312+
313+ # NEW
314+ resource "aws_lambda_event_source_mapping" "id_sync_sqs_trigger" {
315+ event_source_arn = " arn:aws:sqs:eu-west-2:${ var . immunisation_account_id } :${ local . short_prefix } -id-sync-queue"
316+ function_name = aws_lambda_function. id_sync_lambda . arn # TODO
317+
318+ # Optional: Configure batch size and other settings
319+ batch_size = 10
320+ maximum_batching_window_in_seconds = 5
321+
322+ # Optional: Configure error handling
323+ function_response_types = [" ReportBatchItemFailures" ]
324+ }
0 commit comments