[入門] EBSを暗号化しよう

おはようございます、もきゅりんです。
昨夜くらいから目が痒くなってまいりました。春ですね...祭典の季節です。
ストラヴィンスキーです。
春になると、例年ちょっとおかしな人たちが出てきますよね。

そう、そんなときに大事なのが、セキュリティ管理。
セキュリティ管理といえば暗号化、ということで、今回はKMSに触れながらEBSの暗号化です。

実は、KMS関連で諸々触っていたのですが、
それを一記事にまとめると大変な長さになってきそうなので、
区切り良くまとめながら小出しにしていきます。

やること

  1. KMSキーを作成

  2. EBSを暗号化

  3. 後片付けを忘れずに

1 KMSキーを作成

それではまずはともあれ、KMSでキーを作成しましょう。しっかりリージョンを選択しときましょう。

エイリアスを設定します。
(CLIからだとキーを作成した後にエイリアスを設定するみたいでめんどいので、手動で作ります。
(2019年2月20日現在))

この後は以下のような流れです。

タグを設定します。このタグからコスト配分レポートにも利用できます。

・ このキーを管理(編集・削除)できる IAM ユーザーとロールを選択

・ このキーを使用してデータを暗号化および復号化できる IAM ユーザーとロールを選択

すると、キーが出来ました!
そしたら、このKeyIDは大事なので取っておきましょう。

2 EBSを暗号化

で、今回のターゲットはEBSです。
EBSの暗号化については、下記表のようにインスタンスのステータスによって対応が異なっています。

Status 1 2 3 4
Running AMI作成 そのAMIをコピーしてSnapshotの暗号化を設定 コピーしたAMIからインスタンスを起動 -
stopped Snapshot作成 そのSnapshotをコピーして暗号化する コピーしたSnapshotからボリュームを作成 新ボリュームをインスタンスにアタッチ

いやー...なかなか煩雑ですね。。

実際、手でポチポチ...あるいはCLIからちょこちょこ叩きながら確認してみたのですが、
作成が完了したのを見届けると、あれ、次何やるんだっけ...?みたいな感じになりました。。
(同じような作業が多いからですかね)

ということで、下記、実用を全く想定していないスクリプトをチョロっと書きました。
やっていることは上記表をそのままやっているだけです。

なお、稼働中のEBSの暗号化でいうと、
弊社記事に[入門] 稼働中のEC2インスタンスのEBS Volumeを暗号化する [EC2インスタンス]
もございます。(こちらはストレージのI/Oもしっかり考慮された完成度高めの記事です。)

必要なのは、対象のインスタンス名と、先ほど作成したKMSのキーIDです。
(インスタンスにはアタッチされているボリュームは1つと想定しています。例外処理とかロールバックとか冪等性とかないのでお気を付けくだしー。)

あ、jqを利用しているので、もしなかったらMacの人はhomebrew でインストールしてね!

$ brew install jq

それとAWSにはAWS CLIでアクセスできる環境だと信じています!

では、KMSを設定するファイルを作ります。

cat ./kms_key.conf
KMSKeyId=YOUR_KMS_KEY_ID

スクリプトの内容はこんな感じです。

ebs_encrypt.sh

#!/bin/bash

. ./kms_key.conf

echo "What is TargetInstanceName?"
read TargetInstanceName
echo "Ok~"

# 対象インスタンスIDを取得
TargetInstanceId=`aws ec2 describe-instances --filter "Name=tag:Name,Values=${TargetInstanceName}" \
| jq -r '.Reservations[].Instances[].InstanceId'`

# 対象インスタンスのステータスを取得
InstanceStatus=`aws ec2 describe-instance-status --instance-ids $TargetInstanceId \
| jq -r '.InstanceStatuses[].InstanceState.Name'`

