AWSの部屋

AWS学習者向けのブログです

スポンサーリンク

DynamoDB はじめの一歩

はじめに

AWS 認定試験を受けるにあたって避けては通れないサービスの一つが DynamoDB です。DynamoDB は NoSQL データベースということで何となく理解はしているものの実際に使ったことがなく、いまいちイメージが湧きませんでした。そういった経緯があり、今回のエントリーを機に DynamoDB を使ってみることにしました。

使用するサービス

  • Amazon DynamoDB・・・フルマネージド、サーバーレスの key-value NoSQL データベース

サービスに対する詳細な仕様の説明は本エントリーでは割愛しますので、こちらをご参照ください。

手順

  1. テーブルを作成
  2. データをテーブルにロード
  3. データにクエリを実行

1. テーブルを作成

今回はこちらのサイトで紹介されている ProductCatalog テーブルを作成してみます。
以下のような設定でテーブルを作成します。パーティションキーやソートキーについてはこちらをご参照ください。

項目 設定値
テーブル名 ProductCatalog
パーティションキー Id(数値)
ソートキー -

2. データをテーブルにロード

サンプルデータをダウンロードし、以下コマンドでデータをテーブルにロードします。

aws dynamodb batch-write-item --request-items file://ProductCatalog.json

ダウンロードしたデータの中で今回使用するのは以下の JSON です。

3. データにクエリを実行

DynamoDB コンソールで対象のテーブルでクエリを設定し、実行するボタンを押します。

このように結果が取得できます。

コマンドでのクエリの実行に関しては、こちらを参照してください。

さいごに

まだ初歩的な部分だけしか使っていないですが、これだけでも何となく DynamoDB の感覚が掴めた気がします。今後は他のサービスと組み合わせて DynamoDB を使っていこうと思います。

独自ドメインでSSL化した静的 Web サイトを S3 でホスティングしてみる

はじめに

本日は過去のエントリー(S3 で静的WebサイトをホスティングしてみるCloudFront を使用して S3 に格納された画像ファイルにアクセスしてみる)の発展として、独自ドメインSSL化(https)した静的 Web サイトを S3 でホスティングしてみようと思います。

使用するサービス

アーキテクチャ

少し複雑かもしれませんが、名前解決や SSL通信の流れがわかるかと思います。

今回使用する HTML ファイル

シンプルですが、以下の HTML ファイルを使ってみようと思います。

<html>
<head>
<meta charset="utf-8">
<title>AWSの部屋</title>
</head>
<body>
AWSの部屋へようこそ!
</body>
</html>

手順

  1. S3 に静的Webサイトをホスティング
  2. CloudFront を使用して静的Webサイトにアクセス
  3. ドメインを取得
  4. Route53でホストゾーンの作成
  5. ACMSSL証明書を発行する
  6. CloudFrontにSSL証明書を設定する
  7. Route53でDNSレコードを登録
  8. 動作確認

1. S3 に静的Webサイトをホスティング

以下のエントリーに一連の手順を記載していますのでこちらを参照してください。

aws-room.hatenablog.com

今回はこのようなWebサイトをホスティングします。

2. CloudFront を使用して静的Webサイトにアクセス

以下のエントリーに一連の手順を記載していますのでこちらを参照してください。

aws-room.hatenablog.com

3. ドメインを取得

お名前.comで「aws-room.com」というドメインを取得しました。

無料ドメインが欲しいという方はこちらのサイトを参考に取得してみてください。

4. Route53でホストゾーンの作成

ホストゾーンの作成をクリックします。

ドメイン名に取得したドメイン名を入力し、ホストゾーンの作成を押します。

登録をするとドメインに関連付けされたNSレコード4つとSOAレコードが表示されます(お名前.com側にNSレコードの設定が必要になります)。

ns-xxx.awsdns-51.net.
ns-xxx.awsdns-17.org.
ns-xxx.awsdns-53.com.
ns-xxx.awsdns-53.co.uk.

最後にお名前.comでネームサーバーの設定をします。こちらのサイトに手順がまとまっているので参考にしてください。

5. ACMSSL証明書を発行する

