AWSの部屋

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

スポンサーリンク

SQS のメッセージを EC2 から Python で送受信する

はじめに

以前のエントリーでSQS キューのメッセージを Lambda で処理してみましたが、今回は EC2 を使ってみようと思います。

アーキテクチャ

アプリケーション間連携に SQS を使うケースはこんな感じのアーキテクチャになるのではないでしょうか(その場合 EC2 の数はもっと多いかと思いますが)。

手順

  1. インスタンス構築
  2. SQS キュー を作成
  3. EC2 で SQS にメッセージを送信する処理の作成
  4. EC2 でメッセージを SQS から受信する処理の作成
  5. 動作確認

1. インスタンス構築

以下二つのインスタンスを構築します。

ホスト名 OS 用途
producer-server Amazon Linux 2 SQS にメッセージを送信する
consumer-server Amazon Linux 2 SQS からメッセージを受信する
Python3系 のインストール

list installed を実行して、Python 3 がホストにすでにインストールされているかどうかを確認します。

yum list installed | grep -i python3

Python 3 がまだインストールされていない場合は、yum パッケージマネージャーを使用してパッケージをインストールします。

sudo yum install python3 -y
boto3 をインストール

仮想環境をアクティブにして、boto3 をインストールします。

#仮想環境の構築
python3 -m venv my_app/env
#仮想環境をアクティブにする
source ~/my_app/env/bin/activate
#boto3をインストール
pip install boto3

2. SQS キュー を作成

test-queue という名称のキューを作成します。設定はデフォルトでOKです。

3. EC2 で SQS にメッセージを送信する処理の作成

SQS へメッセージを送信する処理です。

import json
import boto3

sqs = boto3.client("sqs")
queue_url = "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxx/test-queue"

response = sqs.send_message(QueueUrl=queue_url, MessageBody=json.dumps({"weather": "sunny", "temperature": 32}))
print(response)

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

{'MD5OfMessageBody': '24a7ffc4a4c761e6f9054c75f933c8f3', 'MessageId': 'a6f5ac1e-da8f-4338-8b14-a38557f9cee9', 'ResponseMetadata': {'RequestId': '3bfd77ab-3837-5377-9088-2bed5d28a434', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '3bfd77ab-3837-5377-9088-2bed5d28a434', 'date': 'Sat, 21 Jan 2023 22:10:39 GMT', 'content-type': 'text/xml', 'content-length': '378'}, 'RetryAttempts': 0}}

メッセージが送信されているか確認します。

4. EC2 でメッセージを SQS から受信する処理の作成

SQS からメッセージを受信する処理です。受信した後に message.delete() をしないとメッセージはキューに残り続けます。

import boto3

sqs = boto3.client("sqs")
queue_url = "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxx/test-queue"

response = sqs.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=1)

print(response)

for message in response["Messages"]:
    sqs.delete_message(QueueUrl=queue_url, ReceiptHandle=message["ReceiptHandle"])      

実行結果は以下のようになります。送信したメッセージを受信したことがわかります。

