Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UML-3738: eventbridge & lambda permissions #3014

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/pull-request-path.yml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ jobs:
- update_documentation
- docker_build_scan_push
- run_behat_suite
- terraform_preproduction_plan_environment
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -332,7 +333,7 @@ jobs:

- name: workflow has ended without issue
run: |
if ${{ contains(needs.run_behat_suite.result, 'success') && contains(needs.ecr_scan_results.result, 'success') }}; then
if ${{ contains(needs.run_behat_suite.result, 'success') && contains(needs.ecr_scan_results.result, 'success') && contains(needs.terraform_preproduction_plan_environment.result, 'success') }}; then
echo "${{ needs.workflow_variables.outputs.safe_branch_name }} PR environment tested, built and deployed"
echo "Tag Used: ${{ needs.workflow_variables.outputs.safe_branch_name }}-${{ needs.workflow_variables.outputs.short_sha }}"
echo "URL: https://${{ needs.workflow_variables.outputs.workspace_name }}.use-lasting-power-of-attorney.service.gov.uk"
Expand Down
23 changes: 18 additions & 5 deletions lambda-functions/event-receiver/app/main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
package main

import (
"context"
"fmt"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)

func Handler(ctx context.Context) (string, error) {
fmt.Println("Hello World")
return "Hello World!", nil
func handler(event events.SQSEvent) error {
for _, record := range event.Records {
err := processMessage(record)
if err != nil {
return err
}
}
fmt.Println("done")
return nil
}

func processMessage(record events.SQSMessage) error {
fmt.Printf("Processed message %s\n", record.Body)
fmt.Printf("Hello, world!\n")
return nil
}

func main() {
lambda.Start(Handler)
lambda.Start(handler)
fmt.Printf("Hello, world!\n")
}
46 changes: 45 additions & 1 deletion terraform/environment/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module "lambda_update_statistics" {
memory = 1024
}


# Additional IAM permissions
resource "aws_iam_role_policy" "lambda_update_statistics" {
name = "lambda-update-statistics-${local.environment_name}"
Expand Down Expand Up @@ -96,9 +97,52 @@ module "event_receiver" {
REGION = data.aws_region.current.name
}
image_uri = "${data.aws_ecr_repository.use_an_lpa_event_receiver.repository_url}:${var.container_version}"
ecr_arn = data.aws_ecr_repository.use_an_lpa_upload_statistics.arn
ecr_arn = data.aws_ecr_repository.use_an_lpa_event_receiver.arn
environment = local.environment_name
kms_key = data.aws_kms_alias.cloudwatch_encryption.target_key_arn
timeout = 900
memory = 128
}

resource "aws_iam_role_policy" "lambda_event_receiver" {
name = "${local.environment_name}-lambda-event-receiver"
role = module.event_receiver.lambda_role.name
policy = data.aws_iam_policy_document.lambda_event_receiver.json
}


data "aws_iam_policy_document" "lambda_event_receiver" {
statement {
sid = "${local.environment_name}EventReceiverSQS"
effect = "Allow"
actions = [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
]
resources = [module.eu_west_1[0].receive_events_sqs_queue_arn[0]]
}

statement {
sid = "${local.environment_name}SQSKMSDecrypt"
effect = "Allow"
actions = [
"kms:Decrypt"
]
resources = [data.aws_kms_alias.sqs.arn]
}
}

resource "aws_lambda_event_source_mapping" "receive_events_mapping" {
event_source_arn = module.eu_west_1[0].receive_events_sqs_queue_arn[0]
function_name = module.event_receiver.lambda_name
enabled = true
}

resource "aws_lambda_permission" "receive_events_permission" {
statement_id = "AllowExecutionFromSQS"
action = "lambda:InvokeFunction"
function_name = module.event_receiver.lambda_name
principal = "sqs.amazonaws.com"
source_arn = module.eu_west_1[0].receive_events_sqs_queue_arn[0]
}
5 changes: 5 additions & 0 deletions terraform/environment/modules/lambda/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ output "lambda_role" {
description = "The lambda role"
value = aws_iam_role.lambda_role
}

output "lambda_name" {
description = "The lambda name"
value = aws_lambda_function.lambda_function.function_name
}
2 changes: 2 additions & 0 deletions terraform/environment/region.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module "eu_west_1" {
lpa_codes_endpoint = local.environment.lpa_codes_endpoint
lpas_collection_endpoint = local.environment.lpas_collection_endpoint
lpa_data_store_endpoint = local.environment.lpa_data_store_endpoint
receive_account_ids = local.environment.receive_account_ids
mock_onelogin_enabled = local.environment.mock_onelogin_enabled
mock_onelogin_service_container_version = local.mock_onelogin_version
mock_onelogin_service_repository_url = data.aws_ecr_repository.mock_onelogin.repository_url
Expand Down Expand Up @@ -120,6 +121,7 @@ module "eu_west_2" {
lpa_codes_endpoint = local.environment.lpa_codes_endpoint
lpas_collection_endpoint = local.environment.lpas_collection_endpoint
lpa_data_store_endpoint = local.environment.lpa_data_store_endpoint
receive_account_ids = local.environment.receive_account_ids
mock_onelogin_enabled = local.environment.mock_onelogin_enabled
mock_onelogin_service_container_version = local.mock_onelogin_version
mock_onelogin_service_repository_url = data.aws_ecr_repository.mock_onelogin.repository_url
Expand Down
10 changes: 6 additions & 4 deletions terraform/environment/region/event_bus.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
module "event_bus" {
source = "./modules/event_bus"
environment_name = var.environment_name
event_bus_enabled = var.event_bus_enabled
current_region = data.aws_region.current.name
source = "./modules/event_bus"
environment_name = var.environment_name
event_bus_enabled = var.event_bus_enabled
current_region = data.aws_region.current.name
receive_account_ids = var.receive_account_ids
queue_visibility_timeout = local.queue_visibility_timeout
providers = {
aws.region = aws.region
}
Expand Down
2 changes: 2 additions & 0 deletions terraform/environment/region/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ locals {
admin_desired_count = local.is_active_region ? 1 : 0
mock_onelogin_desired_count = var.environment_name != "production" && var.mock_onelogin_enabled && local.is_active_region ? 1 : 0

queue_visibility_timeout = 900

# Replace the region in the ARN of the DynamoDB tables with the region of the current stack as the tables are created in the primary region
# and replicated to the secondary region. This allows use to grant access to the tables in the secondary region for applications running in the secondary region.
dynamodb_tables_arns = {
Expand Down
66 changes: 66 additions & 0 deletions terraform/environment/region/modules/event_bus/bus.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
resource "aws_cloudwatch_event_bus" "main" {
count = var.event_bus_enabled ? 1 : 0
name = var.environment_name
provider = aws.region
}

resource "aws_cloudwatch_event_archive" "main" {
count = var.event_bus_enabled ? 1 : 0
name = var.environment_name
event_source_arn = aws_cloudwatch_event_bus.main[0].arn
provider = aws.region
}


resource "aws_cloudwatch_event_rule" "receive_events_from_mlpa" {
count = var.event_bus_enabled ? 1 : 0
name = "${var.environment_name}-mlpa-events-to-use"
description = "Receive events from mlpa"
event_bus_name = aws_cloudwatch_event_bus.main[0].name

event_pattern = jsonencode({
source = ["opg.poas.makeregister"],
detail-type = ["lpa-access-granted"]
})

provider = aws.region
}

resource "aws_cloudwatch_event_bus_policy" "cross_account_receive" {
count = length(var.receive_account_ids) > 0 && var.event_bus_enabled ? 1 : 0
event_bus_name = aws_cloudwatch_event_bus.main[0].name
policy = data.aws_iam_policy_document.cross_account_receive[0].json
provider = aws.region
}

# Allow MLPA account to send messages
data "aws_iam_policy_document" "cross_account_receive" {
count = var.event_bus_enabled ? 1 : 0
statement {
sid = "CrossAccountAccess"
effect = "Allow"
actions = [
"events:PutEvents",
]
resources = [
aws_cloudwatch_event_bus.main[0].arn
]

principals {
type = "AWS"
identifiers = var.receive_account_ids
}
}
}

resource "aws_cloudwatch_event_target" "receive_events" {
count = var.event_bus_enabled ? 1 : 0
rule = aws_cloudwatch_event_rule.receive_events_from_mlpa[0].name
arn = aws_sqs_queue.receive_events_queue[0].arn
event_bus_name = aws_cloudwatch_event_bus.main[0].name
dead_letter_config {
arn = aws_sqs_queue.receive_events_deadletter[0].arn
}

provider = aws.region
}
14 changes: 14 additions & 0 deletions terraform/environment/region/modules/event_bus/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "receive_events_sqs_queue_name" {
description = "The name of the SQS queue created by the event_bus module."
value = aws_sqs_queue.receive_events_queue[*].name
}

output "receive_events_sqs_queue_arn" {
description = "The name of the SQS queue created by the event_bus module."
value = aws_sqs_queue.receive_events_queue[*].arn
}

output "receive_events_bus_arn" {
description = "The ARN of the event bus created by the event_bus module."
value = aws_cloudwatch_event_bus.main[0].arn
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,3 @@
resource "aws_cloudwatch_event_bus" "main" {
count = var.event_bus_enabled ? 1 : 0
name = var.environment_name
provider = aws.region
}

resource "aws_cloudwatch_event_archive" "main" {
count = var.event_bus_enabled ? 1 : 0
name = var.environment_name
event_source_arn = aws_cloudwatch_event_bus.main[0].arn
provider = aws.region
}

resource "aws_cloudwatch_event_rule" "receive_events_mlpa" {
count = var.event_bus_enabled ? 1 : 0
name = "${var.environment_name}-mlpa-events-to-use"
description = "receive events from mlpa"
event_bus_name = aws_cloudwatch_event_bus.main[0].name

event_pattern = jsonencode({
source = ["opg.poas.makeregister"],
})
provider = aws.region
}

data "aws_kms_alias" "sqs" {
name = "alias/sqs-mrk"
provider = aws.region
Expand All @@ -34,39 +9,22 @@ resource "aws_sqs_queue" "receive_events_queue" {
kms_master_key_id = data.aws_kms_alias.sqs.target_key_id
kms_data_key_reuse_period_seconds = 300

visibility_timeout_seconds = 300
visibility_timeout_seconds = var.queue_visibility_timeout

redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.receive_events_deadletter[0].arn
maxReceiveCount = 3
})
policy = data.aws_iam_policy_document.receive_events_queue_policy[0].json

provider = aws.region
}

data "aws_iam_policy_document" "receive_events_queue_policy" {
count = var.event_bus_enabled ? 1 : 0
statement {
sid = "${var.current_region}-ReceiveFromMLPA"
effect = "Allow"

principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}

actions = ["sqs:SendMessage"]
resources = ["*"]
resource "aws_sqs_queue_policy" "receive_events_queue_policy" {
count = var.event_bus_enabled ? 1 : 0
queue_url = aws_sqs_queue.receive_events_queue[0].id
policy = data.aws_iam_policy_document.receive_events_queue_policy[0].json

condition {
test = "ArnEquals"
variable = "aws:SourceArn"
values = [
aws_cloudwatch_event_rule.receive_events_mlpa[0].arn
]
}
}
provider = aws.region
}

resource "aws_sqs_queue" "receive_events_deadletter" {
Expand All @@ -88,13 +46,26 @@ resource "aws_sqs_queue_redrive_allow_policy" "receive_events_redrive_allow_poli
provider = aws.region
}

/*
resource "aws_lambda_event_source_mapping" "reveive_events_mapping" {
count = var.event_bus_enabled ? 1 : 0
event_source_arn = aws_sqs_queue.receive_events_queue[0].arn
enabled = false
function_name = var.ingress_lambda_name
batch_size = 10
provider = aws.region
data "aws_iam_policy_document" "receive_events_queue_policy" {
count = var.event_bus_enabled ? 1 : 0
statement {
sid = "${var.current_region}-ReceiveFromMLPA"
effect = "Allow"

principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}

actions = ["sqs:SendMessage"]
resources = [aws_sqs_queue.receive_events_queue[0].arn]

condition {
test = "ArnEquals"
variable = "aws:SourceArn"
values = [
aws_cloudwatch_event_rule.receive_events_from_mlpa[0].arn
]
}
}
}
*/
17 changes: 10 additions & 7 deletions terraform/environment/region/modules/event_bus/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ variable "event_bus_enabled" {
default = false
}

/*
variable "ingress_lambda_name" {
description = "The name of the ingress lambda"
type = string
}
*/

variable "current_region" {
description = "The current region"
type = string
}

variable "receive_account_ids" {
description = "The account ids that can send events to the event bus"
type = list(string)
}

variable "queue_visibility_timeout" {
description = "The visibility timeout for the SQS queue"
type = number
}
Loading
Loading