まず、リージョンを「米国東部 (バージニア北部) us-east-1」に変更する必要があるようです。(出典:AWS リージョン 用の AWS Certificate Manager

リージョンを「米国東部 (バージニア北部) (us-east-1)」に変更し、「証明書をリクエスト」を押します。

パブリック証明書をリクエストにチェックをして次へをクリックします。

ドメイン名を入力してリクエストをクリックします。

このように証明書が発行されました。

Route53にレコードを作成します(CNAMEレコードを作成します)。

6. CloudFront へ SSL証明書を設定する

CloudFront のディストリビューションを編集します。

発行されたSSL証明書を入力します。

7. Route53でDNSレコードを登録

Route53 で管理することになったドメインと、CloudFront+S3構築を紐づけるためのレコードを作成します。

シンプルルーティングを選択します。

「シンプルなレコードを定義」を押して以下を入力します。

レコードを作成ボタンを押します。(Aレコードを作成します)

8. 動作確認

作成したドメインにブラウザでアクセスすると Webサイトが表示されることが確認できました。

さいごに

今回は様々なサービスを使いましたが、無事目標を達成することができました。今までは座学でしか Route53 のことを理解していなかったのですが、実際に自分で手を動かして使ってみるとサービスに対する理解がより深まりました。まだまだ初歩的なことしか理解できていませんが、少しずつスキルを上げてAWS認定ソリューションアーキテクト-プロフェッショナル合格を目指していこうと思います。

API Gateway + Lambda + Amazon Translateを使って翻訳API を作成してみる

はじめに

筆者はAWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて勉強中ですが、座学はあまり性に合わずできるだけ手を動かして勉強したいため、本ブログを通じて AWS の様々なサービスを使ってみようと思っています。今回は API Gateway、Lambda、Amazon Translate を使って 翻訳API を作成してみようと思います。

使用するサービス

  • Amazon API Gateway・・・API の作成、配布、保守、監視、保護が行えるサービス
  • AWS Lambda・・・サーバレスでコードを実行することが出来るサービス
  • Amazon Translate・・・AWS でサポートされている言語間で翻訳を行うサービス

構成

手順

  1. Amazon Translate を使った英語→日本語翻訳サンプルの作成
  2. Lambda に付与する IAMロールを作成
  3. Lambda関数を作成
  4. API Gateway の設定
  5. 動作確認

1. Amazon Translate を使った英語→日本語翻訳サンプルの作成

Boto3 を使って英語を日本語に翻訳するサンプルを作成します。翻訳する英語は今回「good morning」とします。

import boto3

translate = boto3.client('translate')

# good morning を日本語に翻訳
response = translate.translate_text(
    Text='good morning',
    SourceLanguageCode='en',
    TargetLanguageCode='ja'
)

output_text =response.get('TranslatedText')

print(output_text)

結果は以下のようになります。

このコードをベースにして後の工程で Lambda 関数を作成します。

2. Lambda に付与する IAMロールを作成

Lambda が Amazon Translate と連携できるように 以下のような手順でIAMロールを作成します(ロール名はLambda-Translate-Accessとしました)。

3. Lambda関数を作成

以下のコードで translate-en2ja という Lambda関数を作ってみます。

import json
import boto3

translate = boto3.client(service_name='translate')

def lambda_handler(event, context):

    input_text = event['queryStringParameters']['input_text']
    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="en",
        TargetLanguageCode="ja"
    )

    output_text = response.get('TranslatedText')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

関数の作成を押します。

関数名に「translate-en2ja」と入力します。

「2. Lambda に付与する IAMロールを作成」で作成したロールを選択します。

ラムダ関数をデプロイします。

4. API Gateway の設定

今回は REST API を使ってみようと思います。API の名前は sanvarie-traslate-api とします。

REST API の「構築」ボタンを押します。

AP I名を sanvarie-traslate-api とします。

リソースを作成します。

「3. Lambda関数を作成」で設定した関数名を入力します。

メソッドリクエストを押します。

「URL クエリ文字列パラメータ」に「input_text」と入力します。

Lambda関数の画面を開くと API Gateway が設定されている事がわかります。

API をデプロイします。

デプロイ後にエンドポイントの URLが表示されます

