AWS EC2のCentOSをPVからHVMへ移行する

(2年前の下書きを発見したので、時期を外していると思いつつ投稿します)
この記事では、昔から使われていたParaVirtualのEC2インスタンスをHVM対応とし、旧タイプのインスタンスから脱出するための手法を記します。
特に t1.micro で CPU steal に悩んでいる方は早めに t2.micro への移行をおすすめします。CPUクレジットに注意する必要がありますが、早い(CPU/network/storage)安い/うまい(メモリ1GB)と使わない理由がありません。
何度か作業をし、出来るだけ手順化をしてみたのでみなさんと共有します。
可能な限りコマンドライン一撃で終了できるようにしています。

先人の知恵

http://qiita.com/cs_sonar/items/21dbb3462708e146a426
実際の作業手順は上記のエントリーそのままですが、出来るだけsedなどのコマンドを利用しコピペで片付くような手順になっています。

作業用インスタンスを準備する

t2.micro/Amazon Linux(CentOSなどでも問題ないでしょう)でEC2を起動します。
このインスタンスIDが i-IIIIIIII として進めます。

EBSを準備する

作業用のインスタンスにアタッチするためのEBSが必要になります。
必要なEBSは二種類です。

出力先となるEBSを準備する

以下の例では作業の安定性を考慮してio1/PIOPS1000/100GBのEBSを準備します。
移行元のEBSのサイズより大きなものにしましょう。(でないと収まらない)

aws ec2 create-volume --size 100 --availability-zone ap-northeast-1a --volume-type io1 --iops 1000

ここで作成されたEBSボリュームIDを vol-DDDDDDDD として次に進みます。

出力先EBSをアタッチする

aws ec2 attach-volume --instance-id i-IIIIIIII --device /dev/sdo --volume-id vol-DDDDDDDD

元となるEBSを準備する

元となるEBSですが、以下の順序で作成します。
以下の例では作業の安定性を考慮してio1/PIOPS1000/100GBのEBSを準備します。
– 移行元のEBSからスナップショットを作成します。
– 作成したスナップショットから作業用EBSを作成します。

aws ec2 create-snapshot --volume-id vol-OOOOOOOO

ここで作成されたスナップショットのIDを snap-OOOOOOOO として次に進みます。

aws ec2 create-volume --size 100 --availability-zone ap-northeast-1a --volume-type io1 --iops 1000 --snapshot-id snap-OOOOOOOO

作成されたEBSボリュームIDを vol-SSSSSSSS として次に進みます

元となるEBSをアタッチする

aws ec2 attach-volume --instance-id i-IIIIIIII --device /dev/sdm --volume-id vol-SSSSSSSS

作業用インスタンスでの作業

作業用インスタンスには以下の状態でEBSがマウントされている(はず)です。

デバイス名 利用用途
/dev/xvdm 移行元EBS
/dev/xvdo 移行先EBS

移行先データ用EBSを準備する

yum -y install parted resize2fs
parted /dev/xvdo --script 'mklabel msdos mkpart primary 1M -1s print quit'
partprobe /dev/xvdo
udevadm settle

移行元データの検査とディスクサイズの(見かけ上の)縮小

e2fsck -f /dev/xvdm
resize2fs -M /dev/xvdm

移行元EBSから移行先EBSへのデータ移設と縮小したディスクサイズの復元

dd if=/dev/xvdm of=/dev/xvdo1 bs=4K count=1747941
resize2fs /dev/xvdo1

移行先EBSのマウントとchrootによる作業準備

mount /dev/xvdo1 /mnt
cp -a /dev/xvdo /dev/xvdo1 /mnt/dev/
chroot /mnt

grub導入と設定の調整