{'Messages': [{'MessageId': 'a6f5ac1e-da8f-4338-8b14-a38557f9cee9', 'ReceiptHandle': 'AQEB9wlV11+SyA4VDhX1ne+9Xe+y6tBFeW+7+ySibha5jC9uLECQg/pfXJF3Ez8TMWEeCJt/5Yxzh/Mbhym+3/EO1E1QCJ0gpY569NyBZXEDhVgHGuIX2ZIg9x8l5AL78Qv/r9lDBhSD4qeXeXEQq9Kv7Y9lvFueRHy/bdG1GNKO6dbN7HGaaLt9oEVyWbH2dsHesaxUGJNW8uBd4pQn+kib0ATT4xlcts4ciLnFYgXv6W4HiF8owvJcxqyNkS/gJ3qNcuRoLTeX/7lsLAyjvsLg5pUX4f/bdSTVtvlrn7PyC861vd3x1nlX0G5lN0+ysM2FYaaR7sLgjy+o+tD9T8KtzvRM7Mb+2pUYmudZezSjnWoAftjF4lJbz/Uk80l5zf/HRwIc5GU4Na1HgCIbVACtyA==', 'MD5OfBody': '24a7ffc4a4c761e6f9054c75f933c8f3', 'Body': '{"weather": "sunny", "temperature": 32}'}], 'ResponseMetadata': {'RequestId': 'c3c980fb-b3ef-5283-a91b-dcbddfad4054', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': 'c3c980fb-b3ef-5283-a91b-dcbddfad4054', 'date': 'Sat, 21 Jan 2023 22:41:06 GMT', 'content-type': 'text/xml', 'content-length': '920'}, 'RetryAttempts': 0}}

さいごに

今回は 単純な構成での連携でしたが、次はファンアウトを使った連携等にも挑戦してみたいと思います。

踏み台サーバーを経由してプライベートサブネットにある EC2 に SSH で接続する

はじめに

AWS 上にシステムを構築する際はセキュリティを高める上で踏み台サーバーの存在は欠かせないかと思います。本日は踏み台サーバーを経由してプライベートサブネットにある EC2 に SSH で接続してみようと思います。

踏み台サーバーとは

外部からの直接アクセスを許可しないサーバーやパソコンにアクセスするために設置される中継用のサーバーのことです。踏み台サーバーを導入することによって、機密情報を保管したサーバーへのアクセス元が1か所に限定されるため、外部からの侵入リスクが軽減されるなどのメリットがあります。

アーキテクチャ

①Web Server に SSH でアクセス(Web Server を踏み台サーバーとして使う)
②Web Server から DB Server に SSH でアクセス

実行環境

macOS 13.0.1

手順

  1. ネットワーク・サーバ構築
  2. 秘密鍵を Web Server にアップロード
  3. Web Server に SSH でアクセス
  4. Web Server から DB Server に SSH でアクセス

1. ネットワーク・サーバ構築

以下のようにサブネット、ルートテーブルなどを作成しネットワーク・サーバを構築します。

<ルートテーブル>

ルートテーブル名 設定
public-route-table 10.0.0.0/16, 0.0.0.0/0
private-route-table 10.0.0.0/16

<サブネット>

サブネット名 ルートテーブル
public-subnet public-route-table
private-subnet private-route-table

<セキュリティグループ>

セキュリティグループ名 インバウンドルール
public-security-group ポート22, 443を許可(SSH, HTTPSのポート)
private-security-group ポート22を許可(SSHのポート)

<EC2>

ホスト名 OS セキュリティグループ
web-server Amazon Linux 2 public-security-group
db-server Amazon Linux 2 private-security-group

2. 秘密鍵を Web Server にアップロード

EC2 にSSH でアクセスするには「秘密鍵」が必要ですので、秘密鍵を Web Server に格納します。サーバーにファイル転送をするには「SCP」というプロトコルを使います。

カレントディレクトリに置かれた my-secret-key.pem を転送先のホームディレクトリ(「~/」)に転送するには以下のようにします。

「scp -i 使用する秘密鍵 転送するファイル ユーザ@IPアドレス:コピー先」

scp -i my-secret-key.pem my-secret-key.pem ec2-user@ec2-54-249-215-42.ap-northeast-1.compute.amazonaws.com:~/

3. Web Server に SSH でアクセス

Web Server に割り当てたパブリックIPアドレスに対してアクセスします。

ssh -i my-secret-key.pem ec2-user@ec2-54-249-215-42.ap-northeast-1.compute.amazonaws.com

今回の目的を達成するにおいて必須ではありませんが、秘密鍵を誰でも使えるようにしておくのはセキュリティ上よろしくないので、自分しか使えないように秘密鍵パーミッションを変更します。

chmod 400 my-secret-key.pem

4. Web Server から DB Server に SSH でアクセス

DB Server に割り当てたプライベートIPアドレスに対してアクセスします。

ssh -i my-secret-key.pem ec2-user@10.0.0.177

さいごに

IT業界にいる方にとっては踏み台サーバーを使うことは当たり前かと思いますが、機密情報を保管したサーバーに直接アクセスできるような環境を使っている会社さんも多いのではないかと思います。興味のある方はぜひ本エントリーのように踏み台サーバーを使ってみてください。

VPCエンドポイント経由で S3 にアクセスする ~インターフェイスエンドポイント編~

はじめに

過去エントリーゲートウェイエンドポイント経由での S3 へのアクセスについて書きました。本エントリーではインターフェイスエンドポイントを使って S3 へアクセスしてみようと思います。

VPCエンドポイントとは

VPCAWS サービス間の接続を有効にするコンポーネントのことで、以下2つの種類の VPCエンドポイントがあります。本エントリーでは「インターフェイスエンドポイント」を使います。

ゲートウェイエンドポイント

VPC のサービス専用のゲートウェイをアタッチします。ゲートウェイエンドポイントの対象サービスは S3 と DynamoDB です。

インターフェイスエンドポイント

VCP のサブネットに ENI を作成します。ENI に割り当てられたプライベートIPアドレスを使用してサービスにアクセスします(AWS PrivateLinkという技術を使用)。インターフェイスエンドポイントの対象サービスは S3 を含み数多くあります。

アーキテクチャ

インターネット経由での S3 のアクセスを拒否し、インターフェイスエンドポイント経由での S3 へのアクセスのみを許可します。

手順

  1. S3 バケットの作成
  2. IAMロールの作成
  3. EC2 インスタンスの起動
  4. VPCエンドポイントの作成
  5. バケットポリシーの設定
  6. 動作確認

1. S3 バケットの作成

「20230108-endpoint-interface」というバケットを作成します。

適当にファイルもアップロードします。

2. IAMロールの作成

「EC2toS3」という EC2 が S3 へアクセスするための IAMロールを作成します。

3. EC2 インスタンスの起動

作成した IAMロールを設定し、プライベートサブネットに EC2 インスタンスを起動します。

また、パブリックサブネットにも同様に EC2 インスタンスを起動します。

4. VPCエンドポイントの作成

「エンドポイントを作成」を押します。

サービス「com.amazonaws.ap-northeast-1.s3」を選択します(タイプ=Interfaceの当該サービスを選択します)。

エンドポイントを設定する VPC を選択して、ENI を配置するサブネットを選択します。

ENI に設定するセキュリティグループを選択します。(EC2 からHTTPとHTTPSを受け取れるセキュリティグループとします)

このようにエンドポイントが作成されます。

5. バケットポリシーの設定

バケットポリシーを以下のように設定し、インターフェイスエンドポイントを経由した場合のみバケットへのアクセスを許可します。

{
  "Id": "VPCe",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VPCe",
      "Action": "s3:*",
      "Effect": "Deny",
      "Resource": "arn:aws:s3:::20230108-endpoint-interface",
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpce": [
            "vpce-05f7380178e5d62db"
          ]
        }
      },
      "Principal": "*"
    }
  ]
}

