1+ # Define the directory containing the Docker image and calculate its SHA-256 hash for triggering redeployments
2+ locals {
3+ redis_sync_lambda_dir = abspath (" ${ path . root } /../redis_sync" )
4+ redis_sync_lambda_files = fileset (local. redis_sync_lambda_dir , " **" )
5+ redis_sync_lambda_dir_sha = sha1 (join (" " , [for f in local . redis_sync_lambda_files : filesha1 (" ${ local . redis_sync_lambda_dir } /${ f } " )]))
6+ }
7+
8+ resource "aws_ecr_repository" "redis_sync_lambda_repository" {
9+ image_scanning_configuration {
10+ scan_on_push = true
11+ }
12+ name = " ${ local . short_prefix } -redis-sync-repo"
13+ force_delete = local. is_temp
14+ }
15+
16+ # Module for building and pushing Docker image to ECR
17+ module "redis_sync_docker_image" {
18+ source = " terraform-aws-modules/lambda/aws//modules/docker-build"
19+ version = " 8.0.1"
20+
21+ create_ecr_repo = false
22+ ecr_repo = aws_ecr_repository. redis_sync_lambda_repository . name
23+ ecr_repo_lifecycle_policy = jsonencode ({
24+ " rules" : [
25+ {
26+ " rulePriority" : 1 ,
27+ " description" : " Keep only the last 2 images" ,
28+ " selection" : {
29+ " tagStatus" : " any" ,
30+ " countType" : " imageCountMoreThan" ,
31+ " countNumber" : 2
32+ },
33+ " action" : {
34+ " type" : " expire"
35+ }
36+ }
37+ ]
38+ })
39+
40+ platform = " linux/amd64"
41+ use_image_tag = false
42+ source_path = local. redis_sync_lambda_dir
43+ triggers = {
44+ dir_sha = local.redis_sync_lambda_dir_sha
45+ }
46+ }
47+
48+ # Define the lambdaECRImageRetreival policy
49+ resource "aws_ecr_repository_policy" "redis_sync_lambda_ECRImageRetreival_policy" {
50+ repository = aws_ecr_repository. redis_sync_lambda_repository . name
51+
52+ policy = jsonencode ({
53+ Version = " 2012-10-17"
54+ Statement = [
55+ {
56+ Sid : " LambdaECRImageRetrievalPolicy" ,
57+ Effect : " Allow" ,
58+ Principal : {
59+ Service : " lambda.amazonaws.com"
60+ },
61+ Action : [
62+ " ecr:BatchGetImage" ,
63+ " ecr:DeleteRepositoryPolicy" ,
64+ " ecr:GetDownloadUrlForLayer" ,
65+ " ecr:GetRepositoryPolicy" ,
66+ " ecr:SetRepositoryPolicy"
67+ ],
68+ Condition : {
69+ StringLike : {
70+ " aws:sourceArn" : aws_lambda_function.redis_sync_lambda.arn
71+ }
72+ }
73+ }
74+ ]
75+ })
76+ }
77+
78+ # IAM Role for Lambda
79+ resource "aws_iam_role" "redis_sync_lambda_exec_role" {
80+ name = " ${ local . short_prefix } -redis-sync-lambda-exec-role"
81+ assume_role_policy = jsonencode ({
82+ Version = " 2012-10-17" ,
83+ Statement = [{
84+ Effect = " Allow" ,
85+ Sid = " " ,
86+ Principal = {
87+ Service = " lambda.amazonaws.com"
88+ },
89+ Action = " sts:AssumeRole"
90+ }]
91+ })
92+ }
93+
94+ # Policy for Lambda execution role
95+ resource "aws_iam_policy" "redis_sync_lambda_exec_policy" {
96+ name = " ${ local . short_prefix } -redis-sync-lambda-exec-policy"
97+ policy = jsonencode ({
98+ Version = " 2012-10-17" ,
99+ Statement = [
100+ {
101+ Effect = " Allow"
102+ Action = [
103+ " logs:CreateLogGroup" ,
104+ " logs:CreateLogStream" ,
105+ " logs:PutLogEvents"
106+ ]
107+ Resource = " arn:aws:logs:${ var . aws_region } :${ var . immunisation_account_id } :log-group:/aws/lambda/${ local . short_prefix } -redis_sync_lambda:*"
108+ },
109+ {
110+ Effect = " Allow"
111+ Action = [
112+ " s3:GetObject" ,
113+ " s3:ListBucket" ,
114+ " s3:PutObject" ,
115+ " s3:CopyObject" ,
116+ " s3:DeleteObject"
117+ ]
118+ Resource = [
119+ aws_s3_bucket.batch_data_source_bucket.arn,
120+ " ${ aws_s3_bucket . batch_data_source_bucket . arn } /*"
121+ ]
122+ },
123+ {
124+ Effect = " Allow"
125+ Action = [
126+ " s3:GetObject" ,
127+ " s3:PutObject" ,
128+ " s3:ListBucket"
129+ ]
130+ Resource = [
131+ aws_s3_bucket.batch_data_destination_bucket.arn,
132+ " ${ aws_s3_bucket . batch_data_destination_bucket . arn } /*"
133+ ]
134+ },
135+ {
136+ Effect = " Allow" ,
137+ Action = [
138+ " ec2:CreateNetworkInterface" ,
139+ " ec2:DescribeNetworkInterfaces" ,
140+ " ec2:DeleteNetworkInterface"
141+ ],
142+ Resource = " *"
143+ },
144+ {
145+ Effect = " Allow"
146+ Action = [
147+ " s3:GetObject" ,
148+ " s3:PutObject" ,
149+ " s3:ListBucket"
150+ ]
151+ Resource = [
152+ local.config_bucket_arn,
153+ " ${ local . config_bucket_arn } /*"
154+ ]
155+ },
156+ {
157+ Effect : " Allow" ,
158+ Action : [
159+ " firehose:PutRecord" ,
160+ " firehose:PutRecordBatch"
161+ ],
162+ Resource : " arn:aws:firehose:*:*:deliverystream/${ module . splunk . firehose_stream_name } "
163+ },
164+ {
165+ Effect = " Allow"
166+ Action = " lambda:InvokeFunction"
167+ Resource = [
168+ " arn:aws:lambda:${ var . aws_region } :${ var . immunisation_account_id } :function:imms-${ var . sub_environment } -redis_sync_lambda" ,
169+ ]
170+ },
171+ # NEW
172+ {
173+ Effect = " Allow" ,
174+ Action = [
175+ " sqs:ReceiveMessage" ,
176+ " sqs:DeleteMessage" ,
177+ " sqs:GetQueueAttributes"
178+ ],
179+ Resource = " arn:aws:sqs:eu-west-2:${ var . immunisation_account_id } :${ local . short_prefix } -id-sync-queue"
180+ },
181+ {
182+ Effect = " Allow" ,
183+ Action = [
184+ " kms:Decrypt" ,
185+ " kms:GenerateDataKey"
186+ ],
187+ Resource = data.aws_kms_key.existing_id_sync_sqs_encryption_key.arn
188+ }
189+ ]
190+ })
191+ }
192+
193+ resource "aws_iam_policy" "redis_sync_lambda_kms_access_policy" {
194+ name = " ${ local . short_prefix } -redis-sync-lambda-kms-policy"
195+ description = " Allow Lambda to decrypt environment variables"
196+
197+ policy = jsonencode ({
198+ Version = " 2012-10-17"
199+ Statement = [
200+ {
201+ Effect = " Allow"
202+ Action = [
203+ " kms:Decrypt"
204+ ]
205+ Resource = data.aws_kms_key.existing_lambda_encryption_key.arn
206+ },
207+ {
208+ Effect = " Allow"
209+ Action = [
210+ " kms:Encrypt" ,
211+ " kms:Decrypt" ,
212+ " kms:GenerateDataKey*"
213+ ]
214+ Resource = [
215+ data.aws_kms_key.existing_s3_encryption_key.arn,
216+ ]
217+ }
218+ ]
219+ })
220+ }
221+
222+ # Attach the execution policy to the Lambda role
223+ resource "aws_iam_role_policy_attachment" "redis_sync_lambda_exec_policy_attachment" {
224+ role = aws_iam_role. redis_sync_lambda_exec_role . name
225+ policy_arn = aws_iam_policy. redis_sync_lambda_exec_policy . arn
226+ }
227+
228+ # Attach the kms policy to the Lambda role
229+ resource "aws_iam_role_policy_attachment" "redis_sync_lambda_kms_policy_attachment" {
230+ role = aws_iam_role. redis_sync_lambda_exec_role . name
231+ policy_arn = aws_iam_policy. redis_sync_lambda_kms_access_policy . arn
232+ }
233+
234+ # Lambda Function with Security Group and VPC.
235+ resource "aws_lambda_function" "redis_sync_lambda" {
236+ function_name = " ${ local . short_prefix } -redis_sync_lambda"
237+ role = aws_iam_role. redis_sync_lambda_exec_role . arn
238+ package_type = " Image"
239+ image_uri = module. redis_sync_docker_image . image_uri
240+ architectures = [" x86_64" ]
241+ timeout = 360
242+
243+ vpc_config {
244+ subnet_ids = local. private_subnet_ids
245+ security_group_ids = [data . aws_security_group . existing_securitygroup . id ]
246+ }
247+
248+ environment {
249+ variables = {
250+ CONFIG_BUCKET_NAME = local.config_bucket_name
251+ REDIS_HOST = data.aws_elasticache_cluster.existing_redis.cache_nodes[0 ].address
252+ REDIS_PORT = data.aws_elasticache_cluster.existing_redis.cache_nodes[0 ].port
253+ REDIS_SYNC_PROC_LAMBDA_NAME = " imms-${ var . sub_environment } -redis_sync_lambda"
254+ # NEW
255+ DELTA_TABLE_NAME = aws_dynamodb_table.delta- dynamodb- table.name
256+ PDS_ENV = var.pds_environment
257+ SPLUNK_FIREHOSE_NAME = module.splunk.firehose_stream_name
258+ }
259+ }
260+ kms_key_arn = data. aws_kms_key . existing_lambda_encryption_key . arn
261+
262+ depends_on = [
263+ aws_cloudwatch_log_group . redis_sync_log_group ,
264+ aws_iam_policy . redis_sync_lambda_exec_policy
265+ ]
266+ }
267+
268+ resource "aws_cloudwatch_log_group" "redis_sync_log_group" {
269+ name = " /aws/lambda/${ local . short_prefix } -redis_sync_lambda"
270+ retention_in_days = 30
271+ }
272+
273+ # S3 Bucket notification to trigger Lambda function for config bucket
274+ resource "aws_s3_bucket_notification" "config_lambda_notification" {
275+
276+ bucket = aws_s3_bucket. batch_config_bucket . bucket
277+
278+ lambda_function {
279+ lambda_function_arn = aws_lambda_function. redis_sync_lambda . arn
280+ events = [" s3:ObjectCreated:*" ]
281+ }
282+ }
283+
284+ # Permission for the new S3 bucket to invoke the Lambda function
285+ resource "aws_lambda_permission" "new_s3_invoke_permission" {
286+
287+ statement_id = " AllowExecutionFromNewS3"
288+ action = " lambda:InvokeFunction"
289+ function_name = aws_lambda_function. redis_sync_lambda . function_name
290+ principal = " s3.amazonaws.com"
291+ source_arn = local. config_bucket_arn
292+ }
293+
294+ # NEW
295+ resource "aws_lambda_event_source_mapping" "id_sync_sqs_trigger" {
296+ event_source_arn = " arn:aws:sqs:eu-west-2:${ local . immunisation_account_id } :${ local . short_prefix } -id-sync-queue"
297+ function_name = aws_lambda_function. redis_sync_lambda . arn # TODO
298+
299+ # Optional: Configure batch size and other settings
300+ batch_size = 10
301+ maximum_batching_window_in_seconds = 5
302+
303+ # Optional: Configure error handling
304+ function_response_types = [" ReportBatchItemFailures" ]
305+ }
0 commit comments