Skip to content

Commit 37c01b6

Browse files
committed
init: terraform/id_sync_lambda.tf
1 parent 0a2cd74 commit 37c01b6

File tree

1 file changed

+309
-0
lines changed

1 file changed

+309
-0
lines changed

terraform/id_sync_lambda.tf

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
# Prototype of id_sync_lambda.tf
2+
3+
# This is a WIP.
4+
# This is an attempt to define the terraform for the new NHS MNS id sync lambda.
5+
# Some resources may be unnecessary.
6+
# The ones we do require for SQS queue and its KMS key are at the bottom of the lambda execution policy.
7+
8+
# Define the directory containing the Docker image and calculate its SHA-256 hash for triggering redeployments
9+
locals {
10+
id_sync_lambda_dir = abspath("${path.root}/../id_sync")
11+
id_sync_lambda_files = fileset(local.id_sync_lambda_dir, "**")
12+
id_sync_lambda_dir_sha = sha1(join("", [for f in local.id_sync_lambda_files : filesha1("${local.id_sync_lambda_dir}/${f}")]))
13+
}
14+
15+
resource "aws_ecr_repository" "id_sync_lambda_repository" {
16+
image_scanning_configuration {
17+
scan_on_push = true
18+
}
19+
name = "${local.short_prefix}-id-sync-repo"
20+
force_delete = local.is_temp
21+
}
22+
23+
# Module for building and pushing Docker image to ECR
24+
module "id_sync_docker_image" {
25+
source = "terraform-aws-modules/lambda/aws//modules/docker-build"
26+
version = "8.0.1"
27+
28+
create_ecr_repo = false
29+
ecr_repo = aws_ecr_repository.id_sync_lambda_repository.name
30+
ecr_repo_lifecycle_policy = jsonencode({
31+
"rules" : [
32+
{
33+
"rulePriority" : 1,
34+
"description" : "Keep only the last 2 images",
35+
"selection" : {
36+
"tagStatus" : "any",
37+
"countType" : "imageCountMoreThan",
38+
"countNumber" : 2
39+
},
40+
"action" : {
41+
"type" : "expire"
42+
}
43+
}
44+
]
45+
})
46+
47+
platform = "linux/amd64"
48+
use_image_tag = false
49+
source_path = local.id_sync_lambda_dir
50+
triggers = {
51+
dir_sha = local.id_sync_lambda_dir_sha
52+
}
53+
}
54+
55+
# Define the lambdaECRImageRetreival policy
56+
resource "aws_ecr_repository_policy" "id_sync_lambda_ECRImageRetreival_policy" {
57+
repository = aws_ecr_repository.id_sync_lambda_repository.name
58+
59+
policy = jsonencode({
60+
Version = "2012-10-17"
61+
Statement = [
62+
{
63+
Sid : "LambdaECRImageRetrievalPolicy",
64+
Effect : "Allow",
65+
Principal : {
66+
Service : "lambda.amazonaws.com"
67+
},
68+
Action : [
69+
"ecr:BatchGetImage",
70+
"ecr:DeleteRepositoryPolicy",
71+
"ecr:GetDownloadUrlForLayer",
72+
"ecr:GetRepositoryPolicy",
73+
"ecr:SetRepositoryPolicy"
74+
],
75+
Condition : {
76+
StringLike : {
77+
# "aws:sourceArn" : "arn:aws:lambda:eu-west-2:${local.immunisation_account_id}:function:${local.short_prefix}-id_sync_lambda"
78+
"aws:sourceArn" : aws_lambda_function.id_sync_lambda.arn
79+
}
80+
}
81+
}
82+
]
83+
})
84+
}
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}:${local.immunisation_account_id}:log-group:/aws/lambda/${local.short_prefix}-id_sync_lambda:*"
116+
},
117+
# ** TODO need to ascertain whether we need these S3 policies. possibly not. we WILL need an SQS policy though.
118+
{
119+
Effect = "Allow"
120+
Action = [
121+
"s3:GetObject",
122+
"s3:ListBucket",
123+
"s3:PutObject",
124+
"s3:CopyObject",
125+
"s3:DeleteObject"
126+
]
127+
Resource = [
128+
aws_s3_bucket.batch_data_source_bucket.arn,
129+
"${aws_s3_bucket.batch_data_source_bucket.arn}/*"
130+
]
131+
},
132+
{
133+
Effect = "Allow"
134+
Action = [
135+
"s3:GetObject",
136+
"s3:PutObject",
137+
"s3:ListBucket"
138+
]
139+
Resource = [
140+
aws_s3_bucket.batch_data_destination_bucket.arn,
141+
"${aws_s3_bucket.batch_data_destination_bucket.arn}/*"
142+
]
143+
},
144+
# ** TODO: do we need these ec2 policies? I think they're to do with VPCs
145+
{
146+
Effect = "Allow",
147+
Action = [
148+
"ec2:CreateNetworkInterface",
149+
"ec2:DescribeNetworkInterfaces",
150+
"ec2:DeleteNetworkInterface"
151+
],
152+
Resource = "*"
153+
},
154+
# ** TODO: ditto. The bucket is imms-${local.environment}-fhir-config
155+
# Examine it.
156+
{
157+
Effect = "Allow"
158+
Action = [
159+
"s3:GetObject",
160+
"s3:PutObject",
161+
"s3:ListBucket"
162+
]
163+
Resource = [
164+
local.config_bucket_arn,
165+
"${local.config_bucket_arn}/*"
166+
]
167+
},
168+
{
169+
Effect : "Allow",
170+
Action : [
171+
"firehose:PutRecord",
172+
"firehose:PutRecordBatch"
173+
],
174+
Resource : "arn:aws:firehose:*:*:deliverystream/${module.splunk.firehose_stream_name}"
175+
},
176+
{
177+
Effect = "Allow"
178+
Action = "lambda:InvokeFunction"
179+
Resource = [
180+
"arn:aws:lambda:${var.aws_region}:${local.immunisation_account_id}:function:imms-${local.env}-id_sync_lambda",
181+
]
182+
},
183+
# New: required for SQS queue and its KMS key
184+
185+
# Notes:
186+
# - the SQS queue is defined in terraform/sqs_id_sync.tf in branch VED-80-id-sync-sqs
187+
# - the KMS key in terraform/temp_id_sync_sqs_kms.tf in the same branch; this will eventually be replaced by
188+
# the version of infra/kms.tf in branch VED-80-id-sync-sqs-infra
189+
190+
{
191+
Effect = "Allow",
192+
Action = [
193+
"sqs:ReceiveMessage",
194+
"sqs:DeleteMessage",
195+
"sqs:GetQueueAttributes"
196+
],
197+
Resource = "arn:aws:sqs:eu-west-2:${local.immunisation_account_id}:${local.short_prefix}-id-sync-queue"
198+
}
199+
{
200+
Effect = "Allow",
201+
Action = [
202+
"kms:Decrypt",
203+
"kms:GenerateDataKey"
204+
],
205+
Resource = data.aws_kms_key.existing_id_sync_encryption_key.arn
206+
}
207+
]
208+
})
209+
}
210+
211+
resource "aws_iam_policy" "id_sync_lambda_kms_access_policy" {
212+
name = "${local.short_prefix}-id-sync-lambda-kms-policy"
213+
description = "Allow Lambda to decrypt environment variables"
214+
215+
policy = jsonencode({
216+
Version = "2012-10-17"
217+
Statement = [
218+
{
219+
Effect = "Allow"
220+
Action = [
221+
"kms:Decrypt"
222+
]
223+
Resource = data.aws_kms_key.existing_lambda_encryption_key.arn
224+
},
225+
{
226+
Effect = "Allow"
227+
Action = [
228+
"kms:Encrypt",
229+
"kms:Decrypt",
230+
"kms:GenerateDataKey*"
231+
]
232+
Resource = [
233+
data.aws_kms_key.existing_s3_encryption_key.arn,
234+
]
235+
}
236+
]
237+
})
238+
}
239+
240+
# Attach the execution policy to the Lambda role
241+
resource "aws_iam_role_policy_attachment" "id_sync_lambda_exec_policy_attachment" {
242+
role = aws_iam_role.id_sync_lambda_exec_role.name
243+
policy_arn = aws_iam_policy.id_sync_lambda_exec_policy.arn
244+
}
245+
246+
# Attach the kms policy to the Lambda role
247+
resource "aws_iam_role_policy_attachment" "id_sync_lambda_kms_policy_attachment" {
248+
role = aws_iam_role.id_sync_lambda_exec_role.name
249+
policy_arn = aws_iam_policy.id_sync_lambda_kms_access_policy.arn
250+
}
251+
252+
# Lambda Function with Security Group and VPC.
253+
resource "aws_lambda_function" "id_sync_lambda" {
254+
function_name = "${local.short_prefix}-id_sync_lambda"
255+
role = aws_iam_role.id_sync_lambda_exec_role.arn
256+
package_type = "Image"
257+
image_uri = module.id_sync_docker_image.image_uri
258+
architectures = ["x86_64"]
259+
timeout = 360
260+
261+
vpc_config {
262+
subnet_ids = local.private_subnet_ids
263+
security_group_ids = [data.aws_security_group.existing_securitygroup.id]
264+
}
265+
266+
# ** TODO: we're likely to not need any of the REDIS_ variables
267+
environment {
268+
variables = {
269+
CONFIG_BUCKET_NAME = local.config_bucket_name
270+
REDIS_HOST = data.aws_elasticache_cluster.existing_redis.cache_nodes[0].address
271+
REDIS_PORT = data.aws_elasticache_cluster.existing_redis.cache_nodes[0].port
272+
ID_SYNC_PROC_LAMBDA_NAME = "imms-${local.env}-id_sync_lambda"
273+
SPLUNK_FIREHOSE_NAME = module.splunk.firehose_stream_name
274+
}
275+
}
276+
kms_key_arn = data.aws_kms_key.existing_lambda_encryption_key.arn
277+
278+
depends_on = [
279+
aws_cloudwatch_log_group.id_sync_log_group,
280+
aws_iam_policy.id_sync_lambda_exec_policy
281+
]
282+
}
283+
284+
resource "aws_cloudwatch_log_group" "id_sync_log_group" {
285+
name = "/aws/lambda/${local.short_prefix}-id_sync_lambda"
286+
retention_in_days = 30
287+
}
288+
289+
290+
# S3 Bucket notification to trigger Lambda function for config bucket
291+
resource "aws_s3_bucket_notification" "config_lambda_notification" {
292+
293+
bucket = aws_s3_bucket.batch_config_bucket.bucket
294+
295+
lambda_function {
296+
lambda_function_arn = aws_lambda_function.id_sync_lambda.arn
297+
events = ["s3:ObjectCreated:*"]
298+
}
299+
}
300+
301+
# Permission for the new S3 bucket to invoke the Lambda function
302+
resource "aws_lambda_permission" "new_s3_invoke_permission" {
303+
304+
statement_id = "AllowExecutionFromNewS3"
305+
action = "lambda:InvokeFunction"
306+
function_name = aws_lambda_function.id_sync_lambda.function_name
307+
principal = "s3.amazonaws.com"
308+
source_arn = local.config_bucket_arn
309+
}

0 commit comments

Comments
 (0)