6. 動作確認

以下のようなコマンドを使ってインターフェースエンドポイント経由での動作確認を行います。

aws s3 --endpoint-url https://bucket.<エンドポイントごと固有の値>.s3.ap-northeast-1.vpce.amazonaws.com ls s3://<バケット名>

<エンドポイントごと固有の値>はエンドポイントのDNS名の一部を設定します。

パブリックサブネットからのアクセス

[インターネット経由でのアクセス]

aws s3 ls --region ap-northeast-1 --recursive s3://20220809-endpoint-gateway

アクセスが拒否されました。想定通りの動きですね。

[インターフェースエンドポイント経由でのアクセス]

aws s3 ls --region ap-northeast-1 --endpoint-url https://bucket.vpce-05f7380178e5d62db-9tqbinyi.s3.ap-northeast-1.vpce.amazonaws.com s3://20230108-endpoint-interface

対象の S3 バケットにアクセスすることができました。

プライベートサブネットからのアクセス

[インターフェースエンドポイント経由でのアクセス]

aws s3 ls --region ap-northeast-1 --endpoint-url https://bucket.vpce-05f7380178e5d62db-9tqbinyi.s3.ap-northeast-1.vpce.amazonaws.com s3://20230108-endpoint-interface

対象の S3 バケットにアクセスすることができました。

