Quantcast
Channel: 技術 –サーバーワークスエンジニアブログ
Viewing all 1210 articles
Browse latest View live

Cloud MapでServerlessなリソースのサービスディスカバリを実装する

$
0
0

ちょっとお久しぶりの会社ブログ投稿な照井です。

今年は会期中の過ごし方や旅程を自分のペースで行きたかったのでre:Inventは個人的に参加してきました。とても楽しかったです。

tl;dr

re:Inventでずっと欲しかったServerlessなリソースのディスカバリができるCloud Mapがリリースされたため、実証と実戦投入のための考察などしてみました。
結論から言うと「超便利。でも実戦投入するにはディスカバリ結果のキャッシュを上手く取り回す仕組みが必要だなー」って感じです。

Cloud Map
https://aws.amazon.com/jp/cloud-map/

何がやりたいか

Cloud Mapは今までConsulやRoute53 APIとHealthCheckを駆使して自前で構築していたDNSベースのServiceDiscoveryがフルマネージドサービスでできる(Cloud MapもバックグラウンドでRoute53を使うことでDNSによるディスカバリを提供しているんですが)ということに加えて、HTTPベースでドメインを持たないリソースを登録してその登録された属性をクエリすることでディスカバリを行うことができます。

これを上手く使って、Kinesis Data Streams, SNS, DynamoDBのような固有ドメインのendpointを持たずリソース名でアクセスするサービスをディスカバリしたいわけです。例えば、 StreamName: foo, Environment: prod のように論理名と属性をクエリすることで物理リソース名が返ってきてほしいわけです。

Serverlessでの今までのプラクティスとその問題点

AWS SAMやServerless Frameworkを利用している場合、今までは命名規則を決めてSSM Parameter Storeから取得させたり、CloudFormationのImport/ExportValueを使ってLambdaの環境変数から各種リソース名を注入するというプラクティスがあります。この方法は便利ですが、いくつか問題点がありました。

  • 命名規則でリソース名の取り方が決まるためクエリの表現力が貧弱
  • SSM Parameter Storeは無料で便利だが、大量アクセス耐性や可用性の保証が無い
  • 環境変数から注入している場合、変数の中身はデプロイし直さないと変わらない

これらを良い感じにCloud Mapで解決したいわけです。

実証実験

では、AWS SAMフレームワークを使っていくつか実証実験してみます。

下準備

下記のようなテンプレートをデプロイしてCloud MapのNamespace, Serviceを作成し、そこにKinesisのStreamを env: prod という属性と共に登録してみます。ちなみに2018-12-04現在、LambdaのPython3.6ランタイムに標準で入っているboto3はCloud Mapに対応していないので対応しているバージョンを同梱する必要があります。今回使っているバージョンは 1.9.58 です。

ExampleStream:
    Type: AWS::Kinesis::Stream
    Properties:
      ShardCount: 1

  ExampleNameSpace:
    Type: AWS::ServiceDiscovery::HttpNamespace
    Properties:
      Name: sls.willy.works

  ExampleService:
    Type: AWS::ServiceDiscovery::Service
    Properties:
      Name: example-stream
      NamespaceId: !Ref ExampleNameSpace

  ExampleInstance:
    Type: AWS::ServiceDiscovery::Instance
    Properties:
      InstanceAttributes:
        env: prod
      InstanceId: !Ref ExampleStream
      ServiceId: !Ref ExampleService

ポイントはStreamの Name 属性をしていないことです。多くのAWSサービスはCloudFormationでリソース名を指定しなかった場合、Stack名とランダムな文字列などを使って一意なリソース名を勝手に付与してくれます。Cloud Mapを使うことで物理的な名前は扱わずにあくまで論理的な属性だけで名前解決を行いたいわけです。

NamespaceとServiceは実戦では別StackにしてExportValueして使ったほうが良さそうですが、実証実験なので今は一緒にしちゃってます。

実験①:素直に使ってみる

下記のような ServiceName: example-stream, env: prod をクエリして結果を返すLambda Functionをデプロイして実行してみます。

import json

import boto3

instances = None
client = None

def hello(event, context):
    global client
    if client is None:
        client = boto3.client('servicediscovery')
    instances = client.discover_instances(
        NamespaceName='sls.willy.works',
        ServiceName='example-stream',
        QueryParameters={
            'env': 'prod'
        }
    )

    return {
        "statusCode": 200,
        "body": json.dumps({
            'stream_name': instances['Instances'][0]['InstanceId'],
        })
    }

curlで叩くとStreamの物理名が返ってきますね!

$ curl https://rfk78is730.execute-api.us-west-2.amazonaws.com/Prod/hello/
{"stream_name": "cloudmap-example-ExampleStream-16P1D92Y4IMAA"}

さて、ここで気になるのはCloud Mapをクエリする際のレイテンシです。毎回httpで引くと結構気になってくると思うんですよね・・・

実験②:クエリ結果をキャッシュする

クエリを行わない場合と比較するために下記のように雑にキャッシュするコードをデプロイしてみます。

import json

import boto3

instances = None
client = None


def world(event, context):
    global client
    global instances
    if instances is None:
        if client is None:
            client = boto3.client('servicediscovery')
        instances = client.discover_instances(
            NamespaceName='sls.willy.works',
            ServiceName='example-stream',
            QueryParameters={
                'env': 'prod'
            }
        )

    return {
        "statusCode": 200,
        "body": json.dumps({
            'stream_name': instances['Instances'][0]['InstanceId'],
        })
    }

当然ですが結果は同じです。

$ curl https://rfk78is730.execute-api.us-west-2.amazonaws.com/Prod/world/
{"stream_name": "cloudmap-example-ExampleStream-16P1D92Y4IMAA"}

まあ、キャッシュしてるんだからレイテンシは大幅に改善しているわけで。

結果

Cloud Mapをクエリした場合のレイテンシはランタイムがPython3.6, メモリ割り当て128MBで60~120ms(サンプル数が極端に少ないので参考程度)かかるようです。これはCloud MapのAPI課金も踏まえると、ちょっと毎回引くのは厳しいですね・・・

考察

キャッシュするとキャッシュをパージするタイミングの制御などの実装が必要になります。また、シンプルなディスカバリの実行をトリガーとしたTTLや確率ベースの実装だとキャッシュの更新タイミングにあたった場合のレイテンシは避けられません。コンテナの場合は例えばEnvoyのようにサイドカーパターンで同じホストに別のコンテナをデプロイして、ディスカバリはそちらに任せることで低レイテンシを保ちつつ良い感じにやってくれますが、Lambdaの場合はそのような選択肢は取れません。

ちなみにご参考までに今回のとても雑な検証コードは一応以下に公開してあります。
https://github.com/marcy-terui/lambda-cloudmap-example

さーて、ここからどうするかなー(続く・・・?


AWS Transcribeジョブ結果ファイルのセキュリティについて

$
0
0

AWS Transcribeは音声ファイルを文章に書き起こしてくれるAWSサービスです。
残念ながら現在は日本語には対応していませんが、英語(US/AU/GB)、フランス語、スペイン語に対応しています。

AWS Transcribeに対してTranscribeジョブを投入すると、非同期で処理を実施してくれます。
ジョブの実行結果を問い合わせ、COMPLETEDであれば書き起こした結果ファイルがS3上に配置されており、そのパスが手に入るというわけです。

結果ファイルには誰がアクセスできるのか

ジョブ実行結果を問い合わせると以下のように、結果ファイルのS3パスを示すURLが手に入り、そこからDLできます。

{
    "TranscriptionJob": {
        "TranscriptionJobName": "TranscribeJobTest20181105",
        "TranscriptionJobStatus": "COMPLETED",
        "LanguageCode": "en-US",
        "MediaSampleRateHertz": 44100,
        "MediaFormat": "wav",
        "Media": {
            "MediaFileUri": "https://s3.amazonaws.com/TestS3(略)/2018/11/05/test_wav_file.wav"
        },
        "Transcript": {
            "TranscriptFileUri": "https://s3.amazonaws.com/aws-transcribe-us-east-1-prod/123456789012/test_wav_file/4cfca3(略)6a9d08/asrOutput.json?X-Amz-Security-Token=FQoGZXIvY(略)&X-Amz-Expires=900&(略)384f2bf8"
        },
    ~略~
        }
    }
}

「”TranscriptFileUri”: 」の値が、結果ファイルのパスにあたります。
ん?このファイルってグローバルからアクセス可能なの?と一瞬思いましたが、これは署名付きURLなのです。

参考 S3にて Pre-Signed URLを発行する
http://blog.serverworks.co.jp/tech/2017/07/04/s3_presign/

つまりオブジェクトがパブリックに公開されているわけではないのですが、このURLを知っている人ならばアクセスできる、ということになります。
ただし署名付きURLには有効期限が設定されており(2018/11時点で900秒)この期限が過ぎるとURLは無効になります。クエリストリングス内の X-Amz-Expires=900 という部分が期限です(秒数)。

署名付きURLの扱いには十分注意して、AWS Transcsribeをセキュアに利用しましょう。

Amazon FSx for Windowsでファイルサーバーもマネージドに!

$
0
0

Windowsおじさんこと、技術4課の鎌田です。
re:Inventで発表された、AWSにもついに来ました、マネージドのファイルサーバー!その名もAmazon FSxです。

これは使ってみるしかない、という訳で、実際に環境を構築して触ってみました。
なお、記事執筆時点(2018年12月)では東京リージョンに来ていないため、オレゴンリージョンで展開しています。

前提条件にご注意を

FSxのサービスですが、使うにあたっての前提条件があります。
以下にポイントを3つ挙げておきますので、良くご確認の上ご利用ください。

1.Directory ServerのAWS Directory Service for Microsoft Active Directory(以下、MSAD)を利用していること

これが意外なハードルかも知れません。ドキュメントにもしっかり書いてあります。
既存のドメインを使いたい場合は、MSADを展開の上、既存のドメインと信頼関係を結びます。
信頼関係の結び方は、以前に私が書いたブログ記事を参照してください。

2.アクセスがサポートされるクライアント

2018年12月現在、以下からのアクセスがサポートされています。

  • Amazon Elastic Compute Cloud (Amazon EC2) instances
  • Amazon WorkSpaces instances
  • Amazon AppStream 2.0 instances
  • VMs running in VMware Cloud on AWS environments

オンプレミスからの直接のアクセスは、記事執筆時点ではサポートに入っていません。
ファイルサーバーの移行をご検討の場合は、ご注意ください。

3.アクセスがサポートされるOS

ドキュメントには、以下のOSが挙がっています。

  • Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, and Windows Server 2016
  • Windows Vista, Windows 7, Windows 8, Windows 8.1, and Windows 10 (including the Windows 7 and Windows 10 desktop experiences of Amazon WorkSpaces)
  • Linux (cifs-tuilsを使ったアクセスが可能なOS)

SMB protocol (versions 2.0 through 3.1.1)に対応していることが要件となります。

実際に構築する

実際に触ってみましょう。
なおFSxは東京リージョンにないので、FSxが来ているリージョンを選択しておきましょう。

まずはAmazon FSxのマネジメントコンソールの画面に移動します。
画面の右側にある、「Create File system」をクリック。

今回はWindowsからアクセスするファイルサーバーを作るので、左側の「Amazon FSx for Windows File Server」を選択します。
選択したら、Nextをクリック。

ファイルシステム作成の画面に移動します。
「File system name」は、AWS上の管理名の入力欄です。分かり易い名前を付けておきましょう。
次に、容量を入力します。容量は最低300GiBから64TiBです。私は一旦最低容量の300で作ってみます。
容量は、記事執筆時点では後からの変更が出来ない仕様となっていますので、ご注意ください。

スループットの性能はAWS側で自動計算して最適な値を設定してくれるのですが、指定も可能です。
ドキュメントに、指定可能なスループット性能に関しての記述があるので参考にしてください。
最適値を使うので、ここでは「Recommended throughput capacity」を選択して進めます。

容量とスループット性能を決めると、推定コストをAWSで提示してくれます。

次はFSxを配置するVPC、サブネット、セキュリティグループの設定を行います。
この画面でセキュリティグループを作成できないので、あらかじめ作成しておきましょう。
アクセス要件はこちらのドキュメントに記載があります。

基本は、FSxがファイルサーバーとしてアクセスされる際の、アクセス元IPからのアクセス許可を設定します。
ファイルサーバーということもありますので、サブネット丸ごと許可されるケースが多くなるかと思います。

VPC、AZ、サブネット、セキュリティグループを選択していきます。

次は認証に関する設定です。ここで、Directory ServiceのMSADを選択することになります。
こちらも、FSxがドメイン参加するため、あらかじめ構築しておく必要があります。
ドメインを選択してましょう。

次は暗号化に関する設定です。
FSxはKMSにてデータ領域もバックアップも暗号化がデフォルトとなっています。
ドキュメントもご参照ください。)
KMSキーに指定がある場合は、指定をします。
指定がない場合はデフォルトのまま進めても問題ありません。

最後はメンテナンスの設定です。
RDSにあるような、バックアップウィンドウ、メンテナンスウィンドウの設定です。
No preferenceを選択した場合、FSxのデフォルト設定が使われます。
本番環境で使われるようなケースでは、指定してご利用ください。
バックアップウィンドウは毎日のバックアップ時間をUTCで、メンテナンスウィンドウは毎週の曜日と時間をUTCで、それぞれ指定します。
こちらも、設定後は変更が出来ない仕様のため、ご注意を。

ここまで指定が完了したら、Nextをクリックします。

確認画面になるので、「Create file system」をクリックしましょう。

しばらく待っていますと、出来上がります。待ち時間は15分程度でした。

出来上がった後、File system nameをクリックし、Network & securityをクリックすると、DNS nameが表示されます。
こちらが、ファイルサーバーにアクセスする時のコンピューター名になりますので、控えておきましょう。

WindowsのEC2を立てて、コンピューター名にエクスプローラーからアクセスしてみると、Shareという共有フォルダが見えます。
これで無事、FSxにアクセスできました!

構築して分かったこと

構築して触ってみて分かった点をまとめておきます。

FSxはMulti-AZで動かすには手組みが必要

FSxは、記事執筆時点では、サービス側で冗長化はされておらず、単一AZで動かすことが前提となっています。
Multi-AZで動かす場合、ドキュメントにも記載がありますが、WindowsのDFSを使って冗長化することとなります。
※サポートが明記されています。

共有フォルダ名は変えられない

Shareという共有フォルダ名は、残念ながら変更できません。

バックアップのリストはもう一つFSxが出来上がる