yum install -y grub
ln -s /boot/grub/menu.lst /boot/grub/grub.conf
ln -s /boot/grub/grub.conf /etc/grub.conf
rm -f /boot/grub/*stage*
cp /usr/*/grub/*/*stage* /boot/grub/
rm -f /boot/grub/device.map
cat <<EOF | grub --batch
device (hd0) /dev/xvdo
root (hd0,0)
setup (hd0)
EOF

menu.lstの調整

menu.lstでの root kernel を調整します。
– (hd0)ではなく(hd0,0)とする必要があります。
– デバイス名ではなくラベル名でrootを認識させます。
– シリアルコンソールとHVM対応を明示します。

sed -i.bak -e 's:root(.*)(hd0):root1(hd0,0):;s:root=.*:root=LABEL=/ console=ttyS0 xen_pv_hvm=enable:' /boot/grub/menu.lst 

以下のような形になっているか確認して下さい。 root kernel あたりが要確認項目です。

default=0
timeout=0
hiddenmenu
title SUZ-LAB CentOS 6
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-431.1.2.0.1.el6.x86_64 ro root=LABEL=/ console=ttyS0 xen_pv_hvm=enable
initrd /boot/initramfs-2.6.32-431.1.2.0.1.el6.x86_64.img

fstabの調整

fstabでのroot(/)をラベルで認識するように変更します。

sed -i.bak -e 's:.*(s)/s(.*)defaults(.*):LABEL=/1/2defaults,noatime3:g' /etc/fstab 

以下のような形になっているか確認して下さい。 LABEL=/ / あたりが要確認項目です。

LABEL=/ /        ext4    defaults,noatime        1 1
none             /proc     proc    defaults        0 0
none             /sys      sysfs   defaults        0 0
none             /dev/pts  devpts  gid=5,mode=620  0 0
none             /dev/shm  tmpfs   defaults        0 0
/mnt/swap/0.img  swap      swap    defaults        0 0

ディスクラベルの調整

e2label /dev/xvdo1 /
tune2fs -l /dev/xvdo1 |grep name

chrootを退出して後片付け

chroot状態から元のOSへ戻ります。

exit

一時的に必要とされたデバイス関連ファイルを削除し、マウントを解除します。

rm -f /mnt/dev/xvdo /mnt/dev/xvdo1
sync
umount /mnt

AMIの作成

AMI作成のもととなるスナップショットを作成する

aws ec2 create-snapshot --volume-id vol-b7f1e741

作成したスナップショットからAMIを作成する

続きを読む

AWSのIAMロール・ポリシーをソースコード管理するのに役立つツールライブラリ

AWS の IAM ロールとポリシーをどうやって管理していますか?

JSON ファイルでロールとポリシー定義を管理できるのに便利なツール(npmライブラリ)を作りました。
github.com/tilfin/aws-iam-policy-tool

できること

  • ローカルの JSON ファイルと IAM のロールとポリシー定義の相互インポート・エクスポート
  • ローカルの定義ファイルに沿って IAM ロールとポリシーが構成されているかの検証
  • 正規表現マッチするカスタムポリシーの複数削除(AWS Management Console では一個ずつしか消せない)

できないこと

  • ロールのインラインポリシーはサポートしていない

どのように使えるのか

  • IAM ロールとポリシー定義を JSON ファイルでソースコード同様にGit等のリポジトリで管理できる。
  • npm ライブラリなので Lambda から定期的にデプロイ環境のロールとポリシーが正しいかの検証ができる。

定義ファイルの仕組み

  • IAM のブラウザ上で編集する JSON とほぼ同じです。
  • デプロイ環境別にリソース名に prefix/suffix を付けている場合は ENV としておくことで、コマンド実行時に引数で指定します。
  • AWS アカウント ID も ACCOUNT_ID でコマンド実行時に引数指定することで変えることができます。

ロール

{
    "Role": {
        "RoleName": "yourapp-ec2-api-ENV",
        "Path": "/",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "ec2.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
    },
    "AttachedPolicies": [
        {
            "PolicyName": "yourapp-s3-storage-ENV",
            "PolicyArn": "arn:aws:iam::ACCOUNT_ID:policy/yourapp-s3-storage-ENV"
        }
    ]
}

ポリシー

ポリシー名は内容に含まれないため JSON ファイル名そのものが適用されます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::yourapp-storage-ENV/*"
        }
    ]
}

導入と使い方

npm からインストールします。

$ npm install -g aws-iam-policy-tool

現状のロールを ./roles とポリシーを ./policies にそれぞれ書き出します。

$ awsiamtool export-role ./roles
$ awsiamtool export-policy ./policies

各ファイルの ARN 内の AWS アカウント ID の部分を ACCOUNT_ID に置換します。動作環境を示すもの (例. dev, staging など) が名前に含まれていれば、ENV に置換します。ポリシーの場合はファイル名もリネームします。

検証してみます。

$ awsiamtool validate-role -i 111122223333 -e dev roles
$ awsiamtool validate-policy -i 111122223333  -e dev policies

本番環境に定義を作成します。

$ AWS_PROFILE=prod awsiamtool import-policy -i 111122224444 -e prd policies
$ AWS_PROFILE=prod awsiamtool import-role -i 111122224444 -e prd roles

※ポリシー修正時 import-policy に上書きオプションを --overwrite を指定します。

ライブラリとして使う(別の変数を適用するには)

現状コマンド引数ではサポートしていませんがライブラリとして使えば可能です。

const awsIamPolicyLib = require('aws-iam-policy-tool');

const opts = {
  json: true,
  overwrite: true
};

const varSets = {
  ACCOUNT_ID: '000011112222',
  ENV: 'stg',
  COMMON_ACCOUNT_ID: '333344445555'
};

awsIamPolicyLib.importPolicy('./policies', varSets, opts);
.then(() => {
  return awsIamPolicyLib.importRole('./roles', varSets, opts);  
})
.then(() => { console.info('Importing done') })
.catch(err => { console.error(err) });

その他、コマンドの実行結果例などは README を見てください。

続きを読む

EC2上にS3をマウントする方法

s3fs-fuseインストール

sudo apt-get update

sudo apt-get install build-essential git libfuse-dev libcurl4-openssl-dev libxml2-dev mime-support automake libtool
sudo apt-get install pkg-config libssl-dev

git clone https://github.com/s3fs-fuse/s3fs-fuse

cd s3fs-fuse/
./autogen.sh
./configure --prefix=/usr --with-openssl

make
sudo make install

参照先s3バケットの設定

sudo touch /etc/passwd-s3fs

sudo vi /etc/passwd-s3fs
# 以下を設定
---
s3パケット名:aws_access_key:aws_secret_key
---

sudo chmod 640 /etc/passwd-s3fs

マウント

sudo mkdir /mnt/s3fs

sudo s3fs s3バケット名:/参照ディレクトリ名 /mnt/s3fs -o allow_other -o use_cache=/tmp

【参考】
https://github.com/s3fs-fuse/s3fs-fuse/wiki/Installation%20Notes#tested-on-ubuntu-1404-lts
http://www.mori-soft.com/2008-08-15-01-36-37/os/215-s3-s3

続きを読む

logmonとALBのdrainingでリロード攻撃(F5アタック)へのパッシブ対策

以下の記事で紹介した小ネタの、具体的な利用例です。

1. 対策の内容

リロード攻撃(F5アタック)への対策としては、前段のApacheにmod_dosdetectorやmod_evasiveを入れる、WAFを導入する等があります。
このように、前段ですべて対応できれば良いのですが、

  • リロード攻撃を行っているのが正規ユーザである
  • リクエストによって(また、ユーザ毎に処理に必要なデータ量の多寡によって)レスポンスタイムにばらつきがある

というような場合、なかなか前段だけでの対処は難しいのではないかと思います。
そこで、Webアプリケーションサーバ(Tomcatなど)の処理が詰まってしまったときに、サービスの完全停止を避けるためにWebアプリケーションサーバの再起動を行うことがあると思いますが、

  • 「処理が詰まった」といっても、詰まり始めのうちは「特定の遅い処理」だけが「詰まる」のであり、それ以外のリクエストに対する処理は正常にレスポンスを返すことができている
  • 正常なレスポンスを返すことができるリクエストまで、再起動で中断するのは(なるべく)避けたい

ということで、Apacheのgraceful restartのような処理をしよう…というのが今回の内容です。

※きちんとgracefulな処理をするためには、Webアプリケーションサーバは複数台必要です。

2. ポリシー・IAM Roleの準備

まずは、先ほどの記事にある通り、以下の作業を行います。

  • ポリシーを設定する
  • 設定したポリシーをEC2用IAM Roleにアタッチする
  • そのIAM RoleをEC2(Webアプリケーションサーバ)にアタッチする

なお、今回のケースでは、「ec2:DescribeInstances」に対する権限は不要ですので、この部分はカットしても良いでしょう。

3. EC2上の設定

以下の記事を参考に、EC2(Webアプリケーションサーバ)にlogmonを導入します。

logmon.confには、以下の内容を設定します。

  • 1行目 : 監視対象のログファイル(Apacheのエラーログなら「:/var/log/httpd/error_log」など)
  • 2行目 : 監視対象のキーワード(正規表現/Tomcatのレスポンスが返らない場合を拾うのなら「[error] (70007)The timeout specified has expired」にマッチする内容)
  • 3行目 : 先の記事に示されているとおり

続いて、最初の記事で紹介したスクリプト「aws_utils.sh」を配置し(私の例では「/usr/local/sbin/」内)、「get_instance_id()」の部分だけ以下の内容に置き換えます。

aws_utils.sh(変更部分のみ)
#######################################
# 自身のインスタンス ID を取得する
# Returns:
#   INSTANCE ID
#######################################
get_my_instance_id() {
  instance_id=`/usr/bin/curl http://169.254.169.254/latest/meta-data/instance-id`
  if [ -z "$instance_id" ]; then
    echo 'host not found'
    exit 2
  fi
  echo ${instance_id}
}

※draining(登録解除の遅延)時間の長さに合わせて「SLEEP」の秒数も調整します。

それから、crontabから一定間隔で呼び出すスクリプト(私の例では「/usr/local/sbin/check_count.sh」)を配置します。

check_count.sh
#! /bin/sh

# スクリプトをインポートする
. /usr/local/sbin/aws_utils.sh

# トリガ判定
if [ `cat /tmp/logmon_count` -ge 20 ]; then

  # 閾値越え -> logmonサービス停止
  /sbin/service logmon stop

  # 二重トリガ起動防止(countを0に)
  echo 0 > /tmp/logmon_count

  # ALBでターゲットグループから外す
  ALB_TARGET_GROUP_ARN=('arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/YYYY/zzzzzzzzzzzzzzzz' 'arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/YYYY/zzzzzzzzzzzzzzzz')
  INSTANCE_ID=$(get_my_instance_id)

  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_deregister ${arn} ${INSTANCE_ID}
  done

  # ALBでdraining完了待ち
  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_waiter ${arn} ${INSTANCE_ID} 'unused' > /dev/null
  done

  # Webサービス停止
  /sbin/service tomcat8 stop

  /bin/sleep 10

  # サービス起動
  /sbin/service tomcat8 start

  /bin/sleep 10

  /sbin/service logmon start

  # ALBでターゲットグループに戻す
  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_register ${arn} ${INSTANCE_ID}
  done

  # ターゲットグループに戻ったことを確認する
  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_waiter ${arn} ${INSTANCE_ID} 'healthy' > /dev/null
  done

fi

# countを0に
echo 0 > /tmp/logmon_count

if文の「20」は閾値です。適切な値に調整してください。
この例ではWebアプリケーションサーバとしてTomcat8を使っていますが、適切なものに置き換えてください。Tomcatの場合は、draining前後でPrintClassHistogramの出力などもしておくと良いです。

また、この例ではEC2(Webアプリケーションサーバ)を複数のターゲットグループ(配列「ALB_TARGET_GROUP_ARN」)に登録しています。
それぞれのターゲットグループでdraining時間が違う場合は、時間が短いものを先に記述すると良いです(後述の通りログを記録する場合は特に)。
1つの場合は配列にせず、for文で回す必要もありません。

なお、この例ではログを /dev/null に捨てていますが、実際に使うときにはきちんとログファイルに記録しておいたほうが良いです(時刻などとあわせて)。

最後に、このスクリプトを、実行ユーザ(rootなど)のcrontabに登録します(私の例では1分間隔で実行⇒閾値は1分当たりのカウントに対して設定)。このとき、1行目に「SHELL=/bin/bash」を挿入しておきます。

crontab登録例
SHELL=/bin/bash

*/1 * * * * /bin/sh /usr/local/sbin/check_count.sh