5. 動作確認

エンドポイントの URL に以下のようなリクエストを送ってみます。

https://gj73t4j7rg.execute-api.ap-northeast-1.amazonaws.com/development/translate?input_text=good morning

「good morning」という文章に対して「おはよう」という翻訳結果が得られたことがわかります。

別の文章も試してみました。「I want to eat Sushi」という文章に対しても「お寿司が食べたい」という正しい翻訳結果が得られました。

さいごに

API Gateway を使うことによって API の作成が簡単にできることがわかりました。今回は翻訳の API でしたが、今後は AWS の他の機能と組み合わせて全然違う API も作ってみたいですね。

CloudFront を使用して S3 に格納された画像ファイルにアクセスしてみる

はじめに

筆者はAWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて勉強中ですが、座学はあまり性に合わずできるだけ手を動かして勉強したいため、本ブログを通じて AWS の様々なサービスを使ってみようと思っています。今回は Cloudfront を使用して S3 に格納された画像ファイルにアクセスしてみようと思います。

Amazon CloudFront とは

Amazon CloudFront は、ユーザーへの静的および動的なウェブコンテンツ (.html、.css、.js、イメージファイルなど) の配信を高速化するウェブサービスです。CloudFront では、エッジロケーションというデータセンターの世界的ネットワークを経由してコンテンツを配信します。CloudFront でサービスを提供しているコンテンツをユーザーがリクエストすると、リクエストはエッジロケーションにルーティングされ、レイテンシー (遅延時間) が最小になります。これにより、コンテンツは可能な限り最高のパフォーマンスで配信されます。(出典:Amazon CloudFront とは何ですか?

今回のゴール

  • CloudFront 経由で S3 に格納された画像ファイルにアクセスする
  • 以下のように、S3への直接アクセスはせずに、CloudFront経由でのみ画像へのアクセスを許可する

[イメージ]

使用する画像

こちらのはねぴょんの画像を使用します。

手順

  1. S3 にバケットを作成
  2. S3 に画像ファイルをアップロードする
  3. 画像ファイルへの直接アクセスを確認
  4. CloudFrontディストリビューションを構築する
  5. 動作確認

1. S3 にバケットを作成

以下のバケットを作成します。

「パブリックアクセスをすべてブロック」のチェックを入れてバケットを作成してください。

2. S3 に画像ファイルをアップロードする

作成した S3 バケットを選択し、「アップロード」をクリックします。

ファイルを追加して「アップロード」をクリックします。

3. 画像ファイルへの直接アクセスを確認

オブジェクト URL にブラウザでアクセスします。

バケットのパブリックアクセスがブロックされていることが確認できます。

4. CloudFrontディストリビューションを構築する

以下のように設定しディストリビューションを作成します。

  • オリジナルドメイン・・・フィールドにフォーカスを当てると作成したバケットに対するドメインが選択できます。
  • 名前・・・オリジナルドメインを入力すると自動的に入力されます。
  • S3バケットアクセス・・・「はい、OAIを使用します」を選択します。
  • オリジナルアクセスアイデンティティ・・・新しいOAIボタンからOAIを作成します。
  • バケットポリシー・・・「はい、バケットポリシーを自動で更新します」を選択します。

このように CloudFrontディストリビューションが作成されます。

5. 動作確認

CloudFront経由で画像ににアクセスします。URLは以下のように設定します。今回の設定だと"https://d34ct53yaxe9lx.cloudfront.net/hanepyon.png"になります。

"CloudfrontDomainName"/"S3のファイル名"

このように画像にアクセスすることができました。

さいごに

AWS認定試験でも頻繁に出題される CrontFront ですが、実際に手を動かしてみると座学をするよりもイメージが湧きますね。今度は Route53 を使って独自ドメインからのアクセスにも挑戦してみようと思います。

S3 で静的Webサイトをホスティングしてみる

はじめに

筆者はAWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて勉強中ですが、座学はあまり性に合わずできるだけ手を動かして勉強したいため、本ブログを通じて AWS の様々なサービスを使ってみようと思っています。本日は S3 で静的Webサイトをホスティングしてみようと思います。

S3 とは

Amazon Simple Storage Service (Amazon S3) は、業界をリードするスケーラビリティ、データ可用性、セキュリティ、およびパフォーマンスを提供するオブジェクトストレージサービスです。(出典:Amazon S3とは

今回作ってみる Webサイト

以下をサンプルとして使ってみようと思います。

developers.arcgis.com

ArcGIS に関しては筆者の別ブログをご参照ください。

構成

手順

  1. S3にバケットを作成
  2. バケットポリシーを編集
  3. 静的ウェブサイトホスティングを有効にする
  4. index.html を作成
  5. index.html をバケットにアップロード
  6. 動作確認

1.S3にバケットを作成

以下のバケットを作成します。

「パブリックアクセスをすべてブロック」のチェックを外してバケットを作成してください。

2.バケットポリシーを編集

バケットポリシーを以下のように編集します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*"
        }
    ]
}

