Skip to content

Commit

Permalink
SNS topic (#210)
Browse files Browse the repository at this point in the history
SNS topic, this is preparatory work to support automated emails.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
paulschwarzenberger authored Aug 11, 2024
1 parent 5feeb7e commit bec56c0
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
| <a name="module_rsa_tls_cert_lambda"></a> [rsa\_tls\_cert\_lambda](#module\_rsa\_tls\_cert\_lambda) | ./modules/terraform-aws-ca-lambda | n/a |
| <a name="module_scheduler"></a> [scheduler](#module\_scheduler) | ./modules/terraform-aws-ca-scheduler | n/a |
| <a name="module_scheduler-role"></a> [scheduler-role](#module\_scheduler-role) | ./modules/terraform-aws-ca-iam | n/a |
| <a name="module_sns-ca-notifications"></a> [sns-ca-notifications](#module\_sns-ca-notifications) | ./modules/terraform-aws-ca-sns | n/a |
| <a name="module_step-function"></a> [step-function](#module\_step-function) | ./modules/terraform-aws-ca-step-function | n/a |
| <a name="module_step-function-role"></a> [step-function-role](#module\_step-function-role) | ./modules/terraform-aws-ca-iam | n/a |
| <a name="module_tls_keygen_iam"></a> [tls\_keygen\_iam](#module\_tls\_keygen\_iam) | ./modules/terraform-aws-ca-iam | n/a |
Expand All @@ -55,6 +56,8 @@
| <a name="input_bucket_prefix"></a> [bucket\_prefix](#input\_bucket\_prefix) | First part of s3 bucket name to ensure uniqueness, if left blank a random suffix will be used instead | `string` | `""` | no |
| <a name="input_cert_info_files"></a> [cert\_info\_files](#input\_cert\_info\_files) | List of file names to be uploaded to internal S3 bucket for processing | `list` | `[]` | no |
| <a name="input_csr_files"></a> [csr\_files](#input\_csr\_files) | List of CSR file names to be uploaded to internal S3 bucket for processing | `list` | `[]` | no |
| <a name="input_custom_sns_topic_display_name"></a> [custom\_sns\_topic\_display\_name](#input\_custom\_sns\_topic\_display\_name) | Customised SNS topic display name, leave empty to use standard naming convention | `string` | `""` | no |
| <a name="input_custom_sns_topic_name"></a> [custom\_sns\_topic\_name](#input\_custom\_sns\_topic\_name) | Customised SNS topic name, leave empty to use standard naming convention | `string` | `""` | no |
| <a name="input_env"></a> [env](#input\_env) | Environment name, e.g. dev | `string` | `"dev"` | no |
| <a name="input_filter_pattern"></a> [filter\_pattern](#input\_filter\_pattern) | Filter pattern for CloudWatch logs subscription filter | `string` | `""` | no |
| <a name="input_hosted_zone_domain"></a> [hosted\_zone\_domain](#input\_hosted\_zone\_domain) | Hosted zone domain, e.g. dev.ca.example.com | `string` | `""` | no |
Expand All @@ -79,6 +82,11 @@
| <a name="input_runtime"></a> [runtime](#input\_runtime) | Lambda language runtime | `string` | `"python3.12"` | no |
| <a name="input_s3_aws_principals"></a> [s3\_aws\_principals](#input\_s3\_aws\_principals) | List of AWS Principals to allow access to external S3 bucket | `list` | `[]` | no |
| <a name="input_schedule_expression"></a> [schedule\_expression](#input\_schedule\_expression) | Step function schedule in cron format, interval should normally be the same as issuing\_crl\_days | `string` | `"cron(15 8 * * ? *)"` | no |
| <a name="input_sns_email_subscriptions"></a> [sns\_email\_subscriptions](#input\_sns\_email\_subscriptions) | List of email addresses to subscribe to SNS topic | `list(string)` | `[]` | no |
| <a name="input_sns_lambda_subscriptions"></a> [sns\_lambda\_subscriptions](#input\_sns\_lambda\_subscriptions) | A map of lambda names to arns to subscribe to SNS topic | `map(string)` | `{}` | no |
| <a name="input_sns_policy"></a> [sns\_policy](#input\_sns\_policy) | A string containing the SNS policy, if used | `string` | `""` | no |
| <a name="input_sns_policy_template"></a> [sns\_policy\_template](#input\_sns\_policy\_template) | Name of SNS policy template file, if used | `string` | `"default"` | no |
| <a name="input_sns_sqs_subscriptions"></a> [sns\_sqs\_subscriptions](#input\_sns\_sqs\_subscriptions) | A map of SQS names to arns to subscribe to thSNSis topic | `map(string)` | `{}` | no |
| <a name="input_subscription_filter_destination"></a> [subscription\_filter\_destination](#input\_subscription\_filter\_destination) | CloudWatch log subscription filter destination, last section of ARN | `string` | `""` | no |
| <a name="input_timeout"></a> [timeout](#input\_timeout) | Amount of time Lambda Function has to run in seconds | `number` | `180` | no |

Expand Down
2 changes: 2 additions & 0 deletions examples/rsa-public-crl/ca.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ module "certificate_authority" {
public_crl = true
cert_info_files = ["tls", "revoked", "revoked-root-ca"]

custom_sns_topic_display_name = "My Company CA Notifications Production"

providers = {
aws = aws
aws.us-east-1 = aws.us-east-1 # certificates for CloudFront must be in this region
Expand Down
19 changes: 19 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ module "create_rsa_root_ca_lambda" {
domain = var.hosted_zone_domain
runtime = var.runtime
public_crl = var.public_crl
sns_topic_arn = module.sns-ca-notifications.sns_topic_arn
}

module "create_rsa_issuing_ca_lambda" {
Expand All @@ -210,6 +211,7 @@ module "create_rsa_issuing_ca_lambda" {
domain = var.hosted_zone_domain
runtime = var.runtime
public_crl = var.public_crl
sns_topic_arn = module.sns-ca-notifications.sns_topic_arn
}

module "rsa_root_ca_crl_lambda" {
Expand All @@ -232,6 +234,7 @@ module "rsa_root_ca_crl_lambda" {
domain = var.hosted_zone_domain
runtime = var.runtime
public_crl = var.public_crl
sns_topic_arn = module.sns-ca-notifications.sns_topic_arn
}

module "rsa_issuing_ca_crl_lambda" {
Expand All @@ -254,6 +257,7 @@ module "rsa_issuing_ca_crl_lambda" {
domain = var.hosted_zone_domain
runtime = var.runtime
public_crl = var.public_crl
sns_topic_arn = module.sns-ca-notifications.sns_topic_arn
}

module "rsa_tls_cert_lambda" {
Expand All @@ -276,6 +280,7 @@ module "rsa_tls_cert_lambda" {
public_crl = var.public_crl
max_cert_lifetime = var.max_cert_lifetime
allowed_invocation_principals = var.aws_principals
sns_topic_arn = module.sns-ca-notifications.sns_topic_arn
}

module "cloudfront_certificate" {
Expand Down Expand Up @@ -369,3 +374,17 @@ module "db-reader-role" {
policy = "db_reader"
assume_role_policy = "db_reader"
}

module "sns-ca-notifications" {
source = "./modules/terraform-aws-ca-sns"

project = var.project
function = "ca-notifications"
env = var.env
custom_sns_topic_display_name = var.custom_sns_topic_display_name
custom_sns_topic_name = var.custom_sns_topic_name
kms_key_arn = coalesce(var.kms_arn_resource, module.kms_tls_keygen.kms_arn)
email_subscriptions = var.sns_email_subscriptions
lambda_subscriptions = var.sns_lambda_subscriptions
sqs_subscriptions = var.sns_sqs_subscriptions
}
1 change: 1 addition & 0 deletions modules/terraform-aws-ca-lambda/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ resource "aws_lambda_function" "lambda" {
ROOT_CA_INFO = jsonencode(var.root_ca_info)
ROOT_CRL_DAYS = tostring(var.root_crl_days)
ROOT_CRL_SECONDS = tostring(var.root_crl_seconds)
SNS_TOPIC_ARN = var.sns_topic_arn
}
}

Expand Down
4 changes: 4 additions & 0 deletions modules/terraform-aws-ca-lambda/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ variable "runtime" {
description = "Lambda language runtime"
}

variable "sns_topic_arn" {
description = "SNS Topic ARN for Lambda function to publish to"
}

variable "subscription_filter_destination" {
description = "CloudWatch log subscription filter destination, last section of ARN"
default = ""
Expand Down
3 changes: 3 additions & 0 deletions modules/terraform-aws-ca-sns/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "aws_caller_identity" "current" {}

data "aws_region" "current" {}
9 changes: 9 additions & 0 deletions modules/terraform-aws-ca-sns/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
locals {
sns_topic_display_name = coalesce(var.custom_sns_topic_name, title(replace("${var.project}-${var.function}-${var.env}", "-", " ")))
sns_topic_name = coalesce(var.custom_sns_topic_name, "${var.project}-${var.function}-${var.env}")

tags = merge(var.tags, {
Terraform = "true"
Name = local.sns_topic_name,
})
}
37 changes: 37 additions & 0 deletions modules/terraform-aws-ca-sns/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
resource "aws_sns_topic" "sns_topic" {
name = local.sns_topic_name
display_name = local.sns_topic_display_name
policy = coalesce(var.sns_policy, templatefile("${path.module}/templates/${var.sns_policy_template}.json", { region = data.aws_region.current.id, account_id = data.aws_caller_identity.current.account_id, sns_topic_name = local.sns_topic_name }))

tags = merge(
var.tags,
tomap(
{ "Name" = local.sns_topic_name }
)
)
kms_master_key_id = var.kms_key_arn
}

resource "aws_sns_topic_subscription" "email_subscriptions" {
for_each = toset(var.email_subscriptions)
endpoint = each.key
protocol = "email"
topic_arn = aws_sns_topic.sns_topic.arn
raw_message_delivery = false
}

resource "aws_sns_topic_subscription" "lambda_subscriptions" {
for_each = var.lambda_subscriptions
endpoint = each.value
protocol = "lambda"
topic_arn = aws_sns_topic.sns_topic.arn
raw_message_delivery = false
}

resource "aws_sns_topic_subscription" "sqs_subscriptions" {
for_each = var.sqs_subscriptions
endpoint = each.value
protocol = "sqs"
topic_arn = aws_sns_topic.sns_topic.arn
raw_message_delivery = true
}
3 changes: 3 additions & 0 deletions modules/terraform-aws-ca-sns/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "sns_topic_arn" {
value = aws_sns_topic.sns_topic.arn
}
30 changes: 30 additions & 0 deletions modules/terraform-aws-ca-sns/templates/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Version": "2012-10-17",
"Id": "default_policy",
"Statement": [
{
"Sid": "default_statement",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"sns:GetTopicAttributes",
"sns:SetTopicAttributes",
"sns:AddPermission",
"sns:RemovePermission",
"sns:DeleteTopic",
"sns:Subscribe",
"sns:ListSubscriptionsByTopic",
"sns:Publish",
"sns:Receive"
],
"Resource": "arn:aws:sns:${region}:${account_id}:${sns_topic_name}",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "${account_id}"
}
}
}
]
}
39 changes: 39 additions & 0 deletions modules/terraform-aws-ca-sns/templates/eventbridge.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"Version": "2012-10-17",
"Id": "allow_account_access_to_topic_policy",
"Statement": [
{
"Sid": "allow_account_access_to_topic",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"sns:GetTopicAttributes",
"sns:SetTopicAttributes",
"sns:AddPermission",
"sns:RemovePermission",
"sns:DeleteTopic",
"sns:Subscribe",
"sns:ListSubscriptionsByTopic",
"sns:Publish",
"sns:Receive"
],
"Resource": "arn:aws:sns:${region}:${account_id}:${sns_topic_name}",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "${account_id}"
}
}
},
{
"Sid": "allow_eventbridge_access_to_topic",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": "sns:Publish",
"Resource": "arn:aws:sns:${region}:${account_id}:${sns_topic_name}"
}
]
}
63 changes: 63 additions & 0 deletions modules/terraform-aws-ca-sns/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
variable "project" {
description = "abbreviation for the project, forms the first part of the resource name"
default = ""
}

variable "function" {
description = "forms the second part of the resource name"
default = ""
}

variable "env" {
description = "suffix for environment, e.g. dev"
default = ""
}

variable "custom_sns_topic_display_name" {
description = "Customised SNS topic display name, leave empty to use standard naming convention"
default = ""
}


variable "custom_sns_topic_name" {
description = "Customised SNS topic name, leave empty to use standard naming convention"
default = ""
}

variable "sns_policy" {
description = "A string containing the SNS policy, if used"
default = ""
}

variable "sns_policy_template" {
description = "Name of SNS policy template file, if used"
default = "default"
}

variable "kms_key_arn" {
description = "A KMS key arn to be used to encrypt the queue contents at rest"
default = null
}

variable "email_subscriptions" {
type = list(string)
description = "List of email addresses to subscribe to this topic"
default = []
}

variable "lambda_subscriptions" {
type = map(string)
description = "A map of lambda names to arns to subscribe to this topic"
default = {}
}

variable "sqs_subscriptions" {
type = map(string)
description = "A map of SQS names to arns to subscribe to this topic"
default = {}
}

variable "tags" {
type = map(string)
default = {}
}
38 changes: 38 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ variable "csr_files" {
default = []
}

variable "custom_sns_topic_display_name" {
description = "Customised SNS topic display name, leave empty to use standard naming convention"
default = ""
}

variable "custom_sns_topic_name" {
description = "Customised SNS topic name, leave empty to use standard naming convention"
default = ""
}

variable "env" {
description = "Environment name, e.g. dev"
default = "dev"
Expand Down Expand Up @@ -196,6 +206,34 @@ variable "schedule_expression" {
default = "cron(15 8 * * ? *)" # 8.15 a.m. daily
}

variable "sns_email_subscriptions" {
type = list(string)
description = "List of email addresses to subscribe to SNS topic"
default = []
}

variable "sns_lambda_subscriptions" {
type = map(string)
description = "A map of lambda names to arns to subscribe to SNS topic"
default = {}
}

variable "sns_policy" {
description = "A string containing the SNS policy, if used"
default = ""
}

variable "sns_policy_template" {
description = "Name of SNS policy template file, if used"
default = "default"
}

variable "sns_sqs_subscriptions" {
type = map(string)
description = "A map of SQS names to arns to subscribe to thSNSis topic"
default = {}
}

variable "subscription_filter_destination" {
description = "CloudWatch log subscription filter destination, last section of ARN"
default = ""
Expand Down

0 comments on commit bec56c0

Please sign in to comment.