-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinfra.py
147 lines (133 loc) · 4.05 KB
/
infra.py
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
import os
from urllib.parse import urlparse
from troposphere import GetAtt
from troposphere import Ref
from troposphere import Template
from troposphere import Join
from troposphere import sns
from troposphere import awslambda
from troposphere import iam
from troposphere import apigatewayv2
from jinja2 import Template as jinja_template
domain = os.environ.get("EMAIL_CONTACT_DOMAIN", "http://test")
parsed_domain = urlparse(domain)
if not parsed_domain.scheme:
raise ValueError(f"Domain '{domain}' requires a scheme. This is needed for CORS headers.")
email_target = os.environ.get("EMAIL_TARGET", "[email protected]")
recaptcha_secret = os.environ.get("RECAPTCHA_SECRET")
cdomain = parsed_domain.netloc.replace(".", "-")[:24] # AWS names have a character limit
### SNS
send_to = sns.Subscription(
Protocol="email",
Endpoint=email_target
)
topic = sns.Topic(
"EmailContactForm",
Subscription=[send_to]
)
### Lambda
environment = {
"ORIGIN_DOMAIN": domain,
"TOPIC_ARN": Ref(topic)
}
if recaptcha_secret:
environment["RECAPTCHA_SECRET"] = recaptcha_secret
lambda_environment = awslambda.Environment(
Variables=environment
)
sns_publish_policy = iam.Policy(
PolicyName=f"lambda-sns-publish-policy-contact-form-{cdomain}",
PolicyDocument={
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:*:*:*"
}]
},
)
lambda_logging_policy = iam.Policy(
PolicyName=f"lambda-logging-policy-contact-form-{cdomain}",
PolicyDocument={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": Join(
values=["arn", "aws", "logs", Ref("AWS::Region"), Ref("AWS::AccountId"), "*"],
delimiter=":"
)
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": Join(
values=["arn", "aws", "logs", Ref("AWS::Region"), Ref("AWS::AccountId"), "log-group", "*"],
delimiter=":"
)
}
]
}
)
role = iam.Role(
"LambdaExecutionRole",
Description=f"IAM Execution Role for contact form "
f"lambda function on {domain}",
RoleName=f"lambda-role-contact-form-{cdomain}",
AssumeRolePolicyDocument={
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {
"Service": ["lambda.amazonaws.com"]
},
"Action": ["sts:AssumeRole"]
}
},
Policies=[sns_publish_policy, lambda_logging_policy]
)
with open("lambda_handler.py", 'r') as fin:
code = fin.read()
lambda_function = awslambda.Function(
"LambdaHandler",
FunctionName=f"lambda-handler-contact-form-{cdomain}",
Description=f"Lambda function for contact form on {domain}",
Environment=lambda_environment,
Code=awslambda.Code(
ZipFile=code
),
Handler="index.lambda_handler",
Runtime="python3.7",
MemorySize=128,
Role=GetAtt(role, "Arn")
)
### API Gateway
api = apigatewayv2.Api(
"HttpApi",
Name=f"api-contact-form-{cdomain}",
Description=f"API Gateway for contact form on {domain}",
ProtocolType="HTTP",
Target=GetAtt(lambda_function, "Arn")
)
api_gateway_lambda_permission = awslambda.Permission(
"ApiGatewayLambdaPermission",
Action="lambda:InvokeFunction",
FunctionName=GetAtt(lambda_function, "Arn"),
Principal="apigateway.amazonaws.com",
SourceArn=Join(
values=["arn", "aws", "execute-api", Ref("AWS::Region"), Ref("AWS::AccountId"),
Join(values=[Ref(api), "*"], delimiter="/")],
delimiter=":"
)
)
t = Template()
t.add_resource(topic)
t.add_resource(role)
t.add_resource(lambda_function)
t.add_resource(api)
t.add_resource(api_gateway_lambda_permission)
print(t.to_yaml())