3.静的ウェブサイトホスティングを有効にする

バケットのプロパティから静的ウェブサイトホスティングを有効にします。

4.index.html を作成

以下のように index.html を作成します。

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>
      Highlight feature with effects and blending | Sample | ArcGIS API for
      JavaScript 4.22
    </title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
      #messageDiv {
        padding-left: 10px;
        padding-right: 10px;
      }
    </style>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.22/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.22/"></script>

    <script>
      require([
        "esri/WebMap",
        "esri/views/MapView",
        "esri/layers/VectorTileLayer",
        "esri/Graphic",
        "esri/layers/FeatureLayer",
        "esri/layers/GraphicsLayer",
        "esri/layers/GroupLayer"
      ], (
        WebMap,
        MapView,
        VectorTileLayer,
        Graphic,
        FeatureLayer,
        GraphicsLayer,
        GroupLayer
      ) => {
        const map = new WebMap({
          basemap: {
            portalItem: {
              id: "f35ef07c9ed24020aadd65c8a65d3754" // modern antique vector tiles
            }
          }
        });
        const vtLayer = new VectorTileLayer({
          portalItem: {
            id: "2afe5b807fa74006be6363fd243ffb30" // gray vector tiles canvas
          }
        });
        const countries = new FeatureLayer({
          portalItem: {
            id: "53a1e68de7e4499cad77c80daba46a94" // boundaries of countries
          }
        });
        // This group layer groups the gray canvas vector tiles and
        // countries feature layer.
        // With destination-over blendMode, the background layer covers
        // the top layer. The top layer is put behind the destination layer.
        // So when the app starts, the basemap layer will be shown over this layer
        const groupLayer = new GroupLayer({
          layers: [vtLayer, countries],
          blendMode: "destination-over"
        });
        map.add(groupLayer);
        const view = new MapView({
          container: "viewDiv",
          map: map,
          zoom: 6,
          center: [2, 46],
          constraints: {
            snapToZoom: false,
            minScale: 147914381
          }
        });
        let layerView, animation;
        // countryGraphicsLayer is added to the view's basemap.
        // It will contain black polygon covering the extent of the world
        // the country graphic will also be added to this layer when user clicks a country.
        // With destination-in blend mode, the contents of background layer is
        // kept where it overlaps with top layer. Everything else is made transparent.
        // In this case, the countryGraphicsLayer will be displayed underneath
        // modern antique vector tiles basemap.
        // The bloom effect will add a glow around the selected country.
        const countryGraphicsLayer = new GraphicsLayer({
          blendMode: "destination-in",
          effect: "bloom(200%)"
        });
        map.loadAll().then(async () => {
          addWorld();
          map.basemap.baseLayers.getItemAt(1).blendMode = "multiply";
          // add the buffer graphicslayer to the basemap
          map.basemap.baseLayers.add(countryGraphicsLayer);
          // get a reference ot the countries featurelayer's layerview
          // layerview will be queried to get the intersecting country
          // when user clicks on the map
          layerView = await view.whenLayerView(countries);
        });
        view.ui.add("messageDiv", "top-right");
        const symbol = {
          type: "simple-fill",
          color: "white",
          outline: null
        };
        // listen to the view's click event
        view.on("click", async (event) => {
          // query the countries featurelayer for a country that intersects the point
          // user clicked on
          const {
            features: [feature]
          } = await layerView.queryFeatures({
            geometry: view.toMap(event),
            returnGeometry: true,
            maxAllowableOffset: 10000,
            outFields: ["*"]
          });
          countryGraphicsLayer.graphics.removeAll();
          animation && animation.remove();
          let world = addWorld();
          // add the clicked country feature to the graphicslayer
          if (feature) {
            feature.symbol = symbol;
            countryGraphicsLayer.graphics.add(feature);
            // add a fade animation to show the highlight effect
            // for the selected country
            animation = fadeWorld(world);
            // zoom to the highlighted country
            view.goTo(
              {
                target: view.toMap(event),
                extent: feature.geometry.extent.clone().expand(1.8)
              },
              { duration: 1000 }
            );
          }
        });
        function addWorld(world) {
          world = new Graphic({
            geometry: {
              type: "extent",
              xmin: -180,
              xmax: 180,
              ymin: -90,
              ymax: 90
            },
            symbol: {
              type: "simple-fill",
              color: "rgba(0, 0, 0, 1)",
              outline: null
            }
          });
          countryGraphicsLayer.graphics.add(world);
          return world;
        }
        // add a fading animation when user clicks on a country
        function fadeWorld(world) {
          let timer;
          // requestAnimationFrame method specifies "frame" function
          // to perform an animation where the opacity of the world polygon graphic
          // decreased by 0.1 until it is 0 or completely transparent
          // then the animation is cancelled
          function frame() {
            const symbol = world.symbol.clone();
            symbol.color.a = Math.max(0, symbol.color.a - 0.1);
            world.symbol = symbol;
            if (symbol.color.a > 0) {
              timer = requestAnimationFrame(frame);
            }
          }
          frame();
          return {
            remove() {
              cancelAnimationFrame(timer);
            }
          };
        }
      });
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
    <div id="messageDiv" class="esri-widget esri-heading">
      <h4 class="esri-heading">Click on a country</h4>
    </div>
  </body>
