Skip to content

Commit

Permalink
Fix notifications access from service (#835)
Browse files Browse the repository at this point in the history
Fix ability for ECS service to access Pinpoint:
- Add VPC endpoints for Pinpoint services
- Add IAM policy for accessing Pinpoint and SES to service

Also add notifications test endpoint to example app for testing:
- Add /notifications page where you can enter an email address and get a
test notification to that email address
- Add links to the homepage to all the test pages in the example app
  • Loading branch information
lorenyu authored Jan 16, 2025
1 parent cb15833 commit d22cad4
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 2 deletions.
6 changes: 6 additions & 0 deletions infra/modules/network/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ variable "enable_command_execution" {
default = false
}

variable "enable_notifications" {
type = bool
description = "Whether the application(s) in this network need AWS Pinpoint access."
default = false
}

variable "has_database" {
type = bool
description = "Whether the application(s) in this network have a database. Determines whether to create VPC endpoints needed by the database layer."
Expand Down
3 changes: 3 additions & 0 deletions infra/modules/network/vpc_endpoints.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ locals {

# AWS services used by ECS Exec
var.enable_command_execution ? ["ssmmessages"] : [],

# AWS services used by notifications
var.enable_notifications ? ["pinpoint", "email-smtp"] : [],
)

# S3 and DynamoDB use Gateway VPC endpoints. All other services use Interface VPC endpoints
Expand Down
32 changes: 32 additions & 0 deletions infra/modules/notifications/resources/access_control.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
resource "aws_iam_policy" "access" {
name = "${var.name}-notifications-access"
description = "Policy for calling SendMessages and SendUsersMessages on Pinpoint app ${var.name}"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
# From https://docs.aws.amazon.com/pinpoint/latest/developerguide/permissions-actions.html#permissions-actions-apiactions-messages
{
Effect = "Allow"
Action = [
"mobiletargeting:SendMessages",
"mobiletargeting:SendUsersMessages"
]
Resource = "${aws_pinpoint_app.app.arn}/messages"
},

# From https://docs.aws.amazon.com/pinpoint/latest/developerguide/permissions-ses.html
{
Effect = "Allow"
Action = [
"ses:SendEmail",
"ses:SendRawEmail",
]
Resource = [
var.domain_identity_arn,
"arn:*:ses:*:*:configuration-set/*",
]
}
]
})
}
4 changes: 4 additions & 0 deletions infra/modules/notifications/resources/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
output "app_id" {
value = aws_pinpoint_app.app.application_id
}

output "access_policy_arn" {
value = aws_iam_policy.access.arn
}
4 changes: 4 additions & 0 deletions infra/networks/main.tf.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ locals {
for environment_config in app.environment_configs : true if environment_config.service_config.enable_command_execution == true && environment_config.network_name == var.network_name
])
])

# Whether any of the applications in the network has enabled notifications
enable_notifications = anytrue([for app in local.apps_in_network : app.enable_notifications])
}

terraform {
Expand Down Expand Up @@ -88,6 +91,7 @@ module "network" {
has_database = local.has_database
has_external_non_aws_service = local.has_external_non_aws_service
enable_command_execution = local.enable_command_execution
enable_notifications = local.enable_notifications
}

module "domain" {
Expand Down
5 changes: 4 additions & 1 deletion infra/{{app_name}}/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,10 @@ module "service" {
},
module.app_config.enable_identity_provider ? {
identity_provider_access = module.identity_provider_client[0].access_policy_arn,
} : {}
} : {},
module.app_config.enable_notifications ? {
notifications_access = module.notifications[0].access_policy_arn,
} : {},
)

is_temporary = local.is_temporary
Expand Down
14 changes: 13 additions & 1 deletion template-only-app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from datetime import datetime

import click
from flask import Flask, render_template
from flask import Flask, redirect, render_template, request

import notifications
import storage
from db import get_db_connection

Expand Down Expand Up @@ -63,6 +64,17 @@ def document_upload():
return f'<form method="post" action="{upload_url}" enctype="multipart/form-data">{additional_fields}<input type="file" name="file"><input type="submit"></form>'


@app.route("/email-notifications", methods=["GET", "POST"])
def email_notifications():
if request.method == "POST":
to = request.form["to"]
subject = "Test notification"
message = "This is a system generated test notification. If you received this email in error, please ignore it."
logger.info("Sending test email to %s", to)
notifications.send_email(to, subject, message)
return f'<form method="post">Send test email to:<input type="email" name="to"><input type="submit"></form>'


@app.route("/secrets")
def secrets():
secret_sauce = os.environ["SECRET_SAUCE"]
Expand Down
38 changes: 38 additions & 0 deletions template-only-app/notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os
import boto3

def send_email(to: str, subject: str, message: str):
pinpoint_client = boto3.client("pinpoint")
app_id = os.environ["AWS_PINPOINT_APP_ID"]

response = pinpoint_client.send_messages(
ApplicationId=app_id,
MessageRequest={
"Addresses": {
to: {
"ChannelType": "EMAIL"
}
},
"MessageConfiguration": {
"EmailMessage": {
"SimpleEmail": {
"Subject": {
"Charset": "UTF-8",
"Data": subject
},
"HtmlPart": {
"Charset": "UTF-8",
"Data": message
},
"TextPart": {
"Charset": "UTF-8",
"Data": message
}
}
}
}
}
)
print(response)

return response
8 changes: 8 additions & 0 deletions template-only-app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
<body>
<main>
<h1>Hello, world</h1>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/health">Health</a></li>
<li><a href="/migrations">Migrations</a></li>
<li><a href="/document-upload">Document Upload</a></li>
<li><a href="/email-notifications">Email Notifications</a></li>
<li><a href="/secrets">Secrets</a></li>
</ul>
</main>
</body>
</html>

0 comments on commit d22cad4

Please sign in to comment.