Amazon Web Services ブログ

Amazon Polly を使用して音声電話で AWS アカウントのセキュリティイベントに関するアラートを受信

AWS アカウントのセキュリティは極めて重要です。AWS アカウントのセキュリティに関するイベントの最新情報を把握しておくことが大切です。メールや SMS など、様々な方法で通知を受け取ることができますが、今回のブログでは Amazon Polly といった Amazon AI サービスや、Twilio のようなクラウドベースによるコミュニケーションプラットフォームを使用して音声アラートを受信する方法をご紹介します。

Amazon Polly はテキストを肉声のように読み上げるサービスで、スピーチが可能なアプリケーションの作成を可能にします。これは音声対応製品の全く新しいカテゴリです。Polly はディープラーニング技術を使用して、肉声のような音声を合成します。様々な言語を色々な音声で提供します。

移動が多いエンタープライズ IT セキュリティの社員にとって、AWS アカウントのセキュリティイベントのアラートを音声電話で聞くことができるのは実に便利です。セキュリティイベントは、その重要度や優先度を元にカスタムで定義できます。重要度や優先度のレベルが高いセキュリティイベントに関するアラートを、電話を介してシステムに送ることができます。

音声電話によるアラートを利用する上で、私は音声、ビデオ、メッセージングといった API 機能を提供する Twilio を使用しています。Twilio のプラットフォームを使用し、AWS アカウントでセキュリティイベントが発生した時に音声電話を掛ける API 呼び出しを発行するようにプログラムすることができます。Amazon Polly はテキストのアラートを音声メッセージに変換して電話で再生することができます。

ソリューションの概要

このソリューションは次のアーキテクチャ図で示した 2 つのシステムから構成されています。

  • イベント検出と通知システム
  • テキストを音声に変換するシステム

イベント検出と通知システムは、テキストから音声に変換するシステムから分離されます。他のユーザーが定義したイベント検出において後者が一般的なためです。このブログでは、テキストから音声に変換するシステムを取り上げ、過去のブログで紹介したイベント検出と通知システムをソリューションの例として使用します。

アーキテクチャの図で示したものです。ステップ 3 のアラートメッセージは Amazon SNS トピックに発行され、テキストから音声に変換するシステムで SNS が Lambda 関数をトリガーします。

  1. Lambda 関数は SNS アラートメッセージのサブジェクトを解析し、Amazon Polly を使ってテキストを音声ファイルに変換します。
  2. この音声ファイルは Amazon S3 バケットに保存されます。
  3. Twilio は音声ファイルの場所を使用し、対象となる関係者に通話を発信して音声ファイルを再生します。通話発信に音声ファイルが使用されたら、要件をベースにしてファイルに Amazon S3 オブジェクトライフサイクルポリシーを追加することができます。

演習

前提条件

  • イベント検出と通知システムを少なくても 1 つ取り入れてください。たとえば、AWS アカウントのルートユーザーにモニタリングと通知をセットアップすることができます。
  • API 呼び出しを作成するには Twilio アカウントの認証トークンが必要になります。こちらで Twilio の無料 (トライアル) アカウントにサインアップできます。
  • Twilio アカウントに電話番号が指定されます。電話によるアラートはこの番号で受け取ることになります。
  • トライアルアカウントを使用している場合は、着信側の電話番号を必ず確認してください。

デプロイのステップ

