概要
をもとにAmazon CloudFrontおよびAWS WAFを用いた翻訳アプリを構築してみました
※ハンズオンの内容と全て一致していません
CloudFormation
米国東部 (バージニア北部)リージョンに作成
waf.yml
AWSTemplateFormatVersion: 2010-09-09
Resources:
#======================
# WebACL
#======================
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
DefaultAction:
Allow: {}
Name: handson-waf
Rules:
- Action:
Block:
CustomResponse:
ResponseCode: 400
Name: handson-rule
Priority: 1
Statement:
GeoMatchStatement:
CountryCodes:
- JP
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: BlockRequestsFromJapan
SampledRequestsEnabled: true
Scope: CLOUDFRONT
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: handson-waf
SampledRequestsEnabled: true
アジアパシフィック (東京)に作成
app.yml
AWSTemplateFormatVersion: 2010-09-09
Resources:
#======================
# Distribution
#======================
Distribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CacheBehaviors:
- PathPattern: static/*
TargetOriginId: S3
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: !Ref CachePolicy
- PathPattern: api
TargetOriginId: RestApi
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad
OriginRequestPolicyId: !Ref OriginRequestPolicy
DefaultCacheBehavior:
TargetOriginId: S3
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad
DefaultRootObject: index.html
Enabled: true
Origins:
- DomainName: !Sub "${RestApi.RestApiId}.execute-api.${AWS::Region}.amazonaws.com"
Id: RestApi
CustomOriginConfig:
OriginProtocolPolicy: match-viewer
- DomainName: !GetAtt Bucket.DomainName
Id: S3
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: ''
WebACLId: !Sub "arn:aws:wafv2:us-east-1:${AWS::AccountId}:global/webacl/handson-waf/b5739b66-17f5-4e82-b61c-101517f3f028"
#======================
# CachePolicy
#======================
CachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
DefaultTTL: 86400
MaxTTL: 31536000
MinTTL: 1
Name: CachePolicy
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: none
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
#======================
# OriginRequestPolicy
#======================
OriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: none
Name: OriginRequestPolicy
QueryStringsConfig:
QueryStringBehavior: whitelist
QueryStrings:
- input_text
#======================
# OriginAccessControl
#======================
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: OACj7rotyh3xxkt1uj0wocu
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
#======================
# Bucket
#======================
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: bucketaeb934895097f22ba2d64e053c0c3fa099
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
WebsiteConfiguration:
ErrorDocument: error.html
IndexDocument: index.html
#======================
# BucketPolicy
#======================
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action:
- s3:GetObject
Resource:
- arn:aws:s3:::bucketaeb934895097f22ba2d64e053c0c3fa099/*
Condition:
StringEquals:
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${Distribution}"
#======================
# RestApi
#======================
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: RestApi
#======================
# Method
#======================
Method:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
Type: "AWS_PROXY"
IntegrationHttpMethod: "POST"
Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:Lambdafunction/invocations"
RequestParameters:
integration.request.querystring.input_text: method.request.querystring.input_text
RequestParameters:
method.request.querystring.input_text: true
ResourceId: !GetAtt RestApi.RootResourceId
RestApiId: !Ref RestApi
#======================
# Stage
#======================
Stage:
Type: AWS::ApiGateway::Stage
Properties:
StageName: api
RestApiId: !Ref RestApi
DeploymentId: !Ref Deployment
#======================
# Deployment
#======================
Deployment:
DependsOn: Method
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref RestApi
#======================
# Permission
#======================
Permission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref Function
Principal: apigateway.amazonaws.com
#======================
# Function
#======================
Function:
Type: AWS::Lambda::Function
Properties:
FunctionName: Lambdafunction
Handler: index.lambda_handler
Runtime: python3.11
Role: !GetAtt Role.Arn
Code:
ZipFile: !Sub |
import boto3
def lambda_handler(event, context):
translate = boto3.client(service_name='translate', use_ssl=True)
result = translate.translate_text(Text=event['queryStringParameters']['input_text'], SourceLanguageCode="ja", TargetLanguageCode="en").get('TranslatedText')
return {
'statusCode': 200,
'body': result
}
#======================
# Role
#======================
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/TranslateReadOnly
S3バケットの内容
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="icon" type="image/x-icon" href="static/image/cloudfront.png">
<link href="static/css/styles.css" rel="stylesheet" type="text/css">
<script src="static/js/script.js"></script>
</head>
<body>
<form id="form1" action="#">
<ul>
<li>
<img src="static/image/cloudfront.png" width="100" height="100">
</li>
<li>
<p>Input Message</p>
<textarea id="input_message" rows="4" cols="40"></textarea>
</li>
<li>
<input type="button" onclick="func1()" value="Send" />
<input type="button" onclick="func2()" value="All Clear" />
</li>
<li>
<br />
<p>Output Message</p>
<textarea id="output_message" rows="4" cols="40"></textarea>
</li>
</ul>
</form>
</body>
</html>
static/css/style.css
#form1 { text-align : center ;}
ul li{
list-style: none;
padding: 10px;
}
static/js/script.js
function func1() {
var apiurl = 'https://' + document.domain + '/api?input_text=' + document.getElementById("input_message").value;
var request = new XMLHttpRequest();
request.open('GET', apiurl, true);
request.responseType = 'text';
request.onload = function () {
var data = this.response;
document.getElementById("output_message").innerHTML = data;
};
request.send();
}
function func2() {
document.getElementById("input_message").value = '';
document.getElementById("output_message").innerHTML = '';
}
参考文献