この記事はWHITEPLUS Advent Calendar 2016 10日目になります。
こんにちは。株式会社ホワイトプラス、エンジニアの @hachihiro224です。
一応マネージャーをさせてもらっているので、フロントエンド、バックエンド、インフラといろいろな領域を見ています。
今日は弊社で利用しているAWS Lambdaの環境構築について紹介します。
RDSに接続するAWS Lambdaの環境構築
利用するサービスは次の3つです。
- AWS Lambda(処理本体)
- AWS RDS(データベース)
- AWS KMS(接続情報の暗号化)
次の順で構築していきます。
- Lambdaを配置するVPC Subnetの作成
- KMSを利用した接続情報の暗号化
- RDSに接続するLambda Functionの生成
Lambdaを配置するVPC Subnetの作成
VPCにLamba Functionを配置する際に気をつけるポイントです。
- KMSを利用するためにはインターネットにアクセス出来る必要がある
- パブリックサブネットに配置してもインターネットにアクセスできない
ということで、プライベートサブネットにNATゲートウェイを配置して、インターネットアクセス可能にします。
こちらの記事を参考に構築しました。
http://yoshidashingo.hatenablog.com/entry/2015/12/18/041217
サブネットは異なるアベイラビリティゾーンのものを一つずつ用意します。
KMSを利用した接続情報の暗号化
RDSに接続する際、考慮しなければならないのが接続情報の管理です。
KMSを利用すると接続情報を暗号化し、安心してコードに載せることができます。
KMSの利用はこちらの記事を参考にしました。
http://dev.classmethod.jp/cloud/decrypt-sensitive-data-with-kms-on-lambda-invocation/
環境を構築したら次のコマンドで接続情報を暗号化します。
# db_host
aws kms encrypt --key-id $KEYID --plaintext 'db_host'
# db_user
aws kms encrypt --key-id $KEYID --plaintext 'db_user'
# db_password
aws kms encrypt --key-id $KEYID --plaintext 'db_password'
RDSに接続するLambda Functionの生成
いよいよLambdaでRDSに接続します。
次のような作業ディレクトリを作ります。
sample_function
├── create-function.sh
└── src
└── sample_function.py
必要なパッケージをインストールします。
pip install boto3 PyMySQL
RDSに接続するlambda functionを作成します。
# -*- coding: utf-8 -*-
import sys
import logging
import pymysql
import base64
import boto3
logger = logging.getLogger()
logger.setLevel(logging.INFO)
kms = boto3.client('kms')
def decrypt(encrypted):
return kms.decrypt(CiphertextBlob=base64.b64decode(encrypted))['Plaintext']
# rds settings
rds_host = decrypt('暗号化されたdb_host')
name = decrypt('暗号化されたdb_user')
password = decrypt('暗号化されたdb_password')
db_name = 'データベース名'
try:
conn = pymysql.connect(rds_host, user=name, passwd=password, db=db_name, connect_timeout=5, charset='utf8')
except:
logger.error("ERROR: Unexpected error: Could not connect to MySql instance.")
sys.exit()
def lambda_handler(event, context):
with conn.cursor() as cur:
num = cur.execute('SELECT NOW()')
for row in cur:
logger.info('接続確認 %s' % row[0])
return "Got %d items from RDS MySQL table" % num
Lambda Functionの実行に必要なIAM ROLEを作成します。
VPC権限: https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/vpc.html
KMS権限: インラインポリシーで以下を追加
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1448696327000",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:ap-northeast-1:123456789012:key/xxx-yyy-zzz"
]
}
]
}
lambda functionをAWSに登録します。
sample-function直下で以下のシェルを実行します。
#!/bin/bash
# TODO: update function_name
FUNCTION_NAME=sample_function
cd "$(dirname "$0")"/src
mkdir bundle
cp *.py bundle/
cd bundle
pip freeze > require.txt
[ -s require.txt ] && pip install -r require.txt -t .
zip -r upload.zip .
aws lambda create-function \
--function-name ${FUNCTION_NAME} \
--runtime python2.7 \
--role #lambdaとKMSが使えるIAM ROLEのarn \
--handler ${FUNCTION_NAME}.lambda_handler \
--vpc-config SubnetIds=#1.で作成したvpc subnet,SecurityGroupIds=#RDSに接続可能なsecurity group \
--zip-file fileb://upload.zip \
--timeout 60
cd .. && rm -rf bundle
以下のコマンドでLambda Functionを実行します。
aws lambda invoke --function-name sample_function --payload '' response && cat response
無事にRDSへ接続するLambda Functionの作成ができました。
まとめ
LambdaでのVPC接続はVPCの設定、KMSでの接続情報の暗号化など関連するタスクがあり、始めるまでのハードルが高めです。
今回紹介した内容が少しでも参考になればと思います。
明日は弊社デザイナー @hayaoo の「再考、デザイン・スプリントの誤解と3つのメリット」です。
#ホワイトプラスではエンジニアを募集しています
ホワイトプラスでは、新しい技術にどんどん挑戦したい!という技術で事業に貢献したいエンジニアを募集しております。