設定できたら、カウントファイル(私の例では「/tmp/logmon_count」)に閾値以上の値を書き出して、正しくdraining→ターゲットから削除→Webアプリケーションサーバ再起動→ターゲットに登録が行われるか、確認します。

テスト
echo 20 > /tmp/logmon_count

4. 注意点

drainingすると再起動には時間が掛かるので、Webアプリケーションサーバは最低でも4台程度は必要です。

続きを読む

AWSの用語と解説

AWS(Amazon Web Services)General_AWScloud.png

インフラ系のクラウドサービスを提供しているAWSは2006年3月から始まり、現在10周年。
アメリカでは政府機関が使っているほど高いセキュリティ

サービスや機能は800個以上あり、もはや中の人も何がいつリリースされたかわからないらしい

Region(リージョン)

AWSは世界中のデータセンターのサーバーで実行されており、サービスを開始する時はリージョンを選択する
リージョンは以下の通り

リージョン
米国東部(バージニア北部) us-east-1
米国西部(オレゴン) us-west-2
米国西部(北カリフォルニア) us-west-1
欧州(アイルランド) eu-west-1
欧州(フランクフルト) eu-central-1
アジアパシフィック (シンガポール) ap-southeast-1
アジアパシフィック(東京) ap-northeast-1
アジアパシフィック (ソウル) ap-northeast-2
アジアパシフィック(シドニー) ap-southeast-2
南米 (サンパウロ) sa-east-1
中国(北京) cn-north-1

アジアパシフィックを選んでおけば問題ないが、特定のリージョンにしかないマイナーなサービスがあったりするので注意が必要

AZ(アベイラビリティゾーン)

リージョン内のデータセンターのことで、
東京リージョンだと ap-northeast-1a ap-northeast-1b ap-northeast-1c のAZがある

EC2(Elastic Compute Cloud) Compute_AmazonEC2.png

仮想サーバ

ブラウザ上で何回かクリックするだけで、簡単にインスタンスが立ち上がる
利用料金はインスタンスタイプや性能にもよるが、最低スペックで 744円/月 くらい?

RDS(Relational Database Service) Database_AmazonRDS.png

リレーショナルデータベース

Amazon Aurora  Oracle  Microsoft SQL Server  PostgreSQL  MySQL  MariaDB
からデータベースエンジンを選択可能

中でも MySQL5.6互換がある Amazon Auroraは1分あたり600万回のインサート、3000万件のセレクトが可能らしい。
下記のサイトによれば、DB性能向上が期待できそう?
http://dev.classmethod.jp/cloud/aws/wordpressdb-migrate-aurora/

Redshift  Database_AmazonRedshift.png

データウェアハウス

2TBから最大1.6PBまでスケール可能でログなどのビッグデータを保存するのによく使用される
カラムナー(列指向)と呼ばれるデータ格納方式が特徴

Redshift は、PostgreSQL 8.0.2 に基づいている。
なので、PostgreSQL 9系で追加されたクエリが使えなかったりする。

ElastiCache  Database_AmazonElasticCache.png

KVSのキャッシュサービス

Memcached・Redis から選べる
Elastic Cacheではなく ElastiCache(エラスティキャッシュ) という名前なので注意が必要

S3(Simple Storage Service) Storage_AmazonS3_bucket.png

オンラインストレージサービス

bucket(フォルダ)
object(ファイル)
という名称がある

1B ~ 5TBまでのオブジェクトを書き込み・読み込み・削除が可能
バケットに容量制限はない

・SLAは99.99%
・静的webサイトのホスティングが可能

CloudFront NetworkingContentDelivery_AmazonCloudFront.png

コンテンツデリバリネットワーク(CDN)

CDNはAkamaiなどがあるが、それに比べると割高

VPC(Virtual Private Cloud) General_virtualprivatecloud.png

仮想プライベートクラウド

Amazon VPCは、AWS上に利用者が占有可能な仮想プライベートネットワークを構築するためのサービス。
このVPCの内部にIPサブネットを作成し、その中に仮想サーバーの「EC2」やデータベースサーバーの「RDS」といったAWSのリソースを配置する。

・ユーザ側で使いたいIP空間(VPC) を作成
・VPCにユーザがサブネットを切ることができる
・サブネット単位で アクセスリストが設定できる

Route53 NetworkingContentDelivery_AmazonRoute53.png

DNSサーバ

DNSは通常マスターとスレーブ構成にすることが多く、2台で構成する場合が多いが
Route53では、4つのネームサーバーで構成され、全世界にDNSサーバーを設置しているので高可用性である
米国:20   欧州:16  アジア:12  オーストラリア:2   南米:2

・SLA100% (ほんとに?)
・DNSラウンドロビンでの負荷分散が可能
料金はかなり安い。

ホストゾーン
0.50 USD(ホストゾーンごと)/月 - 最初の25のホストゾーン
0.10 USD(ホストゾーンごと)/月 - それ以上のホストゾーン

標準的クエリ
0.400 USD(100 万クエリごと) - 最初の 10 億クエリ/月
0.200 USD(100 万クエリごと) - 10 億クエリ以上/月

1つのホストゾーンで、10億クエリ行かなければ、月1ドルかからない。

IAM(Identity and Access Management) SecurityIdentityCompliance_IAM.png

ユーザーの権限を管理できるサービス

ポリシーと呼ばれる権限をユーザーにアタッチすることで、該当ユーザーの操作できる範囲を限ることができる