さいごに

ゲートウェイエンドポイントと異なりインターフェースエンドポイントは料金が発生しますので、そこだけご注意ください。

Cognito ユーザープールをオーソライザーとして使って API Gateway のアクセスを制御する

はじめに

本日は Cognito ユーザープールを API Gateway のオーソライザーとして使ってみようと思います。

Cognito ユーザープール とは

以下のエントリーをご参照ください。

www.aws-room.com

オーソライザーを使うメリット

API Gatewayのエンドポイントはグローバルに公開されているおり、誰でもアクセス可能です。IPアドレスなどでアクセスを制御することもできますが、認証されたユーザだけがアクセス可能な API としてデプロイすることでセキュアな状態を維持することができます。

今回のゴール

Cognito 経由で REST API を使って S3 のバケット一覧を取得します

アーキテクチャ

手順

  1. ユーザープールの作成
  2. ユーザ登録
  3. IDトークンの取得
  4. IAMロール 作成
  5. Lambda 関数の作成
  6. API Gateway作成
  7. 動作確認

1. ユーザープールの作成

以下の設定でユーザープールを作成します。

項目
プロバイダーのタイプ Cognito ユーザープール
Cognito ユーザープールのサインインオプション E メール
パスワードポリシーモード Cognito のデフォルト
多要素認証 MFAなし
ユーザーアカウントの復旧 デフォルト
セルフサービスのサインアップ デフォルト
属性検証とユーザーアカウントの確認 デフォルト
属性変更の確認 デフォルト
必須の属性 email
属性変更の確認 デフォルト
E メール Cognito で E メールを送信
ユーザープール名 任意のユーザープール名
ホストされた認証ページ デフォルト
アプリケーションタイプ 秘密クライアント
ホストされた認証ページ デフォルト
アプリケーションクライアント名 任意のアプリケーションクライアント名
クライアントのシークレット クライアントのシークレットを生成しない
高度なアプリケーションクライアントの設定 デフォルト
属性の読み取りおよび書き込み許可 デフォルト

2. ユーザ登録

以下のようにユーザを作成します。

3. IDトークンの取得

このIDトークンを利用して API Gateway へアクセスしますので事前に取得します。

import boto3
import json

# CognitoIdentityProviderクライアント(Using Amazon Cognito user pools API)
idp_client = boto3.client('cognito-idp')

response = idp_client.admin_initiate_auth(
           UserPoolId = "xxx",
           ClientId = "xxx",
           AuthFlow = "ADMIN_NO_SRP_AUTH",
           AuthParameters={
               "USERNAME": "xxx",
               "PASSWORD": "xxx",
           }
 )

print(json.dumps(response, indent=2))

以下のようなイメージでIDトークンが取得できます(以下は値を加工しています)

