Lambdaでサーバレスでやりたいなー、という案件、いろいろあるんじゃ?
- 定期的にMackarelの監視パラメータを変更したいとか
- Backlogに変更があったらSlackに通知して欲しいとか
- Slackにつぶやくと、EC2サーバに処理が走ったり( git pullとか )
でも『APIキーとか平文でソースコードに書いちゃっていいの?』という課題が
仮に自分で何らかの手段で暗号化を行っても
「 暗号化、復号の悩みとして『鍵を使って暗号化するのは技術的に可能』だが『鍵の保管場所』に困る」という点は残るかな、と。
AWS KMSはその辺、AWSにお任せしたい、というサービス、というのが私の認識です。
( 逆にこんな『超重要な鍵の管理をサービスとしてやっちゃうAWS』って凄い。肝が座っているというか流石だ )
ただ、はじめてみると...
「うぉ、IAMロール割り当てる必要がある? いやまぁ そうか...」「なんかIAMロール割り当て面倒だな( 必要なのはわかるよ... )」などありまして、沢山かきづらい感じなんですよね。その辺のコストを減らしたい。できればServerlessFrameworkにやっていただきたい。
暗号化、復号の処理は意外と頻繁に行う作業なので、いま一度まとめてみます。
KMSで暗号化した情報にアクセスするためにIAM Roleの設定が必要ですが、これはServerlessFrameworkにやらせます。
鍵の作成などはクラスメソッド様のページを参考にさせていただきました
前提
*AWS CLIインストール、aws configure( AWSのクレデンシャル情報の登録 )は済み
作業の流れ
*マスターキー作成
*AWS CLIで暗号化・復号の作業
*lambdaで復号する関数( の説明 )
マスターキー作成(既存のマスターキーを使う場合、この項は飛ばす)
AWS WebUI ->[ IAM ]->[ 暗号化キー ]->[ リージョン: ]のプルダウンメニューから[ アジアパシフィック(東京) ]を選択->[ キーの作成 ]
[ エイリアス(必須) ]と[ 説明 ]を入力して 次へ [ タグキー ]と[ タグ値 ]を入力して[ 次へ ]
キー管理者を選択します( 最低限、自分を選択 )
キーの使用アクセス許可の定義 [ 次へ ]
[ キーポリシーのプレビュー ]すみません、ざっと眺めて[ 完了 ]
できあがったキーをクリック、ARNの値( 例: arn:aws:kms:ap-northeast-1:*************:key/**----*********)をコピー
AWS CLIで暗号化・復号の作業
export KEYID=arn:aws:kms:ap-northeast-1:139332511982:key/********-****-****-****-************
aws kms encrypt --region ap-northeast-1 --key-id $KEYID --plaintext 'naisho_mojiretu!' --query CiphertextBlob --output text > angoukaBase64
リダイレクトで出力した angoukaBase64 の中身は後ほどスクリプト内に記載するため使います。
aws kms decrypt --region ap-northeast-1 --ciphertext-blob fileb://<(cat angoukaBase64 | base64 --decode) --query Plaintext --output text | base64 --decode
lambdaで復号する関数( の説明 )
下記の[ naishoAngoukaZumi ]は上記の[ angoukaBase64 ]の中身を入れてください!
'use strict';
const AWS = require('aws-sdk');
const kms = new AWS.KMS({ region: 'ap-northeast-1' });
const naishoAngoukaZumi = 'angoukaBase64の中身!';
/**
* AWS kmsに対して、復号化した文字列を取得する
* @param {string} kmsEncyptedToken - 鍵
* @return {string} 復号化された鍵
*/
function getToken(kmsEncyptedToken) {
return new Promise((resolve, reject) => {
const encryptedBuf = new Buffer(kmsEncyptedToken, 'base64');
const cipherText = { CiphertextBlob: encryptedBuf };
kms.decrypt(cipherText, (err, kmsData) => {
if (err) {
console.log(`token string decrypt error: ${err}`);
reject(new Error(`${err}`));
} else {
try {
resolve(kmsData.Plaintext.toString('ascii'));
} catch (kmsDataErr) {
console.error((kmsDataErr && kmsDataErr.stack) || kmsDataErr);
}
}
});
});
}
module.exports.kmsTest = (event, context, callback) => {
getToken(naishoAngoukaZumi)
.then((naishoMojiretu) => {
console.log(naishoMojiretu);
});
}
npm init -y
npm install --save aws-sdk
lambda-local でローカルでテスト
lambdaは何かイベントで発動しますが、適当なダミーのデータを作成します。
mkdir event-samples
vi event-samples/testEvent.json
{
"key3": "value3",
"key2": "value2",
"key1": "value1"
}
./node_modules/lambda-local/bin/lambda-local -l kms_test.js -h kmsTest -t 5 -e event-samples/testEvent.json
コンソールに秘密の文字列がでてきたでしょうか。これをlambda環境側で動作させたい訳です。
ServerlessFrameworkでデプロイするための設定
IAMロールに『kms:Decrypt』を追加しています! 復号するのに必要です。
service: kms-test
provider:
name: aws
runtime: nodejs4.3
iamRoleStatements:
- Effect: Allow
Action:
- cloudwatch:*
- kms:Decrypt
Resource: "*"
package:
exclude:
- jsconfig.json
- event-samples
- package.json
- node_modules/**
functions:
slackPostFunction:
handler: kms_test.kmsTest
events:
- schedule: cron(5 12 ? * MON-FRI *)
./node_modules/serverless/bin/serverless deploy --region ap-northeast-1 --stage dev
lamba環境でもテストしてみましょう。 いやIAMロールが足りないとかいうエラー出がちなので、実環境でのテスト必須です...(いやホント皆さんどうしてるんでしょう)
前のエントリは時間で起動するようにしていましたが( それでも良いのですが )
待つのが面倒なので、AWS WebUI->[ lambda ]->[ 目的の関数名 ]をクリック->[ テスト ]をクリック->サンプルのままででok->実行
をすると即テスト実行できます。
結果のコンソール出力ですが、lambda関数事にあるページの[ モニタリング ]のタブ->[ CloudWatch のログを表示 ]で確認できます。
いかがだったでしょうか、割とルーチンワークになるので簡単にまとめてみました。
( 正直、面倒ではあるんですが )必要な事ではあるので、なるべく楽になるようにしていきたいですね。
それと弊社、アオイゼミですが絶讃エンジニア募集中です!
今だとAndroidエンジニア。いや隣に弊社 近藤(Androidエンジニア)がいるのですが、
なんだか時々ため息をついたり、最近若干お疲れのご様子。。。増えるといいなー、と思っております!
弊社コーポレートサイトなどご覧いただき『なんか見に行ってもいいかなー』と思う方はぜひぜひご応募いただけると幸いですー!