Skip to content

Commit 338ce53

Browse files
committed
CCM-16644: Add the eventsub module
1 parent 0e3c451 commit 338ce53

19 files changed

Lines changed: 827 additions & 0 deletions
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<!-- BEGIN_TF_DOCS -->
2+
<!-- markdownlint-disable -->
3+
<!-- vale off -->
4+
5+
## Requirements
6+
7+
| Name | Version |
8+
|------|---------|
9+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
10+
## Inputs
11+
12+
| Name | Description | Type | Default | Required |
13+
|------|-------------|------|---------|:--------:|
14+
| <a name="input_access_logging_bucket"></a> [access\_logging\_bucket](#input\_access\_logging\_bucket) | Name of S3 bucket to use for access logging | `string` | `""` | no |
15+
| <a name="input_aws_account_id"></a> [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes |
16+
| <a name="input_component"></a> [component](#input\_component) | The name of the terraformscaffold component calling this module | `string` | n/a | yes |
17+
| <a name="input_default_tags"></a> [default\_tags](#input\_default\_tags) | Default tag map for application to all taggable resources in the module | `map(string)` | `{}` | no |
18+
| <a name="input_enable_event_anomaly_detection"></a> [enable\_event\_anomaly\_detection](#input\_enable\_event\_anomaly\_detection) | Enable CloudWatch anomaly detection alarm for SNS topic message publishing | `bool` | `true` | no |
19+
| <a name="input_enable_event_cache"></a> [enable\_event\_cache](#input\_enable\_event\_cache) | Enable caching of events to an S3 bucket | `bool` | `true` | no |
20+
| <a name="input_enable_firehose_raw_message_delivery"></a> [enable\_firehose\_raw\_message\_delivery](#input\_enable\_firehose\_raw\_message\_delivery) | Enables raw message delivery on firehose subscription | `bool` | `false` | no |
21+
| <a name="input_enable_sns_delivery_logging"></a> [enable\_sns\_delivery\_logging](#input\_enable\_sns\_delivery\_logging) | Enable SNS Delivery Failure Notifications | `bool` | `true` | no |
22+
| <a name="input_environment"></a> [environment](#input\_environment) | The name of the terraformscaffold environment the module is called for | `string` | n/a | yes |
23+
| <a name="input_event_anomaly_band_width"></a> [event\_anomaly\_band\_width](#input\_event\_anomaly\_band\_width) | The width of the anomaly detection band. Higher values (e.g. 4-6) reduce sensitivity and noise, lower values (e.g. 2-3) increase sensitivity. Recommended: 2-4. | `number` | `3` | no |
24+
| <a name="input_event_anomaly_evaluation_periods"></a> [event\_anomaly\_evaluation\_periods](#input\_event\_anomaly\_evaluation\_periods) | Number of evaluation periods for the anomaly alarm. Each period is defined by event\_anomaly\_period. | `number` | `2` | no |
25+
| <a name="input_event_anomaly_period"></a> [event\_anomaly\_period](#input\_event\_anomaly\_period) | The period in seconds over which the specified statistic is applied for anomaly detection. Minimum 300 seconds (5 minutes). Recommended: 300-600. | `number` | `300` | no |
26+
| <a name="input_event_cache_buffer_interval"></a> [event\_cache\_buffer\_interval](#input\_event\_cache\_buffer\_interval) | The buffer interval for data firehose | `number` | `500` | no |
27+
| <a name="input_event_cache_expiry_days"></a> [event\_cache\_expiry\_days](#input\_event\_cache\_expiry\_days) | s3 archiving expiry in days | `number` | `30` | no |
28+
| <a name="input_force_destroy"></a> [force\_destroy](#input\_force\_destroy) | When enabled will force destroy event-cache S3 bucket | `bool` | `false` | no |
29+
| <a name="input_glue_role_arn"></a> [glue\_role\_arn](#input\_glue\_role\_arn) | ARN of the Glue execution role from the parent | `string` | n/a | yes |
30+
| <a name="input_group"></a> [group](#input\_group) | The name of the tfscaffold group | `string` | `null` | no |
31+
| <a name="input_kms_key_arn"></a> [kms\_key\_arn](#input\_kms\_key\_arn) | KMS key arn to use for this function | `string` | n/a | yes |
32+
| <a name="input_log_level"></a> [log\_level](#input\_log\_level) | The log level to be used in lambda functions within the component. Any log with a lower severity than the configured value will not be logged: https://docs.python.org/3/library/logging.html#levels | `string` | `"WARN"` | no |
33+
| <a name="input_log_retention_in_days"></a> [log\_retention\_in\_days](#input\_log\_retention\_in\_days) | The retention period in days for the Cloudwatch Logs events generated by the lambda function | `number` | n/a | yes |
34+
| <a name="input_name"></a> [name](#input\_name) | A unique name to distinguish this module invocation from others within the same CSI scope | `string` | n/a | yes |
35+
| <a name="input_project"></a> [project](#input\_project) | The name of the terraformscaffold project calling the module | `string` | n/a | yes |
36+
| <a name="input_region"></a> [region](#input\_region) | The AWS Region | `string` | n/a | yes |
37+
| <a name="input_shared_infra_account_id"></a> [shared\_infra\_account\_id](#input\_shared\_infra\_account\_id) | The AWS Account ID of the shared infrastructure account | `string` | `"000000000000"` | no |
38+
| <a name="input_sns_success_logging_sample_percent"></a> [sns\_success\_logging\_sample\_percent](#input\_sns\_success\_logging\_sample\_percent) | Enable SNS Delivery Successful Sample Percentage | `number` | `0` | no |
39+
## Modules
40+
41+
| Name | Source | Version |
42+
|------|--------|---------|
43+
| <a name="module_s3bucket_event_cache"></a> [s3bucket\_event\_cache](#module\_s3bucket\_event\_cache) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.2/terraform-s3bucket.zip | n/a |
44+
## Outputs
45+
46+
| Name | Description |
47+
|------|-------------|
48+
| <a name="output_s3_bucket_event_cache"></a> [s3\_bucket\_event\_cache](#output\_s3\_bucket\_event\_cache) | S3 Bucket ARN and Name for event cache |
49+
| <a name="output_sns_topic"></a> [sns\_topic](#output\_sns\_topic) | SNS Topic ARN and Name |
50+
<!-- vale on -->
51+
<!-- markdownlint-enable -->
52+
<!-- END_TF_DOCS -->
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
resource "aws_cloudwatch_log_group" "kinesis_data_firehose" {
2+
count = var.enable_event_cache ? 1 : 0
3+
4+
name = "/aws/firehose/${local.csi}"
5+
kms_key_id = var.kms_key_arn
6+
retention_in_days = var.log_retention_in_days
7+
}
8+
9+
resource "aws_cloudwatch_log_stream" "kinesis_data_firehose_extended_s3" {
10+
count = var.enable_event_cache ? 1 : 0
11+
12+
name = "extended_s3"
13+
log_group_name = aws_cloudwatch_log_group.kinesis_data_firehose[0].name
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
resource "aws_cloudwatch_log_group" "sns_delivery_logging_failure" {
2+
count = var.enable_sns_delivery_logging ? 1 : 0
3+
4+
# SNS doesn't allow specifying a log group and is derived as: sns/${region}/${account_id}/${name_of_sns_topic}/Failure
5+
# (for failure logs)
6+
name = "sns/${var.region}/${var.aws_account_id}/${local.csi}/Failure"
7+
kms_key_id = var.kms_key_arn
8+
retention_in_days = var.log_retention_in_days
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
resource "aws_cloudwatch_log_group" "sns_delivery_logging_success" {
2+
count = var.enable_sns_delivery_logging ? 1 : 0
3+
4+
# SNS doesn't allow specifying a log group and is derived as: sns/${region}/${account_id}/${name_of_sns_topic}
5+
# (for success logs)
6+
name = "sns/${var.region}/${var.aws_account_id}/${local.csi}"
7+
kms_key_id = var.kms_key_arn
8+
retention_in_days = var.log_retention_in_days
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
resource "aws_cloudwatch_metric_alarm" "sns_delivery_failures" {
2+
alarm_name = "${local.csi}-sns-delivery-failures"
3+
alarm_description = "RELIABILITY: Alarm for SNS topic delivery failures"
4+
comparison_operator = "GreaterThanThreshold"
5+
evaluation_periods = 1
6+
metric_name = "NumberOfNotificationsFailed"
7+
namespace = "AWS/SNS"
8+
period = 300
9+
statistic = "Sum"
10+
threshold = 0
11+
treat_missing_data = "notBreaching"
12+
13+
dimensions = {
14+
TopicName = aws_sns_topic.main.name
15+
}
16+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
resource "aws_cloudwatch_metric_alarm" "subscriber_anomaly" {
2+
count = var.enable_event_anomaly_detection ? 1 : 0
3+
4+
alarm_name = "${local.csi}-subscriber-anomaly"
5+
alarm_description = "ANOMALY: Detects anomalous patterns in messages published to the SNS fanout topic"
6+
comparison_operator = "LessThanLowerOrGreaterThanUpperThreshold"
7+
evaluation_periods = var.event_anomaly_evaluation_periods
8+
threshold_metric_id = "ad1"
9+
treat_missing_data = "notBreaching"
10+
11+
metric_query {
12+
id = "m1"
13+
return_data = true
14+
15+
metric {
16+
metric_name = "NumberOfNotificationsDelivered"
17+
namespace = "AWS/SNS"
18+
period = var.event_anomaly_period
19+
stat = "Sum"
20+
21+
dimensions = {
22+
TopicName = aws_sns_topic.main.name
23+
}
24+
}
25+
}
26+
27+
metric_query {
28+
id = "ad1"
29+
expression = "ANOMALY_DETECTION_BAND(m1, ${var.event_anomaly_band_width})"
30+
label = "NumberOfNotificationsDelivered (expected)"
31+
return_data = true
32+
}
33+
34+
tags = merge(
35+
var.default_tags,
36+
{
37+
Name = "${local.csi}-subscriber-anomaly"
38+
}
39+
)
40+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
resource "aws_iam_policy" "sns_delivery_logging_cloudwatch" {
2+
count = var.enable_sns_delivery_logging ? 1 : 0
3+
4+
name = "${local.csi}-${var.name}-sns-delivery"
5+
description = "Policy for ${local.csi}-${var.name} SNS Delivery Logging"
6+
policy = data.aws_iam_policy_document.sns_delivery_logging_cloudwatch[0].json
7+
}
8+
9+
data "aws_iam_policy_document" "sns_delivery_logging_cloudwatch" {
10+
count = var.enable_sns_delivery_logging ? 1 : 0
11+
12+
statement {
13+
sid = "KMSCloudwatchKeyAccess"
14+
effect = "Allow"
15+
16+
actions = [
17+
"kms:GenerateDataKey",
18+
"kms:Decrypt",
19+
]
20+
21+
resources = [
22+
var.kms_key_arn
23+
]
24+
}
25+
26+
statement {
27+
sid = "AllowSNSDeliveryNotifications"
28+
effect = "Allow"
29+
30+
actions = [
31+
"logs:CreateLogStream",
32+
"logs:PutLogEvents",
33+
"logs:PutMetricFilter",
34+
"logs:PutRetentionPolicy",
35+
]
36+
37+
resources = [
38+
aws_cloudwatch_log_group.sns_delivery_logging_success[0].arn,
39+
"${aws_cloudwatch_log_group.sns_delivery_logging_success[0].arn}:log-stream:*",
40+
aws_cloudwatch_log_group.sns_delivery_logging_failure[0].arn,
41+
"${aws_cloudwatch_log_group.sns_delivery_logging_failure[0].arn}:log-stream:*",
42+
]
43+
}
44+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
resource "aws_iam_role" "firehose_role" {
2+
count = var.enable_event_cache ? 1 : 0
3+
4+
name = "${local.csi}-firehose-role"
5+
assume_role_policy = data.aws_iam_policy_document.firehose_assume_role[0].json
6+
}
7+
8+
data "aws_iam_policy_document" "firehose_assume_role" {
9+
count = var.enable_event_cache ? 1 : 0
10+
11+
statement {
12+
effect = "Allow"
13+
14+
principals {
15+
type = "Service"
16+
identifiers = ["firehose.amazonaws.com"]
17+
}
18+
19+
actions = ["sts:AssumeRole"]
20+
}
21+
}
22+
23+
resource "aws_iam_role_policy_attachment" "s3_write_object" {
24+
count = var.enable_event_cache ? 1 : 0
25+
26+
role = aws_iam_role.firehose_role[0].name
27+
policy_arn = aws_iam_policy.s3_write_object[0].arn
28+
}
29+
30+
resource "aws_iam_policy" "s3_write_object" {
31+
count = var.enable_event_cache ? 1 : 0
32+
33+
name = "${local.csi}-${var.name}-s3-write-object"
34+
description = "S3 Put Object policy for ${local.csi}-${var.name} Firehose"
35+
policy = data.aws_iam_policy_document.s3_write_object[0].json
36+
}
37+
38+
data "aws_iam_policy_document" "s3_write_object" {
39+
count = var.enable_event_cache ? 1 : 0
40+
41+
statement {
42+
sid = "AllowWriteObject"
43+
effect = "Allow"
44+
45+
actions = [
46+
"s3:AbortMultipartUpload",
47+
"s3:GetBucketLocation",
48+
"s3:GetObject",
49+
"s3:ListBucket",
50+
"s3:ListBucketMultipartUploads",
51+
"s3:PutObject",
52+
"s3:PutObject",
53+
]
54+
55+
resources = [
56+
"${module.s3bucket_event_cache[0].arn}/*",
57+
]
58+
}
59+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
resource "aws_iam_role" "sns_role" {
2+
name = "${local.csi}-sns-role"
3+
assume_role_policy = data.aws_iam_policy_document.sns_assume_role.json
4+
}
5+
6+
resource "aws_iam_policy" "firehose_delivery" {
7+
count = var.enable_event_cache ? 1 : 0
8+
9+
name = "${local.csi}-${var.name}-firehose-delivery"
10+
description = "Delivery Policy for ${local.csi}-${var.name} Firehose"
11+
policy = data.aws_iam_policy_document.firehose_delivery[0].json
12+
}
13+
14+
resource "aws_iam_role_policy_attachment" "firehose_delivery" {
15+
count = var.enable_event_cache ? 1 : 0
16+
17+
role = aws_iam_role.sns_role.name
18+
policy_arn = aws_iam_policy.firehose_delivery[0].arn
19+
}
20+
21+
22+
data "aws_iam_policy_document" "sns_assume_role" {
23+
statement {
24+
effect = "Allow"
25+
26+
principals {
27+
type = "Service"
28+
identifiers = ["sns.amazonaws.com"]
29+
}
30+
31+
actions = ["sts:AssumeRole"]
32+
}
33+
}
34+
35+
data "aws_iam_policy_document" "firehose_delivery" {
36+
count = var.enable_event_cache ? 1 : 0
37+
38+
statement {
39+
sid = "AllowFirehoseDelivery"
40+
effect = "Allow"
41+
42+
actions = [
43+
"firehose:PutRecord",
44+
"firehose:PutRecordBatch"
45+
]
46+
47+
resources = [
48+
"${aws_kinesis_firehose_delivery_stream.main[0].arn}",
49+
]
50+
}
51+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
resource "aws_iam_role" "sns_delivery_logging_role" {
2+
count = var.enable_sns_delivery_logging ? 1 : 0
3+
4+
name = "${local.csi}-sns-delivery-logging"
5+
assume_role_policy = data.aws_iam_policy_document.sns_delivery_logging_assume_role[0].json
6+
}
7+
8+
data "aws_iam_policy_document" "sns_delivery_logging_assume_role" {
9+
count = var.enable_sns_delivery_logging ? 1 : 0
10+
11+
statement {
12+
effect = "Allow"
13+
14+
principals {
15+
type = "Service"
16+
identifiers = ["sns.amazonaws.com"]
17+
}
18+
19+
actions = ["sts:AssumeRole"]
20+
}
21+
}

0 commit comments

Comments
 (0)