{
  "ChallengeParameters": {},
  "AuthenticationResult": {
    "AccessToken": "eyJrlWcQT0_LDihkbBhWf_zaddMc6k1JEcd1hGlsyOV3D4n2qClnxlFaTDTFXZvM8gco8QX0W0_ib_Ium_4wnORiUAQQeoQK6hEZruY7IJ7EGfkTictJyQl5iOdxCnk7TYA",
    "ExpiresIn": 3600,
    "TokenType": "Bearer",
    "RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.Io5wUP2Aw9ZTCnxO_xmzG-q6riAKfpdhmTLjnT6BGtRH2fowrNIg7XjueMFjztVlkXGqRr2zG1HJLe4azmomdJe1d7_-N61zgiBYG9MZI_1sF8Z",
    "IdToken": "eyJraWQiOiJiV3hrV3FOZ2lCdSsrZDJLWGwxa0JVdjlCSUVjRHZuUUg4YmlaTklSQWVJPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIwNTYyNDVkOS03MzIwLTQzZDgtYWRiNC1kMzY3NDEyNGVjMzciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaX99rEU6uHLA"
  },
  "ResponseMetadata": {
    "RequestId": "ed94d428-8120-4838-9429-49320925d7e6",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Sat, 19 Nov 2022 05:14:08 GMT",
      "content-type": "application/x-amz-json-1.1",
      "content-length": "4132",
      "connection": "keep-alive",
      "x-amzn-requestid": "ed94d428-8120-4838-9429-49320925d7e6"
    },
    "RetryAttempts": 0
  }
}

4. IAMロール 作成

「Lambda-S3Access」という AWS Systems Manager への権限を付与したロールを作成します。

5. Lambda 関数の作成

以下のように Lambda 関数を作成します。

項目
オプション 一から作成
関数名] get-s3-bucket-list
ランタイム] Python 3.9
アーキテクチャ] 86_64
既存のロール]] Lambda-S3Access
ソースコード

S3 のバケット一覧を取得します。

import json
import boto3

s3 = boto3.resource('s3')

def lambda_handler(event, context):

    bucket_list = []
    for bucket in s3.buckets.all():
        bucket_list.append(bucket.name)
    
    return bucket_list

6. API Gateway作成

以下のように API Gateway を作成します。

項目
API タイプを選択 REST API
プロトコルを選択する] REST
新しい API の作成 ] 新しい API
API cognito-authorizer
説明 任意
エンドポイントタイプ デフォルト
API 作成後

リソースを作成します。

「5. Lambda関数の作成」で作成した関数名を入力しメソッドを作成します。

Lambda 関数に自動的に API Gateway のトリガーが設定されます。

API をデプロイします。

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

以下のようにオーソライザーを作成します。

「認可トークン」項目にIDトークンをコピーしてテストすると正常終了します。

リソース > メソッドリクエストを選択します。

作成したオーソライザーを選択し更新します。

再度API をデプロイします。

7. 動作確認

IDトークンなし

以下のように REST API を実行します。

curl https://m158t0jime.execute-api.ap-northeast-1.amazonaws.com/development

認証されていない旨のメッセージが返されました。

{"message":"Missing Authentication Token"}
IDトークンあり

以下のように REST API を実行します。(IDトークンは加工しています)

curl https://m158t0jime.execute-api.ap-northeast-1.amazonaws.com/development -H "Authorization: eyJraWQiOiJiV3hrV3"

S3 のバケット一覧を取得することができました。

["20220514-cloudfront-test", "20220521-web-hosting", "20220807-sqs-test", "20220809-endpoint-gateway", "20220809-vpc-endpoint", "20220810-s3-gateway-endpoint", "20220810-test-bucket", "20220812-rekognition-test", "aws-athena-query-results-370560102364-ap-northeast-1", "aws-cloudtrail-logs-370560102364-44d0a6db", "aws-presigned-url", "cf-templates-lxrja6wfp65n-ap-northeast-1", "data-lake-20210331", "log-from-kinesis-sanvarie", "test-queue-sanvarie"]

さいごに

少しとっつきにくい Cognito ですが、使いこなせば非常に便利なサービスですね。まだまだ触りのところしかわからないので引き続き勉強しようと思います。

RDS Proxy を使って Lambda から Auroraに接続してみる

はじめに

本日は RDS Proxy を使ってみようと思います。RDS Proxyは AWS認定試験で頻出するサービスなのでしっかり押さえておきたいですね。