</html>

5.index.html をバケットにアップロード

index.html をバケットにアップロードします。

バケットのプロパティに Web サイトの URL があるのでこれを使って Web サイトにアクセスしてください。

6.動作確認

Web サイトにアクセスできることを確認しました。

さいごに

AWS認定試験でも頻繁に出題される S3 の Webサイトホスティングですが、ちょっとしたWebサイトを公開するのには非常に便利な機能ですね。今後はただ Web サイトを公開するだけではなくCloudFront などを使ってみようと思います。

S3 に格納したファイルを Lambda で操作してみる

はじめに

筆者はAWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて勉強中ですが、座学はあまり性に合わずできるだけ手を動かして勉強したいため、本ブログを通じて AWS の様々なサービスを使ってみようと思っています。本日はLambdaをメインに勉強してみようと思います。

Lambda とは

AWS Lambda は、サーバーレスでイベント駆動型のコンピューティングサービスであり、サーバーのプロビジョニングや管理をすることなく、事実上あらゆるタイプのアプリケーションやバックエンドサービスのコードを実行することができます。(出典:AWS Lambda

今回考えたアーキテクチャ

ざっくり以下のような感じです。

  1. Boto3を使ってS3にファイルをPUT
  2. S3にファイルがPUTされるとLambdaが起動
  3. Lambdaのローカル保存先(/tmp)にファイルを保存、ファイル名を変更してS3にPUT

実行環境

macOS 11.3.1
Python 3.9.6
Boto3 1.20.53

手順

  1. S3にバケットを作成
  2. S3にファイルをPUTするプログラムを作成
  3. Lambdaに付与するIAMロールを作成
  4. Lambda関数を作成
  5. 作成したバケットにイベント通知を作成
  6. 動作確認

1.S3にバケットを作成

2022-sanvarie-bucket というバケットを作成します。設定はデフォルトでOKです。

2.S3にファイルをPUTするプログラムを作成

Boto3を使ってS3にファイルをPUTします。Boto3に関しては以下のエントリーに書いてありますのでご参照ください。

aws-room.hatenablog.com

また、ファイルは以下の画像(hane.jpg)を使用します。

import os
import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('2022-sanvarie-bucket')
filepath = '/Users/xxx/Documents/AWS/blog/data/hane.jpg'

# S3にアップロード
bucket.upload_file(filepath, os.path.basename(filepath))

試しに動かしてみます。

対象のファイルがPUTされたことがわかりました。

3.Lambdaに付与するIAMロールを作成

LambdaがS3と連携できるようにIAMロールを作成します。

4.Lambda関数を作成

save-file という Lambda関数を作ってみます。

関数を作成すると関数内で実行するコードの編集が可能になります。

import os
from datetime import datetime
import urllib.parse
import boto3
import subprocess

s3 = boto3.resource('s3')

def lambda_handler(event, context):

    # 対象のバケットとファイル名取得
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    
    # Lambdaのローカルのファイル保存先(/tmp)を設定
    file_path = '/tmp/' + datetime.now().strftime('%Y-%m-%d-%H-%M-%S')

    try:
        bucket = s3.Bucket(bucket) 
        
        # /tmpにダウンロード用のフォルダを作成
        cmd = ['mkdir', '-p', file_path]
        subprocess.run(cmd, stdout=subprocess.PIPE)

        # S3に格納したファイルを作成したフォルダにダウンロード
        bucket.download_file(key, os.path.join(file_path, key))   

        # ファイルの名前を変えてS3にPUT
        bucket.upload_file(os.path.join(file_path, key), 'hane2.jpg')

        return
    except Exception as e:
        print(e)

5.作成したバケットにイベント通知を作成

以下のようにイベント通知を作成します。

6.動作確認

「2.S3にファイルをPUTするプログラムを作成」のプログラムを実行し、S3にhane.jpg と hane2.jpg が格納されることを確認しました。

さいごに

S3 と Lambda の連携ですがかなり簡単にできることがわかりました。ただ、まだ基本的なことところしか触ってないので、今後はLambdaと様々なサービスを組み合わせてサーバーレスなアプリを作ってみようと思います。

S3 にファイル格納時に SNS からメールを送信させてみる

概要

本日はS3とSNSの連携を試してみたいと思います。AWS認定ソリューションアーキテクト-アソシエイトに合格したものの、実際にAWSを触ったことがあまりないため、少しずつですが色々なサービスを使っていこうと思います。

今回の目標

S3とSNSを連携させる

使用するサービス

構成

手順

  1. SNSトピックを作成
  2. サブスクリプションの設定
  3. S3にバケットを作成
  4. SNSトピックアクセスポリシーの編集
  5. S3イベント通知の作成
  6. 動作確認

1.SNSトピックを作成

以下のようにSNSトピックを作成します。

2.サブスクリプションの設定

以下のようにサブスクリプションの設定を行います。

3.S3にバケットを作成

S3に適当にバケットを作成します。今回は前回のエントリーで使用したバケットを使用します。

aws-room.hatenablog.com

4.SNSトピックアクセスポリシーの編集

SNSコンソールページに戻り先ほど作成したトピックを選択し、編集を押下しアクセスポリシーを以下のように編集します。(バケットポリシーを編集)

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__default_statement_ID",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "SNS:GetTopicAttributes",
        "SNS:SetTopicAttributes",
        "SNS:AddPermission",
        "SNS:RemovePermission",
        "SNS:DeleteTopic",
        "SNS:Subscribe",
        "SNS:ListSubscriptionsByTopic",
        "SNS:Publish"
      ],
      "Resource":"<SNSトピックのARN>"
      "Condition": {
        "ArnLike": {
          "aws:SourceArn": "arn:aws:s3:*:*:<バケット名>"
        }
      }
    }
  ]
}

5.S3イベント通知の作成

作成したバケットに対してイベント通知の作成を行います。

6.動作確認

バケットにファイルをアップロードするとこのようにメールを受信することができるようになりました。

まとめ

いかがでしたでしょうか。AWS認定試験で頻繁に問われるS3とSNSの連携ですが、実際に行ってみるとすごく簡単にできることがわかりました。やはり自分で手を動かしてみると本を読んで勉強するよりイメージが湧きやすくなりますね。次回は Lambda に挑戦してみようと思います。