-
Notifications
You must be signed in to change notification settings - Fork 45
/
bbb-on-aws-ses.template.yaml
185 lines (168 loc) · 6.05 KB
/
bbb-on-aws-ses.template.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
---
AWSTemplateFormatVersion: '2010-09-09'
Description: >
This Cloudformation Template deploys a Custom SES Provider with DNS validation support.
Disclaimer: Not for production use. Demo and testing purposes only.
Author: David Surey <[email protected]>
Parameters:
BBBHostedZone:
Description: Hosted zone in which the DNS entries for SES should be created
Type: String
Resources:
BBBSESProviderLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Policies:
- PolicyName: CFNSESResourceRecordProvider
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ses:VerifyDomainDkim
- ses:DeleteIdentity
- ses:ListIdentities
- ses:VerifyDomainIdentity
- ses:DescribeActiveReceiptRuleSet
- ses:SetActiveReceiptRuleSet
- ses:GetIdentityVerificationAttributes
- ses:GetIdentityNotificationAttributes
- ses:SetIdentityNotificationTopic
- ses:SetIdentityHeadersInNotificationsEnabled
- ses:SetIdentityFeedbackForwardingEnabled
Resource: '*'
- Effect: Allow
Action:
- route53:GetHostedZone
- route53:ChangeResourceRecordSets
- route53:ListResourceRecordSets
Resource: !Sub "arn:aws:route53:::hostedzone/${BBBHostedZone}"
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource:
- !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${AWS::StackName}-ses-provider'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
BBBSESProviderLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 7
LogGroupName: !Join ["", ["/", !Ref "AWS::StackName", !Ref BBBSESProvider]]
BBBSESProvider:
Type: AWS::Lambda::Function
DependsOn:
- BBBSESProviderLambdaRole
Properties:
FunctionName: !Sub ${AWS::StackName}-ses-provider
Description: CloudFormation SES provider implementation
Code:
Code:
S3Bucket: !Sub "binxio-public-${AWS::Region}"
S3Key: lambdas/cfn-ses-provider-0.8.3.zip
Handler: ses.handler
MemorySize: 128
Role: !GetAtt 'BBBSESProviderLambdaRole.Arn'
Runtime: python3.9
Timeout: 30
BBBSMTPSecretProviderLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
BBBSMTPSecretProviderLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 7
LogGroupName: !Join ["", ["/", !Ref "AWS::StackName", !Ref BBBSMTPSecretProvider]]
BBBSMTPSecretProvider:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.9
Handler: index.main
Role: !Sub ${BBBSMTPSecretProviderLambdaRole.Arn}
Timeout: 60
Code:
ZipFile: |
import cfnresponse
import json
import hmac
import hashlib
import base64
import os
# Values that are required to calculate the signature. These values should
# never change.
DATE = "11111111"
SERVICE = "ses"
MESSAGE = "SendRawEmail"
TERMINAL = "aws4_request"
VERSION = 0x04
def sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def calculateKey(secretAccessKey, region):
signature = sign(("AWS4" + secretAccessKey).encode('utf-8'), DATE)
signature = sign(signature, region)
signature = sign(signature, SERVICE)
signature = sign(signature, TERMINAL)
signature = sign(signature, MESSAGE)
signatureAndVersion = bytes([VERSION]) + signature
smtpPassword = base64.b64encode(signatureAndVersion)
return(smtpPassword.decode('utf-8'))
def main(event, context):
print('## ENVIRONMENT VARIABLES')
print(os.environ)
print('## EVENT')
print(event)
try:
secret = event['ResourceProperties']['SecretKey']
region = event['ResourceProperties']['Region']
plainsmtpPassword = calculateKey(secret,region)
cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, plainsmtpPassword)
except Exception as e:
print(e)
cfnresponse.send(event, context, cfnresponse.FAILED, {}, "This did not work, Sherlock")
Outputs:
BBBSESProvider:
Description: Name of the SES Provider
Value:
Ref: BBBSESProvider
BBBSESProviderLogGroup:
Description: Name of the SES Provider Log Group
Value:
Ref: BBBSESProviderLogGroup
BBBSESProviderLambdaRole:
Description: Name of the SES Provider Lambda Role
Value:
Ref: BBBSESProviderLambdaRole
BBBSESProviderArn:
Description: The Arn of the SES Provider Lambda Function
Value: !Sub ${BBBSESProvider.Arn}
BBBSMTPSecretProvider:
Description: Name of the Secrets Provider
Value:
Ref: BBBSMTPSecretProvider
BBBSMTPSecretProviderLambdaRole:
Description: Name of the Secrets Provider Lambda Role
Value:
Ref: BBBSMTPSecretProviderLambdaRole
BBBSMTPSecretProviderArn:
Description: The Arn of the Secrets Provider Lambda Function
Value: !Sub ${BBBSMTPSecretProvider.Arn}