RDS Proxy とは

Lambda 関数から DB に多くの接続が発生する可能性があるアーキテクチャの場合、リクエストの増加に伴い DB 接続の拒否が発生しますが、RDS Proxy を使うことによって DB 接続プールを確立し再利用することで効率的な接続をすることができるようになります。

RDS Proxy を使わないパターン

RDS Proxy を使うパターン

アーキテクチャ

Amazon Secrets Manager に格納した DB 接続情報を使って Lambda から Aurora に接続します。

手順

  1. DB の作成
  2. IAMロールの作成
  3. Secrets Manager の設定
  4. RDS Proxy の作成
  5. テストデータ作成
  6. Lambda 関数の作成
  7. 動作確認

1. DB の作成

以下の設定で DB を作成します。

[データベース作成方法を選択]:標準作成
[エンジンのタイプ]:Amazon Aurora [エディション]:PostgreSQL との互換性を持つ Amazon Aurora
[テンプレート]:開発/テスト
[DB クラスター識別子]:aws-room-cluster
[マスターユーザー名]:postgres
[パスワードの自動生成]:チェックしない
[DB インスタンスクラス]:メモリ最適化クラス
[可用性と耐久性]:Aurora レプリカを作成しない
[ネットワークタイプ]:IPv4
[Virtual Private Cloud (VPC)]:任意のVPC
[サブネットグループ]:任意のサブネットグループ
[パブリックアクセス]:あり
[VPCセキュリティグループ]:既存の 選択
[既存のセキュリティグループ ]:任意のセキュリティグループ
[アベイラビリティーゾーン]:任意のアベイラビリティーゾーン

DBを作成したら接続確認をします。

2. IAMロールの作成

access-rdb」という Amazon AuroraAWS Secrets Manager への権限を付与したロールを作成します。

3. Secrets Manager の設定

以下のようにシークレットを作成します。

[シークレットのタイプ]:Amazon RDS データベースの認証情報
[ユーザー名]:「1. DB の作成」で設定したユーザ
[パスワード]:「1. DB の作成」で設定したパスワード
[暗号化キー]:任意の暗号化キー
[データベース]:「1. DB の作成」で作成したデータベース

4. RDS Proxy の作成

以下のように RDS Proxy を作成します。

[エンジンファミリー]:PostgreSQL
[プロキシ識別子]:任意の文字列
[データベース]:「1. DB の作成」で作成したAurora DB クラスタ
[接続プールの最大接続数]:100
[Secrets Manager のシークレット]:「4. Secrets Manager の設定」で作成したシークレット
[IAM ロール]:IAMロールを作成
[IAM 認証]:許可されていません

5. テストデータ作成

test というテーブルに以下のようなデータを作成しました。

6. Lambda 関数の作成

以下のように Lambda 関数を作成します。

[オプション]:一から作成
[関数名]:access-rds-through-proxy
[ランタイム]:Python 3.8
[アーキテクチャ]:x86_64
[既存のロール]:access-rdb

レイヤーの追加

psycopg2 を使用して PostgreSQL に接続するために以下のようにレイヤーの追加を行います。

[レイヤーソース]:ARN を指定
[ARNを指定]:arn:aws:lambda:ap-northeast-1:898466741470:layer:psycopg2-py38:1

ソースコード

Secrets Manager からDB 接続情報を取得して 作成したデータベースにあるテーブルにアクセスします。

import boto3
from botocore.exceptions import ClientError
import base64
import psycopg2
import json

secret_name = "aurora"
region_name = "ap-northeast-1"
    
def lambda_handler(event, context):
    secret_dict = json.loads(get_secret())

    connect = psycopg2.connect(
                  host = secret_dict['host'],
                  user = secret_dict['username'],
                  password = secret_dict['password'],
                  port = 5432,
                  dbname = 'postgres'
              )
    with connect.cursor() as cur:
        cur.execute('select * from public.test')
        rows = cur.fetchall()

    print(rows)

