LoginSignup
6
3

More than 5 years have passed since last update.

ServerlessFramework 30分くらい Lambda + node.js + AWS KMS( Key Management Service ) でAPIキーの暗号化と復号まで

Last updated at Posted at 2017-03-29

スクリーンショット 2017-03-29 20.45.45.png

Lambdaでサーバレスでやりたいなー、という案件、いろいろあるんじゃ?

  • 定期的にMackarelの監視パラメータを変更したいとか
  • Backlogに変更があったらSlackに通知して欲しいとか
  • Slackにつぶやくと、EC2サーバに処理が走ったり( git pullとか )

でも『APIキーとか平文でソースコードに書いちゃっていいの?』という課題が

仮に自分で何らかの手段で暗号化を行っても
「 暗号化、復号の悩みとして『鍵を使って暗号化するのは技術的に可能』だが『鍵の保管場所』に困る」という点は残るかな、と。
AWS KMSはその辺、AWSにお任せしたい、というサービス、というのが私の認識です。
( 逆にこんな『超重要な鍵の管理をサービスとしてやっちゃうAWS』って凄い。肝が座っているというか流石だ )

ただ、はじめてみると...

「うぉ、IAMロール割り当てる必要がある? いやまぁ そうか...」「なんかIAMロール割り当て面倒だな( 必要なのはわかるよ... )」などありまして、沢山かきづらい感じなんですよね。その辺のコストを減らしたい。できればServerlessFrameworkにやっていただきたい。

暗号化、復号の処理は意外と頻繁に行う作業なので、いま一度まとめてみます。

KMSで暗号化した情報にアクセスするためにIAM Roleの設定が必要ですが、これはServerlessFrameworkにやらせます。

鍵の作成などはクラスメソッド様のページを参考にさせていただきました:bow:

前提

*AWS CLIインストール、aws configure( AWSのクレデンシャル情報の登録 )は済み

作業の流れ

*マスターキー作成
*AWS CLIで暗号化・復号の作業
*lambdaで復号する関数( の説明 )

マスターキー作成(既存のマスターキーを使う場合、この項は飛ばす)

AWS WebUI ->[ IAM ]->[ 暗号化キー ]->[ リージョン: ]のプルダウンメニューから[ アジアパシフィック(東京) ]を選択->[ キーの作成 ]

[ エイリアス(必須) ]と[ 説明 ]を入力して 次へ [ タグキー ]と[ タグ値 ]を入力して[ 次へ ]
キー管理者を選択します( 最低限、自分を選択 )
キーの使用アクセス許可の定義 [ 次へ ]
[ キーポリシーのプレビュー ]すみません、ざっと眺めて[ 完了 ]

できあがったキーをクリック、ARNの値( 例: arn:aws:kms:ap-northeast-1:*************:key/**----*********)をコピー

AWS CLIで暗号化・復号の作業

環境変数にマスターキーのARNをセット
export KEYID=arn:aws:kms:ap-northeast-1:139332511982:key/********-****-****-****-************
暗号化(この暗号化された文字列はbase64でエンコードされた状態、この文字列を使う)
aws kms encrypt --region ap-northeast-1 --key-id $KEYID --plaintext 'naisho_mojiretu!' --query CiphertextBlob --output text  > angoukaBase64

リダイレクトで出力した angoukaBase64 の中身は後ほどスクリプト内に記載するため使います。

復号(複合できるかの確認です!この復号の処理をnode.jsで行うのがこのエントリの目的)
aws kms decrypt --region ap-northeast-1 --ciphertext-blob fileb://<(cat angoukaBase64 | base64 --decode) --query Plaintext --output text | base64 --decode

lambdaで復号する関数( の説明 )

下記の[ naishoAngoukaZumi ]は上記の[ angoukaBase64 ]の中身を入れてください!

kms_test.js
'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);
    });
}
実行する前にpackage.jsonがないディレクトリの場合は作る
npm init -y
必要モジュールのインストール
npm install --save aws-sdk

lambda-local でローカルでテスト

lambdaは何かイベントで発動しますが、適当なダミーのデータを作成します。

ダミーのイベントファイルを作成します
mkdir event-samples
vi event-samples/testEvent.json
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』を追加しています! 復号するのに必要です。

serverless.yml
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エンジニア)がいるのですが、
なんだか時々ため息をついたり、最近若干お疲れのご様子。。。増えるといいなー、と思っております!:bow:
弊社コーポレートサイトなどご覧いただき『なんか見に行ってもいいかなー』と思う方はぜひぜひご応募いただけると幸いですー!

6
3
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
6
3