AWSでサーバーレスCRUDをするための構成

サーバーレスでCRUDができれば簡単なツールなどは、管理運用の手間が減るのではないか!?と思いついて作成したものになります。
社内ツールとして社内(IP)からのみアクセス可能にするために色々やりました。

参考にした記事はこちら:AWS Lambdaを使ってサーバレスアプリを作成(CRUDのR)
手順通り作成していけば、作成することが出来ます。

こちら参考にしたのですが、データベース(DynamoDB)に登録しようとすると、CORSのエラーが出てしまってCRUDのReadとDeleteしか出来ませんでした。。。
APIゲートウェイの仕様なのか、CORS以外のエラー(APIキーが認証出来ない場合等) でもCORSのエラーを返すようなので、何が間違っているのかの判断ができず。。

しかし下記のセキュリティ構成については試してみたので、参考になるかと思います。

CRUDとは

Create, Read, Update, Deleteの頭文字です。WEB開発の基本と言われています。
リクエストの名前で置き換えると、POST, GET, PUT, DELETEになるでしょうか

AWSの構成

以下のような構成を考えました。

S3にある静的ファイルをCloudFrontを使ってホスティングしています。
そこからAPIにリクエストを送ることでAPIGatewayがそのリクエストの種類ごとにLambdaを叩きます。

セキュリティ

セキュリティについては以下のような構成を取りました。

ユーザーがアクセスするのはCloudFrontです。そちらにはWAFを利用してIPアドレスでのアクセス制限をかけます。
S3には特定のCloudFrontからのみアクセスを可能にする設定があるので、そちらを有効にします。
APIGatewayはWAFを利用して、X-Forwarded-ForのIPアドレスでのアクセス制限をかけます。
LambdaとDynamoDBはIAMでのアクセスになります。

CloudFront

WAFを利用してIPアドレスでのアクセス制限

WAFのコンソールからIP setsを選択してリージョンをGlobal(CloudFront)を選択します。
その後でCreateIP setをクリックします。

その後以下のように、名前とIPアドレスを入力します。
名前は任意の名前で大丈夫です。

下記の画像に表示されているIPアドレスは適当なので各自設定してください。

あとはWeb ACLsから先程作成したIPsetを選択してそれをAllow、デフォルトアクションはBlockにすれば、指定のIP以外のアクセスをブロックすることが出来ます。

S3

指定のCloudFrontからのみアクセスを許可する

パブリック・アクセスをすべてブロックをオフにしてからバケットポリシーに以下を書き込みます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::backet_name/*"
        }
    ]
}

loudFront Origin Access Identity XXXXXXXとbacket_nameの部分をご自身のものに変更してください。

API Gateway

WAFを利用して、X-Forwarded-Forで会社IPを指定してアクセス制限

CloudFrontのときと同じように作成します。リージョンがCloudFrontではなく、APIGatewayと同じリージョンで作成します。

このようにルールを作成することで、X-Forwarded-ForのIPをみて制限することが出来ます。

Lambda

IAMでアクセス制限

作成時にロールに権限がつくはずです

DynamoDB

IAMでアクセス制限

作成時にロールに権限がつくはずです

完成形

ヤッホーブルーイングさんビールを表示するものを作成しました。(私がビール好きなため)

このページはフロントはVue.js、バックエンドはLambdaでnode.jsで作成しました。
一応テーブルヘッダーをクリックするとソートできるようになっています。

このサイトはCloudFrontでホスティングしていて、前述の通りIP制限をかけているので違うIPからアクセスすると、エラーになります。

また社内IPからAPIにアクセスすると、200が返ってきました。成功です。

{"statusCode":200,"headers":{"Content-Type":"application/json","Access-Control-Allow-Headers":"X-Requested-With, Origin, X-Csrftoken, Content-Type, Accept","Access-Control-Allow-Origin":"https://hogehoge.com/","Access-Control-Allow-Methods":"GET","Access-Control-Allow-Credentials":"true"},"body":"[{\"id\":3,\"name\":\"水曜日のネコ\",\"type\":\"ホワイトエール\"},{\"id\":2,\"name\":\"インドの青鬼\",\"type\":\"IPA\"},{\"id\":4,\"name\":\"東京ブラック\",\"type\":\"ポーター\"},{\"id\":1,\"name\":\"よなよなエール\",\"type\":\"アメリカンペールエール\"},{\"id\":5,\"name\":\"僕ビール君ビール\",\"type\":\"セゾン\"}]"}

許可していないIPからアクセスすると、Foridenで失敗していますね。

{"message":"Forbidden"}

ソース

今回作成したソースコードを貼り付けます。

おわりに

サーバーレスを完全に実現するのは大変でした。その前にフロントエンドの知識をもっとつけたいですね。がんばります。