def get_secret():
    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )

    except ClientError as e:
        print(e.response['Error']['Code'])
        if e.response['Error']['Code'] == 'DecryptionFailureException':
            raise e
        elif e.response['Error']['Code'] == 'InternalServiceErrorException':
            raise e
        elif e.response['Error']['Code'] == 'InvalidParameterException':
            raise e
        elif e.response['Error']['Code'] == 'InvalidRequestException':
            raise e
        elif e.response['Error']['Code'] == 'ResourceNotFoundException':
            raise e
    else:
        if 'SecretString' in get_secret_value_response:
            secret = get_secret_value_response['SecretString']
        else:
            secret = base64.b64decode(get_secret_value_response['SecretBinary'])

        return secret

7. 動作確認

Lambda を実行すると以下のように Aurora に格納したテストデータを取得することができました。

さいごに

今まで Aurora はあまり使ってこなかったのですが、RDS Proxy の学習とともに Aurora や Secrets Manager に対する理解も深めることができました。途中つまずくところもあったのですが、やはり座学よりも自分で手を動かした方が知識が身体に染み付く気がしますね。

パラメータストアを使って Lambda から機密情報にアクセスする

はじめに

本日はパラメータストアを使ってみようと思います。AWS認定試験に頻出のサービスなのでしっかり理解しておきたいですね。

パラメータストアとは

AWS Systems Manager のサービスの一つで、データベースへの接続文字列のようなパラメータを一元管理します。

アーキテクチャ

API Gateway 経由でパラメータストアに登録されているDB接続情報を取得します。

手順

  1. 機密情報をパラメータストアに登録
  2. IAMロール 作成
  3. Lambda 関数の作成
  4. API Gateway作成
  5. 動作確認

1. 機密情報をパラメータストアに登録

以下3つの値をパラメータストアに登録します。

DB名

[名前]:db-name
[利用枠]:標準
[タイプ]:安全な文字列
[KMS キーソース]:現在のアカウント
[KMS キー ID]:alias/aws/ssm
[値]:test

ユーザ名

[名前]:user-name
[利用枠]:標準
[タイプ]:安全な文字列
[KMS キーソース]:現在のアカウント
[KMS キー ID]:alias/aws/ssm
[値]:sanvarie

パスワード

[名前]:password
[利用枠]:標準
[タイプ]:安全な文字列
[KMS キーソース]:現在のアカウント
[KMS キー ID]:alias/aws/ssm
[値]:hoge

2. IAMロール 作成

access-parameter-store」という AWS Systems Manager への権限を付与したロールを作成します。

3. Lambda 関数の作成

以下のように Lambda 関数を作成します。

[オプション]:一から作成
[関数名]:get-db-connection
[ランタイム]:Python 3.9
[アーキテクチャ]:x86_64
[既存のロール]:access-parameter-store

ソースコード

パラメータストアに登録されている値を取得します。

import json
import boto3

parameter_names = ['db-name','user-name','password']

def lambda_handler(event, context):

    output_text = get_ssm_param()

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

def get_ssm_param():
    ssm = boto3.client('ssm')
    
    response = ssm.get_parameters(
        Names = parameter_names,
        WithDecryption = True
    )
    
    params = {}
    
    # パラメータを配列に格納
    for param in response['Parameters']:
        params[param['Name'] ] = param['Value']

    return params

4. API Gateway作成

REST API として API を作成します。

リソースを作成します。

「3. Lambda関数の作成」で作成した関数名を入力しメソッドを作成します。

Lambda 関数に自動的に API Gateway のトリガーが設定されます。

API をデプロイします。

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

5.動作確認

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

https://1f9hnppgfj.execute-api.ap-northeast-1.amazonaws.com/development/parameter

パラメータストアに格納した値を取得することができました。

さいごに