ファイル単位で戻すといった運用は、マネジメントコンソール上ではできません。

考えられるユースケース

こんな場合に、良いのではないでしょうか。

1.WorkSpacesをAWSで初期構築し利用する際に、ファイルサーバーも用意したい場合
2.AWS上でシステム構築する中でファイルサーバーが必要になったが、メンテナンスコストをかけたくない場合

まとめ

1.MSAD必須だが、構築は簡単にできる
2.色々と注意点があるため理解して利用、運用する必要がある

Windows Updateから開放されるだけでも、利用価値は高いと思います。是非皆さんも、お試しください!

Amazon Polly はじめての SSML入門

$
0
0

今年の re:Invent もたくさんのサービスが発表されましたね。
2日間キーノートを日本からリアルタイムで聞いていましたが、自動運転ミニカー「AWS DeepRacer」の登場にはびっくりしました。
そしてre:InventでまさかCOBOLという単語が出てくるとは…。

さて、今日はそんな re:Invent で発表されたサービスではなく Amazon Polly で使えるSSMLについて初心者向けに説明します。
Amazon Polly は新しいサービスではないけれど、これからいろんなところで活用が期待できるサービスなのでこの機会に再確認しておきましょう。

Amazon Polly とは

高度な深層学習技術を使用したテキスト読み上げサービスです。
「テキストの読み上げ」というと聞くほうが疲れてしまう不自然な出来栄えのものが少し前までは多かったですよね。
最近は日本語でもナチュラルな発音をする読み上げサービスが増えてきました。
Amazon Polly もテキストを用意するだけで、とても流暢に日本語を読み上げてくれます。

Amazon Polly で作成した音声はダンロードして利用したり、S3に格納しあらゆるシステムから利用することが可能です。
Alexaスキルから Amazon Polly を使用し、おしゃべりさせちゃうこともできます。

また、クラウド型コンタクトセンター Amazon Connect でも問い合わせフローの中で Amazon Polly を使うことができます。
録音した音声データを用意しなくていいのは便利ですよね。
ちょっとだけ音声のメッセージを変更したい。なんていう場面でも、全文章の再録音ではなくテキストの部分修正だけで変更対応ができてしまいます。

そんな自然な読み上げをしてくれる Amazon Polly ですが、場面によっては発音、声量、声の高さ、速度など気になるときも出てきます。
そんなときはSSMLで調整ができるんです。

音声マークアップ言語SSMLとは

テキスト読み上げ (TTS) 音声の音色を変更できるようにするのが、音声合成マークアップ言語 (SSML) 機能です。
超雑にまとめると、HTMLタグの音声版って思っておけば雰囲気よさそうです。

サポートされているタグは以下ドキュメントに記載があります。
本エントリでは非常にざっくりとした説明にしぼりますので、詳細はドキュメントを参照してください。
Amazon Polly でサポートされている SSML タグ – Amazon Polly

この中から頻度の高そうな3つのタグだけをピックアップして、SSMLを知らなかった人でも「SSML?オレつかえるぜ」って思わせるのが本日のゴールです。

よく使いそうな3つのSSML

<break> 一時停止の追加

区切りを入れるタグは<p>や<s>もあります。こちらは長文で便利そうです。
ちょっとだけ読み上げる音声を調整する場合はとりあえず<break>だけでものりきれそうです。

ちょっとだけ区切りを入れたい場合は以下のタグを入れればOK。

<break time=“1s"/>

これで1秒の間が空きます。秒(s)の他にミリ秒(ms)も使えます。

Amazon Connect で音声読み上げをすると冒頭部分が欠けて聞こえることがあります。
そんなときは冒頭部分に<break>をいれておくとよさそうです。

<say-as> 特殊なタイプの単語の発声方法を制御する

特定の文字、単語、および数字を発声する方法を Amazon Polly に指示します。
例えば「12345」というテキストは「いちまん にせん さんびゃく よんじゅう ご」と読まれます。
これを「いち に さん し ご」と読ませたい場合は以下のように記述します。

<say-as interpret-as="digits">12345</say-as>

interpret-as で利用できる値はたくさんありますが、日本語の場合は使えるものが限定されます。
初心者は以下2つを覚えておくと使えそうな予感がします。

digits: 各桁を個別 (例: 1-2-3-4) にスペルアウトします
spell-out: a-b-c のようにテキストの各文字をスペルアウトします

<prosody> 音量、話す速度、ピッチを制御する

強調するタグ <emphasis> もありますが、いまいち自然な感じの強調になる気がします。
<prosody>でお好みにあわせてコントロールした方がよさそうです。
音量:volume/速度:rate/ピッチ:pitch の3つが制御できます。
それぞれmedium といった定義値または相対数値で指定ができます。
同じタグの中で複数の属性を含めることもできます。

<speak> Each morning when I wake up, <prosody volume="loud" rate="x-slow">I speak quite slowly and deliberately until I have my coffee.</prosody> </speak>

実際に聞いてみよう

上記の3つのタグを使った音声を準備しました。


読み上げている原稿


こんにちは、ミズキです。
PollyでSSMLの動作確認をします。

数字そのままだと12345。
スペルアウトすると1234512345とゆっくり読むこともできます

AWS マネジメントコンソールの Amazon Polly 画面で簡単に読み上げとSSMLを試すことができます。


ここまで読んだあなたはSSML初心者卒業です。やったね!

インターフェイスVPCエンドポイント(PrivateLink)に発行される複数のDNS名

$
0
0

PrivateLinkのインターフェイスVPC Endpointを作った時に複数のDNS名が割り当てられますが、これらが何を意味しているのかについて書いてみます。

PrivateLinkとは?

PrivateLink、便利なんです。原則的にインターネット経由でリーチしなければいけないAWSのAPI群ですが、PrivateLink (Interface VPC Endpoint) を利用すればインターネットを経由することなく、VPC内からAWSサービスへ到達できます。
またAWSサービスだけでなく、EC2インスタンス等で実装したサービスに対してもPrivateLink経由でネットワーク的に到達することができます。全く新しいサービス提供の形が実現できるかもしれません。

「違うVPC間でEC2インスタンス間の通信をさせたいけど、IPレンジがかぶっちゃってるからVPC Peeringで繋ぐわけにもいかない。どうしよう…」というときもPrivateLinkが使えます。サービス提供側で「NLB」「エンドポイントサービス」を作成し、サービス利用側で「インターフェイスVPC Endpoint」を作成すればよいのです。

DNS名が複数・・・

早速、エンドポイントを作ってみました。
可用性のため、複数のAZにまたがるインターフェイス群とします。
エンドポイントにはDNS名が発行されますので、利用するEC2インスタンス等からそのDNS名に対してアクセスすればよいのです。

ん?

複数のDNS名がありますね…なんでしょうこれは。どれを使えばいいの?
となりましたので調べてみました。

インターフェイスエンドポイントを介したサービスへのアクセス
https://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpce-interface.html#access-service-though-endpoint

・インターフェイスエンドポイント用に生成したエンドポイント固有のリージョン DNS ホスト名。このホスト名には、一意のエンドポイント識別子、サービス識別子、リージョン、および vpce.amazonaws.com が含まれます (例: vpce-0fe5b17a0707d6abc-29p5708s.ec2.us-east-1.vpce.amazonaws.com)。
・エンドポイントが使用できるアベイラビリティーゾーンごとに生成したエンドポイント固有のゾーン DNS ホスト名。このホスト名には、アベイラビリティーゾーンが含まれます (例: vpce-0fe5b17a0707d6abc-29p5708s-us-east-1a.ec2.us-east-1.vpce.amazonaws.com)。アーキテクチャーでアベイラビリティーゾーンが分離されている場合 (たとえば障害抑制のためや、リージョン内データ転送コスト削減のため)、このオプションを使用できます。

というわけで、インターフェイスエンドポイントには「リージョン固有のDNSホスト名」と「ゾーンごとのDNSホスト名」が発行されるようです。
リージョンDNSホスト名は紐づいている全てのENIのプライベートIPアドレスを返します。
ゾーンDNSホスト名は各AZ毎に生成され、そのゾーンにあるENIのプライベートIPアドレスを返します。

DNS名に “ap-northeast-1” とだけあるのがリージョンDNSホスト名で “ap-northeast-1a”, “ap-northeast-1c” とあるのがそれぞれのゾーンのDNSホスト名だと分かりますね。

使い分け

原則的にはリージョンDNS名を利用し、AZまたぎのレイテンシや通信料金が気になる場合のみゾーン固有のDNSを利用するのがよさそうです。

Connect と Lex で音声ベースのチャットボットを作成する

$
0
0

はじめに

こんにちは、技術一課の山中です。

先日の re:Invent 2018 にて以下ワークショップに参加したのですが、その内容が面白く簡単だったのでこちらでご紹介いたします。

BAP401-R – [REPEAT] Build a Voice-Based Chatbot for Your Amazon Connect Contact Center

注意としては、ワークショップ一本分をひとつのブログにしているので正直、 長いです。

できあがるもの

本ブログを通してできあがるものは以下のとおりです。

私:(電話かける)

ボット:「Hi Daishi Yamanaka, Welcome to the IT help desk」

ボット:「How can I help?」

私:「I can't access the internet」

ボット:「Please try to access to the internet once more.」

電話でボットと会話をしながらパスワードのリセット等ユーザへのサポートを提供することができます。

作成の流れ

音声ベースのチャットボット作成の流れは以下のようになります。

  1. Connect インスタンスの作成
  2. 電話番号取得
  3. チャットボットの作成
  4. Lex を利用したワークフロー作成
  5. ワークフローを電話番号へ関連付け
  6. ユーザデータへアクセスするための Lambda ファンクション作成
  7. ワークフローに Lambda ファンクションを追加

流れを見ると大変そうに見えますが、一つ一つの処理は大したことはないので、早速やっていきましょう。