if [ "$InstanceStatus" = "running" ]; then

    # 対象インスタンスのAMIを作成
    AMIId=`aws ec2 create-image --instance-id $TargetInstanceId --name "Origin-AMI" --description "An AMI for my server" \
    | jq -r '.ImageId'`

    # AMI作成の状態を確認
    while [ "$ImageStatus" != "available" ]
    do
        sleep 10
        ImageStatus=`aws ec2 describe-images --image-ids $AMIId | jq -r '.Images[].State'`
        echo $ImageStatus
    done

    echo "Image created."

    # AMIからコピーして暗号化AMI作成
    EncryptedAMIId=`aws ec2 copy-image --encrypted --kms-key-id ${KMSKeyId} \
    --source-image-id ${AMIId} --source-region ap-northeast-1 --name "EncryptedAMI" \
    | jq -r '.ImageId'`

    # AMI作成の状態を確認
    while [ "$EncryptedImageStatus" != "available" ]
    do
        sleep 10
        EncryptedImageStatus=`aws ec2 describe-images --image-ids $EncryptedAMIId | jq -r '.Images[].State'`
        echo $EncryptedImageStatus
    done

    echo "EncryptedImage created."

    # AMIIDからスナップショットIDを取得 // 超絶雑。
    EncryptedAMISnapId=`aws ec2 describe-snapshots --filters Name=description,Values="*${EncryptedAMIId}*" \
    | jq -r '.Snapshots[].SnapshotId'`

    Result=`aws ec2 describe-snapshots --snapshot-ids $EncryptedAMISnapId \
    | jq '.Snapshots[].Encrypted'`

    if [ "$Result" = "true" ]; then
        echo "Task is Done"
    else
        echo "Error! Something wrong..." >&2
    fi

else

    # 対象インスタンスのボリュームIDを取得
    TargetVolumeId=`aws ec2 describe-instances --instance-ids $TargetInstanceId \
    | jq -r '.Reservations[].Instances[].BlockDeviceMappings[].Ebs.VolumeId'`

    # moqrin-snapshotというSnapshotを作成
    SnapshotId=`aws ec2 create-snapshot --volume-id $TargetVolumeId --tag-specifications 'ResourceType=snapshot,\
    Tags=[{Key=Name,Value=moqrin-snapshot}]' \
    | jq -r '.SnapshotId'`

    while [ "$SnapshotStatus" != "completed" ]
    do
        sleep 10
        SnapshotStatus=`aws ec2 describe-snapshots --snapshot-id $SnapshotId | jq -r '.Snapshots[].State'`
        echo $SnapshotStatus
    done

    echo "Snapshot created."

    # スナップショットをコピーして暗号化する
    EncryptSnapId=`aws ec2 copy-snapshot --source-region ap-northeast-1 --source-snapshot-id $SnapshotId \
    --encrypted --kms-key-id ${KMSKeyId} --description "Snapshot encrypted" \
    | jq -r '.SnapshotId'`

    while [ "$EncryptSnapshotStatus" != "completed" ]
    do
        sleep 10
        EncryptSnapshotStatus=`aws ec2 describe-snapshots --snapshot-id $EncryptSnapId | jq -r '.Snapshots[].State'`
        echo $EncryptSnapshotStatus
    done

    echo "EncryptSnap created."

    Result=`aws ec2 describe-snapshots --snapshot-ids $EncryptSnapId \
    | jq -r '.Snapshots[].Encrypted'`

    if [ "$Result" = "true" ]; then
        echo "Task is Done"
    else
        echo "Error! Something wrong..." >&2
    fi

fi

対象のインスタンスが稼働中か停止中かで上記表の行に対応します。

なお、暗号化処理までしか実行していませんので、あしからず。

実行権限を付与しておきます。

$ sudo chmod a+x ./ebs_encrypt.sh

叩くとこんな感じです。

$ ./ebs_encrypt.sh
What is TargetInstanceName?
YOUR_INSTANCE_NAME
Ok~

終わるとこんな感じです。 (AMIの作成は結構時間かかります。)

available
EncryptedImage created.
Task is Done

暗号化AMI

暗号化スナップショット

3 後片付けを忘れずに

無益なAMIとスナップショットは漏れなく削除しておきましょう。(特にスナップショット)

感想

KMSとの交友関係は、まだまだ浅い...。
そしてまたつまらぬスクリプトを書いてしまった...。

参考

[入門] 稼働中のEC2インスタンスのEBS Volumeを暗号化する [EC2インスタンス]