From 4cab7ea9d698ff54c4259e65f19f9d545cb42438 Mon Sep 17 00:00:00 2001 From: Josep Boix Requesens Date: Thu, 21 Nov 2024 17:02:02 +0100 Subject: [PATCH] feat: add sns topic for grafana alerts Resolves #8 by adding an SNS topic for grafana alerts. Changes made: - Exposed SNS as a vpc endpoint. - Created the SNS topic. - Assigned necessary IAM roles to the Grafana workspace. - Added an email subscription to the new topic, the email list can be configured through a variable. --- .../data_transfer_service.tf | 2 +- .../20-pillarbox-monitoring-app/grafana.tf | 37 +++++++++++++++---- .../20-pillarbox-monitoring-app/iam.tf | 21 +++++++++++ .../20-pillarbox-monitoring-app/main.tf | 37 ++++++++++++++++++- .../20-pillarbox-monitoring-app/outputs.tf | 5 +++ .../20-pillarbox-monitoring-app/variables.tf | 4 ++ 6 files changed, 97 insertions(+), 9 deletions(-) diff --git a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/data_transfer_service.tf b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/data_transfer_service.tf index d3847ba..7a02cca 100644 --- a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/data_transfer_service.tf +++ b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/data_transfer_service.tf @@ -26,7 +26,7 @@ resource "aws_security_group" "transfer_task_sg" { resource "aws_cloudwatch_log_group" "transfer_log_group" { name = "/ecs/pillarbox-monitoring-transfer" - retention_in_days = 7 # Adjust the retention period as necessary + retention_in_days = 7 tags = { Name = "data-transfer-log-group" diff --git a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/grafana.tf b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/grafana.tf index 0707137..d5ab5ed 100644 --- a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/grafana.tf +++ b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/grafana.tf @@ -33,12 +33,13 @@ resource "aws_security_group" "grafana_sg" { ## Create a Grafana Workspace for monitoring with OpenSearch as the data source resource "aws_grafana_workspace" "grafana_workspace" { - name = "${var.application_name}-grafana" - account_access_type = "CURRENT_ACCOUNT" # Restrict Grafana workspace to the current AWS account - authentication_providers = ["AWS_SSO"] # Use AWS SSO for authentication - permission_type = "SERVICE_MANAGED" # Permissions managed by the service - role_arn = aws_iam_role.grafana_workspace_role.arn # IAM Role to assume for workspace access - data_sources = ["AMAZON_OPENSEARCH_SERVICE"] # Data source for Grafana + name = "${var.application_name}-grafana" + account_access_type = "CURRENT_ACCOUNT" # Restrict Grafana workspace to the current AWS account + authentication_providers = ["AWS_SSO"] # Use AWS SSO for authentication + permission_type = "SERVICE_MANAGED" # Permissions managed by the service + role_arn = aws_iam_role.grafana_workspace_role.arn # IAM Role to assume for workspace access + data_sources = ["AMAZON_OPENSEARCH_SERVICE"] # Data source for Grafana + notification_destinations = ["SNS"] # VPC Configuration: Attach workspace to subnets and security group vpc_configuration { @@ -53,7 +54,7 @@ resource "aws_grafana_workspace" "grafana_workspace" { "pluginAdminEnabled" = true }, "unifiedAlerting" = { - "enabled" = false + "enabled" = true } } ) @@ -62,3 +63,25 @@ resource "aws_grafana_workspace" "grafana_workspace" { Name = "grafana-workspace" } } + +# ----------------------------------- +# AWS SNS Topic for Alerts +# ----------------------------------- + +# Create an SNS Topic for Grafana Alerts +resource "aws_sns_topic" "grafana_alerts" { + name = "grafana-alerts" + + tags = { + Name = "grafana-alert-sns-topic" + } +} + +# Create SNS Topic Subscriptions for Email List +resource "aws_sns_topic_subscription" "email_subscriptions" { + for_each = toset(var.alert_emails) + + topic_arn = aws_sns_topic.grafana_alerts.arn + protocol = "email" + endpoint = each.key +} diff --git a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/iam.tf b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/iam.tf index 9ee06e3..f886dcc 100644 --- a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/iam.tf +++ b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/iam.tf @@ -130,6 +130,27 @@ resource "aws_iam_role_policy_attachment" "grafana_opensearch_policy_attach" { policy_arn = aws_iam_policy.grafana_opensearch_policy.arn } +# SNS Publish Policy Document for Grafana +data "aws_iam_policy_document" "grafana_sns_publish_policy" { + statement { + actions = ["sns:Publish", "sns:GetTopicAttributes"] + resources = [aws_sns_topic.grafana_alerts.arn] + } +} + +# SNS Publish Policy for Grafana +resource "aws_iam_policy" "grafana_sns_publish_policy" { + name = "grafana-sns-publish-policy" + policy = data.aws_iam_policy_document.grafana_sns_publish_policy.json +} + +# Attach SNS Publish Policy to Grafana Role +resource "aws_iam_role_policy_attachment" "grafana_sns_publish_policy_attach" { + role = aws_iam_role.grafana_workspace_role.name + policy_arn = aws_iam_policy.grafana_sns_publish_policy.arn +} + + # ----------------------------------- # OpenSearch Access Policies # ----------------------------------- diff --git a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/main.tf b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/main.tf index 4a00270..1535dde 100644 --- a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/main.tf +++ b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/main.tf @@ -128,7 +128,7 @@ resource "aws_security_group" "vpc_endpoints_sg" { to_port = 443 security_groups = [ aws_security_group.dispatch_task_sg.id, - aws_security_group.transfer_task_sg.id + aws_security_group.transfer_task_sg.id, ] } @@ -191,3 +191,38 @@ resource "aws_vpc_endpoint" "cloudwatch_logs" { Name = "vpc-cloudwatch-logs-endpoint" } } + + +# Security Group for the SNS VPC Endpoint +resource "aws_security_group" "sns_vpc_endpoint_sg" { + name = "sns-vpc-endpoint-sg" + description = "Associated to SNS Endpoint" + vpc_id = local.vpc_id + + # Ingress rule to allow access to VPC endpoints + ingress { + description = "Allow Grafana to publish to SNS topics" + protocol = "tcp" + from_port = 443 + to_port = 443 + security_groups = [aws_security_group.grafana_sg.id] + } + + tags = { + Name = "sns-vpc-endpoint-sg" + } +} + +# VPC Endpoint for SNS +resource "aws_vpc_endpoint" "sns" { + vpc_id = data.aws_vpc.main_vpc.id + service_name = "com.amazonaws.${data.aws_region.current.name}.sns" + vpc_endpoint_type = "Interface" + subnet_ids = data.aws_subnets.private_subnets.ids + security_group_ids = [aws_security_group.sns_vpc_endpoint_sg.id] + private_dns_enabled = true + + tags = { + Name = "vpc-sns-endpoint" + } +} diff --git a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/outputs.tf b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/outputs.tf index a8a1b3a..e52c8ec 100644 --- a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/outputs.tf +++ b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/outputs.tf @@ -12,3 +12,8 @@ output "dispatch_dns_name" { description = "The DNS name of the Dispatch Service Load Balancer" value = aws_alb.dispatch_alb.dns_name } + +output "grafana_alert_topic" { + description = "The ARN of the topic for grafana alerts" + value = aws_sns_topic.grafana_alerts.arn +} diff --git a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/variables.tf b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/variables.tf index e947de3..a8acd7e 100644 --- a/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/variables.tf +++ b/pillarbox-monitoring-terraform/20-pillarbox-monitoring-app/variables.tf @@ -24,5 +24,9 @@ variable "pillarbox_domain_name" { description = "The public domain name of the service" type = string default = "pillarbox.ch" +} +variable "alert_emails" { + description = "List of email addresses to subscribe to SNS topic for Grafana alerts" + type = list(string) }