お問い合わせフォーム付きWeサイトを
- S3で
- Slack通知ありで
- 独自ドメインで(お名前.comよりCNAMEを利用)
- 独自SSLで(https/SNIベース)
公開するまでの備忘録
どこにでもやり方やリンクは転がってますが個人的にまとめます。
前回でS3での静的コンテンツ配信は可能となりましたので、
次はlambda/Cognitoを使って問い合わせフォームより送信があった場合はslack通知をしましょう。
流れは、
Cognitoで一時的なIAM Userを作成して、
そのアカウントを使ってフォームの入力内容をS3でテキストでアップロード、
S3のアップロードをLambdaでフックして内容をSlack通知です。
各リンクは以下
技術要件
- AWS
- S3
- aws-cli
- Cognito <-今回
- Lambda <-今回
- aws-sdk <-今回
- CloudFront
- dnsまわり
参考リンク
S3 + Lambda + Cognitoを使って、簡単お問い合わせシステム構築
Slack
Incoming Webhook取得
1.Slackログイン状態で、https://api.slack.com/incoming-webhooks にアクセス
2.通知をしたいチャンネルまたは個人を選択
3.Incoming Webhook用のURLを取得
必要があればアイコンや名前など上記ページの下「Integration Settings」でいじれます。
Cognito
S3にアップロードするための一時的なIAM Userを作成するためにCognitoを使用します。
1.Identity Poolの作成
Amazon Management Consoleより「Cognito」を選択。
「Create New Identity Pool」
「Name」は適用に分かりやすいやつを
「Unauthenticated identities」にチェックを入れましょう
特定の認証(ID/PASSだったり、Facebook認証だったり)をしないでもIAM Userを作成できるようにするため
2.新しいIAM Roleの確認
上が「authenticated role」
認証をした場合のIAM Role
下が「unauthenticated role」
認証をしなかった場合のIAM Role
3.Identity Pool Id の取得
4.作成したunauthenticated Roleに権限を付与
Amazon Management Consoleより「Identity and Access Management」を選択。
左メニュー「Role」より先ほど作成した「UnAuth」のロールをクリック
今回は以下のようなポリシーを追加 : 特定のBucketへのアップロード権限
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::example.co.jp/*" <- アクセス許可するBucket
}
]
}
aws-sdk-js
フォームのための処理
アップロードする箱と権限は設定したの実際にアップロードしてみましょう。
aws-sdkを使うのでHTMLのヘッダで読み込んでおきましょう。
今回はCDNで読み込みます。
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
以下のようなHTMLとJSをS3に置きます。
こんな感じのフォームがあったとします(あくまで例です)
<div>
<input type="text" id="ContactCompanyName"/>
<input type="text" id="ContactName"/>
<input type="text" id="ContactEmail"/>
<input type="text" id="ContactTel"/>
<textarea cols="40" rows="4" id="ContactDetailBody"></textarea>
<a href="#" id="put_contact"><img src="/send_btn.gif" alt="送信"/></a>
</div>
aws-sdkを使って送信ボタンがクリックしたときにフォームの内容をuploadします
$('#put_contact').on('click', function() {
AWS.config.region = "ap-northeast-1";
AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: "取得した Identity Pool Id"});
AWS.config.credentials.get();
//作成したBucketを指定しましょう
var bucket = 'example.co.jp';
var s3 = new AWS.S3({
params: {
Bucket: bucket
}
});
var now = new Date();
var obj = {
"問い合わせ時間" : now.toLocaleString(),
"御社名" : $("#ConfirmContactCompanyName").text(),
"お名前" : $("#ConfirmContactName").text(),
"メールアドレス" : $("#ConfirmContactEmail").text(),
"電話番号" : $("#ConfirmContactTel").text(),
"お問い合わせ内容" : $("#ConfirmContactDetailBody").text(),
};
var blob = new Blob([JSON.stringify(obj, null, 2)], {type:'text/plain'});
//Bucketの「contacts」フォルダの下にアップロード
s3.putObject({Key: "contacts/" + now.getTime()+".txt", ContentType: "text/plain", Body: blob},
function(err, data){
if(data !== null){
window.location.href = '/contact_end.html';
}
else{
alert("お問い合わせ送信に失敗しました。お手数ですが再度ご入力をお願いします。");
window.location.href = '/contact.html';
}
});
});
S3にCORSの設定
アップロードまでもう少し。
JavaScriptでS3にアクセスするにはCORSの設定が必要となります。
CORS…http://dev.classmethod.jp/etc/about-cors/
Amazon Management ConsoleからS3で作成したBucketに行きましょう
ここにこんな感じに記述
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>アクセス元(今回はBucketの静的コンテンツ配信のためのエンドポイントのURL)</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
さて、疲れましたね。
もうアップロードは出来るはず。
lambda
アップロードは出来たので最後にSlack通知のためのlambda functionを設置します。
1.lambda function作成のための準備
npmをインストール(CentOS6の場合)
yum install epel-release
yum install nodejs npm --enablerepo=epel
npmより「reqest」「aws-sdk」をインストール
- request…HTTPリクエストを簡単にするため
- aws-sdk…S3からアップロードされたファイルの内容取得のため
npm install aws-sdk
npm install request
2.コードサンプル
index.jsを「node_modules」と同じ階層に作成
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var request = require('request');
exports.handler = function(event, context) {
var bucket = event.Records[0].s3.bucket.name;
var key = event.Records[0].s3.object.key;
s3.getObject({Bucket:bucket, Key:key}, function(err, data) {
//アップロードされたファイルの内容を取得
var contentType = data.ContentType;
var body = data.Body.toString("utf-8");
var options = {
uri: '取得したSlackのIncoming Webhook URL',
json: true
};
if (key.match(/^contacts/)) {
options['form'] = {
payload: JSON.stringify({
'username': 'webhookのusername',
'channel': '通知するchannel',
'text': 'お問い合わせがありました。'
})
};
}
request.post(options, function(err, responce, body) {
if(!err && responce.statusCode == 200) {
console.log('success');
} else {
console.log('error: ' + responce.statusCode);
}
context.done(null, '');
});
});
};
3.zip化
「index.html」と「node_modules」をzip化しましょう
zip -r contact.zip index.js node_modules
4.lambda用のIAM Roleを作成
デプロイ前にひと手間
今回、lambda function内でS3の中身を取得しているので、lambda用のRoleを作成しましょう。
Amazon Management Consoleより「Identity and Access Management」を選択。
左メニュー「Role」より新しいRoleを作成しましょう
Role名は適当に分かりやす名前で
Role type でLambdaを選択
S3のReadOnlyのポリシーを付与
これで、lambda用のRoleが完成
5.lambdaにデプロイ
さて、いよいよデプロイです。
Amazon Management Consoleより「lambda」を選択
「Create a Lambda Function」
色々雛形が出てきますが、今回はスルー
名前は適当に分かりやすいものを
Upload a ZIP fileで先ほど作成したlambda functionをまとめたzipをアップロード
Roleに先ほど作成したlambda用のRoleを選択します。
最終確認画面でEnableを選択すればlambda functionが有効となります。
ただ最後に最後にあと一仕事
lambdaが何のEventにhookされるのか設定しましょう。
作成されたlambda functionの「Event source」を選択
「Add event source」でhookするポイントを追加します
BucketはアップロードするBucket
Event typeはS3へオブジェクトがクリエイトされた時
prefixは今回は「contacts/」にアップロードされるので記入しているだけです
ここまででサイトとしては機能している
さて、長くなりましたが今回はここで終了です。
きっと静的コンテンツ越しにアップロードされたファイルがslackで通知されている(ハズ
次はamazonから与えられるエンドポイント用の長いURLではなく
独自のドメインでサイトにアクセスするのと、通信のSSL化です。