Connect インスタンスの作成

  1. Amazon Connect から [Add an instance] ボタンをクリックします。今回は日本の電話番号を取得するために、シドニーリージョンにて進めていきます。

  1. Access URL に任意の文字列を入力し、 [Next step] ボタンをクリックします。

  1. 管理者用ユーザの情報を入力して、 [Next step] ボタンをクリックします。

  1. そのまま [Next step] ボタンをクリックします。

  1. そのまま [Next step] ボタンをクリックします。

  1. 内容を確認したら [Create instance] ボタンをクリックします。

  1. これでインスタンスの作成は終了です。(ここで Connect が Safari に対応していなかったことを思い出して Chrome に切り替えました。。

[Get started] ボタンをクリックした際に、 CloudFront の 403 エラーがでることがありますが、その際は時間を置いてアクセスしてみてください。

電話番号の取得

  1. [Get started] ボタンをクリックすると以下画面が表示されるので、 [Let’s go] ボタンをクリックします。

  1. 電話番号取得画面が表示されるので、 Country で Japan を選択し [Next] ボタンをクリックします。ランダムに日本の電話番号が取得できます。

  1. 発行された電話番号に電話を掛けてみて、問題なくつながったら [Continue] ボタンをクリックします。

  1. これにて電話番号の取得は完了です。

チャットボットの作成

続いて Lex にてチャットボットの作成を進めていきます。

ただし、 Amazon Lex は残念ながらシドニーリージョンではまだ利用できないため、バージニアリージョンにて作成していきます。

  1. Amazon Lex から [Get Started] ボタンをクリックします。

  1. [Custom bot] を選択して、ボットの名前と声の種類を選んでください。残念ながら現状、言語は英語しか対応していません…

  1. 作成が完了すると以下のような画面が表示されるので、 [Create Intent] ボタンをクリックして、インテントを作成していきます。

  1. 今回は新規に作成していくので、 [Create intent] を選択。

  1. NetworkProblem と入力して、 [Add] ボタンをクリックします。

  1. Sample utterances にユーザが言いそうな内容を予め登録しておきます。(utterances って発生とか発話とかの意味なんですね、知らなかった

入力が終わったら、下部の [Save Intent] ボタンをクリックして保存します。

  1. パスワード初期化用の Intent をもう一つ追加していきます。

  1. NetworkProblem の時と同様、 Sample utterances を埋めていきます。

  1. Slots に AccountID を追加します。

AccountID として番号が入ることを想定しているので、 Slot type に AMAZON.NUMBER を選択しています。
Prompt にはスロットを埋めるための質問文を入力します。

入力が終わったら、保存します。

  1. 保存ができたら、 [Build] ボタンをクリックします。

確認画面がでるので [Build] ボタンをクリックします。

  1. 以下ポップアップが表示されたらビルド成功です!

  1. ビルドが成功したら右側でテストができるので以下のようにテストしてみましょう。

  1. テストが問題なさそうであれば [Publish] ボタンをクリックします。

Alias の指定画面がでてくるので prd を入力して [Publish] ボタンをクリックします。

  1. これにてチャットボットの作成は完了です。

Lex を利用したワークフロー作成

作成したチャットボットを Amazon Connect に適用していきます。

  1. Amazon Connect の Instance Alias を選択します。

  1. 左ペインから [Contact flows] を選択し、作成したチャットボットを追加します。

  1. 左ペインから [Overview] を選択、 Login URL にアクセスしログインします。

  1. 左ペインから [Contact flows] を選択し、以下画面に [Create contact flow] ボタンをクリックします。

  1. まずは Name に ItHelpDesk (任意)を入力します。

  1. 声の設定

電話の声を設定していきます。
今回チャットボットが英語なので英語を設定しましょう。声は Justin を選びました。

  1. 電話を掛けてきた相手に対する始めの文言を設定します。

Text to speech を選択し、 How can I help? と入力します。

  1. 更に、 Amazon Lex タブを選択後、作成したチャットボットを選択し、該当のインテントを追加します。

  1. 保存するとこのようになります。

  1. 次に Play prompt を縦に 3 つ並べます。(料理番組みたい

  1. 一番上の prompt を選択し、 NetworkProblem 時の返答文言を入力し保存します。

  1. 同様に 上から二番目の prompt を選択し、 PasswordReset 時の返答文言を入力し保存します。

$.Lex.Slots.AccountID でスロットに存在する AccountID を動的に取得することができます。

  1. 上から三番目の prompt を選択し、想定外の発話がされた場合やエラーが発生した場合の返答文言を入力し保存します。

今回はエージェントに転送する旨の文言を設定しました。

  1. 電話を切断するための Disconnect / hang up と異なるキューにまわすための Transfer to queue を追加します。

  1. すべての線を繋ぎ

  1. 右上の ▼ から [Save & Publish] を選択すると作成完了です。

ワークフローを電話番号へ関連付け

  1. 左ペインから Phone numbers を選択し、取得した電話番号を選択します。

  1. 作成したコンタクトフローをプルダウンから選択し、保存します。

  1. ここまでできたら一度取得した電話番号に電話してみましょう。

電話で How can I help? と聞かれたら reset my password というと Lex にて設定したとおり Account ID を聞かれると思います。

ユーザデータ格納用 DB 作成

今回はユーザの情報を DynamoDB テーブルへ格納します。

  1. DynamoDB から [Create table] ボタンをクリックします。

  1. テーブル名に任意の値を入力し、 Primary key に phoneNumber を入力後、 [Create] ボランをクリックします。

これで、テーブルの作成は完了です。

ユーザデータへアクセスするための Lambda ファンクション作成

ユーザの情報を DynamoDB から取得及び登録するための Lambda ファンクションを作成していきます。

IAM ロール作成

作成する Lambda ファンクションからは DynamoDB へ接続する必要があるため、その権限をもつ IAM ロールを作成します。

  1. IAM ロール から [Create role] ボタンをクリックします。

  1. Lambda を選択し [Next: Permissions] ボタンをクリックします。

  1. AmazonDynamoDBFullAccess を選択し [Next: Tags] ボタンをクリックします。

  1. [Next: Review] ボタンをクリックします。

  1. ロール名に任意の値を入力し、 [Create role] ボタンをクリックします。

これで IAM ロールの作成は完了です。

Lambda ファンクション作成

  1. AWS Lambda から [Create function] ボタンをクリックします。

  1. 任意の名前を入力し、ランタイムに Node.js 8.10 、ロールに作成したロールを選択後、 [Create function] ボタンをクリックします。

  1. Function code に Amazon Connect Demo Site の [References] – [Dynamic Flow Lambda] の以下コードを貼り付けます。

// Get the AWS SDK and Dynamo SDKs ready
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
 
//Sets the timezone environment variable for the Lambda function
process.env.TZ = "America/New_York";
 
exports.handler = (event, context, callback) => {
    // set the options for the date format
    var dateOptions = {
        weekday: "short",
        year: "numeric",
        month: "short",
        day: "numeric"
    };
 
    // set the variables to record the current local date and time
    var currentShortDate = new Date().toLocaleDateString();
    var currentLongDate = new Date().toLocaleDateString("en-US", dateOptions);
    var currentTime = new Date().toLocaleTimeString("en-US");
    var currentTimeStamp = new Date().toString();
 
    //log the incoming event from Amazon Connect for troubleshooting purposes
    console.log("Received event from Amazon Connect at: " + currentTimeStamp);
    console.log("Amazon Connect Event Details: " + JSON.stringify(event));
 
    //set the variables for the customer ANI and unique contact ID
    var sourcePhoneNumber = event.Details.ContactData.CustomerEndpoint.Address;
    var currentContactId = event.Details.ContactData.ContactId;
 
    //set up the database query to be used to lookup customer information from DynamoDB
    var paramsQuery = {
        //DynamoDB Table Name.  Replace with your table name
        TableName: 'connectDemo',
        KeyConditionExpression: "phoneNumber = :varNumber",
 
        ExpressionAttributeValues: {
            ":varNumber": sourcePhoneNumber
        }
    };
 
    //set up the database query to be used to update the customer information record in DynamoDB
    var paramsUpdate = {
        //DynamoDB Table Name.  Replace with your table name
        TableName: 'connectDemo',
        Key: {
            "phoneNumber": sourcePhoneNumber
        },
 
        ExpressionAttributeValues: {
            ":var1": currentTimeStamp,
            ":var2": currentLongDate,
            ":var3": currentTime,
            ":var4": currentContactId,
        },
 
        UpdateExpression: "SET lastCalledTimeStamp = :var1, lastCalledDate = :var2, lastCalledTime = :var3, lastCalledCallId = :var4"
    };
 
    //use the lookup query (paramsQuery) we set up to lookup the customer data based on the source phone number from DynamoDB 
    docClient.query(paramsQuery, function (err, dbResults) {
        //check to make sure the query executed correctly, if so continue, if not error out the lambda function
        if (err) {
            console.log(err); // an error occurred
            context.fail(buildResponseFailed);
        }
        //if no error occured, proceed to process the resutls that came back from DynamoDB
        else {
            //log the results from the DynamoDB query
            console.log("DynamoDB Query Results:" + JSON.stringify(dbResults));
 
            //check to ensure only 1 record came back for the customer phone number
            if (dbResults.Items.length === 1) {
 
                //set variables for the pertinet information from the returned database record:
                var lastCalledDate = dbResults.Items[0].lastCalledDate;
                var lastCalledTime = dbResults.Items[0].lastCalledTime;
                var customerFirstName = dbResults.Items[0].firstName;
                var customerLastName = dbResults.Items[0].lastName;
 
                //check to see if there is a record of a previous call, and set the previous call variable accordingly
                var customerFirstCall = true;
                if (lastCalledDate) {
                    customerFirstCall = false
                }
 
                //update the customer record in the database with the new call information using the paramsUpdate query we setup above:
                docClient.update(paramsUpdate, function (err, data) {
                    if (err) console.log("Unable to update item. Error: ", JSON.stringify(err, null, 2));
 
                    else console.log("Updated item succeeded: ", JSON.stringify(data, null, 2));
 
                });
 
                callback(null, buildResponseNumberFound(customerFirstName, customerLastName, lastCalledDate, lastCalledTime, customerFirstCall));
            } else {
                customerFirstCall = true;
                docClient.update(paramsUpdate, function (err, data) {
                    if (err) console.log("Unable to update item. Error: ", JSON.stringify(err, null, 2));
 
                    else console.log("Updated item succeeded: ", JSON.stringify(data, null, 2));
 
                });
 
                callback(null, buildResponseNumberNotFound(customerFirstCall));
            }
 
        }
    });
};
 
 
//This is the function that will be called on a successful callback if we find the phone number in our database
function buildResponseNumberFound(customerFirstName, customerLastName, lastCalledDate, lastCalledTime, customerFirstCall) {
    var results = {
        firstName: customerFirstName,
        lastName: customerLastName,
        lastCalledDate: lastCalledDate,
        lastCalledTime: lastCalledTime,
        firstCall: customerFirstCall,
        phoneNumberFound: true,
        lambdaResult: "Success"
    };
    console.log("Lambda's Response to Amazon Connect is: " + JSON.stringify(results));
    return results;
}
 
 
//This is the function that will be called on a successful callback if we don't find the phone number in our database
function buildResponseNumberNotFound(customerFirstCall) {
    var results = {
        firstCall: customerFirstCall,
        phoneNumberFound: false,
        lambdaResult: "Success"
    };
    console.log("Lambda's Response to Amazon Connect is: " + JSON.stringify(results));
    return results;
}
 
//This is the function that will be called on an error
function buildResponseFailed() {
    var results = {
        lambdaResult: "Error"
    };
    console.log("Lambda's Response to Amazon Connect is: " + JSON.stringify(results));
    return results;
}

34 行目及び 45 行目に connectDemo という文字列があるので、これを今回作成した DynamoDB テーブル名に修正後、タイムアウト値を 30 秒に変更し保存してください。

これで Lambda ファンクションの作成も完了です。

ワークフローに Lambda ファンクションを追加

先程作った Connect のワークフローに Lambda ファンクションを追加していきます。

  1. Amazon Connect から今回作成したインスタンスの Alias を選択します。

  1. 左ペインから Contact flows を選択し、作成した Lambda ファンクションを追加してください。
    (こないだまでは CLI で権限付与してたんですがこっちのほうが便利ですね

  1. 左ペインで Overview を選択し、 Login URL からログインします。

  1. 該当のコンタクトフローを開き、 Invoke AWS Lambda function をドラッグアンドロップします。

  1. Invoke AWS Lambda function を開き、作成した Lambda ファンクションの ARN を入力及びタイムアウト値を 8 秒に変更し保存します。

  1. Play prompt を 2 つ配置します。

  1. 上の prompt を選択し Hi $.External.firstName $.External.lastName, welcome to the IT Helpdesk. を入力します。

$.External.firstName 及び $.External.lastName には DynamoDB から取得した架電者の名前が入ります。

  1. 下の prompt には Welcome to the IT helpdesk を入力します。

この prompt は架電者が DB に登録されていない場合に流れます。

  1. フローを以下のように繋ぎ直し、 [Save & Publish] をクリックします。

これでフローの作成は完了です!

試してみよう

遂に完成しました。

早速 Amazon Connect で取得した電話番号に電話してみましょう。

以下のような会話ができるはずです。

私:(電話かける)

ボット:「Welcome to the IT help desk」

ボット:「How can I help?」

私:「Reset my password」

ボット:「What is your account ID?」

私:「123456789」

ボット:「The password for account ID 123456789 has been reset.」

電話をかけると DynamoDB に以下のようなレコードが登録されます。

登録されたアイテムをクリックして、 firstName 及び lastName を追加します。

そして、もう一度電話をかけてみてください。

今度は以下のような会話ができるはずです。

私:(電話かける)

ボット:「Hi Daishi Yamanaka, Welcome to the IT help desk」

ボット:「How can I help?」

私:「I can't access the internet」

ボット:「Please try to access to the internet once more.」

おわりに

いかがでしょうか。

簡単にチャットボットを利用したヘルプデスクを作成することができました。

現在は残念ながら英語にしか対応していませんが、これから日本語対応がされればいろいろなところで活用できそうですね。

RDSの過去のイベントを見る方法

$
0
0

PS課の杉村です。ちょっとしたTIPSですがRDSインスタンスやAuroraクラスタの過去のイベント履歴を見る方法についてです。

最近のイベント

RDSインスタンスやAuroraクラスタの起動、停止、バックアップ、アップグレードなどはイベント履歴に残ります。RDSやAuroraのイベント履歴は、過去24時間分にさかのぼってマネジメントコンソールから見ることができます。
日本語コンソールだと「最近のイベント」、英語コンソールだと「Recent events」ですね。

下記のコンソールは2018年11月現在

しかしマネジメントコンソール上では過去24時間分のイベントしか表示されません。
それより以前の履歴が見たい場合、AWS CLIなどを使いAPIから取得する必要があります。

aws rds describe-events --source-identifier your-db-resource --source-type db-cluster --start-time 2018-12-01T09:00+9

–source-identifierに対象のクラスタ識別子やDB識別子を、–source-typeにはdb-clusterやdb-instanceを指定します。

–start-timeを明示的に指定しない場合、デフォルトだと1時間前までのイベントが返されます。最大でも14日前までの履歴を見ることができます。
時刻はISO 8601という表記法で指定します。上記の例は末尾を+9にしているので日本時間になります。末尾をZにする(2018-12-01T18:00Z)とUTCです。※返ってくる情報の中にはDateがありますが、末尾がZのUTC表記です。

参照: DescribeEvents
https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeEvents.html

返ってくる情報は以下のようなものです。(JSONの場合)

{
    "Events": [
        {
            "EventCategories": [
                "notification"
            ],
            "SourceType": "db-cluster",
            "SourceArn": "arn:aws:rds:ap-northeast-1:123456789012:cluster:your-db-resource",
            "Date": "2018-12-01T00:04Z",
            "Message": "DB cluster started",
            "SourceIdentifier": "your-db-resource"
        }
    ]
}

また単純に以下のようにすれば、過去n分間前までのイベントがすべて返ってきます。(durationには”分”を入れる)
aws rds describe-events --duration 10080

ポイント

・マネコンでは過去24時間分しかイベントを見られない
・それより以前を見たいなら、AWS CLI等を使う(それでも14日前までしか見られない)

参考ドキュメント(公式): Amazon RDS のイベントの表示

AWS Direct Connectの概念の整理…Connectionとは?VIFとは?

$
0
0

PS課の杉村です。Direct Connect(通称DX)は、オンプレミス環境とAWS環境をつなぐ専用線サービスであり多くの企業で利用されています。しかし概念を正確に理解されている人はあまりいらっしゃらないのではないでしょうか。非常に簡単にですがDirect Connectに登場する概念について整理してみます。

なおAWSさん公式でDirect Connectに関する非常に分かりやすい資料を公開しています(いわゆるBlackbelt)のでお時間がある方は下記を読んでみてもよいでしょう。日本語でこんなに充実した資料が読めるなんて、いつもながらすごいと思ってしまいます。
https://d1.awsstatic.com/webinars/jp/pdf/services/20181114-AWS-Blackbelt-DirectConnect.pdf

大きく分けると2つ

DXは大きく分けると以下の2つの概念で成り立ちます。
1. Connection
2. Virtual Interface

Connection(接続)は物理的な回線に相当します。1 Gbpsまたは10 Gbpsとなります。
ただし後述のHosted Connectionであればそれ以下の帯域もありえます。
マネジメントコンソール上で「ポートスピード」という表示を確認することができます。

しかしConnectionだけではDirect Connectを利用することはできず、Virtual Interfaceが必要です。
Virtual Interface(仮想インターフェイス、通称VIF)は仮想的な回線でありVLAN IDを持ちます。ConnectionをVLAN(802.1Q)で区切っているのですね。
一つのConnectionの中に複数のVIFを作成することができます。

このVirtual Interfaceを、直接「Virtual Private Gateway(通称VGW。VPCにアタッチする)」や「Direct Connect Gateway(DXのハブのようなもの)」または「AWS Transit Gateway(VPCやVPNを含めてハブになってくれる新サービス。2018/12時点でDX未対応だが、来年対応予定)」に紐づけることで、オンプレとAWSが晴れて通信できるわけです。

マネジメントコンソールでConnectionとVIFそれぞれの一覧を見ることができます。
しかし、ご利用の契約形態によってはConnectionが表示されておらずVIFだけだったりします。また、Connectionが表示されていても「ホスト接続(Hosted Connection)」と表示されているケースもあります。
いったいどういうことなのでしょう?

ConnectionとVIF(通常利用)

ConnectionとVIFの関係を図にすると以下のようになります。
ご利用の環境でConnectionが存在していれば、その中に複数のVIFを作成することが可能です。(マネコンから操作)
VIFを増やした時にはオンプレ側ルータの設定も必要です。

Hosted Virtual Interface

ご利用の環境でConnectionが表示されていないのにVirtual Interfaceだけが表示されている場合、こちらの利用方法にあたります。
Connectionは別のAWSアカウント(ご契約のパートナー)が持っていて、そこからVirtual Interfaceが払い出されているのです。これをHosted Virtual Interface(ホスト仮想インターフェイス)と言います。
ただし明示的にマネジメントコンソールに「このVIFは他のAWSアカウントから払い出されたHosted VIFだよ」と表示されているわけではありません。
Virtual Interfaceには自分の親のConnectionのIDが表示されますが、そのConnectionが自分のAWSアカウントになければ、そのVIFはHosted VIFだと分かるわけです。

この利用形態の場合、コンソール画面から帯域を確認することはできないため、ご契約を確認ください。(帯域はパートナーによってVLANのQoSで制御されているはずです。)

Hosted Connection (Sub 1G)

パートナーから顧客のAWSアカウントに仮想的なConnectionを払い出す、Hosted Connectionというものも存在します。
帯域が500Mbpsや100Mbps等、1Gbps未満の接続であることからSub-1G Connectionとも呼ばれます。

Hosted Connectionを払い出されたAWSアカウントでは、Virtual Interfaceを一つだけ作成し、自由に利用することができます。
Hosted Connectionをコンソール画面で確認すると「ホスト接続」と表示されています。
「割り当て済み VLAN」としてVLAN IDも表示されているので、実際にはVLANで分離されたものであることが分かります。それゆえにHosted ConnectionではVIFを一つしか作れないのですね。

モニタリング

通常のConnectionの利用状況はCloudWatchでモニタリングすることができます。Up/Downのステータスや利用帯域(bps)、秒間パケット数(Pps)などを確認できます。

一方でHosted ConnectionやVirtual Interfaceの利用状況はCloudWatchで見ることができません。これらの利用状況はオンプレのNW機器側でSNMPなどでモニタリングする必要があるのです。パートナーからのサービス提供であれば、モニタリングのためのコンソール画面などがサービスとして提供されているかもしれないので、ご確認ください。

ポイント

・Direct Connect(DX)にはConnectionとVirtual Interface(VIF)がある
・Virtual InterfaceをVirtual Private Gateway(VGW)等と紐づけることでAWSとオンプレの通信が可能になる
・Connectionには通常のConnectionとパートナーから共有されるHosted Connectionがある
・Virtual Interfaceには通常のVirtual Interfaceとパートナーから共有されるHosted Virtual Interfaceがある


【祝・東京リージョン対応】みんなはAmazon Connectで何を解決しようとしている?

$
0
0

クラウド型コンタクトセンター Amazon Connect がいよいよ東京にやってきました。

【東京リージョンでできるようになったこと】
・今までの050、0800番号に追加して 0120番号の取得ができるようになりました
・よりスムーズな接続、通話になった感じがします

そして気になる料金はシドニーリージョンよりも安めになっています。
サーバーワークスオリジナルのAmazon Connect利用料試算シートを公開しています。
東京リージョンでの具体的なケースにおける利用料金を今すぐ知りたい方はご活用ください。

本エントリでは、東京リージョンにやってくる前から Amazon Connect を調査・検討してきたお客様がどんなことを考えていたかを共有します。

他社は Amazon Connect をどんなときに活用しようとしている?

ありがたいことに、当社ではすでに Amazon Connect に関するお引き合いを想定以上に頂いております。
これまでお客様から伺ったAmazon Connect で解決したい課題の傾向をまとめます。

よくあがる課題

・回線や物理的な制約からの開放
回線を増やすのに時間がかかる
コールセンターもしくは自社内で物理的に増設が難しい状況になっている
等のお悩みをよく伺います。
みなさま、いままで物理的な制約にずっと苦しんできているようで「もう無理、助けてほしい」という状況のお話を何度も聞きました。
Amazon Connectは物理的な制約は一切なくなります。
要件があうようでしたらすぐに活用をご検討ください。
 
他にも以下の課題を非常に多く聞きます。
・対応音声のテキスト化
・繁忙期対応
・アウトコール(リスト/イベントドリブン)
対応音声のテキスト化は、弊社では横河電機株式会社の事例の実績がございます。
しかしこの事例は言語が英語となっており、日本語でテキスト化するのはまだまだ実用レベルとして難しい、というのが正直な状況です。
しかし、今すぐにできなくても Amazon Connect では録音音声をオープンな形で再利用可能としています。
日本語のテキスト化の技術をあとから組み込むことも可能です。
 
繁忙期対応やアウトコールシステムは Amazon Connect でいますぐ解決できる方法があります。
Amazon Connect だけでは解決できないこともでてきます。
そんなときはAWSの他のサービスを上手に利用するのが設計のポイントになります。
 

想定範囲内の課題

・自社の電話対応業務を効率化したい
小規模なサポートセンターでは人の力でなんとか運用を行っているケースも多いようです。
Amazon Connectを活用することで例えば、担当者が直接電話に対応できるようにして無駄な取次を減らすことができます。
固定の場所、物理的な電話機にとらわれない自由な仕事環境を構築することもできます。
 

想定より差し迫っていなかった課題

・コスト
比較項目の一つとしてコストはでてきますが、コストよりも他の課題のほうが優先度が高い傾向です。
 
以下の理由が考えられます。
  • コンタクトセンターのコストはすでに計画的に予算化されている
  • 大型コンタクトセンターの場合もともとの金額が膨大すぎて比較するまでもない

まとめ

Amazon Connect で解決できる課題はたくさんあります。
一方で Amazon Connect では「できないこと」もあります。
次のエントリーではよく質問される「Amazon Connect でできること・できないこと」をまとめます。

【祝・東京リージョン対応】Amazon Connectできること・できないこと

$
0
0
クラウド型コンタクトセンター Amazon Connect がいよいよ東京にやってきました。
に続いての投稿です。
 
本エントリでは、Amazon Connect の導入を検討しているお客様から Amazon Connect ってこんなことできますか?
と何度も聞かれた質問について対応可否についてまとめました。
 
Amazon Connect はセルフサービスで利用できるとてもすてきなサービスです。
でも導入・設計には工夫も必要となります。
みなさまが Amazon Connect を一番上手に活用できるように、サーバーワークスではこれまでの実績を生かしてサポートさせていただきます。
以下にない質問や相談がございましたら、お気軽にお問い合わせくださいませ。
 

 

Amazon Connect でできる?できない?

○:Amazon Connectの機能として利用可能
△:AWS他サービス等と連携して実装可能
☓:利用不可能
※実現可否は本日(2018-12-12)時点の情報です
 

電話番号

やりたいこと 可否 説明
電話番号の新規取得 東京リージョンでは
DID:050
TollFree:0800,0120が取得可能です。
別途03番号の取得申請も可能です。
ナンバーポータビリティ 現時点では東京リージョンにおけるナンバーポータビリティについて発表されていません。期待!
現在利用しているフリーダイヤル(0120)の転送先をAmazon Connectとしたい 転送料金はかかる
転送元電話番号の表示は可能
現在利用しているフリーダイヤル(0120)で発生したあふれ呼の転送先をAmazon Connectとしたい フリーダイヤルで「話中時迂回」オプションを利用し、お話中の転送先をAmazon Connectにすることが可能
現在利用しているフリーダイヤル(0120)で営業時間外の対応をAmazon Connectで実現したい フリーダイヤルで「接続先変更(受付先変更)」オプションを利用し、曜日や時間帯によって転送先をAmazon Connectにすることが可能

電話機能

やりたいこと 可否 説明
留守番電話機能を使いたい Amazon Connectの機能として現時点で提供されていない
擬似的な留守電機能を実装する回避方法あり(実運用では非推奨)
内線を使いたい Amazon Connectの機能として現時点で提供されていない
電話をかけるという運用なら対応可能
クイック接続を利用可能すればワンクリックでコール可能
一斉着信をしたい Amazon Connectの機能として現時点で提供されていない
ルーティングルールによって着信するオペレータを判定する仕様
携帯電話で受発信をしたい 現時点ではアプリ等の提供がなく利用不可
iPhone/Android ともにCCP(ソフトフォン)の利用要件を満たさない
ただし、携帯電話番号に転送された電話を受けることは可能

問い合わせフロー(IVR)

やりたいこと 可否 説明
着信番号で判定し、担当営業につなぎたい Lambdaで担当営業を特定する情報(CRMシステム等)と連携を実装すれば実現可能
着信した電話を外出している担当営業につなぎたい 携帯電話番号に転送することが可能
転送先をクイック接続として事前に登録することも可能
営業時間外は対応を変えたい オペレーション時間で営業時間の定義が可能
[オペレーション時間を確認する]ブロックで「時間内」と「時間内」で処理を分岐することが可能
オペレーション時間では曜日・時間のみ設定可能
同じ曜日の設定を複数設定できますので、昼休みを表現したりすることも可能
祝日や年末年始の休暇の定義は設定できない
オペレーション時間の設定変更はいつでも容易に可能
祝日、会社の営業日の判断を自動的にしたい Lambdaで営業日の判定をすれば実装可能
エージェントが電話にでるときに、カスタマーがプッシュした番号をしりたい [顧客の入力を取得]した後[問い合わせ属性の設定]をすることで入力値をコールフローで利用可能
エージェントウィスパーフロー機能を利用し、エージェントに入力値を音声で伝えることが可能
読み上げるメッセージを時間帯や状況によって動的に変更したい Lambdaで動的にメッセージを生成する機能を実装すれば実現可能
コールバック機能(混雑時に応対できなかった電話に発信) コールバック機能を利用することで実現可能
コールバックキューは、エージェントが受付可能になったタイミングで自動的にコールバックを実施
コールバック先が応答するとエージェントと通話が確立し
コールバックの要件がコールバック機能では満たされない場合は、Lambdaで独自機能を実装可能
かかってきた電話番号または入力された電話番号へSMSを送信したい LamdaでSNSをコールすることで実現可能

マネジメント

やりたいこと 可否 説明
コールセンターの稼働状況をリアルタイムで把握したい リアルタイムモニタリング機能が用意されてる
エージェントマップを利用したい エージェントマップの機能は提供されていない
通話モニタリングしたい リアルタイムモニタリングから通話中の電話をモニタリングすることが可能

ACD(自動振り分け)

やりたいこと 可否 説明
スキルベースルーティングをしたい ルーティングプロファイルの設定で対応可能

システム・環境

やりたいこと 可否 説明
席数の急な増減に対応したい スケーラブルで伸縮自在な設計
席数の考えはないため柔軟な対応が可能

 

今まで質問にはあがってこなかったけれど、Amazon Connect ならできることもたくさんあります。
既存の「コンタクトセンター」という枠組みからはみだした、Amazon Connect の可能性をもっと引き出すような使い方をぜひしてみたいと思っています。

AWS 機械学習サービスまとめ 2018年版

$
0
0

こんにちは、PS課のミネです。

昨年のre:invent 2017ではSageMakerが発表され、今年のre:invent 2018でもAmazon PersonalizeやAmazon Forecastなどが発表されました。AWSの機械学習サービスもかなり充実してきたのではないでしょうか。

今回はそれぞれのサービスの概要とユーズケースをまとめたいと思います。

何があるか

そもそもAWSの機械学習サービスに分類されるサービスには何があるのでしょうか。だいたい以下ののものが機械学習サービスとなるかと思います。

  • Amazon Machine Learning
  • Amazon SageMaker
  • Amazon Rekognition
  • Amazon Lex
  • Amazon Polly
  • Amazon Comprehend
  • Amazon Transcribe
  • Amazon Translate
  • Amazon Textract (New!)
  • Amazon Personalize (New!)
  • Amazon Forecast (New!)
  • AWS DeepLens
  • AWS DeepRacer (New!)

もちろん上記はAWSから提供されている機械学習サービスなので、ユーザー側でEC2やECS、S3などのその他のサービスを組み合わせ、モデルのトレーニング/デプロイを行うこともあるかと思います。

一口に機械学習サービスといっても…

一口に機械学習サービスといっても、その利用方法ははさまざまです。AWSの機械学習サービスは、ざっくり以下のように分けられると考えています。

  1. ユーザーからのINPUTから予測のみ行うサービス(Transcribe, Pollyなど)
  2. ユーザーは学習データのみ用意し、サービス側でモデルをトレーニングするサービス(Comprehend, Machine Learningなど)
  3. インフラを気にせずにユーザーがモデルのトレーニング/評価/デプロイを行えるサービス(SageMaker)

1・2は機械学習の知識がなくて利用できる系のサービスです。3はインフラの管理が減り、データサイエンティストや機械学習エンジニアがより本業に集中できる、もしくはプロジェクトに関わるインフラエンジニアの負担が減るというようなサービスです。それでは各サービスについてみていきましょう。

Amazon Machine Learning

機械学習のことをよく知らなくても機械学習ができる系のサービスです。使えるモデルは線形回帰、ロジスティック回帰、多項ロジスティック回帰の3つ。この3つのモデルの具体的な計算はわからなくとも、使い分けさえ分かっていれば利用できます。ユーザーはCSVでデータを用意するだけでモデルをトレーニング/評価/デプロイし予測ができます。

参考

Amazon Machine Learning (SlideShare)
Amazon Machne Learningドキュメント

Amazon SageMaker

最近はやりのSageMakerは、どちらかというとデータサイエンティスト・機械学習エンジニア向けのサービスです。SageMakerの利点はインフラの管理が少ないことにあります。小さいインスタンスタイプのノートブックインスタンスでコードを書き、トレーニングは大きなインスタンスタイプで、モデルをAPIとしてデプロイするのもAPIサーバーの構築などを考えることなく簡単です。「インフラの管理めんどくさいよ~」ていうデータサイエンティスト・機械学習エンジニアにおすすめのサービスです。独自のアルゴリズムを利用することも可能ですが、SageMaker組み込みのアルゴリズムがすぐに利用できるのでおススメです。ただし、学習時にリアルタイムなデータがほしい場合には向かないので注意しましょう。

参考

Amazon SageMaker (SlideShare)
Amazon SageMakerドキュメント

Amazon Rekognition

ユーザーが画像や動画を用意するだけで、画像や動画から顔/テキストの検出、安全でないコンテンツなどの検出が出来るサービスです。動画を扱うサービスは特にAmazon Rekognition Videoと呼ばれます。Amazon Rekognition VideoはKinesis Video Streamsと組み合わせてストリーミングビデオからの検出も可能です。

参考

Amazon Rekognitionドキュメント

Amazon Lex

テキストもしくは音声を利用する会話型のインターフェイスを簡単に構築することができます。いわゆる「チャットボット」が簡単に構築できるというサービスになっています。Lambdaと連携することも可能で、Lambda経由で他のAWSサービスと連携することもできます。Webサービスやチャットアプリに組み込むことはもちろんですが、Amazon Connectに統合することも可能です。

参考

Amazon Lexドキュメント
Amazon Connect と Amazon Lex のインテグレーション

Amazon Polly

テキストを音声に変換するサービスです。音声の速度や発音を調整することも可能です。

参考

Amazon Pollyドキュメント

Amazon Comprehend

Amazon Comprehendは自然言語処理のサービスです。ユーザーは分析したいテキストを用意し、エンティティ分析/キーフレーズ分析/言語の分析(何語か?を分析)/感情分析/構文分析を行うことができます。分析の仕方もいくつかあり、アプリケーションに組み込み単一のテキストを分析することも、S3へためたテキストをいっぺんに分析することもできます。Comprehend Customという機能もあり、こちらはユーザー側で学習データを用意する必要があります。しかし機械学習の知識がなくとも、Comprehendへそのデータを学習させ、ユーザー側でモデルを「カスタム」することができます。Comprehend Customは現在、ドキュメントの分類とエンティティ分析で利用可能です。

参考

Amazon Comprehendドキュメント(英語)

Amazon Transcribe

文字起こしサービスです。単に音声を文字へ起こすだけでなく、設定した人数でもしくは音声のチャンネルで話者の識別も可能です。また、例えば会議などの文字起こしに利用するとなると専門用語を正確に文字起こしする必要がありますが、カスタム語彙を設定してやることでより正確に文字起こしすることができます。

参考

Amazon Transcribeドキュメント

Amazon Textract (New!)

今年のre:inventで発表された新サービスの1つです。書類からテキストの抽出/分析が行えます。テキストだけでなく、表も抽出できます。

参考

Amazon Textractドキュメント(英語)

Amazon Personalize (New!)

パーソナライゼーションとレコメンデーションを誰でも容易にできるサービスです。利用の流れははデータセット用スキ―マを用意、データセットを準備、アルゴリズムの選択・学習、モデルのデプロイという感じです。Personalizeではアルゴリズムはレシピと呼ばれ、事前に定義されたレシピはもちろん、独自のアルゴリズムをレシピとして追加することも可能です。AutoMLを有効にすると差的なレシピが自動で選択されます。

参考

Amazon Personalizeドキュメント(英語)

Amazon Forecast (New!)

時系列予測のサービスになります。時間に依存したデータの予測を行うことができます。こちらもデータセットを用意し、レシピ(アルゴリズム)を選択、モデルのデプロイ(プレディクターの作成)という流れで利用します。独自のレシピは使えなさそう…?

参考

Amazon Forecastドキュメント(英語)

  • AWS DeepLens
  • AWS Deeplensは専用のカメラと専用の開発プラットフォームです。サンプルプロジェクトも用意されており、事前に学習したモデルを使って、初心者が深層学習による画像認識を学ぶこともできます。もちろん自身でモデルをトレーニングし、専用カメラにデプロイすることもできます。

    参考

    AWS Deeplensドキュメント(英語)
    AWS DeepLens

    AWS DeepRacer (New!)

    今年のre:invenで発表されたAWS DeepRacerですが、あのミニカーが印象的でした。AWS DeepRacerは強化学習を用いて、ミニカー自律走行させることができます。コンソールではモデルの学習・チューニングだけでなく、走行のシミュレーションもできるため大変便利です。DeepRacerを使った大会も開催されているようです。

    参考

    AWS DeepRacerドキュメント(英語)
    AWS DeepRacer League
    DeepRacer

    まとめ

    いかがでしょうか。TranscribeやTranslateのようにユーザーがすぐに利用できるものもたくさんあります、Machine Learningのようにユーザーはデータを用意するだけでも使えるサービスもありますが、モデルに対して理解しておけばよりよく使いこなせると思います。PersonalizeやForecastのレシピについてもそれぞれ理解しておく必要がありそうです。SageMakerはユーザーインフラを気にせずに利用できるので、ゴニョゴニョしてモデルをデプロイする必要がある場合は、SageMakerで実現できるか検討してもいいかもしれません。冒頭にも述べましたが、EC2やECSなどを活用すして、モデルのトレーニング/デプロイを行うこともできます。機械学習サービスで間に合うのであれば、どんどん使っていきましょう。

    AWS Transit GatewayとAlibaba Cloud CENの接続

    $
    0
    0

    はじめに

    2018年11月にAWS Transit Gatewayが登場しました。
    これは複数のVPCを接続するHUBとなるサービスです。
    一方、Alibaba CloudではCEN(Cloud Enterprise Network)という同様のサービスが既にあります。
    まず、両サービスの構成図を比較してみましょう。

    なお、この記事はAlibaba Cloudアドベントカレンダー2018の12日目となります。

    AWS Transit Gateway

    https://aws.amazon.com/jp/transit-gateway/

    Alibaba Cloud CEN

    https://jp.alibabacloud.com/help/doc-detail/59870.htm

    どうでしょう?とても似てますよね。
    AWSのVPCはTransit Gatewayを介して、お互いに通信可能です。
    Alibaba CloudのVPCもCENを介して、お互いに通信可能です。
    それなら、Transit GatewayとCENを接続すれば、全て通信可能だと思いませんか?

    こんな構成を作って見ました。

    Transit GatewayとCENをVPN接続し、両クラウドの全VPCが通信可能となる構成です。

    構築手順

    1. VPC作成

    普通にVPC、サブネットなどを作ります。
    ここの手順説明は省略させていただきますが、図のような感じでVPCを作成しました。

    2. CENの作成

    2-1.CEN作成

    Alibaba CloudのコンソールでExpress Connectを選択します。
    Express ConnectとCENは別サービスなのですが、設定画面への入り口は現在のところ共通になっています。

    CENの作成をクリックします。

    CENの名前と接続するVPCを選択します。
    東京側のVPCでも北京側のVPCでもどちらでも問題ありません。(後で他方も接続するので)

    作成完成すると、以下のような画面が表示されます。

    2-2.CENにVPCをアタッチ

    作成したCENインスタンスをクリックします。

    ネットワークのアタッチをクリックします。

    CEN作成時にアタッチしていなかったVPNをここでアタッチします。

    この時点でAlibaba CloudのVPC間の通信は完了です。
    なお、リージョン跨ぎの帯域は標準1Kbpsとなります。
    帯域購入もできますが、今回は疎通テストをゴールとするため、そのままとします。

    CENの状態は下記のようになります。
    Japan(Tokyo)とChina(Beijing)のVPCが一つずつCENにアタッチされました。

    ルートも自動設定です。
    VPCのCIDRではなく、実際に設定されているサブネット向けのルートが自動登録されます。
    最終的にAWS向けのルートも入る必要がありますが、それは作業の終盤に行います。

    3. Transit Gatewayの作成

    3-1. Transit Gateway作成

    AWSコンソールのVPC設定画面の左下の方にTransit Gatewayがあるのでクリックします。
    (但し、非対応リージョンの場合は表示されません。)

    Create Transit Gatewayをクリックします。

    いろいろ設定項目ありますが、Nameタグの設定以外はデフォルトで大丈夫です。

    3-2.Transit GatewayにVPCをアタッチ

    作成したTransit GatewayにVPCをアタッチします。
    Transit Gateway Attachmentsをクリックします。

    Create Transit Gateway Attachmentをクリックします。

    下記のように設定を入力し、作成します。

    Transit GatewayにアタッチしたいVPCの数だけ作業を繰り返します。
    今回は二つのVPCなので、以下のようになります。
    なお、後の工程でVPNを追加することになります。

    3-3. Subnet Route Tableにルート追加

    Transit GatewayにVPCが接続されたのですが、実際はまだVPC間の通信はできません。
    サブネットに紐づいているRouteTableにTransit Gatewayを経由させるエントリを追加する必要があります。

    今回はAWSの別VPC(172.17.0.0/16)をTransit Gateway経由にするだけでなく、Alibaba Cloudのアドレス(10.0.0.0/8と192.168.0.0/16)へもTransit Gateway経由にするため、エントリを3つ追加しました。
    各サブネットのRouteTableで同様の設定が必要です。

    この時点でAWSのVPC間の通信は完了です。

    4.VPN Gatewayの作成

    両クラウドにVPN Gatewayを作成します。
    なお、Alibaba CloudとAWSのVPN接続についてはSBCloud様の下記ページを参考とさせていただきました。

    Alibaba CloudとAWSをVPN接続する

    ちなみに本記事の冒頭の構成図を見てもらうとわかるのですが、微妙に配置に違いがあります。

    • Alibaba CloudのVPN Gatewayは、いずれかのVPCに接続する
    • AWSのVPN Gatewayは、Transit Gatewayに直接接続する

    4-1.Alibaba Cloud の VPN Gateway作成

    Alibaba CloudのコンソールでVPN Gatewayの作成をします。

    作成後、VPN GatewayのIPアドレスが確認できます。
    このアドレスは、AWS側でVPN設定をする時に使います。

    4-2.AWS の VPN作成

    AWSで普通にVPN作成する時は、「VPN接続」という項目で設定しますが、Transit Gatewayの場合は異なります。
    Transit Gateway Attachmentsで設定します。
    「3-2.Transit GatewayにVPCをアタッチ」で設定したのと同じ箇所です。

    上記を行うと、「VPN接続」欄にVPN接続が表示されます。
    AWS側のIPアドレスが確認できます。
    このアドレスは、Alibaba Cloud側でVPN設定をする時に使います。

    4-3.Alibaba Cloud の Customer Gateway作成

    Alibaba CloudのコンソールでCustomer Gatewayを作成します。

    4-4. Alibaba Cloud の VPN接続作成

    IPsec ConnectionsでVPN接続の作成をします。

    AWS側とAlibaba Cloudの双方にVPC CIDRが複数あるため、「追加ローカルネットワーク」「追加リモートネットワーク」をしたくなります。
    それをするためにはVPNをIKEv2とする必要があります。
    ところが、AWSのVPNはIKEv1しか使えません。
    やや苦し紛れに以下のように設定したところ、問題なく通信できました。
    – ローカルネットワーク:0.0.0.0/0
    – リモートネットワーク:172.16.0.0/12

    VPN接続が成功となりました。

    5. 再びルート設定

    5-1. Transit Gateway Route Tableにルートを追加

    Transit Gateway Route TableにAlibaba Cloud向けのルートエントリを追加します。
    「3-3. Subnet Route Tableにルート追加」では、サブネットからTransit Gatewayまでのルートを追加しました。
    ここではTransit GatewayからAlibaba CloudへのルートをVPNに向ける設定を追加します。

    5-2. Alibaba Cloud のへルート追加

    VPN GatewayのあるVPC(東京VPC)でAWS向けのルートをVPNに向ける設定を追加します。
    これで東京VPCとAWSのVPCは通信可能になります。
    ところが、これだけだと北京VPCはAWSと通信できません。

    CENのルートステータスを 公開 にすると、CENのルートテーブルにこのルートが伝播し、北京VPCもAWSと接続できるようになります。

    これで完成です。

    疎通テスト

    各VPCからpingで疎通テストをしてみます。

    Alibaba (北京) 〜 AWS(バージニア) 

    [root@iZ2ze1wjgvrqaur6iskr5lZ ~]# ping -c 5 172.17.0.111
    PING 172.17.0.111 (172.17.0.111) 56(84) bytes of data.
    64 bytes from 172.17.0.111: icmp_seq=1 ttl=252 time=229 ms
    64 bytes from 172.17.0.111: icmp_seq=2 ttl=252 time=229 ms
    64 bytes from 172.17.0.111: icmp_seq=3 ttl=252 time=229 ms
    64 bytes from 172.17.0.111: icmp_seq=4 ttl=252 time=229 ms
    64 bytes from 172.17.0.111: icmp_seq=5 ttl=252 time=229 ms
    
    --- 172.17.0.111 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4004ms
    rtt min/avg/max/mdev = 229.109/229.220/229.375/0.088 ms

    Alibaba (北京) 〜 Alibaba (東京)

    [root@iZ2ze1wjgvrqaur6iskr5lZ ~]# ping -c 5 10.0.0.17
    PING 10.0.0.17 (10.0.0.17) 56(84) bytes of data.
    64 bytes from 10.0.0.17: icmp_seq=1 ttl=64 time=55.2 ms
    64 bytes from 10.0.0.17: icmp_seq=2 ttl=64 time=55.0 ms
    64 bytes from 10.0.0.17: icmp_seq=3 ttl=64 time=55.1 ms
    64 bytes from 10.0.0.17: icmp_seq=4 ttl=64 time=55.1 ms
    64 bytes from 10.0.0.17: icmp_seq=5 ttl=64 time=55.0 ms
    
    --- 10.0.0.17 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4005ms
    rtt min/avg/max/mdev = 55.063/55.122/55.211/0.216 ms

    AWS(バージニア) 〜 AWS(バージニア) 

    [ec2-user@ip-172-16-0-132 ~]$ ping -c 5 172.17.0.111
    PING 172.17.0.111 (172.17.0.111) 56(84) bytes of data.
    64 bytes from 172.17.0.111: icmp_seq=1 ttl=254 time=1.07 ms
    64 bytes from 172.17.0.111: icmp_seq=2 ttl=254 time=0.776 ms
    64 bytes from 172.17.0.111: icmp_seq=3 ttl=254 time=0.785 ms
    64 bytes from 172.17.0.111: icmp_seq=4 ttl=254 time=0.923 ms
    64 bytes from 172.17.0.111: icmp_seq=5 ttl=254 time=0.772 ms
    
    --- 172.17.0.111 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4030ms
    rtt min/avg/max/mdev = 0.772/0.865/1.071/0.120 ms

    AWS(バージニア) 〜 Alibaba(東京) 

    [ec2-user@ip-172-16-0-132 ~]$ ping -c 5 10.0.0.17
    PING 10.0.0.17 (10.0.0.17) 56(84) bytes of data.
    64 bytes from 10.0.0.17: icmp_seq=1 ttl=62 time=181 ms
    64 bytes from 10.0.0.17: icmp_seq=2 ttl=62 time=180 ms
    64 bytes from 10.0.0.17: icmp_seq=3 ttl=62 time=180 ms
    64 bytes from 10.0.0.17: icmp_seq=4 ttl=62 time=180 ms
    64 bytes from 10.0.0.17: icmp_seq=5 ttl=62 time=180 ms
    
    --- 10.0.0.17 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4004ms
    rtt min/avg/max/mdev = 180.011/180.382/181.831/0.817 ms

    AWS(バージニア) 〜 Alibaba(北京) 

    [ec2-user@ip-172-16-0-132 ~]$ ping -c 5 192.168.0.92
    PING 192.168.0.92 (192.168.0.92) 56(84) bytes of data.
    64 bytes from 192.168.0.92: icmp_seq=1 ttl=62 time=230 ms
    64 bytes from 192.168.0.92: icmp_seq=2 ttl=62 time=229 ms
    64 bytes from 192.168.0.92: icmp_seq=3 ttl=62 time=229 ms
    64 bytes from 192.168.0.92: icmp_seq=4 ttl=62 time=229 ms
    64 bytes from 192.168.0.92: icmp_seq=5 ttl=62 time=228 ms
    
    --- 192.168.0.92 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4004ms
    rtt min/avg/max/mdev = 228.938/229.342/230.317/0.585 ms

    全て上手くつながりましたね。

    Proxy環境下で使うAWS Systems Manager

    $
    0
    0

    PS課の杉村です。AWS Systems Managerは本当に便利になってきました。特にEC2では、Agentをインストールすることでログインすることなく様々なオペレーションが実施できます。しかし特にエンタープライズのお客様ではいろいろな制約から、なかなか有効活用できていないケースがあるのではないでしょうか。

    「社内LANに存在するすべてのPC、サーバーはインターネットに出る場合はHTTP Proxyを経由せよ。それは専用線やVPNで社内LANと接続されているVPCも同様である」
    そんなルールを課され、AWSを利用するときにいつも四苦八苦しているお客様も多いことでしょう。

    SSMを便利に使いこなしたいのに、Proxy設定が大変。。。という目に私自身遭遇したので、今回はそれについて書いてみます。

    SSM Agent自体のProxy設定

    Amazon Linux (1/2) や最近のWindowsインスタンスにはSSM Agentが最初からインストールされています。
    SSM Agentは、APIを実行するためにSSMのエンドポイントにアクセスしたり、特定のS3バケットへ接続する必要があります。そのためインターネットアクセスが必須なのです。

    以下の手順で、SSMがProxyを経由してインターネットへ出るように設定してあげましょう。

    Linuxの場合: プロキシを使用するように SSM エージェント を設定する

    Windowsの場合: SSM エージェント が Windows インスタンス用にプロキシを使用するように設定する

    さらにもう一歩。Linuxの場合…

    例えばSSM RunCommandでスクリプトを実行するようなとき、そのスクリプトの中でAWS CLIを利用しているとします。
    その場合はAWS CLIがProxyを利用するように設定してあげなければいけません。
    下記を参照し、スクリプト内で環境変数を設定してあげてください。
    HTTP プロキシを使用する

    さらにもう一歩。Windowsの場合…

    Linuxの場合と同様にSSM RunCommandでスクリプトを実行するようなときは、スクリプト内で環境変数をセットしてあげてください。
    ただしAWS-RunPatchBaselineのように出来合いのRunCommand用ドキュメントを実行するときに、裏ではAWS Tools for Powershellを用いてS3のAPIを呼んだりしています。そのためには SYSTEMアカウントのwininet.dll 用のProxy設定をしてあげなくてはいけません。
    また、自動更新Windows UpdateはWinHttpのProxy設定を見に行くため、そちらも設定する必要があります。
    …非常に面倒で、分かりづらいですね。
    以下にその手順を記載します。

    winhttp.dll用のProxy設定

    Windows Update クライアントのために必要です。

    参照: Windows Update クライアントが Windows Update Web サイトへの接続に使用するプロキシ サーバーを決定するしくみ

    1. コマンドプロンプトを管理者として開く
    2. 以下のコマンドを実行する

    netsh winhttp set proxy proxy-server="your.proxy.net:80" bypass-list="169.254.169.254"

    ※your.proxy.net:80の部分は実際のHTTPプロキシのホスト名に置き換えてください

    SYSTEMアカウントのwininet.dll用Proxy設定

    SSM Agentが実行されるのはWindows上のSYSTEMアカウントです。RunCommandの各種ドキュメントは同アカウントにより実行されるのですが、ドキュメント内でAWSのAPIを呼んでいる場合、Proxy経由にするために以下の設定をしなくてはいけません。

    1. 下記MicrosoftのサイトからツールをDLして対象マシン上に展開する
    PsExec https://technet.microsoft.com/ja-jp/sysinternals/bb897553.aspx
    2. コマンドプロンプトを管理者として開く
    3. psexecがあるディレクトリにcdしてから以下のコマンドを実行する

    .\psexec -i -s powershell.exe

    4. psexecの使用許諾を問うプロンプトが現れたら、Agreeボタンを押下
    5. 新しく開いたPowershellのプロンプトで以下のコマンドを実行(インターネットのプロパティが開く)

    inetcpl.cpl

    6. 「接続」タブを選択>ボタン「LAN の設定」をクリック
    7. 以下設定を実施
    7-1. チェックボックス「LAN にプロキシ サーバーを使用する(~)」をON
    7-2. “アドレス”に ProxyサーバのFQDNを、 “ポート”に ポート番号 を入力
    7-3. チェックボックス「ローカル アドレスにはプロキシ サーバーを使用しない」をON
    7-4. ボタン「詳細設定」をクリック
    7-5. 例外に 169.254.169.254;*.local;localhost を入力

    ポイント

    ・SSM AgentでProxyを使いたいなら基本的にはSSM Agentに設定すればOK
    ・ただしスクリプト内でAWS CLI/SDKを使う場合は要注意
    ・WindowsでRunCommandでAWS管理のドキュメントを使う場合も要注意

    PowerShellでLambdaを実装しよう!~準備編~

    $
    0
    0

    技術4課のPowerShellおじさんこと、鎌田です。
    日本、いや全世界のPowerShell大好きな皆様、PowerShell使いだって、サーバーレスしたいですよね?
    Pythonのコードを書いたことがある私でも、PowerShellでサーバーレスしてみたいぞ!ということで、LambdaがPowerShellの実装に対応したことを記念し、実際に実装してみたいと思います!

    まずは環境準備が大事!ということで、環境作りから進めましょう!

    0.前提

    • 本ブログは、AWS上に構築したEC2に、Lambdaをデプロイするのに必要となる権限を付与したIAM roleをアタッチして、各種コマンドを実行しています。
    • ブログの執筆にあたっては、Windows Server 2016で環境構築を実施しています。Windows 10でも動作を確認しています。

    1.必要なものをインストールする

    PowerShellでLambda開発するにあたって、必要なものは以下の通りです。

    • PowerShell Core 6.0 release
    • Visual Studio Code for PowerShell core
    • .NET Core 2.1 SDK
    • AWSLambdaPSCore module

    PowerShell core 6.0 release

    PowerShellのgithubリリースページから入手できます。
    msiで提供されていますので、環境にあったものをダウンロードし、インストールしてください。

    Visual Studio

    Visual Studioのダウンロードページから入手できます。
    ダウンロードの上、インストールをしてください。

    ]

    インストールが完了したらvisual Studio codeを起動します。
    左ペインのExtensionをクリックして(1)、テキストエリアにPowerShellを入力し(2)、検索します。
    PowerShellのExtensionが出てきますので、installをクリック(3)します。

    インストールが完了したら、 Reload to aciveをクリックし、有効にします。

    このままでも良いですが、開発時に日本語も使いたいので、Visual Studio Codeを日本語化しましょう。
    起動したら、左ペインのExtensionをクリックして(1)、テキストエリアにjapaneseを入力し(2)、検索します。
    Japanese Language Pack for VS Codeが一番上に表示されるので、installをクリック(3)します。

    インストールが完了したら、 先程と同様にReload to aciveをクリックし、有効にします。

    これだけでは日本語化されません。Visual Studio Codeの設定を修正します。
    上のメニューよりViewをクリックし、command palletをクリックします。
    configure display language と入力します。

    選択肢が一つに絞られるので、クリックすると、右ペインにファイルが開きます。
    “locale”:”en”となっていますので、enをjaに変更しましょう。

    上書き保存したら、一旦終了させ、再度Visual Studio Codeを起動しましょう。これで日本語化されます。

    Visual Studioが使うPowerShellの6.0化も実施しましょう。
    上のメニューより、ファイル -> 基本設定 -> 設定と進みます。

    設定の検索でsettingと入力し(1)、右ペインからsettings.jsonで編集のリンクをクリック(2)します。

    {}の間に次の設定を埋め込みます。

    "powershell.powerShellExePath": "c:/Program Files/PowerShell/6-preview/pwsh.exe"

    編集が終わったら、上書き保存します。
    Visual Studio Codeの設定はここまでです。

    .NET Core 2.1 SDK

    続いて、.NETをインストールしましょう。ダウンロードページより入手できます。
    ダウンロードの上、インストールをしてください。

    AWSLambdaPSCore module

    こちらは、PowerShellからインストールします。
    PowerShell6を起動して、以下のコマンドを入力し、インストールします。

    Install-Module AWSLambdaPSCore -Scope CurrentUser

    Untrusted repositoryと出てきたら、Aを入力し、進めましょう。

    2. 最後に、大事なものを。

    最後に、大事なものを入れましょう。AWS Tools for PowerShellです。
    PowerShell6では、PowerShellのコマンドラインからインストールできます。
    PowerShell6を起動して、以下のコマンドを入力し、インストールします。
    Untrusted repositoryと出てきたら、同じくAを入力し、進めましょう。

    Install-Module -Name AWSPowerShell

    インストールが終わったら、準備完了です。実際に、コードを書いてみましょう!
    次のブログで、実際にLambdaをデプロイするまでを実施します!

    PowerShellでLambdaを実装しよう!~コードの準備からデプロイまで~

    $
    0
    0

    技術4課のPowerShellおじさんこと、鎌田です。
    先のブログで、PowerShellでLambdaを実装するための準備をしました。さあいよいよ、実装していきましょう。

    1.実装の基礎知識

    PowerShell Lambdaを実装する時は、専用コマンドでテンプレートからスターターコードを作成し、テンプレート中にあるファイルを編集して、実装します。
    テンプレートは以下のコマンドで種類を確認できます。

    Get-AWSPowerShellLambdaTemplate

    いくつかありますが、Basicでまずは実装に慣れると良いでしょう。

    2.テンプレートからスターターコードを生成する

    まずは、テンプレートからスターターとなるコードを生成します。

    New-AWSPowerShellLambda -ScriptName <スクリプト名> -Template Basic
    例) New-AWSPowerShellLambda -ScriptName test -Template Basic

    こちらで、testフォルダが作られ、test.ps1とreadme.txtが入っています。

    PowerShellのファイル名は、コマンドで指定したScriptNameが使われます。
    このPowerShellファイルにコードを追加します。

    3.実装

    ファイルを開くと、次のようになっています。Requires以下に、実装をしていきましょう。

    ここは基本の、”Hello World”を実装してみます。
    Write-Hostで、Cloud Watch Logsに文字を出力できます。

    出来上がったコードはこちら。

    # PowerShell script file to be executed as a AWS Lambda function. 
    # 
    # When executing in Lambda the following variables will be predefined.
    #   $LambdaInput - A PSObject that contains the Lambda function input data.
    #   $LambdaContext - An Amazon.Lambda.Core.ILambdaContext object that contains information about the currently running Lambda environment.
    #
    # The last item in the PowerShell pipeline will be returned as the result of the Lambda function.
    #
    # To include PowerShell modules with your Lambda function, like the AWSPowerShell.NetCore module, add a "#Requires" statement 
    # indicating the module and version.
    
    #Requires -Modules @{ModuleName='AWSPowerShell.NetCore';ModuleVersion='3.3.335.0'}
    
    # Uncomment to send the input event to CloudWatch Logs
    # Write-Host (ConvertTo-Json -InputObject $LambdaInput -Compress -Depth 5)
    
    Write-Host "Hello World!"

    4Lambdaへデプロイしてみる

    コードが書けたらデプロイです。
    PowerShell6を起動し、New-AWSPowerShellLambdaのコマンドで生成したフォルダに移動した上で、次のコマンドを実行します。

    Publish-AWSPowerShellLambda -ScriptPath .\<スクリプト名>.ps1 -Name <スクリプト名> -Region ap-northeast-1
    例) Publish-AWSPowerShellLambda -ScriptPath .\test.ps1 -Name test -Region ap-northeast-1

    初回デプロイ時は、付与するroleをどうするか選択することになりますので、roleをあらかじめ作っておくことをお勧めします。

    5.テスト実行してみよう

    デプロイできたら、マネージメントコンソールでLambdaの画面にアクセスしてみましょう。
    PowerShellのコードが、ばっちりデプロイされています!

    普通にテストもできます。テストイベントを作って実行してみると・・・!
    お、ありました、HelloWorld!

    まとめ

    みなさま、LambdaのPowerShell実装、いかがでしたでしょうか。
    PowerShellでもLambdaを実装したかった皆様には嬉しい!?アップデートですね。

    せっかくなので、私はSlack Botを実装してみました。
    次回はそのネタをお送りしたいと思います!


    ACM発行の証明書の自動更新条件

    $
    0
    0

    PS課の杉村です。AWS Certificate Manager(以下、ACM)を使うと、無料でSSL/TLS証明書(ただしDV、Domain Validation証明書)を発行することができます。
    発行した証明書はElastic Load Balancer(ELB)やCloud Formationにデプロイして使用することができます。
    さらに魅力的なのは、毎年(じゃないかもしれませんが)めんどうなあの作業、そう証明書の更新です。ACMでは一定の条件を満たしていれば、何もしなくても自動で証明書が更新されるのです。

    それでは一定の条件とは何でしょうか?以下のブログで弊社社員が記載していますが、その後サービスのアップデートで「DNS検証」という選択肢が増えましたので、本稿では最新情報を記載してみます。

    参考(弊社ブログ): AWS Certificate Manager(ACM)の証明書更新の注意ポイント

    2種類の検証方法

    まずACM無料証明書の発行に際して、そのドメインが確かに申請者の持ち物であるという検証をする必要があります。
    1つはEメールによる検証、2つ目はDNSによる検証です。

    Eメール検証では特定のメールアドレスに対して承認URLが記載されたメールが送付され、そのURLをクリックすることで検証します。
    DNS検証では特定の文字列を持ったCNAMEレコードを対象ドメインのDNSサーバに登録し、AWSがその名前解決をすることで検証します

    検証条件…Eメール検証の場合

    以下の全ての条件を満たすとき、証明書は自動で更新されます。

    1. 証明書が使用されている(ELB等にセットされている)
    2. 証明書のドメインに対してパブリックからHTTPS接続ができる

    大事なのは2番です。対象のドメインに対してパブリックからHTTPSアクセスができる必要があります。セキュリティグループ等でGlobal IP制限をしていると、自動更新が失敗します。
    なおAWSがどこからサイトに対してHTTPSの接続確認をするのか、その接続元IPアドレスは公開されていません。

    自動更新が失敗したらどうなるのか?それは、発行時と同じEメールアドレスにまた検証用のURLが記載されたEメールが送付されます。担当者がそのURLをクリックすれば、無事更新ができます。
    ちょっとこれは面倒ですし、証明書の更新時期をすっかり忘れたうえメールを見落とすと証明書が期限切れになってしまいます。要注意です。

    参考(公式ドキュメント): ドメイン検証の仕組み

    検証条件…DNS検証の場合

    以下の全ての条件を満たすとき、証明書は自動で更新されます。

    1. 証明書が使用されている(ELB等にセットされている)
    2. DNSに登録したCNAMEレコードが名前解決できる

    こちらであれば発行時と同様に、DNSに登録したレコードが名前解決できればサイトがパブリックにオープンになっていなくても証明書の自動更新ができます。(もちろん、名前解決だけはパブリックからできる必要があります)

    もし更新時にCNAMEレコードが削除されてしまっている場合は、特定のドメイン管理者メールアドレスに対して確認のメールが送付されます。ただしEメール検証の時とは違い、検証用URLは記載されていませんので更新するためにはDNSに再度、CNAMEレコードを登録する必要があります。

    参考(公式ドキュメント): DNS を使用したドメインの所有権の検証

    ポイント

    ・ACM証明書はEメール検証とDNS検証がある
    ・自動更新の条件はそれぞれ違う
    ・Eメール検証ではパブリックからサイトがアクセスできる必要があるため注意

    なお自動更新の条件が満たされているかどうかはマネジメントコンソールから確認できますため、ご参考にどうぞ。

    ACM証明書をEメール検証からDNS検証に切り替える

    $
    0
    0

    PS課の杉村です。AWS Certificate Manager(以下、ACM)ではEメール検証とDNS検証の2通りの方法でSSL/TLS証明書(DV)を発行することができます。

    DNS検証はサービスリリース当初には無かった選択肢ですので、自動更新の理由でEメール検証の証明書をDNS検証に切り替えたい場合があるかもしれません。
    参考: AWS Certificate Managerで発行した証明書の自動更新条件

    では、一度Eメール検証で発行したACM証明書をDNS検証に切り替える方法はあるのでしょうか。

    発行済の証明書を単に変更することはできない

    のっけから矛盾的ですが、既に一度Eメール検証で発行したACM証明書をDNS検証に”変更”ことはできません。

    同じドメイン名でDNS検証で証明書を新規発行し、ELB/CloudFront等側にセットする証明書を切り替えることはできます。

    ELB等の証明書を変更すると、新規コネクションから新しい証明書を適用することになりますので、既存のコネクションが切断されるなどは無く、ダウンタイム無しで切り替えることができます。(セットする証明書を間違える、というリスクが無いわけではないですが…)

    切り替えたいときは以下のような手順になります。
    1. 新規にDNS検証でACM証明書を発行する
    2. ELB等に紐づける証明書を新規発行の証明書に切り替える
    3. 旧証明書(Eメール認証)を削除する

    非常に短いですが、以上です。

    ポイント

    ・Eメール検証のACM証明書をDNS検証に切り替えるためにはDNS検証の証明書を新規発行して使用サービス側で新しい証明書を使うようセットする

    DNS検証のACM証明書のほうが何かと使い勝手がいいため、DNSレコードを自由に追加できない等の理由が無ければDNS検証を選択することをお勧めします。

    Lambda・SESを使って、添付ファイル付きメールを送信する

    $
    0
    0

    渡辺です。
    S3バケットにあるファイルをメールで毎月1回送信すべしというお仕事が発生しました。
    パッと思いついた実装方法は以下となります。

    1. CloudWatch Events ルールのスケジュール式 で毎月1回Lambda Function を動かす。
    2. Lambda Functionの実装
      1. S3バケットにある指定ファイルを取得する。
      2. SESのメールで添付ファイルとして送信する。

    CloudWatch Eventsの部分は特に問題なかったのですが、LambdaでS3から添付ファイル付きメールをSESで送信するという部分で少しコツがいることがわかりました。

    SES

    まず、SESの部分です。
    AWSのドキュメントにサンプルコードがあるので、それを利用しました。
    毎度おなじみのPythonとboto3での実装例が載っています。

    1. AWS SDK for Python (Boto) を使用して E メールを送信する
    2. AWS SDKs を使用して raw E メールを送信する

    サンプルコードは上記の通り、2つありました。
    1の方はsend_email()メソッドを使ったサンプル、2の方はsend_raw_email()メソッドを使ったサンプルとなっています。
    添付ファイルをつけるには、send_raw_email()を使う必要があるようなので、2のサンプルコードを元にして開発してみました。

    その前にsend_raw_email()のドキュメントを少しみてみます。

    • verified email addresses or domainsからしかメール送信できません。
    • もしAWSアカウントが、Amazon SES sandbox のままなら、verified email addressesか、 Amazon SES mailbox simulatorにしか送信できません。

    今回は特定のメールアドレスのみへの送信でいいため、サンドボックスのまま利用します。
    マネージメントコンソールでSESにメールアドレスを登録します。
    すると、登録したメールアドレスに確認メールが来るので、そこに書かれたURLリンクをクリックするとverifidとなります。

    • 添付ファイルを含む最大メッセージサイズは10MBです。

    添付ファイルのサイズが大きい時などは要注意ですね。
    今回はLambdaで圧縮処理し、サイズを小さくしてから、メールに添付します。
    「え、S3保存した時点で圧縮した方がいい?ですよね。」

    Lambda

    次にサンプルコードから変更が必要な箇所をみていきます。

    送信元アドレスと宛先アドレスの設定

    # Replace sender@example.com with your “From” address.
    # This address must be verified with Amazon SES.
    SENDER = Sender Name <sender@example.com>

    # Replace recipient@example.com with a “To” address. If your account
    # is still in the sandbox, this address must be verified.
    RECIPIENT = recipient@example.com

    送信元アドレスと宛先アドレスは、SESでverifiedされたものに変更しましょう。

    CONFIGURATION_SETの設定

    # Specify a configuration set. If you do not want to use a configuration
    # set, comment the following variable, and the
    # ConfigurationSetName=CONFIGURATION_SET argument below.
    CONFIGURATION_SET = ConfigSet

    SESの設定でConfiguration Setというのがあるのですが、それを指定します。
    マネージメントコンソールで簡単に作成できるので、それを指定しても構いません。(設定値はデフォルトのままでOK)
    または、サンプルコードの下の方にあるConfigurationSetName=CONFIGURATION_SET をコメントアウトしても動きます。

    S3オブジェクトをローカルに一時保存してから添付する

    S3オブジェクトを添付ファイルとして扱いたいのですが、直接S3オブジェクトのURLやARNは指定ができません。
    Lambda関数が動いているローカルマシンのファイルシステムに一時的に保存した後で、それを添付ファイルとして指定します。
    但し、Lambdaには、書き込み可能なディレクトリが /tmp のみという制限があります。

    以下はs3オブジェクトをローカルに保存する例です。
    例では、Bucket名/reports/yyyy/mm/xxxx.csv といった形で保存されているオブジェクトをdownload_fileで/tmpに保存し、zipfileで圧縮しています。
    このコードはさておき、Lambdaでは/tmpにしか保存できないとだけ覚えておいていただければと思います。

    # get last month
        today = datetime.datetime.today()
        thismonth = datetime.datetime(today.year, today.month, 1)
        lastmonth = thismonth + datetime.timedelta(days=-1)
        lastmonth_begin = lastmonth.strftime("%Y-%m") + '-01'
        lastmonth_end = lastmonth.strftime("%Y-%m-%d")
    
        # s3 location
        obj_path = f'reports/{lastmonth.strftime("%Y")}/{lastmonth.strftime("%m")}'
    
        s3 = boto3.resource('s3')
        bucket = s3.Bucket(Bucket名)
    
        for obj in bucket.objects.filter(Prefix=obj_path):
            basename = os.path.basename(obj.key)
            if re.search(r'\.csv$',basename):
                bucket.download_file(obj.key, '/tmp/' + basename)
                with zipfile.ZipFile('/tmp/report.zip', "w", zipfile.ZIP_DEFLATED) as zf:
                    zf.write('/tmp/' + basename, "report.csv")

    そして、保存したファイルをATTACHMENTで指定します。

    # The full path to the file that will be attached to the email.
        ATTACHMENT = "/tmp/report.zip"

    これで添付ファイル付きのメールを送信できるようになっています。
    以下はAWS SDKs を使用して raw E メールを送信するを元にして作ったコードの全文となります。
    (本題と関係ないため説明省略しましたが、datetimeとreとzipfileをimportしています。)

    import os
    import boto3
    import datetime
    import re
    import zipfile
    from botocore.exceptions import ClientError
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from email.mime.application import MIMEApplication
    
    def lambda_handler(event, context):
    
        # get last month
        today = datetime.datetime.today()
        thismonth = datetime.datetime(today.year, today.month, 1)
        lastmonth = thismonth + datetime.timedelta(days=-1)
        lastmonth_begin = lastmonth.strftime("%Y-%m") + '-01'
        lastmonth_end = lastmonth.strftime("%Y-%m-%d")
    
        # s3 location
        obj_path = f'reports/{lastmonth.strftime("%Y")}/{lastmonth.strftime("%m")}'
    
        s3 = boto3.resource('s3')
        bucket = s3.Bucket(Bucket名)
    
        for obj in bucket.objects.filter(Prefix=obj_path):
            basename = os.path.basename(obj.key)
            if re.search(r'\.csv$',basename):
                bucket.download_file(obj.key, '/tmp/' + basename)
                with zipfile.ZipFile('/tmp/report.zip', "w", zipfile.ZIP_DEFLATED) as zf:
                    zf.write('/tmp/' + basename, "report.csv")
    
        # Replace sender@example.com with your "From" address.
        # This address must be verified with Amazon SES.
        SENDER = "XXX <xxx@example.co.jp>"
    
        # Replace recipient@example.com with a "To" address. If your account
        # is still in the sandbox, this address must be verified.
        RECIPIENT = "yyy@example.co.jp"
    
        # Specify a configuration set. If you do not want to use a configuration
        # set, comment the following variable, and the
        # ConfigurationSetName=CONFIGURATION_SET argument below.
        CONFIGURATION_SET = "ConfigSet"
    
        # If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
        AWS_REGION = "us-east-1"
    
        # The subject line for the email.
        SUBJECT = "Customer service contact info"
    
        # The full path to the file that will be attached to the email.
        ATTACHMENT = "/tmp/report.zip"
    
        # The email body for recipients with non-HTML email clients.
        BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
    
        # The HTML body of the email.
        BODY_HTML = """\
        <html>
        <head></head>
        <body>
        <h1>Hello!</h1>
        <p>Please see the attached file for a list of customers to contact.</p>
        </body>
        </html>
        """
    
        # The character encoding for the email.
        CHARSET = "utf-8"
    
        # Create a new SES resource and specify a region.
        client = boto3.client('ses',region_name=AWS_REGION)
    
        # Create a multipart/mixed parent container.
        msg = MIMEMultipart('mixed')
        # Add subject, from and to lines.
        msg['Subject'] = SUBJECT
        msg['From'] = SENDER
        msg['To'] = RECIPIENT
    
        # Create a multipart/alternative child container.
        msg_body = MIMEMultipart('alternative')
    
        # Encode the text and HTML content and set the character encoding. This step is
        # necessary if you're sending a message with characters outside the ASCII range.
        textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
        htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)
    
        # Add the text and HTML parts to the child container.
        msg_body.attach(textpart)
        msg_body.attach(htmlpart)
    
        # Define the attachment part and encode it using MIMEApplication.
        att = MIMEApplication(open(ATTACHMENT, 'rb').read())
    
        # Add a header to tell the email client to treat this part as an attachment,
        # and to give the attachment a name.
        att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))
    
        # Attach the multipart/alternative child container to the multipart/mixed
        # parent container.
        msg.attach(msg_body)
    
        # Add the attachment to the parent container.
        msg.attach(att)
        #print(msg)
        try:
            #Provide the contents of the email.
            response = client.send_raw_email(
                Source=SENDER,
                Destinations=[
                    RECIPIENT
                ],
                RawMessage={
                    'Data':msg.as_string(),
                },
                #ConfigurationSetName=CONFIGURATION_SET
            )
        # Display an error if something goes wrong.
        except ClientError as e:
            print(e.response['Error']['Message'])
        else:
            print("Email sent! Message ID:"),
            print(response['ResponseMetadata']['RequestId'])
    
    # Main Function
    if __name__ == "__main__":
        lambda_handler({}, {})

     

    まとめ

    • SESで添付ファイルが必要な時は、send_raw_emailメソッドを使う。
    • SESで添付ファイルはs3オブジェクトを指定できないので、Lambdaに一時保存する。
    • Lambdaは/tmpにしかファイルを保存できない。

    トランジットゲートウェイをAWS CLIで設定する

    $
    0
    0

    こんにちは、技術4課の城です。
    先日、トランジットゲートウェイが東京リージョンにもリリースされました。
    というわけで、私も触ってみました。「AWS CLI」で。
    備忘も兼ねて、手順を紹介させていただきます。

    概要

    172.16.0.0/16、172.17.0.0/16の2つのVPCを用意し、トランジットゲートウェイ経由で疎通させてみます。
    ※VPC等の準備については割愛しています。

    AWS CLIのアップデート

    AWS CLIをアップデートします。

    $ sudo pip install -U awscli

    バージョン確認

    12/16 時点では 1.16.76でした。

    【コマンド】

    aws --version

    【結果例】

    aws-cli/1.16.76 Python/3.5.2 Linux/4.4.0-17134-Microsoft botocore/1.12.66

    プロファイルの設定

    利用するプロファイルに変更します。
    IAMロールやIAMユーザーで利用している方は本項目をスキップしてください。

    【コマンド】

    export AWS_DEFAULT_PROFILE=【利用するプロファイル名】

    トランジットゲートウェイの作成

    変数の設定

    【コマンド】

    TRANSIT_GW_DESC='for test on 20181216'

    変数の確認

    【コマンド】

    cat << ETX
    
      TRANSIT_GW_DESC: ${TRANSIT_GW_DESC}
    
    ETX

    【結果例】

    TRANSIT_GW_DESC: for test on 20181216

    トランジットゲートウェイの作成

    【コマンド】

    aws ec2 create-transit-gateway \
      --description "${TRANSIT_GW_DESC}" \
      | tee create-transit-gw-result.json

    【結果例】

    {
        "TransitGateway": {
            "State": "pending",
            "OwnerId": "************",
            "CreationTime": "2018-12-16T12:20:33.000Z",
            "TransitGatewayId": "tgw-06273aae66096e98a",
            "Description": "for test on 20181216",
            "Options": {
                "DefaultRouteTableAssociation": "enable",
                "VpnEcmpSupport": "enable",
                "AssociationDefaultRouteTableId": "tgw-rtb-0c6aecb37236d32d7",
                "AmazonSideAsn": 64512,
                "DefaultRouteTablePropagation": "enable",
                "PropagationDefaultRouteTableId": "tgw-rtb-0c6aecb37236d32d7",
                "AutoAcceptSharedAttachments": "disable",
                "DnsSupport": "enable"
            },
            "TransitGatewayArn": "arn:aws:ec2:ap-northeast-1:************:transit-gateway/tgw-06273aae66096e98a"
        }
    }

    ※今回はデフォルトにて作成しましたが–optionsにて詳細パラメーター(結果のOptionsの項目)を指定することが可能です。

    トランジットゲートウェイIDの取得

    【コマンド】

    TRANSIT_GW_ID=$( \
      jp.py -f create-transit-gw-result.json \
        'TransitGateway.TransitGatewayId' \
      | sed -e "s/\"//g" \
    )  \
    && echo ${TRANSIT_GW_ID}

    【結果例】

    tgw-013b4414f3e1f9752

    トランジットゲートウェイのアタッチ

    VPC IDの取得

    アタッチするVPCのIDが必要なため取得します。

    変数の設定

    各VPCのネットワークCIDRを設定します。

    VPC_CIDR01='172.16.0.0/16'
    VPC_CIDR02='172.17.0.0/16'

    VPC IDの取得

    【コマンド】

    VPC_ID01=$( \
      aws ec2 describe-vpcs \
        --filters Name=cidr,Values=${VPC_CIDR01} \
        --query 'Vpcs[].VpcId' \
        --output text \
    ) \
    && echo ${VPC_ID01}
    
    VPC_ID02=$( \
      aws ec2 describe-vpcs \
        --filters Name=cidr,Values=${VPC_CIDR02} \
        --query 'Vpcs[].VpcId' \
        --output text \
    ) \
    && echo ${VPC_ID02}

    【結果例】

    vpc-04ff85daf466a2497
    
    vpc-0f99a9e9ce6475e1f

    サブネットIDの取得

    アタッチするサブネットのIDが必要なため取得します。

    変数の設定

    各VPCのネットワークCIDRを設定します。

    【コマンド】

    VPC_SUBNET_CIDR01='172.16.0.0/24'
    VPC_SUBNET_CIDR02='172.17.0.0/24'

    サブネットIDの取得

    【コマンド】

    VPC_SUBNET_ID01=$( \
      aws ec2 describe-subnets \
        --filters Name=cidrBlock,Values=${VPC_SUBNET_CIDR01} \
        --query 'Subnets[].SubnetId' \
        --output text \
    ) \
    && echo ${VPC_SUBNET_ID01}
    
    VPC_SUBNET_ID02=$( \
      aws ec2 describe-subnets \
        --filters Name=cidrBlock,Values=${VPC_SUBNET_CIDR02} \
        --query 'Subnets[].SubnetId' \
        --output text \
    ) \
    && echo ${VPC_SUBNET_ID02}

    【結果例】

    subnet-07c2fbaa545b89e9f
    
    subnet-0b8d6b9df5471a503

    変数の確認

    【コマンド】

    cat << ETX
    
      TRANSIT_GW_ID:   ${TRANSIT_GW_ID}
      VPC_ID01:        ${VPC_ID01}
      VPC_ID02:        ${VPC_ID02}
      VPC_SUBNET_ID01: ${VPC_SUBNET_ID01}
      VPC_SUBNET_ID02: ${VPC_SUBNET_ID02}
    
    ETX

    【結果例】

    TRANSIT_GW_ID:   tgw-06273aae66096e98a
      VPC_ID01:        vpc-04ff85daf466a2497
      VPC_ID02:        vpc-0f99a9e9ce6475e1f
      VPC_SUBNET_ID01: subnet-07c2fbaa545b89e9f
      VPC_SUBNET_ID02: subnet-0b8d6b9df5471a503

    トランジットゲートウェイのアタッチ

    それぞれのVPCに対しアタッチメントを作成することでアタッチされます。

    【コマンド】

    aws ec2 create-transit-gateway-vpc-attachment \
      --transit-gateway-id ${TRANSIT_GW_ID} \
      --vpc-id ${VPC_ID01} \
      --subnet-ids ${VPC_SUBNET_ID01} \
    | tee create-transit-gw-atatthment01.json

    【結果例】

    {
        "TransitGatewayVpcAttachment": {
            "VpcOwnerId": "************",
            "SubnetIds": [
                "subnet-07c2fbaa545b89e9f"
            ],
            "VpcId": "vpc-04ff85daf466a2497",
            "TransitGatewayId": "tgw-06273aae66096e98a",
            "CreationTime": "2018-12-16T12:40:53.000Z",
            "Options": {
                "DnsSupport": "enable",
                "Ipv6Support": "disable"
            },
            "TransitGatewayAttachmentId": "tgw-attach-0d85e66ca886d25f3",
            "State": "pending"
        }
    }

    【コマンド】

    aws ec2 create-transit-gateway-vpc-attachment \
      --transit-gateway-id ${TRANSIT_GW_ID} \
      --vpc-id ${VPC_ID02} \
      --subnet-ids ${VPC_SUBNET_ID02} \
    | tee create-transit-gw-atatthment02.json

    【結果例】

    {
        "TransitGatewayVpcAttachment": {
            "SubnetIds": [
                "subnet-0b8d6b9df5471a503"
            ],
            "Options": {
                "DnsSupport": "enable",
                "Ipv6Support": "disable"
            },
            "CreationTime": "2018-12-16T12:42:14.000Z",
            "VpcId": "vpc-0f99a9e9ce6475e1f",
            "State": "pending",
            "TransitGatewayId": "tgw-06273aae66096e98a",
            "TransitGatewayAttachmentId": "tgw-attach-0e774a432cdb6207e",
            "VpcOwnerId": "************"
        }
    }

    ※出力結果をファイルとして保存するのは後ほど削除するのにIDが必要なためです。

    ルートテーブルへのルート追加

    各サブネットに紐づいているルートテーブルにルートを追加します。

    ルートテーブルIDの取得

    【コマンド】

    ROUTE_TABLE_ID01=$( \
      aws ec2 describe-route-tables \
        --filters Name=association.subnet-id,Values=${VPC_SUBNET_ID01} \
        --query 'RouteTables[].Associations[].RouteTableId' \
        --output text \
    ) \
    && echo ${ROUTE_TABLE_ID01}
    
    ROUTE_TABLE_ID02=$( \
      aws ec2 describe-route-tables \
        --filters Name=association.subnet-id,Values=${VPC_SUBNET_ID02} \
        --query 'RouteTables[].Associations[].RouteTableId' \
        --output text \
    ) \
    && echo ${ROUTE_TABLE_ID02}

    【結果例】

    rtb-08a496d3d59856054
    
    rtb-0ef2bcaab0bd6e506

    変数の確認

    【コマンド】

    cat << ETX
    
      TRANSIT_GW_ID:    ${TRANSIT_GW_ID}
      VPC_ID01:         ${VPC_ID01}
      VPC_ID02:         ${VPC_ID02}
      ROUTE_TABLE_ID01: ${ROUTE_TABLE_ID01}
      ROUTE_TABLE_ID02: ${ROUTE_TABLE_ID02}
    
    ETX

    【結果例】

    TRANSIT_GW_ID:    tgw-06273aae66096e98a
      VPC_ID01:         vpc-04ff85daf466a2497
      VPC_ID02:         vpc-0f99a9e9ce6475e1f
      ROUTE_TABLE_ID01: rtb-08a496d3d59856054
      ROUTE_TABLE_ID02: rtb-0ef2bcaab0bd6e506

    ルートの追加

    【コマンド】

    aws ec2 create-route \
      --route-table-id ${ROUTE_TABLE_ID01} \
      --destination-cidr-block ${VPC_CIDR02} \
      --transit-gateway-id ${TRANSIT_GW_ID}
    
    aws ec2 create-route \
      --route-table-id ${ROUTE_TABLE_ID02} \
      --destination-cidr-block ${VPC_CIDR01} \
      --transit-gateway-id ${TRANSIT_GW_ID}

    【結果例】

    {
        "Return": true
    }

    通信確認

    それぞれのVPCにEC2を立てて、通信を確認してみます。

    出来てますね!

    環境の削除

    トランジットゲートウェイは一つのVPCに対するアタッチメントにつき、$0.07/h(東京リージョン、12/16時点)、月額にするとおよそ$50とそこそこコストがかかるので、検証目的の場合は削除しておきましょう。
    トランジットゲートウェイの料金

    ルートの削除

    【コマンド】

    aws ec2 delete-route \
      --route-table-id ${ROUTE_TABLE_ID01} \
      --destination-cidr-block ${VPC_CIDR02}
    
    aws ec2 delete-route \
      --route-table-id ${ROUTE_TABLE_ID02} \
      --destination-cidr-block ${VPC_CIDR01}

    【結果例】
    戻り値なし

    トランジットゲートウェイ アタッチメントの削除

    トランジットゲートウェイ アタッチメントIDの取得

    削除するトランジットゲートウェイ アタッチメントIDが必要なため取得します。

    【コマンド】

    TRANSIT_GW_ATTACHMENT_ID01=$( \
      jp.py -f create-transit-gw-atatthment01.json \
        'TransitGatewayVpcAttachment.TransitGatewayAttachmentId' \
      | sed -e "s/\"//g" \
    )  \
    && echo ${TRANSIT_GW_ATTACHMENT_ID01}
    
    TRANSIT_GW_ATTACHMENT_ID02=$( \
      jp.py -f create-transit-gw-atatthment02.json \
        'TransitGatewayVpcAttachment.TransitGatewayAttachmentId' \
      | sed -e "s/\"//g" \
    )  \
    && echo ${TRANSIT_GW_ATTACHMENT_ID02}

    【結果例】

    tgw-attach-0d85e66ca886d25f3
    
    tgw-attach-0e774a432cdb6207e

    トランジットゲートウェイ アタッチメントの削除

    aws ec2 delete-transit-gateway-vpc-attachment \
      --transit-gateway-attachment-id ${TRANSIT_GW_ATTACHMENT_ID01}
    
    aws ec2 delete-transit-gateway-vpc-attachment \
      --transit-gateway-attachment-id ${TRANSIT_GW_ATTACHMENT_ID02}

    【結果例】

    {
        "TransitGatewayVpcAttachment": {
            "VpcId": "vpc-04ff85daf466a2497",
            "TransitGatewayId": "tgw-06273aae66096e98a",
            "CreationTime": "2018-12-16T12:40:53.000Z",
            "State": "deleting",
            "TransitGatewayAttachmentId": "tgw-attach-0d85e66ca886d25f3",
            "VpcOwnerId": "************"
        }
    }
    
    {
        "TransitGatewayVpcAttachment": {
            "State": "deleting",
            "TransitGatewayAttachmentId": "tgw-attach-0e774a432cdb6207e",
            "TransitGatewayId": "tgw-06273aae66096e98a",
            "CreationTime": "2018-12-16T12:42:14.000Z",
            "VpcOwnerId": "************",
            "VpcId": "vpc-0f99a9e9ce6475e1f"
        }
    }

    トランジットゲートウェイの削除

    【コマンド】

    aws ec2 delete-transit-gateway \
      --transit-gateway-id ${TRANSIT_GW_ID}

    【結果例】

    {
        "TransitGateway": {
            "State": "deleting",
            "OwnerId": "************",
            "Description": "for test on 20181216",
            "CreationTime": "2018-12-16T12:20:33.000Z",
            "Options": {
                "AssociationDefaultRouteTableId": "tgw-rtb-0c6aecb37236d32d7",
                "DefaultRouteTableAssociation": "enable",
                "DefaultRouteTablePropagation": "enable",
                "AutoAcceptSharedAttachments": "disable",
                "VpnEcmpSupport": "enable",
                "DnsSupport": "enable",
                "AmazonSideAsn": 64512,
                "PropagationDefaultRouteTableId": "tgw-rtb-0c6aecb37236d32d7"
            },
            "TransitGatewayId": "tgw-06273aae66096e98a"
        }
    }

    おわりに

    今回の試してみた環境ではVPC1対1ですが、実際には多数のVPCをつなぐケースで威力を発揮するサービスかと思います。
    VPCピアリングではフルメッシュ型での設定が必要なのに対し、ハブ&スポークで構成できるのは強みですね。
    また、Direct Connectも対応予定とのことで、リリースされれば更に便利なサービスとなるでしょう。
    ただし、VPCピアリングとは違い、各VPCへのアタッチメントが課金対象となるので、比較検討が必要になるかと思います。

    どなたかの助けになれば幸いです。

    【参考】
    AWS News Blog 「New – Use an AWS Transit Gateway to Simplify Your Network Architecture」
    AWS CLIコマンドリファレンス

    Cloud AutomatorにRedshiftのスナップショット作成アクションを追加しました!

    $
    0
    0

    既存のRedshiftクラスターからクラスタースナップショットを作成する機能が、Cloud Automatorに追加されたのでご紹介します。

    アクションについて

    Redshiftのスナップショットを作成したい時、今まではAWSが標準で提供している自動スナップショットか、マネージメントコンソールまたはAPI経由で手動作成するのが普通でした。
    しかし、自動スナップショットは世代管理が出来ますが細かい時間指定ができず、API経由では世代管理のコードを作成する必要があり少なからず手間がかかってしまいます。

    Cloud Automatorに今回追加された「Redshift: クラスタースナップショットを作成」アクションを利用すると、下記の機能をブラウザから簡単にご利用できるようになります。

    • 細かい時間指定を含む複数のトリガーを利用したスナップショット取得
    • 50世代までのスナップショット世代管理
    • タグ指定で複数のRedshiftクラスターからスナップショット取得

    ご利用方法

    今回追加されたアクションのご利用方法は、こちらにマニュアルを用意しております。

    終わりに

    今後のリリース計画については、ロードマップページにて公開しております。
    これからもCloud Automatorをよろしくお願いいたします。

    Viewing all 1210 articles
    Browse latest View live