ポリシーは自由に設定可能で、管理者が細かく設定可能で
例えば、とある管理者が s3-readonly-userを作成し S3の閲覧だけを許可するポリシーを作成してアタッチ。など

随時追加中…

続きを読む

Serverless FrameworkでAWS Lamda関数を作成する

概要

Serverless Frameworkとは、Lambda、API Gateway、DynamoDBなどを作成、管理、デプロイできるツールです。
Frameworkと付いていますが、ツールです。
この記事では、python3でLambda関数を作成します。

環境

  • CentOS7.2
  • serverless 1.23.0
  • node v6.11.3
  • npm 3.10.10
  • OpenSSL 1.0.2k-fips 26 Jan 2017

npmのインストール

以下の記事を参照
npmのインストール手順

Serverless Frameworkのインストール

slsというディレクトリを作成し、そこで作業を行います。

$ mkdir sls
$ cd sls
$ npm init
$ npm install --save serverless

serverlessコマンドのパスを通します

$ npm bin serverless
$ echo 'export PATH="$HOME/sls/node_modules/.bin/:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile

インストール確認

$ serverless -v
1.23.0

aws credential登録

以下のコマンドで、AWSのキーを登録します。

$ serverless config credentials --provider aws --key XXXXXXXXXXXXEXAMPLE --secret XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEXAMPLEKEY
Serverless: Setting up AWS...
Serverless: Saving your AWS profile in "~/.aws/credentials"...
Serverless: Success! Your AWS access keys were stored under the "default" profile.

Lambda関数の作成

以下のコマンドで、Lambda関数を作成します。

$ serverless create -t aws-python3 -p sample-app

Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/home/vagrant/sls/sample-app"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  ___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.23.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"

オプションの説明ですが、
-pは、Lambda関数名のprefixとなります。

また、-tで実装する言語を選びます。
以下のいずれかを選択します。

  • -t

    • aws-nodejs
    • aws-python
    • aws-python3
    • aws-java-maven
    • aws-java-gradle
    • aws-scala-sbt
    • aws-csharp
    • openwhisk-nodejs

すると、以下のファイルが生成されます。
handler.pyは、Lambda関数のテンプレート、serverless.ymlは設定ファイルになります。

$ ll sample-app/
total 8
-rw-rw-r--. 1 vagrant vagrant  497 Oct 10 04:42 handler.py
-rw-rw-r--. 1 vagrant vagrant 2758 Oct 10 04:42 serverless.yml

関数の情報を設定

serverless.ymlに関数の設定情報が書かれているので、環境合わせて編集します。

serverless.yml
provider:
  name: aws
  runtime: python3.6

# you can overwrite defaults here
- #  stage: dev
-#  region: us-east-1
+  stage: production
+  region: ap-northeast-1

# *snip*

# 関数名などの定義
functions:
-  hello:
-    handler: handler.hello
+  sample-func:
+    handler: handler.main

serverless.ymlで、関数のメソッド名を変更したので、handler.pyも以下のように編集します。

handler.py
-def hello(event, context):
+def main(event, context):

deploy

以下のコマンドでデプロイをします。

$ cd sample-app
$ serverless deploy

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (389 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: sample-app
stage: production
region: ap-northeast-1
stack: sample-app-production
api keys:
  None
endpoints:
  None
functions:
  sample-func: sample-app-production-sample-func

すると、sample-app-production-sample-funcという名前のLambda関数が作成されます。

Lambda関数の実行

deployが出来たら、以下のコマンドで、Lambda関数を実行することができます。

$ serverless invoke -f sample-func

{
    "statusCode": 200,
    "body": "{"message": "Go Serverless v1.0! Your function executed successfully!", "input": {}}"
}

パラメータを付ける場合は、-dオプションで指定します。
戻り値にinputの項目が増えているのが確認できます。

$ serverless invoke -f sample-func -d '{"key":"value"}'

{
    "statusCode": 200,
    "body": "{"message": "Go Serverless v1.0! Your function executed successfully!", "input": {"key": "value"}}"
}

以下のようなjsonファイルを作成して、パラメータを渡すこともできます。

event.json
{
  "key" : "value"
}

-pオプションでjsonファイルを指定して実行

$ serverless invoke -f sample-func -p event.json
{
    "statusCode": 200,
    "body": "{"message": "Go Serverless v1.0! Your function executed successfully!", "input": {"key": "value"}}"
}

Lambda関数の削除

関数の削除は以下のコマンドで行います。
関連するS3のファイルもすべて消してくれます。
AWS Console上で手動でLambda関数を削除すると、S3のファイルなどが残ってしまいます。

関数のあるディレクトリに移動でして実行します。

$ cd sample-function
$ serverless remove -v

-sオプションで、特定のstageのみを削除することもできます。

$ serverless remove -v -s dev

その他

以下のモジュールで、擬似的にローカルでApi Gateway、DynamoDBを使うことができます。

$ npm install aws-sdk
# 擬似的Api Gateway
$ npm install --save-dev serverless-offline
# 擬似的DynamoDB
$ npm install --save-dev serverless-dynamodb-local

参考

続きを読む

CloudFront に SSL 証明書を導入する際のポイントまとめ

CloudFront に SSL を入れる際に気をつける項目のまとめです。

2017年9月時点では、特に S3 との連携で大きな制約があり、将来的には改善されていくのではと思います。現在の状況を確認してください。

SNI か専用 IP か

まず、ブラウザと CloudFront 間の通信で、SNI (Server Name Indication) が使えるかどうか検討します。

ガラケーやWindowsXP の IE は SNI に対応していません。これらの古い環境でサイトが見えなくても構わないかどうかを確認します。

SNI 非対応のブラウザに対応するには、専用 IP を使う必要があります。専用 IP は $600/月かかります。

専用 IP 独自 SSL の料金体系はシンプルです。SSL 証明書ごとの専用 IP アドレスに伴う追加コストのため、CloudFront ディストリビューションに関連付けられた各独自 SSL 証明書ごとに、毎月 600 USD をお支払いいただきます。

SNI は無料です。

SNI 独自 SSL 証明書管理には、前払い料金や最低月額料金は不要です。お客様にお支払いいただくのは、Amazon CloudFront のデータ転送と HTTPS リクエストに対する通常料金のみです。

証明書の取得について

どのドメインでどんな証明書が必要か、証明書は有料か無料か、を確認します。

証明書の取得方法には、以下の選択肢があります。

  1. 代理店などから購入する (有料)
  2. ACM (AWS Certificate Manager) を使う (無料、ただし EC2 にはインストール不可)
  3. Let’s Encrypt を使う (無料、ただし Amazon Linux 未対応)
  4. etc.

CloudFront – オリジン間を HTTPS にする

通常は、ビューア – CloudFront 間だけでなく、 CloudFront – オリジン間も通信を暗号化します。(表向き暗号化している風を装って、裏を平文で流して良いのかは微妙な問題です…)

CloudFront とオリジンの両方で、証明書が必要になる可能性があります。

オリジンが EC2 の場合、 ELB を入れるか検討する

ACM で取得した証明書を EC2 にインストールすることはできません。

https://aws.amazon.com/jp/certificate-manager/faqs/

Q: ACM により提供された証明書を使用できるのは、AWS のどのサービスですか?

ACM は AWS の以下のサービスと連携できます。
• Elastic Load Balancing – Elastic Load Balancing のドキュメントを参照してください。
• Amazon CloudFront – CloudFront のドキュメントを参照してください。
• Amazon API Gateway – API Gateway のドキュメントを参照してください。
• AWS Elastic Beanstalk – AWS Elastic Beanstalk のドキュメントを参照してください。

https://aws.amazon.com/jp/certificate-manager/faqs/

Q: Amazon EC2 インスタンスや自分のサーバーに証明書を使用できますか?

いいえ。現在のところ、ACM により提供される証明書は、AWS の特定のサービスのみで使用できます。

EC2 で ACM を使いたい場合は、CloudFront – ELB – EC2 の構成にします。証明書が無料になる代わりに、ELB の費用が発生します。

S3 に証明書を入れる必要はない

  • Amazon S3 は SSL/TLS 証明書を提供するため、その必要はありません。

この日本語訳はいまいち何を言っているのかわかりませんが、、

  • Amazon S3 provides the SSL/TLS certificate, so you don’t have to.

「S3 が証明書を提供するので、あなたが(提供する)必要はない」という意味です。

今のところ、S3 に独自の証明書を入れる手段はありません。オリジンに S3 の CNAME を指定することもできません。

http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/DownloadDistS3AndCustomOrigins.html

以下の形式を使用してバケットを指定しないでください。

  • Amazon S3 のパススタイル (s3.amazonaws.com/bucket-name)
  • Amazon S3 の CNAME (ある場合)

CloudFront – S3 間の HTTPS には大きな制約がある

S3 をウェブサイトエンドポイントとしてオリジンに設定すると、HTTPS が使えなくなります。

Amazon S3 バケットがウェブサイトエンドポイントとして構成されている場合、オリジンとの通信に HTTPS を使用するように CloudFront を構成することはできません。Amazon S3 はその構成で HTTPS 接続をサポートしていないためです。

ウェブサイトエンドポイントは、

http://example-bucket.s3-website-ap-northeast-1.amazonaws.com/

のような URL での配信方法です。「静的ウェブサイトホスティング」の設定です。この URL をオリジンに設定すると、CloudFront – S3 間で HTTPS が使えません。

ウェブサイトエンドポイントは、以下の機能で必要です。

  • /foo/bar//foo/bar/index.html を返す
  • 独自のエラー画面を表示する
  • リクエストを全てリダイレクトする (例えば、www なしドメインを www ありにリダイレクトする)

ウェブサイトエンドポイントを使わず、S3オリジンで設定すると、サイトのトップ / (Default Root Object) 以外、index.html が見えるようにはなりません。

CloudFrontではDefault Root Objectという設定項目でIndex Documentを指定することができますが、これはRootへのアクセス時(例:http://example.com/) に対してのみ有効であり、サブディレクトリ(例:http://example.com/foo/) に対しては有効になりません。そのため、階層構造のあるWEBサイトをホストする際には不向きだと思われます。

ウェブサイトエンドポイントを使う場合は、裏が暗号化されていなくてもいいのか、バレなければいいのか、を検討しなければならなくなります。。ちなみに、オリジンが S3 であることは Server レスポンスヘッダで判別できます。S3 がウェブサイトエンドポイントかどうかは、/foo/bar/ の挙動で判別できます。

また、ウェブサイトエンドポイントにすると、Origin Access Identity を使うことができなくなります。バケット名を推測して、S3 に直接アクセスされる可能性があります。

ワイルドカード証明書の取得を検討する

CloudFront にもオリジンにも、ワイルドカード証明書が使えます。例えば、以下のような組み合わせが考えられます。

  • CloudFront *.example.com → Origin *.example.com

    • 1つのワイルドカード証明書を使う
  • CloudFront www.example.com → Origin www.example.com
    • 1つの非ワイルドカードの証明書を使う
    • CloudFront から Host ヘッダを転送する場合のみ、オリジンの証明書で Host ヘッダのドメイン名が使える
  • CloudFront www.example.com → Origin *.example.com
    • 表は高い非ワイルドカード証明書を使い、裏は安いワイルドカード証明書で済ませる
  • CloudFront www.example.com → Origin origin.example.com
    • 表と裏と、別々に非ワイルドカード証明書を購入する
    • または、証明書に別名 (SAN) を設定する
  • CloudFront www.example.com → Origin origin.example.jp
    • オリジンは .example.com でなくてもよい。DNS の自由が効かない場合、裏は Route53 で独自のドメインを取得すると便利

詳細は以下のドキュメントを参照してください。

カスタムオリジンを使用する場合、オリジンの SSL/TLS 証明書の共通名フィールドにドメイン名が含まれ、さらにサブジェクト代替名フィールドにもドメイン名がいくつか含まれることがあります。 (CloudFront は証明書ドメイン名にワイルドカード文字を使用できます)。

証明書のドメイン名のうち 1 つは、オリジンドメイン名に指定したドメイン名と一致する必要があります。ドメイン名が一致しない場合、CloudFront は、ビューワーに HTTP ステータスコード 502 (Bad Gateway) を返します。

内部の証明書を安くあげる

エンドユーザの目に触れないオリジン用の証明書にまでコストをかける必要があるかどうかを検討します。安価な証明書でも十分かもしれません。

オリジンが ELB なら ACM が使えます。

DNS を操作する権限があるか確認する

表側の DNS を操作する権限がない場合、オリジンに Route53 で取得した独自ドメインを設定すると、自由度が上がります。

オリジンに独自のドメインを使う場合は、その証明書が必要です。

リリース前の確認方法を検討する

リリース前に CloudFront に別のドメインを割り当てて確認する場合は、ワイルドカード証明書があったほうが便利です。

例えば https://staging.example.com/ のような URL を CloudFront に設定します。

Naked ドメインを使うか確認する

https://example.com/ のような Naked ドメイン (Zone Apex) を使うかどうか確認します。

Route53 を使わずに、Naked ドメインを CloudFront や ELB や S3 に割り当てることはできません。CloudFront を通さず、例えば EC2 で直接リクエストを受ける必要が出てきます。

Naked ドメインへのリクエストを EC2 で受ける場合

Naked ドメインへのリクエストを EC2 で直接受ける場合は、ACM が使えません。ACM で取得した証明書は EC2 にインストールできないからです。

証明書の購入が必要になる可能性があります。

Naked ドメインの DNS に Route53 を使っている場合

Route53 でエイリアスを使うと、CloudFront に Naked ドメイン (Zone Apex) を設定できます。

この場合は、Naked ドメインの証明書取得に ACM が使えます。

ワイルドカード証明書を使う場合、ワイルドカードに Naked ドメインは含まれないので、*.example.com に別名で example.com を設定します。

既存の証明書がある場合は SAN を確認する


既に証明書があって、足りない証明書を購入する場合。

既存の証明書の別名 (SAN) が何になっているのかを確認します。特に Naked ドメインなど、必要なドメインが SAN に設定されているかもしれません。

証明書をインポートするリージョンに注意する

CloudFront の証明書は、バージニア北部リージョンに入れる必要があります。

ACM で証明書を取得する場合にも、バージニア北部リージョンを選ぶ必要があります。

ビューワーと CloudFront との間で HTTPS を必須にするには、証明書をリクエストまたはインポートする前に AWS リージョンを 米国東部(バージニア北部) に変更する必要があります。

CloudFront とオリジンとの間で HTTPS を必須にする場合、オリジンとして ELB ロードバランサーを使用しているなら、任意のリージョンで証明書をリクエストまたはインポートできます。

例えば、オリジンが東京の ELB だとしたら、東京とバージニア北部リージョンの両方の ACM で証明書を取得 (またはインポート) します。

ACM の本人確認について

ACM で証明書を取得する場合は、本人確認 (取得意思の確認) メールが、証明書のドメイン宛てに送信されます。

Whois 情報の更新状態をチェックする

本人確認メールは、公開されている Whois の連絡先アドレスにも送信されます。

Whois に正しいアドレスが公開されている場合は、そのアドレスでメールを受け取るのが簡単です。

SES で ACM の認証を通す

ドキュメントの通りにやれば、ACM の確認メールを SES で受信するのは、さほど難しくありません。

SES の受信設定を行い、DNS に MX レコードを設定、受信したメールを SNS トピックで受け取るようにして、そのトピックに任意のメールアドレスをサブスクライブします。

ルールセットがアクティブになっているかどうかに注意する

SES のメール受信設定には、「ルールセット」というバージョン管理の仕組みがあります。

現行のルールセットをコピーし、編集し、アクティブなルールセットを入れ替える、という手順で設定を変更します。Inactive Rule Sets に新しいルールセットを足しても何も起こりません。

続きを読む

AWSでServerlessの環境をCIするための選択肢を調べたメモ

利用するサービスはAWSに限定するとした場合に開発・テスト・デプロイを継続するための選択肢をいくつか調べてみました。

開発したいものは、「API Gateway – Lambda – DynamoDB」で構成されるWebサービスとします。

正直なところ、対象像を少し絞らないと選択肢が多すぎて好みの問題になりそうなので・・・

注意

調査用のメモです。

実際に全ての選択肢で開発をしてみたわけではなく、入門記事やドキュメントを少しみた程度で判断しています。

そのため正確性に欠ける内容となっている可能性が高いことをご了承ください。

共通点

開発ツールで対応していない部分についてのデプロイについては、AWS CLIで対応していくことになるでしょう。

LocalStack

モックサービスの対応数にまず驚いた。

https://github.com/localstack/localstack

LocalStack はローカルでAWSのサービスのモックを動かしてしまうというツールです。
DockerコンテナでAWS各種サービスを一気に立ち上げることができるので、ローカル環境で開発を完結させることが出来ます。

これ自体にはAWSを管理する機能はなく、Lambdaをローカル環境で開発してテストするときに、ローカルで同時にAPI Gateway + DynamoDBを動かしたいという場合に必要となりそうです。
DynamoDB自身はAmazonからDynamoDB Localが提供されているので、どちらを使うかは検証が必要でしょう。

起動コマンドも簡単で、一発で全て立ち上げることが出来ます。

docker-compose up

macの場合は、$TMPDIRにシンボリックリンクがある場合、少しコマンドを変える必要があるようです。

TMPDIR=/private$TMPDIR docker-compose up

DynamoDB Local

ローカル開発用のDynamoDB。
ほとんどのLambda開発ツールがAPI Gatewayもサポートしていることから、DynamoDBを接続するローカル環境ではLocalStackよりはこちらを使用することになるのではないかと。公式提供でもあるし。

ダウンロードとインストールガイドはこちら

aws-sam-local

SAM は Serverless Application Modelのことで、aws-sam-localはAmazon公式がサポートしているローカル開発環境です。今はまだbetaですが、近いうちに良くなりそうです。

https://github.com/awslabs/aws-sam-local

AWS Blogで利用例が紹介されていて、DynamoDB Localを使う場合についても少し触れられています。
https://aws.amazon.com/jp/blogs/news/new-aws-sam-local-beta-build-and-test-serverless-applications-locally/

作成したLambda FunctionをローカルDockerコンテナで実行したり、現時点ではPythonとNode.jsはデバッグ出来るようです。(自分で試したところ、上手くいかなかった)

また、Lambda関数を単純に実行するだけではなく、ローカルのAPI Gatewayを通して実行を確認できます。

PostManで簡単にAPIの動作検証が行えたり、実際のHTTPアクセスの形でLambda関数の検証がローカルで行えます。
また、実行時間やメモリ消費量が表示されるため、AWSにデプロイする前に関数の効率化が出来ます。

Serverless Framework

現状で一番正解に近いと思います。

https://github.com/serverless/serverless

こちらのQitta記事こっちのQiita記事が参考になりそうです。
DynamoDB Localと連携するためのプラグインが存在し、serverless.ymlファイルにAWS上での構成を記載していき、そのままAWSにデプロイ出来るようです。

Apex

Go言語でLambdaが書ける!!!

純粋にLambdaの開発だけで見ればとても良さそうです。
ただし、ローカル実行はサポートしておらず、AWSリソースの操作もLambdaに限定されています。
その辺りは、Terraformで補う考えのようです。

公式

https://github.com/apex/apex

chalice

Python用のマイクロサービスフレームワークです。

https://github.com/aws/chalice

次の様なコードで、APIを定義できます。

chalice
@app.route('/resource/{value}', methods=['PUT'])
def put_test(value):
    return {"value": value}

デプロイでAPI Gateway, Lambdaに反映されるため、コードの見通しが良くなりそうです。
IAM Rolesなどは自動生成される様なので、とにかく簡単にコードを書いて、すぐデプロイということが出来そうです。

インストールからコード記述、デプロイまでの操作がHelloworldならこんなに簡単に出来るようです。

$ pip install chalice
$ chalice new-project helloworld && cd helloworld
$ cat app.py

from chalice import Chalice

app = Chalice(app_name="helloworld")

@app.route("/")
def index():
    return {"hello": "world"}

$ chalice deploy
...
https://endpoint/dev

$ curl https://endpoint/api
{"hello": "world"}

Zappa

こちらも、とにかく簡単にPythonで作成した関数をAWSにデプロイ出来ることがウリのようです。

https://github.com/Miserlou/Zappa

gifアニメーションで実演が付いています。(README.mdから引用しました)
README.md

Zappa Demo Gif

REST APIを作成する以外にも、AWS Eventsに対応するものや、Asynchronous Task Executionといって、別のLamdba関数を非同期に呼び出すことが出来る機能を持っているようです。
というか、chaliceに比べると非常に多彩。

また、ZappaはWSGI(Web Server Gateway Interface)をサポートしているので、他のアプリケーションサーバーにデプロイすることも可能です。

chalice vs Zappa

こちらに比較記事がありました。

続きを読む

【HashiCorp Vault】Dynamic Secrets (Secret Backend) の Lease 機能を試す

はじめに

Dynamic Secrets (Secret Backend) の Lease 機能について動作を確認しましたので備忘録として記録しておきます。

やったこと

  1. Vaultが作成したAWSユーザの有効期限(TTL)を確認する
  2. Lease機能を利用して有効期限(TTL)を設定する
  3. Lease機能を利用してAWSユーザの有効期限(TTL)を延長する

HashiCorp Vaultとは?

HashiCorpが提供している機密情報の管理ツールです。

Dynamic Secrets (Secret Backend) とは

VaultにAWSやDatabaseなどのアカウントを管理させる機能です。

この機能を利用することでVaultを通じてAWSなどのユーザ作成、削除を実施できるようになります。
有効期間が経過したユーザについてはVaultが自動で削除を行ってくれます。

参考

公式サイト

Vault by HashiCorp

ドキュメント

AWS Secret Backend – HTTP API – Vault by HashiCorp
/sys/leases – HTTP API – Vault by HashiCorp

過去の投稿

HashiCorp Vault の Dynamic Secrets (Secret Backend) を試す – Qiita


事前準備

VaultをDevモードで起動

$ vault server -dev

...
    export VAULT_ADDR='http://127.0.0.1:8200'
...
Root Token: dae8c23c-3749-0286-abc5-fbdf57b634f1

環境変数の設定

$ export VAULT_ADDR='http://127.0.0.1:8200'
$ export VAULT_TOKEN='dae8c23c-3749-0286-abc5-fbdf57b634f1'

AWS Backendをマウント

$ vault mount aws
Successfully mounted 'aws' at 'aws'!

AWSのTokenを設定

$ vault write aws/config/root 
    access_key=AKIAIFOCRMPWZMVED74Q 
    secret_key=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
Success! Data written to: aws/config/root

ポリシーを設定

policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1426528957000",
      "Effect": "Allow",
      "Action": [
        "ec2:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
$ vault write aws/roles/deploy policy=@policy.json
Success! Data written to: aws/roles/deploy

1. Vaultが作成したAWSユーザの有効期限(TTL)を確認する

初期状態でLease設定や有効期限(TTL)を確認します。

Lease設定を確認する

Lease設定を確認しても、未設定のため取得できません。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    $VAULT_ADDR/v1/aws/config/lease

{"errors":[]}

VaultにAWSユーザを作成させる

この状態(Lease未設定)でAWSユーザを作成せた場合、lease_duration": 2764800となっています。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    $VAULT_ADDR/v1/aws/creds/deploy

{
  "request_id": "333374cd-1d0e-6015-adc9-85656d78a1c9",
  "lease_id": "aws/creds/deploy/6ceb69a0-249a-e65e-ff9a-9996a85bed45",
  "renewable": true,
  "lease_duration": 2764800,
  "data": {
    "access_key": "AKIAJIFBBLEAXHS4NQNQ",
    "secret_key": "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",
    "security_token": null
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

Lease設定を確認

AWSユーザのLease設定を確認すると、

  • “issue_time” : “2017-10-08T17:30:30.873476458+09:00”
  • “expire_time”: “2017-11-09T17:30:30.873476739+09:00”

となっており、有効期限(TTL)が 2764800秒 = 32日間 であることがわかりました。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/6ceb69a0-249a-e65e-ff9a-9996a85bed45" }' 
    $VAULT_ADDR/v1/sys/leases/lookup

{
  "request_id": "21234bd6-e722-8993-22f7-175f2c4d8dc6",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "expire_time": "2017-11-09T17:30:30.873476739+09:00",
    "id": "aws/creds/deploy/6ceb69a0-249a-e65e-ff9a-9996a85bed45",
    "issue_time": "2017-10-08T17:30:30.873476458+09:00",
    "last_renewal": null,
    "renewable": true,
    "ttl": 2764126
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

2. Lease機能を利用して有効期限(TTL)を設定する

初期設定では有効期限(TTL)が長いので、短い有効期限(TTL)を設定して、AWSユーザが実際に削除されるのか確認したいと思います。

Lease設定

lease30mlease_max12hに設定します。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request POST 
    --data '{ "lease": "30m",  "lease_max": "12h" }' 
    $VAULT_ADDR/v1/aws/config/lease

Lease設定を確認すると、lease, lease_maxが指定した値になっています。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    $VAULT_ADDR/v1/aws/config/lease 

{
  "request_id": "3b09ce08-b6b6-848f-3622-f3711d1a7d26",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "lease": "30m0s",
    "lease_max": "12h0m0s"
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

AWSユーザ作成

Lease設定後にAWSユーザを作成させると、lease_duration": 1800となっています。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    $VAULT_ADDR/v1/aws/creds/deploy

{
  "request_id": "5413657e-78e4-4128-e7c0-ed61c6158bc8",
  "lease_id": "aws/creds/deploy/5d7f8036-762b-8fcb-fcea-7bb7f1842f13",
  "renewable": true,
  "lease_duration": 1800,
  "data": {
    "access_key": "AKIAJCVNQTVWYDKAEIMA",
    "secret_key": "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",
    "security_token": null
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

AWSユーザのLease設定を確認すると、

  • “issue_time” : “2017-10-08T17:52:06.741853365+09:00”
  • “expire_time”: “2017-10-08T18:22:06.741853771+09:00”

となっており、有効期限(TTL)が1800秒 = 30分となってることがわかります。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/5d7f8036-762b-8fcb-fcea-7bb7f1842f13" }' 
    $VAULT_ADDR/v1/sys/leases/lookup

{
  "request_id": "e528ba92-53f0-cee0-973d-069612a24207",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "expire_time": "2017-10-08T18:22:06.741853771+09:00",
    "id": "aws/creds/deploy/5d7f8036-762b-8fcb-fcea-7bb7f1842f13",
    "issue_time": "2017-10-08T17:52:06.741853365+09:00",
    "last_renewal": null,
    "renewable": true,
    "ttl": 1646
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

AWSユーザの削除確認

AWSの管理コンソールを確認したところ、expire_timeに到達したタイミングでVaultが作成したAWSユーザ(vault-root-deploy-1507452723-604)が削除されました。

expire_time到達前
vault_lease01.png

expire_time到達後
vault_lease02.png

3. Lease機能を利用してAWSユーザの有効期限(TTL)を延長する

Lease機能には有効期限(TTL)を延長(renew)させる機能があるので、こちらの動作も確認してみます。

AWSユーザ作成

前回と同様にVaultにAWSユーザを作成させます。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    $VAULT_ADDR/v1/aws/creds/deploy

{
  "request_id": "15e22c37-ff2f-2277-6bc5-0834f4dd4eba",
  "lease_id": "aws/creds/deploy/f822cb89-98d6-0cd5-05e7-69020bda05b9",
  "renewable": true,
  "lease_duration": 1800,
  "data": {
    "access_key": "AKIAIGFBKDIZ6VU7UOUA",
    "secret_key": "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",
    "security_token": null
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

前回と同様にAWSユーザの有効期限(TTL)は30分間です。

  • “issue_time” : “2017-10-08T18:34:39.368521987+09:00”
  • “expire_time”: “2017-10-08T19:04:39.368522185+09:00”
$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/f822cb89-98d6-0cd5-05e7-69020bda05b9" }' 
    $VAULT_ADDR/v1/sys/leases/lookup

{
  "request_id": "f1848a4a-7f3f-8e0c-90cf-7024dd242c35",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "expire_time": "2017-10-08T19:04:39.368522185+09:00",
    "id": "aws/creds/deploy/f822cb89-98d6-0cd5-05e7-69020bda05b9",
    "issue_time": "2017-10-08T18:34:39.368521987+09:00",
    "last_renewal": null,
    "renewable": true,
    "ttl": 1753
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

有効期限(TTL)の延長

Lease機能を利用してAWSユーザの有効期限(TTL)を3600秒(30分)延長させます。

$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9", "increment": 3600 }' 
    $VAULT_ADDR/v1/sys/leases/renew

{
  "request_id": "86f059ec-1680-c886-2ade-3e15635ed38e",
  "lease_id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9",
  "renewable": true,
  "lease_duration": 3600,
  "data": null,
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

Lease設定を確認するとexpire_timeが更新されてます。

issue_timeから+3600秒(30分)されるわけではなく、延長(renew)コマンドを実行した時点(last_renewal)から3600秒(30分)延長されるようです。

延長前

  • “issue_time” : “2017-10-08T18:34:39.368521987+09:00”
  • “expire_time”: “2017-10-08T19:04:39.368522185+09:00”

延長後

  • “issue_time” : “2017-10-08T18:27:57.65077363+09:00”
  • “last_renewal”: “2017-10-08T18:35:52.918241764+09:00”
  • “expire_time” : “2017-10-08T19:35:52.918241648+09:00”
$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9" }' 
    $VAULT_ADDR/v1/sys/leases/lookup
{
  "request_id": "f8e035a6-a72b-395a-aca0-641ed7c747ce",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "expire_time": "2017-10-08T19:35:52.918241648+09:00",
    "id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9",
    "issue_time": "2017-10-08T18:27:57.65077363+09:00",
    "last_renewal": "2017-10-08T18:35:52.918241764+09:00",
    "renewable": true,
    "ttl": 3556
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

有効期限(TTL)の最大値を確認

lease_max12hに設定していたので12時間を超える有効期限(TTL)は設定できなくなっています。

有効期限(TTL)を 43200秒(1日)延長(renew)させても、expire_timeissue_timeの12時間後となっており、lease_maxを超えた有効期限(TTL)が設定できないことがわかります。

  • “issue_time” : “2017-10-08T18:27:57.65077363+09:00”
  • “last_renewal”: “2017-10-08T18:38:06.850822545+09:00”
  • “expire_time” : “2017-10-09T06:27:57.650782301+09:00”
$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9", "increment": 43200 }' 
    $VAULT_ADDR/v1/sys/leases/renew

{
  "request_id": "9ed0ca65-18ee-2186-689a-1569f4f9e058",
  "lease_id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9",
  "renewable": true,
  "lease_duration": 42590,
  "data": null,
  "wrap_info": null,
  "warnings": null,
  "auth": null
}
$ curl 
    --header "X-Vault-Token: $VAULT_TOKEN" 
    --request PUT 
    --data '{ "lease_id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9" }' 
    $VAULT_ADDR/v1/sys/leases/lookup

{
  "request_id": "00d1c93f-431d-61f0-a116-b5d8a57af815",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "expire_time": "2017-10-09T06:27:57.650782301+09:00",
    "id": "aws/creds/deploy/28def48b-c990-d1d4-1691-610a8f2be0e9",
    "issue_time": "2017-10-08T18:27:57.65077363+09:00",
    "last_renewal": "2017-10-08T18:38:06.850822545+09:00",
    "renewable": true,
    "ttl": 42560
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

続きを読む

HashiCorp Vault の Dynamic Secrets (Secret Backend) を試す

はじめに

HashiCorpのVaultが提供しているDynamic Secrets (Secret Backend) 機能について公式ドキュメントを参考に動作を確認しましたので備忘録として残しておきます。

やったこと

Vaultの Dynamic Secrets (Secret Backend) 機能を利用してAWSユーザの作成・削除を行う。

HashiCorp Vaultとは?

HashiCorpが提供している機密情報の管理ツールです。

Dynamic Secrets (Secret Backend) とは

VaultにAWSやDatabaseなどのユーザを管理させる機能です。

この機能を利用することでVaultを通じてAWSなどのユーザ作成、削除を実施できるようになります。
有効期間が経過したユーザについてはVaultが自動で削除を行ってくれます。

参考

公式サイト

Vault by HashiCorp

ドキュメント

Dynamic Secrets – Getting Started – Vault by HashiCorp
AWS Secret Backend – Vault by HashiCorp


事前準備

VaultをDevモードで起動

DevモードではVaultを停止させるとデータが消えてしまいますが、今回は動作確認のためDevモードで起動します。

$ vault server -dev

...
    export VAULT_ADDR='http://127.0.0.1:8200'

環境変数の設定

$ export VAULT_ADDR='http://127.0.0.1:8200'

AWS Backendをマウント

$ vault mount aws
Successfully mounted 'aws' at 'aws'!

AWSユーザの作成

vaultがAWSを操作するためのユーザ(vault)を作成します。

本来であれば目的に応じたポリシーを付与するべきですが、今回は動作確認のため「AdministratorAccess」ポリシーを適用しました。

作成したユーザの「アクセスキー ID」と「シークレットアクセスキー」はvaultで利用するためメモしておきます。

vault01.png

vault02.png

vault03.png

vault04.png

vault05.png


AWS Backendの設定

Vault用に準備したAWSユーザの「アクセスキー ID」と「シークレットアクセスキー」をaws/config/rootに登録します。

$ vault write aws/config/root 
    access_key=AKIAJDCIHPTOLCKLM6WA 
    secret_key=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

Success! Data written to: aws/config/root

aws/config/rootに書き込んだ情報は読み取れなくなります。

$ vault read aws/config/root

Error reading aws/config/root: Error making API request.

URL: GET http://127.0.0.1:8200/v1/aws/config/root
Code: 405. Errors:

* 1 error occurred:

* unsupported operation

ロールの作成

Getting Started を参考にjsonファイルを作成します。
Actionにec2:*という記載があるので、EC2を操作するアカウントが作成されそうです。

policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1426528957000",
      "Effect": "Allow",
      "Action": [
        "ec2:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

作成したjsonファイルを指定してロールを作成します。

$ vault write aws/roles/deploy policy=@policy.json

Success! Data written to: aws/roles/deploy

AWSユーザの作成

ロールを指定してAWSユーザを作成させます。
レスポンスとして作成したユーザの「アクセスキー ID」と「シークレットアクセスキー」が返却されます。

$ vault read aws/creds/deploy

Key             Value
---             -----
lease_id        aws/creds/deploy/2cfb960b-7f2e-74c4-d351-917401d27f3b
lease_duration  768h0m0s
lease_renewable true
access_key      AKIAIYMLSSQ434JIRMUQ
secret_key      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
security_token  <nil>

AWSの管理画面を確認すると新しいユーザ(vault-root-deploy-1507372260-9128)が作成されて、EC2を操作するアクセス権限をもってることがわかります。

vault06.png

vault07.png

vault08.png


AWSユーザの削除

lease_idを指定してユーザを削除します。

$ vault revoke aws/creds/deploy/2cfb960b-7f2e-74c4-d351-917401d27f3b

Success! Revoked the secret with ID 'aws/creds/deploy/2cfb960b-7f2e-74c4-d351-917401d27f3b', if it existed.

AWSの管理画面でもVaultが作成したユーザ(vault-root-deploy-1507372260-9128)が削除されたことがわかります。

vault09.png

補足

【HashiCorp Vault】Dynamic Secrets (Secret Backend) の Lease 機能を試す – Qiita

続きを読む