GitHub ActionsでCloudFront + S3にファイルをアップロードする
先日、仕事で初めてAWSでシステムを構築したんですが、S3のアップロード方法を全く考えられておらず、S3に直アップロードという方法を取りました。
当然、チームでの作業にかなり支障をきたしてしまいました・・・。
今回はその反省としてGitHub Actionsを使ってS3にアップロードすることに成功したので、備忘録として書いておきます。
CloudFront経由のS3の公開については過去記事にて紹介しているので割愛します。 suguru-no-rururu.hatenablog.com
1.レポジトリ作成
まずはgithubに管理用のレポジトリを作成します。 久々にレポジトリ作ると毎回忘れているのでこの記事を参考にしています。 qiita.com
2. Github Actionsの設定
レポジトリが作成できたら、Actionsをクリック。
「Set up this workflow」があるので、それをクリック。
Actionsには以下のように書きました。
access_key_idとsecret_access_keyは後々githubで設定するので、直書きはしないでください。
name: CI on: push: branches: [ main ] pull_request: branches: [ main ] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Configure AWS credentials from account uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.TEST_AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.TEST_AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-1 - name: Copy Files to s3 run: | aws s3 sync ./public s3://test-aws-service-k --delete
コードの紹介をしていきます。
mainというブランチにpushされた時にjobsが走るようにしています。
masterなど使っているブランチ名に変更してください。
on: push: branches: [ main ] pull_request: branches: [ main ]
リージョンはS3のバケットがあるリージョンに変更してください。
aws-region: ap-northeast-1
今回はpublic配下にあるファイルを付け足すようにしています。
--deleteオプションはS3のバケットにあるが、githubのレポジトリにないファイル・ディレクトリを削除するものです。
aws s3 sync ./public s3://test-aws-service-k --delete
3. SercretsにAWSのaccess_key_idとsecret_access_keyを設定
続いてgithubのSettings > サイドバーのSecretsから「New repository secret」をクリック。
そちらにIAMユーザーのaccess_key_idとsecret_access_keyを貼り付けます。
keyは先ほど、Github Actionsに設定したTEST_AWS_ACCESS_KEY_ID、TEST_AWS_SECRET_ACCESS_KEYとします。
以上で設定は完了です。
作成したレポジトリにpushするとS3のバケットに反映されていると思います。
AWS SESの登録~メールアドレス認証・サンドボックス解除~
今回はAWS SESでメールを送信する機能を作成したので、そのメモとして残しておきます。
まずはSESを普通に使えるようにするために設定していきます。
メールアドレスの認証
まずはAWSコンソールでSES(Simple Email Service)を開く。
サイドバーの「Verified identities」をクリック。
すると、メールアドレスの認証画面が出るので、Create identityを選択。
Identity TypeをEmail addressにし、Email addressのところに自分が使用したいメールアドレス(送信元のメールアドレス)を入力します。
すると、メールのリンクをクリックして確認してくださいというお知らせがくるので、AWSから届いているメールのリンクをクリックします。
こんな感じのメールが届いていると思います。
リンクをクリックして、先ほどのSESのメールアドレス認証の画面に戻ると、Identity statusがVerifedになっていると思います。
以上でメールアドレスの認証は終了です。
サンドボックスから除外する
SESに登録すると、まずはサンドボックスというところに置かれます。
ここに置かれたままだと、
- 認証したメールアドレス宛にしかメールを送信できない
- 1日200通まで送信可能
など、使い物になりません。
そのため、このサンドボックスから外すという作業が必要になります。
ちなみに迷惑メール送信防止の観点などからサンドボックスがあるようです。
以下のリンクを開きます。 https://console.aws.amazon.com/ses/
そして、サイドバーのSending Statisticsをクリック。
Production AccessがSandBoxになっています。
設定をするために、真ん中あたりのEdit your account detailsをクリック。
ポップアップが出てくるので、一つづつ入力していきます。
- Enable Production AccessをYes。
- Mail Typeは使用用途によってTransactionalにするか、Marketingにするか分けてください。
自分はMarketingにしました。 - Website URLはご自身が使いたいWebサイトのURL。
- Use case descriptionは以下について書くと良いそうです。日本語で大丈夫です。
- ユースケースの説明
- メーリングリストの管理をどうやってやるか
- バウンスや苦情があった時の対処法
- オプトアウトをどうやってやるか
自分が申請した時は全て合計して300文字くらいで書きました。
適当に提出すると落ちるので、数百文字くらいは書いておきましょう。
入力ができたらSubmit for reviewを押します。
申請を送信すると、送信内容がメールで来ます。
解除には24時間以内に対応すると書いてあるので、少し待ちます。
対応までの時間は結構バラバラでした。
初めは10時間くらい経ってから解除されたんですが、2回目は15分ほどで解除されたりなどでした。
申請が解除されるとstatusがEnabledになります。
これにてサンドボックスの解除が完了です。
参考:
- SESのサンドボックス解除方法 docs.aws.amazon.com
Lambda+Cognitoでユーザーの登録
LambdaからCognitoのユーザープールにユーザーを作成することが仕事であったので、その方法をメモしておきます。
ユーザープール作成
AWSコンソールからCognitoを開きます。
ユーザープールの管理を選択します。
右上の「ユーザープールを作成する」を選択。
プール名を入力し、ステップに従って設定するを選択。
今回はemailも入力させたいので、emailにチェックを入れました。
続いてサイドバーのポリシーからパスワードの強度を設定します。
今回は一旦小文字だけにしました。
実際に使う場合にはよりセキュアにした方が良いと思います。
サイドバーのアプリクライアントから「アプリクライアントの追加」を押します。
すると、アプリクライアントの作成画面に移行するので、画面通り設定していきます。
アプリクライアント名は任意の名前で大丈夫です。
設定ができたらアプリクライアントの作成を押します。
その他の設定はデフォルトで大丈夫です。
最後にサイドバーの確認から入力内容を確認し、プールの作成を押します。
プールの作成ができたら、プールID・プールARNをメモしておきます。
サイドバーのアプリクライアントから、アプリクライアントIDもメモしておきます。
フェデレーティッドアイデンティティの作成
続いて、フェデレーティッドアイデンティティを作成します。
ユーザープールの右のフェデレーティッドアイデンティティを選択。
新しいIDプールの作成を押します。
すると作成画面に移行するので、IDプール名を入力します。
こちらも任意の名前で大丈夫です。
下にスクロールすると、認証プロバイダーというところがあるので、
こちらに先ほどメモしたユーザープールIDとアプリクライアントIDを入力します。
入力ができたらプールの作成を押します。
英語で説明が出てきますが、許可で大丈夫です。
作成完了画面が出てくるので、IDプールのIDをメモしておきます。
以上でユーザープールの作成は完了です。
Lambdaにコードを記述
今回はadminCreateUserを使用し、ユーザー登録を行いました。
'use strict'; const AWS = require('aws-sdk'); const cognito = new AWS.CognitoIdentityServiceProvider(); const querystring = require('querystring') exports.handler = async (event, context, callback) => { const parse = querystring.parse const request_body = parse(event.body); const userId = request_body.email const params = { Username: userId, MessageAction: 'SUPPRESS', UserPoolId: '先ほどメモしたユーザーIDを入力', UserAttributes: [ { Name: 'email', Value: userId, }, { Name: 'email_verified', Value: 'true', }, { Name: 'phone_number_verified', Value: 'false', }, ], }; let result = ''; try { result = await cognito.adminCreateUser(params).promise() } catch (error) { return console.log('エラーです'); } return console.log('登録完了!!') // TODO implement const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; callback(null, event); };
LambdaからHubSpotのコンタクトを作成・更新する
今回はAWS LambdaからHubSpotのAPIを叩く機会があったので、それについてまとめておきます。
調べてみると意外とやってみたという記事がほとんどなく、もしかしたら稀なケースなのかもしれません。
LambdaのランタイムはNode.jsを使用しています。
Lambda自体の動かし方については前回の記事でまとめているので、そちらをご覧ください。 suguru-no-rururu.hatenablog.com
HubSpotは開発者用のアカウントを作成すると、試しにコンタクトを作成したり削除できたりするので、作っておくことをお勧めします。 developers.hubspot.jp
モジュールをインストールし、zip化する
今回使用しているrequestですが、Lambdaでパッケージをインストールしなければならなかったので、その方法も記述しておきます。
手順
- ローカル環境(Desktopとか)にnodejs/node_modulesフォルダを作成
- nodejs/node_modulesで
$ npm install request @hubspot/api-client
$ zip -r request.zip nodejs/
でnodejsファイルごとzip化する(macであればfinderからzipすることも可能)
先ほど作成したzipをLambdaのレイヤーに追加する
Lambdaのサイドバー > レイヤーからレイヤーの作成を押します。
作成画面で先ほどzip化したファイルをアップロードします。 名前は任意のものを入力し、ランタイムはNode.jsとしておきます。
作成ができたら、Lambda関数のところに戻り、Layersからレイヤーの追加をします。
以上でレイヤーの追加は完了です。
コンタクトを取得する場合
var request = require("request"); var hs_get_options = { method: 'GET', url: `https://api.hubapi.com/contacts/v1/contact/email/${email}/profile`, qs: { hapikey: 'ここにHubSpotのAPIキーが入る' }} request(hs_get_options, function (error, response, body) { // このbodyにプロパティ情報が入っている // data.properties.hs_object_idなどで取り出し可能 const data = JSON.parse(body) })
コンタクトがなければ作成、あれば更新する場合
var request = require("request"); var options = { method: 'POST', url: `https://api.hubapi.com/contacts/v1/contact/createOrUpdate/email/{email}/`, qs: {hapikey: 'ここにHubSpotのAPIキーが入る'}, headers: { 'Content-Type': 'application/json'}, body: { properties: [ { property: 'firstname', value: '' }, { property: 'lastname', value: name }, { property: 'その他必要なproperty', value: '' } ] }, json: true }; // ------------------------------- const hs_response = { statusCode: 200, body: JSON.stringify(await new Promise((resolve, reject) => { request(options, (err, resp, b1) => { if (err) { } else { resolve(resp) } }) })), };
参考:
コンタクトを作成する場合
上のコードのurlをhttps://api.hubapi.com/contacts/v1/contact/
に変更
propertiesに{ property: 'email', value: '登録したいemailを入れる' }
を挿入すればOKです。
コンタクトを更新する場合
var request = require("request"); var hs_update_options = { method: 'POST', url: `https://api.hubapi.com/contacts/v1/contact/vid/{HubSpotのコンタクトのID}/profile`, qs: { hapikey: 'ここにHubSpotのAPIキーが入る' }, headers: { 'Content-Type': 'application/json' }, body: { properties: [ { property: '更新したい内部値', value: 'バリュー' } ] }, json: true }; request(hs_update_options, function (error, response, body) { }); }
参考:HubSpot APIドキュメント
S3 + API Gatewayを使ってLambdaを動かす
今回はAPI Gatewayを使ってLambdaを発火させることができたので、その方法をメモしておきます。
こちらは前回の続きです。
suguru-no-rururu.hatenablog.com
Lambda関数の作成
AWSコンソールでLambdaを開きます。 右上の「関数の作成」を選択。
すると、関数の作成画面が出てくるので、
任意の関数名を入力します。今回はtestFunctionとしました。
ランタイムはNode.js 14.xにしました。
ここは自由に選んで良いと思いますが、ネットの情報を見る感じ、PythonとNode.jsが多い印象なので、どちらかを選んでおくと無難です。
入力ができたら関数の作成ボタンを押す。
作成が完了するとこんな感じの画面になります。
コードを変更しておきましょう。
コードを選択し、サイドバーのindex.jsをopenにします。
そして以下のようにコードを変更します。
exports.handler = (event, context, callback) => { // TODO implement const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; callback(null, event); };
変更ができたら必ずDeployを押してください。
API GatewayでAPIの開設
AWSコンソールからAPI Gatewayの画面を開きます。
そして右上のAPIの作成を選択。
今回はREST APIを選択しました。
「構築」を選択。
画像のように設定していきます。
ここでもAPI名は任意のもので大丈夫です。
入力が完了したら、「APIの作成」を選択。
すると、APIのページに遷移します。
左上のアクションから「リソースの作成」を選択。
リソース名を入力します。
ここも任意のもので大丈夫です。
入力ができたら「リソースの作成」を選択します。
続いて、アクションからメソッドの作成をします。
先ほど作成したリソースの下に小さくメソッドを選択するとことが出てきます。
今回はformから送信ボタンを押した際に動作するAPIを作成したいので、POSTにしました。
選択ができたら、右のチェックボタンをクリックします。
セットアップ画面が出るので、ここで先ほど作成したLambda関数を選択します。
保存をクリックすると、権限を追加する警告が出ますが、OKで大丈夫です。
忘れずにAPIのデプロイをしておきましょう。
忘れがちですが、これをしないと設定が反映されません。
今回はステージ名をtest_lambdaとしました。 デプロイをすると、先ほどのAPIのパスが表示されるのでメモしておきます。
マッピングテンプレートの追加もしておきます。
リソース > POST > 統合リクエストの順でクリックしていきます。
一番下にマッピングテンプレートというところがあるので、Content-Typeのところにapplication/x-www-form-urlencoded
と入力します。
入力ができたら右のチェックマークを押します。
すると下に入力するフォームが出てくるので、以下を入力します。
{ "body" : $input.json('$') }
入力ができたら保存してください。
S3にフォームのHTMLをアップロード
続いて先ほどのAPIを叩くためのフォームを用意します。
formタグのactionのところに先ほどのパスを貼り付けてください。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> </head> <h1>S3#index.html<h1> <form action="https://{先ほどメモしたパスを貼り付け}/test_lambda/form" method="post"> <input type="submit" value="送信"> </form> </html>
S3のアップロードから先ほど作成したindex.htmlをアップします。
今回はCloudFront経由で配信しているので、Domain Nameのところからページを開きます。
先ほどのフォームが見れると思います。
送信を押してみると、レスポンスの設定を何もしていないので、{}のような文字が出ると思います。
Lambdaのログを見てLambda関数が動いているか確認しましょう。
Lambdaの先ほど作成した関数から中央あたりのメニューから
モニタリング > CloudWatchのログを表示を選択。
こちらに何か記述があればLambdaが動いている証です。
リンクになっているところをクリックすると、中身が見れます。
Lambda内でconsole.logなどをすると、こちらに表示されます。
以上で終了です。
CloudFront経由でS3を公開する
今回はFrontCloud経由でS3にある静的ファイルを公開することができたので、その方法を書いておきます。
S3でバケットの作成
1.バケット作成ボタンを押す
AWSコンソールでS3のページにアクセスし、右上のバケットを作成を選択。
2.バケット名とリージョンを選択
バケット名を入力し、リージョンを選択します。
バケット名は任意の名前で構いません。今回はtest-aws-service-k
としました。
※バケット名はアカウント関係なく、すでに存在名前だと作成できないので注意してください。
リージョンも任意の場所で大丈夫です。
日本で使用する場合には東京リージョンにするのが一般的かと思います。
3. ブロックパブリックアクセス設定
今回はCloudFront経由の公開を考えているので、こちらは「パブリックアクセスをすべてブロック」で大丈夫です。
S3のまま公開したい場合にはこちらのチェックは外す必要があります。
4.その他の設定
基本的に理由がなければ以下の設定にしておくと良いと思います。 設定が完了したらバケットの作成を選択。
- バケットのバージョニング: 有効
- デフォルトの暗号化: 有効
- 暗号化キータイプ: Amazon S3キー
- 詳細設定: 変更なし
すると、バケット作成完了の通知がきます。
5.静的ファイルをホスティングする
先ほど作成したバケットが静的ファイルをホスティングするように設定していきます。
先ほど作成したバケットを選択する。
プロパティ > (一番下にスクロール) 静的ウェブサイトホスティングを選択します。
画像通り設定していきます。
インデックスドキュメントはホームURLでどのファイルを表示させるかの設定になるので、今回はindex.htmlとしておきます。
もしサイトを開いたときにtop.htmlというファイルを表示させたければtop.htmlに変更するという感じです。
後でも変更できるので仮で決めてもOKです。
6. ファイルをアップロードする
ここで、先ほど作成したバケット今回表示させるファイルをアップロードします。
今回は仮にindex.htmlだけアップロードします。
以下のようなファイルを作りました。
index.html
<h1>S3#index.html<h1>
バケットからアップロードを選択します。
「ファイルを追加」を選択し、アップロードしたいファイルを追加します。 追加ができたら下の「アップロード」ボタンを押します。 アップロードに成功すると通知が出ます。
以上でS3の設定は完了です。
CloudFrontの設定
続いてCloudFront側の設定をします。
AWSコンソールでCloudFrontを開きます。
左上に「Create Distribution」のボタンがあるので、そちらを選択。
画像のように設定していきます。
Origin Domain Nameには先ほど作成したバケットを選択します。
バケット名を少し打つと、サジェスチョンが出てくると思います。
ここまで設定ができたら一番下のCreate Distributionを選択します。
すると、こちらのstatusが、In ProgressからDeployedになるまで待ちます。
Deployedになったら作成したDistributionを選択し、GeneralからDomain Nameをコピーします。
自分はindex.htmlというファイルをアップロードしたので、
ドメインname/index.html
で先ほどのindex.htmlが表示されます!
以上で設定完了です。
お疲れ様でした。
AWS CLIでアカウント切り替え
たまにAWS CLI使うと、アカウント切り替えとS3のダウンロードのコマンドを忘れてしまうので備忘録的に書いておきます。
アカウント変更
1. 現在のアカウントを確認する
$ cd ~/.aws
$ ls config credentials
$ cat credentials [default] aws_access_key_id = wwwwwwwwwwwwwwwwww aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxx [account_name] aws_access_key_id = yyyyyyyyyyyyyyyyyyyyy aws_secret_access_key = zzzzzzzzzzzzzzzzzzzzzzz
2. アカウント変更
先ほど確認したユーザー名を入れてアカウントを変更します。
$ export AWS_DEFAULT_PROFILE=ユーザー名
もし先ほどのaccount_nameに変更したい場合はこちら
$ export AWS_DEFAULT_PROFILE=account_name
アカウント確認すると、先ほど変更したアカウントになっている。
$ aws configure list Name Value Type Location ---- ----- ---- -------- profile test manual --profile access_key ****************IEPM shared-credentials-file secret_key ****************VPOT shared-credentials-file region ap-northeast-1 config-file ~/.aws/config