このように パラメータストアを使うことによって簡単に機密情報へのアクセスをすることができます。AWS Secrets Manager を使っても同様のことができますので、二つのサービスの違いを知るために AWS Secrets Manager も使ってみようと思います。

Amazon Rekognition を使った画像分析の結果を DynamoDB に格納する

はじめに

近年、画像を分析してそこから情報やインサイトを抽出することが一般的になってきています。画像の分析は高度な知識が必要ですが、Amazon Rekognition を使うことによって簡単に画像を分析することができるので本エントリーで試してみようと思います。

Amazon Rekognition とは

画像や動画を分析するサービスです。有名人を検出したり表情から感情を分析したりすることができます。Amazon Rekognition には以下2つサービスがあり、本エントリーでは「Amazon Rekognition Image」を使います。

Amazon Rekognition が提供する機能

本エントリーでは Amazon Rekognition Image の「ラベル検出」を使います。

例えば、ラベル検出を以下の画像に対して実行すると、画像内の「車」「自動車」「人」などがラベルとして検出されて、それぞれの信頼度がパーセンテージで表示されます。

アーキテクチャ

S3 にアップロードした画像の分析を行い、結果を DynamoDB に保存します。

役割
サービス名 内容
Amazon S3 画像ファイルの格納を Lambda に通知
AWS Lambda Amazon Rekognition の実行と分析結果の DynamoDB への格納
Amazon Rekognition 画像分析の実行
Amazon DynamoDB 画像分析結果の格納

手順

  1. S3 バケットの作成
  2. DynamoDB テーブルの作成
  3. IAM ロールの作成
  4. Lambda 関数の作成
  5. S3 バケットへのイベント通知の作成
  6. 動作確認

1. S3 バケットの作成

「20220812-rekognition-test」バケットを作成します。

2. DynamoDB テーブルの作成

検出したラベルを保存する DynamoDB のテーブルを作成します。

[テーブル名]:rekognition-label
[パーティションキー]:image
[ソートキー]:label

3. IAM ロールの作成

S3、Rekognition、DynamoDBへの権限を付与したロールを作成します。

4. Lambda 関数の作成

以下のように Lambda 関数を作成します。

[オプション]:一から作成
[アーキテクチャ]:x86_64
[関数名]:rekognitionFunction
[ランタイム]:Python 3.9
[既存のロール]:execute-rekognition

コード

Amazon Rekognition の実行と分析結果を DynamoDB へ格納する Lambda 関数のコードです。

import json
import urllib
import boto3

# 使用するサービス
s3 = boto3.client('s3')
rekognition = boto3.client('rekognition')
dynamodb = boto3.resource('dynamodb')

# DynamoDB テーブル
table = dynamodb.Table('rekognition-label')
 
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')
    
    # ラベル検出の実行
    detect = rekognition.detect_labels(
        Image={
            'S3Object': {
                'Bucket': bucket,
                'Name': key
            }
        }
    )
    
    # ラベルを取得
    labels = detect['Labels']
    
    for i in range(len(labels)):
        label_name = labels[i]['Name']
        label_confidence = int(labels[i]['Confidence'])
        
        # 信頼度が80%以上のラベルのみDynamoDBに保存する
        if label_confidence >= 80:
            table.put_item(
                Item={
                    'image': key,
                    'label': label_name,
                    'confidence': label_confidence,
                }
            )

5. S3 バケットへのイベント通知の作成

作成方法については以下のエントリーをご参照ください。

www.aws-room.com

6. 動作確認

使用する画像

こちらの画像を使用します。

処理実行

S3 バケットに上記の画像をアップロードします。

DynamoDBにラベルが格納されたことを確認します。Boardwalk や Building など写真にある物体を認識していることがわかります。

さいごに

Amazon Rekognition を使えばさくっと画像分析の実行が可能ということがわかりました。今後は Amazon Rekognition Video を使って動画の分析もやってみようと思います。