hello
Last active
March 28, 2024 20:40
-
-
Save jhw/a0bba03627b6210acec2dc3d018bc2e0 to your computer and use it in GitHub Desktop.
AWS ApiGatewayV2 web api demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
env | |
*.pyc | |
__pycache__ | |
tmp | |
setenv-priv.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AppName=apigwv2-webapi-demo | |
AllowedOrigins=http://localhost:3000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- this file needs to be served from a server in order to test CORS; server needs to be specified as an allowed origin; python3 -m http.server 3000 --> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>CORS 200</title> | |
<script> | |
window.onload = function() { | |
fetch('https://apigwv2demo.spaaseu.link/public-get?message=Hello%20World') | |
.then(response => { | |
if (!response.ok) { | |
throw new Error('Network response was not ok'); | |
} | |
return response.text(); | |
}) | |
.then(data => { | |
document.getElementById('response').textContent = data; | |
}) | |
.catch(error => { | |
console.error('There has been a problem with your fetch operation:', error); | |
document.getElementById('response').textContent = 'Error: Could not retrieve data. Check console for details.'; | |
}); | |
}; | |
</script> | |
</head> | |
<body> | |
<div id="response">Loading...</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- this file needs to be served from a server in order to test CORS; server needs to be specified as an allowed origin; python3 -m http.server 3000 --> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>CORS 400</title> | |
<script> | |
window.onload = function() { | |
fetch('https://apigwv2demo.spaaseu.link/public-get?whatevs=Hello%20World') | |
.then(response => { | |
if (!response.ok) { | |
throw new Error('Network response was not ok'); | |
} | |
return response.text(); | |
}) | |
.then(data => { | |
document.getElementById('response').textContent = data; | |
}) | |
.catch(error => { | |
console.error('There has been a problem with your fetch operation:', error); | |
document.getElementById('response').textContent = 'Error: Could not retrieve data. Check console for details.'; | |
}); | |
}; | |
</script> | |
</head> | |
<body> | |
<div id="response">Loading...</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, os, re, sys, yaml | |
def hungarorise(text): | |
return "".join([tok.capitalize() | |
for tok in re.split("\\-|\\_", text)]) | |
def fetch_outputs(cf, stackname): | |
outputs={} | |
for stack in cf.describe_stacks()["Stacks"]: | |
if (stack["StackName"].startswith(stackname) and | |
"Outputs" in stack): | |
for output in stack["Outputs"]: | |
outputs[output["OutputKey"]]=output["OutputValue"] | |
return outputs | |
if __name__=="__main__": | |
try: | |
props=dict([tuple(row.split("=")) | |
for row in open("app.props").read().split("\n") | |
if row!='']) | |
stackname=props["AppName"] | |
if len(sys.argv) < 3: | |
raise RuntimeError("please enter email, password") | |
email, password = sys.argv[1:3] | |
cf=boto3.client("cloudformation") | |
outputs=fetch_outputs(cf, stackname) | |
userpoolkey=hungarorise("app-user-pool") | |
if userpoolkey not in outputs: | |
raise RuntimeError("userpool not found") | |
userpool=outputs[userpoolkey] | |
clientkey=hungarorise("app-user-pool-client") | |
if clientkey not in outputs: | |
raise RuntimeError("client not found") | |
client=outputs[clientkey] | |
cognito=boto3.client("cognito-idp") | |
resp0=cognito.sign_up(ClientId=client, | |
Username=email, | |
Password=password) | |
print (yaml.safe_dump(resp0, | |
default_flow_style=False)) | |
resp1=cognito.admin_confirm_sign_up(UserPoolId=userpool, | |
Username=email) | |
print (yaml.safe_dump(resp1, | |
default_flow_style=False)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation delete-stack --stack-name $AppName |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, os, re, sys, yaml | |
def hungarorise(text): | |
return "".join([tok.capitalize() | |
for tok in re.split("\\-|\\_", text)]) | |
def fetch_outputs(cf, stackname): | |
outputs={} | |
for stack in cf.describe_stacks()["Stacks"]: | |
if (stack["StackName"].startswith(stackname) and | |
"Outputs" in stack): | |
for output in stack["Outputs"]: | |
outputs[output["OutputKey"]]=output["OutputValue"] | |
return outputs | |
if __name__=="__main__": | |
try: | |
props=dict([tuple(row.split("=")) | |
for row in open("app.props").read().split("\n") | |
if row!='']) | |
stackname=props["AppName"] | |
if len(sys.argv) < 2: | |
raise RuntimeError("please enter email") | |
email=sys.argv[1] | |
cf=boto3.client("cloudformation") | |
outputs=fetch_outputs(cf, stackname) | |
userpoolkey=hungarorise("app-user-pool") | |
if userpoolkey not in outputs: | |
raise RuntimeError("userpool not found") | |
userpool=outputs[userpoolkey] | |
cognito=boto3.client("cognito-idp") | |
resp=cognito.admin_delete_user(UserPoolId=userpool, | |
Username=email) | |
print (yaml.safe_dump(resp, | |
default_flow_style=False)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
echo "DomainName: $DOMAIN_NAME" | |
echo "CertificateArn: $CERTIFICATE_ARN" | |
aws cloudformation deploy --stack-name $AppName --template-file stack.json --capabilities CAPABILITY_NAMED_IAM --parameter-overrides DomainName=$DOMAIN_NAME CertificateArn=$CERTIFICATE_ARN AllowedOrigins=$AllowedOrigins | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, os, re, sys, time | |
def fetch_log_events(logs, kwargs): | |
events, token = [], None | |
while True: | |
if token: | |
kwargs["nextToken"]=token | |
resp=logs.filter_log_events(**kwargs) | |
events+=resp["events"] | |
if "nextToken" in resp: | |
token=resp["nextToken"] | |
else: | |
break | |
return sorted(events, | |
key=lambda x: x["timestamp"]) | |
if __name__=="__main__": | |
try: | |
if len(sys.argv) < 3: | |
raise RuntimeError("please enter lambda name, window") | |
lambdaname, window = sys.argv[1:3] | |
if not re.search("^\\d+$", window): | |
raise RuntimeError("window is invalid") | |
window=int(window) | |
logs=boto3.client("logs") | |
starttime=int(1000*(time.time()-window)) | |
loggroupname="/aws/lambda/%s" % lambdaname | |
kwargs={"logGroupName": loggroupname, | |
"startTime": starttime, | |
"interleaved": True} | |
events=fetch_log_events(logs, kwargs) | |
for event in events: | |
msg=re.sub("\\r|\\n", "", event["message"]) | |
print (msg) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json, os | |
if __name__=="__main__": | |
if not os.path.exists("tmp"): | |
os.mkdir("tmp") | |
struct=json.loads(open("stack.json").read()) | |
with open("tmp/stack.json", 'w') as f: | |
f.write(json.dumps(struct, | |
indent=2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation describe-stack-events --stack-name $AppName --query "StackEvents[].{\"1.Timestamp\":Timestamp,\"2.Id\":LogicalResourceId,\"3.Type\":ResourceType,\"4.Status\":ResourceStatus,\"5.Reason\":ResourceStatusReason}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation describe-stacks --stack-name $AppName --query 'Stacks[0].Outputs' --output table |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
. app.props | |
aws cloudformation describe-stack-resources --stack-name $AppName --query "StackResources[].{\"1.Timestamp\":Timestamp,\"2.LogicalId\":LogicalResourceId,\"3.PhysicalId\":PhysicalResourceId,\"4.Type\":ResourceType,\"5.Status\":ResourceStatus}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
aws cloudformation describe-stacks --query "Stacks[].{\"1.Name\":StackName,\"2.Status\":StackStatus}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, os, re, sys, yaml | |
def hungarorise(text): | |
return "".join([tok.capitalize() | |
for tok in re.split("\\-|\\_", text)]) | |
def fetch_outputs(cf, stackname): | |
outputs={} | |
for stack in cf.describe_stacks()["Stacks"]: | |
if (stack["StackName"].startswith(stackname) and | |
"Outputs" in stack): | |
for output in stack["Outputs"]: | |
outputs[output["OutputKey"]]=output["OutputValue"] | |
return outputs | |
if __name__=="__main__": | |
try: | |
props=dict([tuple(row.split("=")) | |
for row in open("app.props").read().split("\n") | |
if row!='']) | |
stackname=props["AppName"] | |
cf=boto3.client("cloudformation") | |
outputs=fetch_outputs(cf, stackname) | |
userpoolkey=hungarorise("app-user-pool") | |
if userpoolkey not in outputs: | |
raise RuntimeError("userpool not found") | |
userpool=outputs[userpoolkey] | |
cognito=boto3.client("cognito-idp") | |
resp=cognito.list_users(UserPoolId=userpool) | |
print (yaml.safe_dump(resp, | |
default_flow_style=False)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, json, os, re, requests, sys, urllib.parse | |
def hungarorise(text): | |
return "".join([tok.capitalize() | |
for tok in re.split("\\-|\\_", text)]) | |
def fetch_outputs(cf, stackname): | |
outputs={} | |
for stack in cf.describe_stacks()["Stacks"]: | |
if (stack["StackName"].startswith(stackname) and | |
"Outputs" in stack): | |
for output in stack["Outputs"]: | |
outputs[output["OutputKey"]]=output["OutputValue"] | |
return outputs | |
if __name__=="__main__": | |
try: | |
props=dict([tuple(row.split("=")) | |
for row in open("app.props").read().split("\n") | |
if row!='']) | |
stackname=props["AppName"] | |
if len(sys.argv) < 4: | |
raise RuntimeError("please enter email, password, message") | |
email, password, message = sys.argv[1:4] | |
cf=boto3.client("cloudformation") | |
outputs=fetch_outputs(cf, stackname) | |
userpoolkey=hungarorise("app-user-pool") | |
if userpoolkey not in outputs: | |
raise RuntimeError("userpool not found") | |
userpool=outputs[userpoolkey] | |
clientkey=hungarorise("app-user-pool-client") | |
if clientkey not in outputs: | |
raise RuntimeError("client not found") | |
client=outputs[clientkey] | |
cg=boto3.client("cognito-idp") | |
authresp=cg.admin_initiate_auth(UserPoolId=userpool, | |
ClientId=client, | |
AuthFlow='ADMIN_NO_SRP_AUTH', | |
AuthParameters={"USERNAME": email, | |
"PASSWORD": password}) | |
token=authresp["AuthenticationResult"]["IdToken"] | |
print (token) | |
url="https://apigwv2demo.spaaseu.link/private-get?message=%s" % urllib.parse.quote(message) | |
headers={"Origin": "http://localhost:3000", | |
"Authorization": "Bearer %s" % token, | |
"Accept": "application/json"} | |
resp=requests.get(url, | |
headers=headers) | |
print ("%s > %s" % (resp.status_code, | |
resp.text)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from botocore.exceptions import ClientError | |
import boto3, json, os, re, requests, sys, urllib.parse | |
def hungarorise(text): | |
return "".join([tok.capitalize() | |
for tok in re.split("\\-|\\_", text)]) | |
def fetch_outputs(cf, stackname): | |
outputs={} | |
for stack in cf.describe_stacks()["Stacks"]: | |
if (stack["StackName"].startswith(stackname) and | |
"Outputs" in stack): | |
for output in stack["Outputs"]: | |
outputs[output["OutputKey"]]=output["OutputValue"] | |
return outputs | |
if __name__=="__main__": | |
try: | |
props=dict([tuple(row.split("=")) | |
for row in open("app.props").read().split("\n") | |
if row!='']) | |
stackname=props["AppName"] | |
if len(sys.argv) < 4: | |
raise RuntimeError("please enter email, password, message") | |
email, password, message = sys.argv[1:4] | |
cf=boto3.client("cloudformation") | |
outputs=fetch_outputs(cf, stackname) | |
userpoolkey=hungarorise("app-user-pool") | |
if userpoolkey not in outputs: | |
raise RuntimeError("userpool not found") | |
userpool=outputs[userpoolkey] | |
clientkey=hungarorise("app-user-pool-client") | |
if clientkey not in outputs: | |
raise RuntimeError("client not found") | |
client=outputs[clientkey] | |
cg=boto3.client("cognito-idp") | |
authresp=cg.admin_initiate_auth(UserPoolId=userpool, | |
ClientId=client, | |
AuthFlow='ADMIN_NO_SRP_AUTH', | |
AuthParameters={"USERNAME": email, | |
"PASSWORD": password}) | |
token=authresp["AuthenticationResult"]["IdToken"] | |
print (token) | |
url="https://apigwv2demo.spaaseu.link/private-post" | |
headers={"Origin": "http://localhost:3000", | |
"Authorization": "Bearer %s" % token, | |
"Content-Type": "application/json"} | |
struct={"message": message} | |
resp=requests.post(url, | |
headers=headers, | |
data=json.dumps(struct)) | |
print ("%s > %s" % (resp.status_code, | |
resp.text)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
except ClientError as error: | |
print ("Error: %s" % str(error)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests, sys, urllib.parse | |
if __name__=="__main__": | |
try: | |
if len(sys.argv) < 2: | |
raise RuntimeError("please enter message") | |
message=sys.argv[1] | |
url="https://apigwv2demo.spaaseu.link/public-get?message=%s" % urllib.parse.quote(message) | |
headers={"Origin": "http://localhost:3000"} | |
resp=requests.get(url, | |
headers=headers) | |
print ("%s > %s" % (resp.status_code, | |
resp.text)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json, requests, sys | |
if __name__=="__main__": | |
try: | |
if len(sys.argv) < 2: | |
raise RuntimeError("please enter message") | |
message=sys.argv[1] | |
url="https://apigwv2demo.spaaseu.link/public-post" | |
headers={"Origin": "http://localhost:3000", | |
"Content-Type": "application/json"} | |
struct={"message": message} | |
resp=requests.post(url, | |
headers=headers, | |
data=json.dumps(struct)) | |
print ("%s > %s" % (resp.status_code, | |
resp.text)) | |
except RuntimeError as error: | |
print ("Error: %s" % str(error)) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
awscli | |
boto3 | |
botocore | |
pyyaml | |
requests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
export AWS_DEFAULT_OUTPUT=table | |
export AWS_PROFILE=#{your-aws-profile-here} | |
export CERTIFICATE_ARN=#{your-certificate-arn-here} | |
export DOMAIN_NAME=#{your-fully-qualified-domain-name-here} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"Outputs": { | |
"AppApi": { | |
"Value": { | |
"Ref": "AppApi" | |
} | |
}, | |
"AppIdentityPool": { | |
"Value": { | |
"Ref": "AppIdentityPool" | |
} | |
}, | |
"AppStage": { | |
"Value": { | |
"Ref": "AppStage" | |
} | |
}, | |
"AppUserPool": { | |
"Value": { | |
"Ref": "AppUserPool" | |
} | |
}, | |
"AppUserPoolClient": { | |
"Value": { | |
"Ref": "AppUserPoolClient" | |
} | |
} | |
}, | |
"Parameters": { | |
"AllowedOrigins": { | |
"Type": "String" | |
}, | |
"CertificateArn": { | |
"Type": "String" | |
}, | |
"DomainName": { | |
"Type": "String" | |
} | |
}, | |
"Resources": { | |
"AppApi": { | |
"Properties": { | |
"CorsConfiguration": { | |
"AllowCredentials": true, | |
"AllowHeaders": [ | |
"Content-Type", | |
"X-Amz-Date", | |
"Authorization", | |
"X-Api-Key" | |
], | |
"AllowMethods": [ | |
"GET", | |
"POST" | |
], | |
"AllowOrigins": { | |
"Fn::Split": [ | |
"|", | |
{ | |
"Ref": "AllowedOrigins" | |
} | |
] | |
}, | |
"ExposeHeaders": [ | |
"X-Custom-Header" | |
], | |
"MaxAge": 3600 | |
}, | |
"Name": { | |
"Fn::Sub": "app-api-${AWS::StackName}" | |
}, | |
"ProtocolType": "HTTP" | |
}, | |
"Type": "AWS::ApiGatewayV2::Api" | |
}, | |
"AppApiMapping": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"DomainName": { | |
"Ref": "DomainName" | |
}, | |
"Stage": { | |
"Ref": "AppStage" | |
} | |
}, | |
"Type": "AWS::ApiGatewayV2::ApiMapping" | |
}, | |
"AppAuthorizer": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"AuthorizerType": "JWT", | |
"IdentitySource": [ | |
"$request.header.Authorization" | |
], | |
"JwtConfiguration": { | |
"Audience": [ | |
{ | |
"Ref": "AppUserPoolClient" | |
} | |
], | |
"Issuer": { | |
"Fn::Sub": "https://cognito-idp.${AWS::Region}.amazonaws.com/${AppUserPool}" | |
} | |
}, | |
"Name": { | |
"Fn::Sub": "app-authorizer-${AWS::StackName}" | |
} | |
}, | |
"Type": "AWS::ApiGatewayV2::Authorizer" | |
}, | |
"AppDomainName": { | |
"Properties": { | |
"DomainName": { | |
"Ref": "DomainName" | |
}, | |
"DomainNameConfigurations": [ | |
{ | |
"CertificateArn": { | |
"Ref": "CertificateArn" | |
} | |
} | |
] | |
}, | |
"Type": "AWS::ApiGatewayV2::DomainName" | |
}, | |
"AppIdentityPool": { | |
"Properties": { | |
"AllowUnauthenticatedIdentities": true, | |
"CognitoIdentityProviders": [ | |
{ | |
"ClientId": { | |
"Ref": "AppUserPoolClient" | |
}, | |
"ProviderName": { | |
"Fn::GetAtt": [ | |
"AppUserPool", | |
"ProviderName" | |
] | |
} | |
} | |
] | |
}, | |
"Type": "AWS::Cognito::IdentityPool" | |
}, | |
"AppIdentityPoolAuthorizedPolicy": { | |
"Properties": { | |
"PolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"cognito-sync:*" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
}, | |
{ | |
"Action": [ | |
"cognito-identity:*" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
}, | |
{ | |
"Action": [ | |
"lambda:InvokeFunction" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
], | |
"Version": "2012-10-17" | |
}, | |
"PolicyName": { | |
"Fn::Sub": "app-identity-pool-authorized-policy-${AWS::StackName}" | |
}, | |
"Roles": [ | |
{ | |
"Ref": "AppIdentityPoolAuthorizedRole" | |
} | |
] | |
}, | |
"Type": "AWS::IAM::Policy" | |
}, | |
"AppIdentityPoolAuthorizedRole": { | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"sts:AssumeRoleWithWebIdentity" | |
], | |
"Condition": { | |
"ForAnyValue:StringLike": { | |
"cognito-identity.amazonaws.com:amr": "authorized" | |
}, | |
"StringEquals": { | |
"cognito-identity.amazonaws.com:aud": { | |
"Ref": "AppIdentityPool" | |
} | |
} | |
}, | |
"Effect": "Allow", | |
"Principal": { | |
"Federated": "cognito-identity.amazonaws.com" | |
} | |
} | |
], | |
"Version": "2012-10-17" | |
} | |
}, | |
"Type": "AWS::IAM::Role" | |
}, | |
"AppIdentityPoolRoleAttachment": { | |
"Properties": { | |
"IdentityPoolId": { | |
"Ref": "AppIdentityPool" | |
}, | |
"Roles": { | |
"authenticated": { | |
"Fn::GetAtt": [ | |
"AppIdentityPoolAuthorizedRole", | |
"Arn" | |
] | |
}, | |
"unauthenticated": { | |
"Fn::GetAtt": [ | |
"AppIdentityPoolUnauthorizedRole", | |
"Arn" | |
] | |
} | |
} | |
}, | |
"Type": "AWS::Cognito::IdentityPoolRoleAttachment" | |
}, | |
"AppIdentityPoolUnauthorizedPolicy": { | |
"Properties": { | |
"PolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"cognito-sync:*" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
], | |
"Version": "2012-10-17" | |
}, | |
"PolicyName": { | |
"Fn::Sub": "app-identity-pool-unauthorized-policy-${AWS::StackName}" | |
}, | |
"Roles": [ | |
{ | |
"Ref": "AppIdentityPoolUnauthorizedRole" | |
} | |
] | |
}, | |
"Type": "AWS::IAM::Policy" | |
}, | |
"AppIdentityPoolUnauthorizedRole": { | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"sts:AssumeRoleWithWebIdentity" | |
], | |
"Condition": { | |
"ForAnyValue:StringLike": { | |
"cognito-identity.amazonaws.com:amr": "unauthorized" | |
}, | |
"StringEquals": { | |
"cognito-identity.amazonaws.com:aud": { | |
"Ref": "AppIdentityPool" | |
} | |
} | |
}, | |
"Effect": "Allow", | |
"Principal": { | |
"Federated": "cognito-identity.amazonaws.com" | |
} | |
} | |
], | |
"Version": "2012-10-17" | |
} | |
}, | |
"Type": "AWS::IAM::Role" | |
}, | |
"AppPrivateGetFunction": { | |
"Properties": { | |
"Code": { | |
"ZipFile": "Headers = {\n \"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,GET\"\n}\n\ndef handler(event, context = None, respheaders = Headers):\n try:\n if \"headers\" not in event:\n raise RuntimeError(\"request headers not found\")\n reqheaders = event[\"headers\"]\n if \"origin\" not in reqheaders:\n raise RuntimeError(\"origin not present in request headers\")\n respheaders[\"Access-Control-Allow-Origin\"] = reqheaders[\"origin\"]\n if \"queryStringParameters\" not in event:\n raise RuntimeError(\"querystring not found\")\n qs = event[\"queryStringParameters\"]\n if \"message\" not in qs:\n raise RuntimeError(\"message parameter not found\")\n message = qs[\"message\"]\n if message in [\"\", None]:\n raise RuntimeError(\"message parameter can't be blank\")\n respbody = f\"you sent '{message}' via GET\" \n return {\"statusCode\": 200,\n \"headers\": respheaders,\n \"body\": respbody}\n except RuntimeError as error:\n return {\"statusCode\": 400,\n \"headers\": respheaders,\n \"body\": str(error)}\n\nif __name__ == \"__main__\":\n for headers in [{},\n {\"origin\": \"http://localhost:3000\"}]:\n for event in [{},\n {\"queryStringParameters\": {\"message\": \"Hello World\"}},\n {\"queryStringParameters\": {\"message\": \"\"}},\n {\"queryStringParameters\": {\"messag\": \"Hello World\"}}]:\n event[\"headers\"] = headers # NB\n resp = handler(event)\n print (\"%s\\t%s\" % (resp[\"statusCode\"], resp[\"body\"]))\n\n" | |
}, | |
"Handler": "index.handler", | |
"MemorySize": 512, | |
"Role": { | |
"Fn::GetAtt": [ | |
"AppPrivateGetRole", | |
"Arn" | |
] | |
}, | |
"Runtime": "python3.10", | |
"Timeout": 5 | |
}, | |
"Type": "AWS::Lambda::Function" | |
}, | |
"AppPrivateGetIntegration": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"IntegrationMethod": "POST", | |
"IntegrationType": "AWS_PROXY", | |
"IntegrationUri": { | |
"Fn::Sub": [ | |
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations", | |
{ | |
"arn": { | |
"Fn::GetAtt": [ | |
"AppPrivateGetFunction", | |
"Arn" | |
] | |
} | |
} | |
] | |
}, | |
"PayloadFormatVersion": "2.0" | |
}, | |
"Type": "AWS::ApiGatewayV2::Integration" | |
}, | |
"AppPrivateGetPermission": { | |
"Properties": { | |
"Action": "lambda:InvokeFunction", | |
"FunctionName": { | |
"Ref": "AppPrivateGetFunction" | |
}, | |
"Principal": "apigateway.amazonaws.com", | |
"SourceArn": { | |
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppApi}/${AppStage}/GET/private-get" | |
} | |
}, | |
"Type": "AWS::Lambda::Permission" | |
}, | |
"AppPrivateGetPolicy": { | |
"Properties": { | |
"PolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:PutLogEvents" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
}, | |
{ | |
"Action": [ | |
"s3:GetObject" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
], | |
"Version": "2012-10-17" | |
}, | |
"PolicyName": { | |
"Fn::Sub": "app-private-get-policy-${AWS::StackName}" | |
}, | |
"Roles": [ | |
{ | |
"Ref": "AppPrivateGetRole" | |
} | |
] | |
}, | |
"Type": "AWS::IAM::Policy" | |
}, | |
"AppPrivateGetRole": { | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"sts:AssumeRole" | |
], | |
"Effect": "Allow", | |
"Principal": { | |
"Service": "lambda.amazonaws.com" | |
} | |
} | |
], | |
"Version": "2012-10-17" | |
} | |
}, | |
"Type": "AWS::IAM::Role" | |
}, | |
"AppPrivateGetRoute": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"AuthorizationType": "JWT", | |
"AuthorizerId": { | |
"Ref": "AppAuthorizer" | |
}, | |
"RouteKey": "GET /private-get", | |
"Target": { | |
"Fn::Sub": "integrations/${AppPrivateGetIntegration}" | |
} | |
}, | |
"Type": "AWS::ApiGatewayV2::Route" | |
}, | |
"AppPrivatePostFunction": { | |
"Properties": { | |
"Code": { | |
"ZipFile": "import base64, json\n\nHeaders = {\n \"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,POST\"\n}\n\ndef handler(event, context = None, respheaders = Headers):\n try:\n if \"headers\" not in event:\n raise RuntimeError(\"request headers not found\")\n reqheaders = event[\"headers\"]\n if \"origin\" not in reqheaders:\n raise RuntimeError(\"origin not present in request headers\")\n respheaders[\"Access-Control-Allow-Origin\"] = reqheaders[\"origin\"]\n if \"body\" not in event:\n raise RuntimeError(\"body not found\")\n rawbody = event[\"body\"]\n if (\"isBase64Encoded\" in event and\n event[\"isBase64Encoded\"]):\n rawbody = base64.b64decode(rawbody)\n try:\n reqbody = json.loads(rawbody)\n except:\n raise RuntimeError(\"couldn't parse JSON request body\")\n if not isinstance(reqbody, dict):\n raise RuntimeError(\"request body must be a dict\")\n if not \"message\" in reqbody:\n raise RuntimeError(\"message attribute not found\")\n message = reqbody[\"message\"]\n if message in [\"\", None]:\n raise RuntimeError(\"message attribute can't be blank\")\n respbody = f\"you sent '{message}' via POST\"\n return {\"statusCode\": 200,\n \"headers\": respheaders,\n \"body\": respbody}\n except RuntimeError as error:\n return {\"statusCode\": 400,\n \"headers\": respheaders,\n \"body\": str(error)}\n\nif __name__ == \"__main__\":\n for headers in [{},\n {\"origin\": \"http://localhost:3000\"}]:\n for event in [{},\n {\"body\": json.dumps([])},\n {\"body\": json.dumps({\"message\": \"Hello World\"})},\n {\"body\": base64.b64encode(json.dumps({\"message\": \"Hello World\"}).encode(\"utf-8\")),\n \"isBase64Encoded\": True},\n {\"body\": json.dumps({\"message\": \"\"})}, \n {\"body\": json.dumps({\"messag\": \"Hello World\"})}]:\n event[\"headers\"] = headers # NB\n resp = handler(event)\n print (\"%s\\t%s\" % (resp[\"statusCode\"], resp[\"body\"]))\n \n" | |
}, | |
"Handler": "index.handler", | |
"MemorySize": 512, | |
"Role": { | |
"Fn::GetAtt": [ | |
"AppPrivatePostRole", | |
"Arn" | |
] | |
}, | |
"Runtime": "python3.10", | |
"Timeout": 5 | |
}, | |
"Type": "AWS::Lambda::Function" | |
}, | |
"AppPrivatePostIntegration": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"IntegrationMethod": "POST", | |
"IntegrationType": "AWS_PROXY", | |
"IntegrationUri": { | |
"Fn::Sub": [ | |
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations", | |
{ | |
"arn": { | |
"Fn::GetAtt": [ | |
"AppPrivatePostFunction", | |
"Arn" | |
] | |
} | |
} | |
] | |
}, | |
"PayloadFormatVersion": "2.0" | |
}, | |
"Type": "AWS::ApiGatewayV2::Integration" | |
}, | |
"AppPrivatePostPermission": { | |
"Properties": { | |
"Action": "lambda:InvokeFunction", | |
"FunctionName": { | |
"Ref": "AppPrivatePostFunction" | |
}, | |
"Principal": "apigateway.amazonaws.com", | |
"SourceArn": { | |
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppApi}/${AppStage}/POST/private-post" | |
} | |
}, | |
"Type": "AWS::Lambda::Permission" | |
}, | |
"AppPrivatePostPolicy": { | |
"Properties": { | |
"PolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:PutLogEvents" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
}, | |
{ | |
"Action": [ | |
"s3:GetObject", | |
"s3:PutObject" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
], | |
"Version": "2012-10-17" | |
}, | |
"PolicyName": { | |
"Fn::Sub": "app-private-post-policy-${AWS::StackName}" | |
}, | |
"Roles": [ | |
{ | |
"Ref": "AppPrivatePostRole" | |
} | |
] | |
}, | |
"Type": "AWS::IAM::Policy" | |
}, | |
"AppPrivatePostRole": { | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"sts:AssumeRole" | |
], | |
"Effect": "Allow", | |
"Principal": { | |
"Service": "lambda.amazonaws.com" | |
} | |
} | |
], | |
"Version": "2012-10-17" | |
} | |
}, | |
"Type": "AWS::IAM::Role" | |
}, | |
"AppPrivatePostRoute": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"AuthorizationType": "JWT", | |
"AuthorizerId": { | |
"Ref": "AppAuthorizer" | |
}, | |
"RouteKey": "POST /private-post", | |
"Target": { | |
"Fn::Sub": "integrations/${AppPrivatePostIntegration}" | |
} | |
}, | |
"Type": "AWS::ApiGatewayV2::Route" | |
}, | |
"AppPublicGetFunction": { | |
"Properties": { | |
"Code": { | |
"ZipFile": "Headers = {\n \"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,GET\"\n}\n\ndef handler(event, context = None, respheaders = Headers):\n try:\n if \"headers\" not in event:\n raise RuntimeError(\"request headers not found\")\n reqheaders = event[\"headers\"]\n if \"origin\" not in reqheaders:\n raise RuntimeError(\"origin not present in request headers\")\n respheaders[\"Access-Control-Allow-Origin\"] = reqheaders[\"origin\"]\n if \"queryStringParameters\" not in event:\n raise RuntimeError(\"querystring not found\")\n qs = event[\"queryStringParameters\"]\n if \"message\" not in qs:\n raise RuntimeError(\"message parameter not found\")\n message = qs[\"message\"]\n if message in [\"\", None]:\n raise RuntimeError(\"message parameter can't be blank\")\n respbody = f\"you sent '{message}' via GET\" \n return {\"statusCode\": 200,\n \"headers\": respheaders,\n \"body\": respbody}\n except RuntimeError as error:\n return {\"statusCode\": 400,\n \"headers\": respheaders,\n \"body\": str(error)}\n\nif __name__ == \"__main__\":\n for headers in [{},\n {\"origin\": \"http://localhost:3000\"}]:\n for event in [{},\n {\"queryStringParameters\": {\"message\": \"Hello World\"}},\n {\"queryStringParameters\": {\"message\": \"\"}},\n {\"queryStringParameters\": {\"messag\": \"Hello World\"}}]:\n event[\"headers\"] = headers # NB\n resp = handler(event)\n print (\"%s\\t%s\" % (resp[\"statusCode\"], resp[\"body\"]))\n\n" | |
}, | |
"Handler": "index.handler", | |
"MemorySize": 512, | |
"Role": { | |
"Fn::GetAtt": [ | |
"AppPublicGetRole", | |
"Arn" | |
] | |
}, | |
"Runtime": "python3.10", | |
"Timeout": 5 | |
}, | |
"Type": "AWS::Lambda::Function" | |
}, | |
"AppPublicGetIntegration": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"IntegrationMethod": "POST", | |
"IntegrationType": "AWS_PROXY", | |
"IntegrationUri": { | |
"Fn::Sub": [ | |
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations", | |
{ | |
"arn": { | |
"Fn::GetAtt": [ | |
"AppPublicGetFunction", | |
"Arn" | |
] | |
} | |
} | |
] | |
}, | |
"PayloadFormatVersion": "2.0" | |
}, | |
"Type": "AWS::ApiGatewayV2::Integration" | |
}, | |
"AppPublicGetPermission": { | |
"Properties": { | |
"Action": "lambda:InvokeFunction", | |
"FunctionName": { | |
"Ref": "AppPublicGetFunction" | |
}, | |
"Principal": "apigateway.amazonaws.com", | |
"SourceArn": { | |
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppApi}/${AppStage}/GET/public-get" | |
} | |
}, | |
"Type": "AWS::Lambda::Permission" | |
}, | |
"AppPublicGetPolicy": { | |
"Properties": { | |
"PolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:PutLogEvents" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
}, | |
{ | |
"Action": [ | |
"s3:GetObject" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
], | |
"Version": "2012-10-17" | |
}, | |
"PolicyName": { | |
"Fn::Sub": "app-public-get-policy-${AWS::StackName}" | |
}, | |
"Roles": [ | |
{ | |
"Ref": "AppPublicGetRole" | |
} | |
] | |
}, | |
"Type": "AWS::IAM::Policy" | |
}, | |
"AppPublicGetRole": { | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"sts:AssumeRole" | |
], | |
"Effect": "Allow", | |
"Principal": { | |
"Service": "lambda.amazonaws.com" | |
} | |
} | |
], | |
"Version": "2012-10-17" | |
} | |
}, | |
"Type": "AWS::IAM::Role" | |
}, | |
"AppPublicGetRoute": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"AuthorizationType": "NONE", | |
"RouteKey": "GET /public-get", | |
"Target": { | |
"Fn::Sub": "integrations/${AppPublicGetIntegration}" | |
} | |
}, | |
"Type": "AWS::ApiGatewayV2::Route" | |
}, | |
"AppPublicPostFunction": { | |
"Properties": { | |
"Code": { | |
"ZipFile": "import base64, json\n\nHeaders = {\n \"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,POST\"\n}\n\ndef handler(event, context = None, respheaders = Headers):\n try:\n if \"headers\" not in event:\n raise RuntimeError(\"request headers not found\")\n reqheaders = event[\"headers\"]\n if \"origin\" not in reqheaders:\n raise RuntimeError(\"origin not present in request headers\")\n respheaders[\"Access-Control-Allow-Origin\"] = reqheaders[\"origin\"]\n if \"body\" not in event:\n raise RuntimeError(\"body not found\")\n rawbody = event[\"body\"]\n if (\"isBase64Encoded\" in event and\n event[\"isBase64Encoded\"]):\n rawbody = base64.b64decode(rawbody)\n try:\n reqbody = json.loads(rawbody)\n except:\n raise RuntimeError(\"couldn't parse JSON request body\")\n if not isinstance(reqbody, dict):\n raise RuntimeError(\"request body must be a dict\")\n if not \"message\" in reqbody:\n raise RuntimeError(\"message attribute not found\")\n message = reqbody[\"message\"]\n if message in [\"\", None]:\n raise RuntimeError(\"message attribute can't be blank\")\n respbody = f\"you sent '{message}' via POST\"\n return {\"statusCode\": 200,\n \"headers\": respheaders,\n \"body\": respbody}\n except RuntimeError as error:\n return {\"statusCode\": 400,\n \"headers\": respheaders,\n \"body\": str(error)}\n\nif __name__ == \"__main__\":\n for headers in [{},\n {\"origin\": \"http://localhost:3000\"}]:\n for event in [{},\n {\"body\": json.dumps([])},\n {\"body\": json.dumps({\"message\": \"Hello World\"})},\n {\"body\": base64.b64encode(json.dumps({\"message\": \"Hello World\"}).encode(\"utf-8\")),\n \"isBase64Encoded\": True},\n {\"body\": json.dumps({\"message\": \"\"})}, \n {\"body\": json.dumps({\"messag\": \"Hello World\"})}]:\n event[\"headers\"] = headers # NB\n resp = handler(event)\n print (\"%s\\t%s\" % (resp[\"statusCode\"], resp[\"body\"]))\n \n" | |
}, | |
"Handler": "index.handler", | |
"MemorySize": 512, | |
"Role": { | |
"Fn::GetAtt": [ | |
"AppPublicPostRole", | |
"Arn" | |
] | |
}, | |
"Runtime": "python3.10", | |
"Timeout": 5 | |
}, | |
"Type": "AWS::Lambda::Function" | |
}, | |
"AppPublicPostIntegration": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"IntegrationMethod": "POST", | |
"IntegrationType": "AWS_PROXY", | |
"IntegrationUri": { | |
"Fn::Sub": [ | |
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations", | |
{ | |
"arn": { | |
"Fn::GetAtt": [ | |
"AppPublicPostFunction", | |
"Arn" | |
] | |
} | |
} | |
] | |
}, | |
"PayloadFormatVersion": "2.0" | |
}, | |
"Type": "AWS::ApiGatewayV2::Integration" | |
}, | |
"AppPublicPostPermission": { | |
"Properties": { | |
"Action": "lambda:InvokeFunction", | |
"FunctionName": { | |
"Ref": "AppPublicPostFunction" | |
}, | |
"Principal": "apigateway.amazonaws.com", | |
"SourceArn": { | |
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppApi}/${AppStage}/POST/public-post" | |
} | |
}, | |
"Type": "AWS::Lambda::Permission" | |
}, | |
"AppPublicPostPolicy": { | |
"Properties": { | |
"PolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:PutLogEvents" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
}, | |
{ | |
"Action": [ | |
"s3:GetObject", | |
"s3:PutObject" | |
], | |
"Effect": "Allow", | |
"Resource": "*" | |
} | |
], | |
"Version": "2012-10-17" | |
}, | |
"PolicyName": { | |
"Fn::Sub": "app-public-post-policy-${AWS::StackName}" | |
}, | |
"Roles": [ | |
{ | |
"Ref": "AppPublicPostRole" | |
} | |
] | |
}, | |
"Type": "AWS::IAM::Policy" | |
}, | |
"AppPublicPostRole": { | |
"Properties": { | |
"AssumeRolePolicyDocument": { | |
"Statement": [ | |
{ | |
"Action": [ | |
"sts:AssumeRole" | |
], | |
"Effect": "Allow", | |
"Principal": { | |
"Service": "lambda.amazonaws.com" | |
} | |
} | |
], | |
"Version": "2012-10-17" | |
} | |
}, | |
"Type": "AWS::IAM::Role" | |
}, | |
"AppPublicPostRoute": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"AuthorizationType": "NONE", | |
"RouteKey": "POST /public-post", | |
"Target": { | |
"Fn::Sub": "integrations/${AppPublicPostIntegration}" | |
} | |
}, | |
"Type": "AWS::ApiGatewayV2::Route" | |
}, | |
"AppRecordSet": { | |
"Properties": { | |
"AliasTarget": { | |
"DNSName": { | |
"Fn::GetAtt": [ | |
"AppDomainName", | |
"RegionalDomainName" | |
] | |
}, | |
"EvaluateTargetHealth": false, | |
"HostedZoneId": { | |
"Fn::GetAtt": [ | |
"AppDomainName", | |
"RegionalHostedZoneId" | |
] | |
} | |
}, | |
"HostedZoneName": { | |
"Fn::Sub": [ | |
"${prefix}.${suffix}.", | |
{ | |
"prefix": { | |
"Fn::Select": [ | |
1, | |
{ | |
"Fn::Split": [ | |
".", | |
{ | |
"Ref": "DomainName" | |
} | |
] | |
} | |
] | |
}, | |
"suffix": { | |
"Fn::Select": [ | |
2, | |
{ | |
"Fn::Split": [ | |
".", | |
{ | |
"Ref": "DomainName" | |
} | |
] | |
} | |
] | |
} | |
} | |
] | |
}, | |
"Name": { | |
"Ref": "DomainName" | |
}, | |
"Type": "A" | |
}, | |
"Type": "AWS::Route53::RecordSet" | |
}, | |
"AppStage": { | |
"Properties": { | |
"ApiId": { | |
"Ref": "AppApi" | |
}, | |
"AutoDeploy": true, | |
"StageName": "prod" | |
}, | |
"Type": "AWS::ApiGatewayV2::Stage" | |
}, | |
"AppUserPool": { | |
"Properties": { | |
"AutoVerifiedAttributes": [ | |
"email" | |
], | |
"Policies": { | |
"PasswordPolicy": { | |
"MinimumLength": 8, | |
"RequireLowercase": true, | |
"RequireNumbers": true, | |
"RequireSymbols": true, | |
"RequireUppercase": true | |
} | |
}, | |
"Schema": [ | |
{ | |
"AttributeDataType": "String", | |
"Mutable": true, | |
"Name": "email", | |
"Required": true, | |
"StringAttributeConstraints": { | |
"MinLength": "1" | |
} | |
} | |
], | |
"UsernameAttributes": [ | |
"email" | |
] | |
}, | |
"Type": "AWS::Cognito::UserPool" | |
}, | |
"AppUserPoolClient": { | |
"Properties": { | |
"ExplicitAuthFlows": [ | |
"ALLOW_USER_SRP_AUTH", | |
"ALLOW_ADMIN_USER_PASSWORD_AUTH", | |
"ALLOW_REFRESH_TOKEN_AUTH" | |
], | |
"PreventUserExistenceErrors": "ENABLED", | |
"UserPoolId": { | |
"Ref": "AppUserPool" | |
} | |
}, | |
"Type": "AWS::Cognito::UserPoolClient" | |
} | |
} | |
} |
- move setenv-priv stuff into setenv or app.props
- move simple email user pool into web_api demo
- see if AltNamespaceMixin can be retired
-
scripts to ping public endpoints
-
include origin localhost:3000 in ping_private scripts
-
new cors_400.html script
-
rename cors.html as cors_200.html
-
add variable for permitted domain
-
add permitted domain variable to deploy stack
-
revert AWS_PROFILE
-
update CERTIFICATE_ARN
-
copy new stack
-
CORS not working
-
private-post 500 error
[ERROR] JSONDecodeError: Expecting value: line 1 column 1 (char 0)Traceback (most recent call last): File "/var/task/index.py", line 3, in handler body=json.loads(event["body"]) File "/var/lang/lib/python3.10/json/__init__.py", line 346, in loads return _default_decoder.decode(s) File "/var/lang/lib/python3.10/json/decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/var/lang/lib/python3.10/json/decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None
- private endpoints not working :(
- test public endpoints
Resource handler returned message: "Unexpected or malformed target in route null. Correct format should be integrations/<integration_id>. (Service: AmazonApiGatewayV2; Status Code: 400; Error Code: BadRequestException; Request ID: 9577f060-14f7-4511-a138-22629c5b3175; Proxy: null)" (RequestToken: 44bc3fe1-4bcb-bfd7-faf8-c8584b0aa327, HandlerErrorCode: GeneralServiceException) |
Resource handler returned message: "Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: querystrings.message] (Service: AmazonApiGatewayV2; Status Code: 400; Error Code: BadRequestException; Request ID: 85caa3aa-f9ec-4019-92b7-e95a604413f9; Proxy: null)" (RequestToken: 173dc5c4-75f6-c96e-3318-450d44368b93, HandlerErrorCode: GeneralServiceException) |
| 2024-03-27T11:54:08.817Z| AppApiMapping | AWS::ApiGatewayV2::ApiMapping | CREATE_FAILED | Properties validation failed for resource AppApiMapping with message:
#: required key [Stage] not found
| 2024-03-27T11:54:09.204Z| AppRecordSet | AWS::Route53::RecordSet | CREATE_FAILED | Requested attribute DistributionHostedZoneId does not exist in schema for AWS::ApiGatewayV2::DomainName |
024-03-27T11:27:47.482Z| AppDomainName | AWS::ApiGatewayV2::DomainName | CREATE_FAILED | Resource handler returned message: "Invalid certificate ARN: arn:aws:acm:us-east-1:119552584133:certificate/77b7bf9e-38e9-4115-82bf-4403bbb30c02. Certificate must be in 'eu-west-1'. (Service: AmazonApiGatewayV2; Status Code: 400; Error Code: BadRequestException; Request ID: 66b08e2c-5128-4a8c-97dc-c79d7dbbce4e; Proxy: null)" (RequestToken: 78213f09-fb8e-1dcb-93ff-5a943c3cc418, HandlerErrorCode: GeneralServiceException) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment