LoginSignup
11
4

More than 5 years have passed since last update.

AWS LambdaでKMSを使ってセキュアにRDSへ接続する(インフラ編)

Last updated at Posted at 2016-12-09

この記事はWHITEPLUS Advent Calendar 2016 10日目になります。

こんにちは。株式会社ホワイトプラス、エンジニアの @hachihiro224です。
一応マネージャーをさせてもらっているので、フロントエンド、バックエンド、インフラといろいろな領域を見ています。

今日は弊社で利用しているAWS Lambdaの環境構築について紹介します。

RDSに接続するAWS Lambdaの環境構築

利用するサービスは次の3つです。

  • AWS Lambda(処理本体)
  • AWS RDS(データベース)
  • AWS KMS(接続情報の暗号化)

次の順で構築していきます。

  1. Lambdaを配置するVPC Subnetの作成
  2. KMSを利用した接続情報の暗号化
  3. 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を作成します。

sample_function.py
# -*- 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直下で以下のシェルを実行します。

create-function.sh
#!/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つのメリット」です。

ホワイトプラスではエンジニアを募集しています

ホワイトプラスでは、新しい技術にどんどん挑戦したい!という技術で事業に貢献したいエンジニアを募集しております。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4