AWS Key Management Serviceを使ってセキュアにAWS LambdaからTweetする

AmazonLambda

はじめに

プログラムの作成において機密情報をどのように扱うかは重要な課題です。AWS LambdaFAQでは以下のように記載されています。

Q: 機密情報を環境変数に格納できますか?

データベースのパスワードなどの機密情報については、AWS Key Management Service を使用してクライアント側で暗号化し、この暗号化した値を環境変数に暗号文として格納することをお勧めします。これらの値の復号化では、AWS Lambda 関数コードにロジックを含める必要はなくなります。

なるほど。ということで実際にやってみました。

やってみた

Twitter認証情報を取得する

Twitterの認証情報はhttps://dev.twitter.com/から取得します。詳細は割愛します。

  • Consumer Key
  • Consumer Secret
  • Access Token
  • Access Token Secret

の4つのKeyを取得します。

KMSでKeyを作成する

AWS Key Management Service(KMS)でTwitterの認証情報を暗号化するために、Keyを作成します。

AWS管理コンソールのIAM画面で、Encryption Keysを選択します。[Get Started Now]ボタンをクリックします。

IAM_Management_Console

[Region]は、今回Lambda Functionを設定する[Asia Pacific (Tokyo)]を選択します。[Create Key]ボタンをクリックします。

IAM_Management_Console 2

[Create Alias and Description]画面が表示されます。[Alias]を設定し、[Next Step]ボタンをクリックします。

IAM_Management_Console 3

[Add Tags]画面は特に設定せず[Next Step]ボタンをクリックします。

IAM_Management_Console 4

[Define Key Administrative Permissions]画面では、このKeyの管理者となるIAM Userを指定します。[Next Step]ボタンをクリックします。

IAM_Management_Console 5

次に[Define Key Usage Permissions]画面で、このKeyの利用するものとして、LambdaのExecute Roleを指定します。[Next Step]ボタンをクリックします。

IAM_Management_Console 6

[Preview Key Policy]画面が表示されるので、内容を確認し、[Finish]ボタンをクリックします。

IAM_Management_Console 7

Keyが作成されました。Key IDをメモしておきます。

IAM_Management_Console 8

Twitter認証情報をKMSで暗号化する

以下の作業はAWS CLIを使える環境で行います。今回はローカルのMac環境にて実施しています。

Key IDを環境変数に入れておきます。KEY_IDは取得したKey IDに置き換えてください。

$KEYID=<KEY_ID>

以下のコマンドを実行することで、KEY_TEXTがKMSによって暗号化されbase64エンコードされた文字列が取得できます。Twitter認証情報のConsumer Key、Consumer Secret、Access Token、Access Token Secretの4つのKeyに対してそれぞれ実行し、実行結果をメモしておきます。

$ aws kms encrypt --key-id $KEYID --plaintext '<KEY_TEXT>' --query CiphertextBlob --output text

なお、この作業自体は、Lambdaの環境変数の設定の際にEnable encryption helpersを選択することでも出来ますが、今回は手動で行いました。

Lambda Functionの作成

TwitterにTweetするLambda Functionを作成します。今回使ったPythonの環境は以下の通りです。

$ python --version
Python 2.7.12

作業ディレクトリを作成します。

$ mkdir ./lambda-twitter
$ cd ./lambda-twitter

TwitterのAPIにアクセスするために、OAuthを扱うライブラリであるrequests_oauthlibpip installします。

$ pip install requests requests_oauthlib -t ./

そしてソースコードはこんな感じで作成します。data.txtからランダムに1行読み込んでTweetするだけのものです。

$ vi ./lambda-twitter.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from requests_oauthlib import OAuth1Session
import boto3
import json
import base64
import os
import random

# 引数をDecryptする関数
def getDecryptKey(text):
  client = boto3.client('kms')
  return client.decrypt(CiphertextBlob=base64.b64decode(text))['Plaintext']

def lambda_handler(event, context):
  # Twitter認証情報を取得
  consumer_key    = getDecryptKey(os.environ['CONSUMER_KEY'])
  consumer_secret = getDecryptKey(os.environ['CONSUMER_SECRET'])
  access_token    = getDecryptKey(os.environ['ACCESS_TOKEN'])
  access_secret   = getDecryptKey(os.environ['ACCESS_TOKEN_SECRET'])

  # data.txtからランダムに1行抽出
  f=open("data.txt","r")
  l=f.readlines()
  tweet=random.sample(l,1)

  # Twitterに投稿
  twitter = OAuth1Session(consumer_key, consumer_secret, access_token, access_secret)
  params = {"status": tweet }
  req = twitter.post("https://api.twitter.com/1.1/statuses/update.json",params = params)
  return

同じディレクトリにdata.txtを作成します。元ネタとしてこちらからデータを頂いています。

$ vi ./data.txt

Lambda Funcitonをライブラリを含めた形でzip圧縮します。

$ zip -r ~/lambda_function.zip .

Lambdaの設定

ではLambdaを設定します。Lambda Dashboardで[Create a Lambda function]ボタンをクリックします。

Lambda_Management_Console

[Select blueprint]画面では[Blank Function]を選択します。

Lambda_Management_Console 2

[Configure triggers]画面では何も設定せずに[Next]ボタンをクリックします。

Lambda_Management_Console 3

[Configure function]画面が表示されます。[Name]と[Description]を設定します。[Runtime]は今回は[Python 2.7]です。[Code entry type]として[Upload a ZIP file]を選択し、[Upload]ボタンをクリックし、作成したZIPファイルをアップロードします。

Lambda_Management_Console 4

ZIPファイルがアップロードされたことを確認します。次に環境変数の設定です。前述の通り、今回は手動でKMSによる暗号化を行っているため、[Enable encryption helpers]は使いません。[Environment variables]でTwitter認証情報を環境変数として設定します。

Lambda_Management_Console 5

[Lambda function handler and role]で、[Handler]と[Existing role]を適切に設定します[Next]ボタンをクリックします。

Lambda_Management_Console 6

確認画面で問題なければ[Create function]ボタンをクリックします。

Lambda_Management_Console 7

Lambda Functionが作成されます。では試してみます。[Test]ボタンをクリックします。

Lambda_Management_Console 8

問題なく動いたことを確認します。

Lambda_Management_Console 9

CloudWatch Eventsの設定

さて、これでLambdaからTweetすることが出来ました。最後に、このLambda Functionが定期的に動くように、Cloud Watch Eventsでスケジュール設定します。

CloudWatch管理画面で[Events]-[Rules]を選択します。[Create rule]ボタンをクリックします。

CloudWatch_Management_Console

[Create rule]画面が表示されます。[Event Source]を[Schedle]として設定します。今回は毎日22時に動作するようスケジューリングしました。[Targets]-[Add target]ボタンをクリックします。

CloudWatch_Management_Console 2

[Target]として作成したLambda Functionを設定します。[Configure details]ボタンをクリックします。

CloudWatch_Management_Console 3

[Configure rule details]画面で[Name]を設定し、[Create rule]ボタンをクリックします。

CloudWatch_Management_Console 4

Ruleが作成されました。

CloudWatch_Management_Console 5

実行結果

こんな感じのTweetが毎日22時に行われます。

smokeymonkey

さいごに

Twitterに限らず、機密情報はソースコードに持たせずにKMSで暗号化したものを環境変数に持たせることで、安全なLambda Functionの開発が出来ます。更にencryption helpersを使えば管理画面上から暗号化することもできます。実はAWS Lambdaを触ったのは久しぶりなのですが、これらの機能のおかげでとても使いやすくなったと感じました。

AWS Cloud Roadshow 2017 福岡