次のデプロイ用のステップは下記の図で示したように、テキストから音声への変換システムをデプロイするための方法です。

  1. AWS CloudFormation コンソールで [Create Stack] を選択します。CloudFormation JSON テンプレートを使用します。[Next] を選択します。(注意: Amazon Polly は中国と AWS GovCloud (米国) リージョンではご利用いただけません。
  2. イベント検出と通知システムをデプロイしているリージョンにスタックを作成します。
  3. 次のパラメータ詳細を入力し、[Next] を選んでから [Next] を選択します。
    1. ToPhoneNo: Twilio が電話を掛ける番号です。番号に国コードを追加します (例: +14561237890)。
    2. FromPhoneNo: Twilio が電話を掛ける仮想の番号です。この情報はご自分の Twilio アカウントで確認できます。前提条件のセクションを参照してください。
    3. TwilioAccntSid: Twilio アカウントの SID を入力します。これは https://www.twilio.com/ でのサインアップ時に提供されます。
    4. TwilioAuthToken: Twilio の認証トークン ID を入力します。
    5. BucketName: 作成したいバケットの名前を入力します。このバケットには、イベントアラートの音声ファイルが保存されます。
    6. PollyVoiceId: アラートで呼び込む Amazon Polly の音声を入力します。デフォルトの音声は「Amy」です。
    7. LambdaS3Bucket: Lambda 関数の zip ファイルを保存している Amazon S3 バケットの名前です。
    8. LambdaS3Key: Lambda 関数の zip ファイルの名前です。プレフィックスを含む S3 オブジェクトへの完全パスです。たとえば「dir1/dir2/lambdafunction.zip」です。Lambda 関数の zip ファイルは、このブログの Lambda 関数のセクションに記載されているリンクからダウンロードできます。
  4. [Capabilities Acknowledgement] を選び [Create] を選択します。このフィールドは、スタックが IAM ロールとポリシーを作成できるようにします。こうしたロールやポリシーは、SNS トピックへのメッセージの発行、アカウントのエイリアスのリスティングなど、特定のアクションを実施するために Lambda 関数が使用するものです。
  5. CloudFormation スタックが完了したら、[output] で利用可能な Lambda 関数の名前を確認します。
  6. 次に、Lambda 関数にトリガーを追加します。Lambda コンソールで、先ほど作成した Lambda 関数を選択し、[triggers]、[add trigger] を選択します。
  7. トリガーボックスで [SNS] を選び、電話連絡の対象となる [Event Detection & notification] の SNS トピックを選択します。[Submit] を選択します。
  8. これで「イベント検出と通知」システムの SNS トピックにより、Lambda 関数がトリガーされるようになりました。様々なイベント検出や通知システムに好きなだけトリガーを追加することができます。AWS Lambda のトリガーに関する詳細はこちらをご覧ください。

SNS がトリガーする Lambda 関数

テキストを音声に変換する Lambda 関数は、トリガーされた場合に SNS メッセージのサブジェクトを解析します。次に、そのサブジェクトフィールドにあるテキストを Amazon Polly サービスに送り、テキストを音声ファイルに変換します。テキストが音声ファイルに変換されると、ファイルは先述の CloudFormation スタックが作成した S3 バケットに保存されます。

その後、Twilio API を呼び出して通話を発信し、S3 バケットからイベント通知の音声ファイルを再生します。

import boto3
import os
from contextlib import closing
import botocore.session
from botocore.exceptions import ClientError
session = botocore.session.get_session()
import logging
import uuid
import twilio
from twilio.rest import Client

import urllib
from urllib import request, parse
from urllib.parse import quote

logging.basicConfig(level=logging.DEBUG)
logger=logging.getLogger(__name__)

def lambda_handler(event, context):
    logger.setLevel(logging.DEBUG)
    logger.debug("Event is --- %s" %event)
    speak = event["Records"][0]["Sns"]["Subject"]
	
	# Converting the Subject text of the SNS message into an mp3 audio file.
	
    polly = boto3.client('polly')
    response = polly.synthesize_speech( OutputFormat='mp3',
                                        Text = 'ALERT !' + speak,
                                        SampleRate='22050',
                                        VoiceId = os.environ['VoiceId']  
                                        )
    logger.debug("Polly Response is-- %s" %response)
    id = str(uuid.uuid4())
    logger.debug("ID= %s" %id)
    
    
    #Save the audio stream returned by Amazon Polly on Lambda's temp 
    # directory. If there are multiple text blocks, the audio stream
    # will be combined into a single file.
    if "AudioStream" in response:
        with closing(response["AudioStream"]) as stream:
            filename=id + ".mp3"
            output = os.path.join("/tmp/",filename)
            with open(output, "wb") as file:
                file.write(stream.read())
	
	# Upload the Audio MP3 file to an S3 location
	
    s3 = boto3.client('s3')
    s3upload_response = s3.upload_file('/tmp/' + filename, os.environ['BUCKET_NAME'],filename,ExtraArgs={"ContentType": "audio/mp3"})
    logger.debug("S3 UPLOAD RESPONSE IS--- %s" %s3upload_response)
    s3.put_object_acl(ACL='public-read', Bucket=os.environ['BUCKET_NAME'], Key= filename)
    
    location = s3.get_bucket_location(Bucket=os.environ['BUCKET_NAME'])
    logger.debug("Location response is -- %s" %location)
    region = location['LocationConstraint']
    
    if region is None:
    	url_begining = "https://s3.amazonaws.com/"
    else:
    	url = url_begining + str(os.environ['BUCKET_NAME']) + "/" + filename
    
    url = '{}/{}/{}'.format(s3.meta.endpoint_url, os.environ['BUCKET_NAME'], filename)
    
    #Encode URL
    encode_url = quote(url, safe='')
    logger.debug("ENCODED URL-- %s" %encode_url)
    
    # Get these credentials from http://twilio.com/user/account
    account_sid = os.environ['account_sid']
    auth_token = os.environ['auth_token']
    client = Client(account_sid, auth_token)
    
    # Make the phone call using Twilio 
    call_response = client.api.account.calls.create(to=os.environ['ToPhoneNo'],  # Any phone number
    												from_=os.environ['FromPhoneNo'], # Must be a valid Twilio number
    												url="http://twimlets.com/message?Message%5B0%5D=" + encode_url + "&"
    												)
    												
    logger.debug("Call_response is-- %s" %call_response)

この AWS Lambda コードの zip ファイルはこちらからダウンロードすることができます。これは CloudFormation スタックデプロイで使用されます。

ソリューションの検証

次のサンプル音声ファイルでは、イベント検出システムをデプロイし (ルート API アクティビティで通知)、テキストから音声に変換するシステムで統合した後で、ルート API が AWS アカウントで検出されるたびに音声電話でアラートを聞く様子を示しています。

ルートによるコンソールログインアラートを電話で受信した場合のサンプル:

今すぐ聞く

Amazon Polly の声

次に、ルートの認証情報を使用して Amazon EBS ボリュームを作成し、別のアラートが電話で連絡されるようにします。

今すぐ聞く

Amazon Polly の声

まとめ

今回のブログでは、既存のアラートシステムやモニタリングシステムと統合できる、電話連絡による音声のアラートシステムを作成する方法について説明しました。ほぼリアルタイムで AWS アカウントの重要なイベントのアラートを電話で聞く場合に、このフレームワークは便利です。

詳細については次のブログ記事をご覧ください。


今回のブログの投稿者について

Sudhanshu Malhotra は AWS プロフェッショナルサービスのソリューションアーキテクトです。 Sudhanshu はユーザーが DevOps、コードとしてのインフラストラクチャ、設定管理などにおいて複雑なソリューションを AWS で利用できるようにサポートしています。家族と時間を過ごしたり、ハイキングや車いじりが趣味です。