Hatena::ブログ(Diary)

ablog このページをアンテナに追加 RSSフィード

2018-11-12

ECS で EC2 と Fargate の起動タイプのタスクを併用して同じアプリケーションを実行する

ECSEC2 と Fargate の起動タイプのタスクを併用して同じアプリケーションを実行してみた。ワークロードがない場合は、EC2 の1タスクだけ実行され(Fargate のタスクは 0)、EC2CPU使用率が50%を超えると EC2 に1タスク追加され、EC2CPU使用率が80% を超えると Fargate のタスクが追加されていくというのを試してみた。


EC2インスタンスから ab で負荷をかけて、

f:id:yohei-a:20181115013739p:image:w640

ECSEC2 インスタンスログインして htop でワークロードを確認するとこんな感じ。

f:id:yohei-a:20181115013720p:image:w640

CloudWatch のダッシュボードを見るとこんな感じで、CPU使用率が上がり、

f:id:yohei-a:20181115014144p:image:w640

ECSEC2 は +1、Fargate は +1 タスクがスケールアウトしている。

f:id:yohei-a:20181115013658p:image:w640

手順は以下の通り。


準備

キーペア作成
  • ECSを利用するリージョンでキーペアを作成していない場合は作成しておく。
セキュリティグループ作成
タイププロトコルポート範囲ソース
HTTPTCP80マイIP
SSHTCP22マイIP
すべてのTCPTCPすべて自分自身のセキュリティグループID

ELB

ELB作成

ECS

ECSタスク定義(EC2タイプ)作成
ECSタスク定義(Fargateタイプ)作成
クラスター作成
サービス(EC2起動タイプ)作成
  • 起動タイプ: EC2
  • タスク定義: ec2-task
  • クラスター: ec2-fg-mix-cluster
  • サービス名: ec2-service
  • タスクの数: 1
  • ELBタイプ: Application Load Balancer
  • ELB名: ec2-fg-mix-alb
  • パスパターン: /
  • 評価順:1
  • ヘルスチェックパス: /
  • Service Auto Scaling: Service Auto Scaling の設定を変更することで、サービスの必要数を調整する
  • タスクの最小数: 1
  • タスクの最大数: 2
  • 自動タスクスケーリングポリシー
    • ポリシー名: EC2ScaleOutPolicy
      • 既存のアラームの使用: EC2ScaleOutAlarm
      • スケーリングアクション: 追加 1 tasks、次の条件の場合 50 <= CPUUtilization
      • クールダウン期間: 30
    • ポリシー名: EC2ScaleInPolicy
      • 既存のアラームの使用: EC2ScaleInAlarm
      • スケーリングアクション: 削除 1 tasks、次の条件の場合 40 <= CPUUtilization
      • クールダウン期間: 30
サービス(FARGATE起動タイプ)作成
  • 起動タイプ: FARGATE
  • タスク定義: fargate-task
  • クラスター: ec2-fg-mix-cluster
  • サービス名: fg-service
  • タスクの数: 1
  • クラスター VPC: デフォルトVPC
  • サブネット: ap-northeast-1a のサブネット
  • パブリック IP の自動割り当て: ENABLED
  • セキュリティグループ: ECS-SG
  • ELBタイプ: Application Load Balancer
  • ELB名: ec2-fg-mix-alb
  • パスパターン: /
  • 評価順:1
  • ヘルスチェックパス: /
  • Service Auto Scaling: Service Auto Scaling の設定を変更することで、サービスの必要数を調整する
  • タスクの最小数: 1
  • タスクの最大数: 10
  • 自動タスクスケーリングポリシー
    • ポリシー名: FgScaleOutPolicy
      • 既存のアラームの使用: FgScaleOutAlarm
      • スケーリングアクション: 追加 1 tasks、次の条件の場合 80 <= CPUUtilization
      • クールダウン期間: 30
    • ポリシー名: Fg2ScaleInPolicy
      • 既存のアラームの使用: FgScaleInAlarm
      • スケーリングアクション: 削除 1 tasks、次の条件の場合 70 <= CPUUtilization
      • クールダウン期間: 30

CloudWatch Alarm

EC2起動タイプのスケールアウト用
  • 名前: EC2ScaleOutAlarm
  • CPUUtilization: >= 50
  • 期間: 1 / 1 データポイント
  • アクション
    • アラームが次の時: 警告
    • リソースタイプから: EC2 Container Service
    • 次から: service/ec2-fg-mix-cluster/ec2-service
    • 次のアクションを実行: EC2ScaleOutPolicy
EC2起動タイプのスケールイン用
  • 名前: EC2ScaleInAlarm
  • CPUUtilization: <= 40
  • 期間: 1 / 1 データポイント
  • アクション
    • アラームが次の時: 警告
    • リソースタイプから: EC2 Container Service
    • 次から: service/ec2-fg-mix-cluster/ec2-service
    • 次のアクションを実行: EC2ScaleInPolicy
Fargate起動タイプのスケールアウト用
  • 名前: FgScaleOutAlarm
  • CPUUtilization: >= 80
  • 期間: 1 / 1 データポイント
  • アクション
    • アラームが次の時: 警告
    • リソースタイプから: EC2 Container Service
    • 次から: service/ec2-fg-mix-cluster/fg-service
    • 次のアクションを実行: FgScaleOutPolicy
Fargate起動タイプのスケールイン用
  • 名前: FgScaleInAlarm
  • CPUUtilization: <= 70
  • 期間: 1 / 1 データポイント
  • アクション
    • アラームが次の時: 警告
    • リソースタイプから: EC2 Container Service
    • 次から: service/ec2-fg-mix-cluster/fg-service
    • 次のアクションを実行: FgScaleInPolicy

負荷をかけてスケールアウト/インを試す

$ sudo yum -y install htop 
$ sudo yum -y install httpd
  • 負荷をかける
$ ab -k -n 900000000 -c 100 http://*****.ap-northeast-1.elb.amazonaws.com/ &
$ ab -k -n 900000000 -c 100 http://*****.ap-northeast-1.elb.amazonaws.com/ &
$ ab -k -n 900000000 -c 100 http://*****.ap-northeast-1.elb.amazonaws.com/ &
$ ab -k -n 900000000 -c 100 http://*****.ap-northeast-1.elb.amazonaws.com/ &
$ ab -k -n 900000000 -c 100 http://*****.ap-northeast-1.elb.amazonaws.com/ &
$ ab -k -n 900000000 -c 100 http://*****.ap-northeast-1.elb.amazonaws.com/ &

補足

  • ECSのサービスを作成時にスケールアウト/インポリシーを仮で作成後に、CloudWatch Alarm でスケールアウト/インのアラームを作成し、ECSのサービスを更新して作成した CloudWatch Alarm と紐付ける。
  • 同じサービス名で削除して作り直すとマネジメントコンソールでは消えていても、バックグラウンドで削除完了していないと "Unable to Start a service that is still Draining." というエラーになる模様。しばらくして作り直すと成功した。
  • 同一クラスターEC2とFARGATEのタスク共存させる場合に以下のネットワークモードの組合せは可能なことを確認済。
  • 起動タイプがEC2ネットワークモードを awsvpc にした場合、1タスクで1つのENIを使うので、EC2インスタンスの ENI の最大数を超えるタスクを起動することはできない。ENIの最大数を超えるタスクを起動しようとすると RESOURCE:ENI エラーが発生する。

RESOURCE:* (container instance ID)

タスクによってリクエストされたリソースは、指定したコンテナインスタンスで使用できません。リソースCPU、メモリ、ポート、または Ellastic Network Interface の場合は、コンテナインスタンスクラスターへの追加が必要になる場合があります。RESOURCE:ENI エラーの場合、awsvpc ネットワークモードを使用するタスクで必要な Elastic Network Interface アタッチメントポイントが、クラスターで利用できないことを示しています。Amazon EC2 インスタンスにアタッチできるネットワークインターフェイスの数には制限があり、プライマリネットワークインターフェイスも 1 つ分としてカウントされます。各インスタンスタイプでサポートされる Network Interface の数の詳細については、Linux インスタンスAmazon EC2 ユーザーガイドの「各インスタンスタイプのネットワークインターフェイスごとの IP アドレス」を参照してください。

API failures エラーメッセージ - Amazon Elastic Container Service

2018-11-07

S3オブジェクトのバージョン一覧を表示する

S3 で複数バージョン存在するオブジェクトをリストアップする。

$ aws s3api list-object-versions --bucket az-test-bucket|jq -r '.Versions[].Key'|sort|uniq -c|perl -lane '$F[0] > 1 and print'
      2 swingbench/data/gz/sh10/sales/test2.txt
      3 swingbench/data/gz/sh10/sales/test.txt

参考

バケット内のオブジェクトバージョン一覧を表示するには、[Show] を選択します。各オブジェクトバージョンについて、一意のバージョン ID、そのバージョンが作成された日時、その他のプロパティがコンソールに表示されます (バージョニング状態を設定する前にバケットに格納されているオブジェクトには、バージョン ID null が付けられています)。

バージョンのないオブジェクトをリストするには、[Hide] を選択します。

f:id:yohei-a:20181107175036p:image:w640

S3 オブジェクトのバージョンを表示するには - Amazon Simple Storage Service

f:id:yohei-a:20181107175929p:image

$ aws s3api list-object-versions --bucket az-test-bucket|head -30
{
    "Versions": [
        {
            "LastModified": "2018-05-11T06:31:01.000Z",
            "VersionId": "null",
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "StorageClass": "STANDARD",
            "Key": "bigdata-handson/",
            "Owner": {
                "DisplayName": "yoheia",
                "ID": "..."
            },
            "IsLatest": true,
            "Size": 0
        },
        {
            "LastModified": "2018-05-08T06:19:00.000Z",
            "VersionId": "null",
            "ETag": "\"1dd76d97a608b7b3ccb9e6da4f80a8cb-4\"",
            "StorageClass": "STANDARD",
            "Key": "swingbench/data/gz/sh10/sales/sh10_sales_0000_part_00.gz",
            "Owner": {
                "DisplayName": "yoheia",
                "ID": "..."
            },
            "IsLatest": true,
            "Size": 32481061
        },
        {
            "LastModified": "2018-05-08T06:19:00.000Z",

2018-11-04

Parquet ファイルに Presto でクエリ時の Column Projection について調べた

確認したかったこと

  • Parquet ファイルに対して Presto で select count(year) のように特定カラムのみ参照するとそのカラムのみをストレージから読んでいる。
  • select count(*) すると Parquet ファイルのフッターのメタデータ(Row group の num rows)のみをストレージから読んでいる。

検証シナリオ

#クエリ
1select count(*) from amazon_reviews_parquet
2select count(year) from amazon_reviews_parquet
3select count(review_body) from amazon_reviews_parquet
4select * from amazon_reviews_parquet limit 10000
5select year from amazon_reviews_parquet limit 10000
6select review_body from amazon_reviews_parquet limit 10000

検証ポイント

Presto のスキャンサイズ
システムコール
$ sudo iotop
$ sudo csysdig
Linux カーネルのブロックレイヤーI/O
  • iostat で見たI/O量が select count(year) より select count(review_body) のほうが多いこと
  • blktrace + btt で見たI/O量が select count(year) より select count(review_body) のほうが多いこと
$ sudo mount -t debugfs none /sys/kernel/debug
$ sudo blktrace -w 60 -d /dev/nvme1n1p2 -o nvme1n1p2
$ sudo btt -i nvme1n1p2.blktrace.0 -B nvme1n1p2.blktrace.0.btt
ハイパーバイザーレイヤーI/O
  • EC2I/O 量が select count(year) より select count(review_body) のほうが多いこと
観測面から見える実装
$ ps -u hdfs
$ sudo ~/perf-map-agent/bin/perf-java-top <PID>
ソースコードの実装
  • Presto から HDFS に対してリクエストを出すコード
  • HDFS のランダムアクセスAPI
  • HDFSファイルシステムからランダムアクセスするコード
  • Sさんに教えてもらったやつ

環境


参考

  • Parquet ファイルの定義
$ aws s3 cp s3://amazon-reviews-pds/parquet/product_category=Apparel/part-00000-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet ./
$ java -jar parquet-tools-1.6.0.jar meta ~/part-00000-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
file:              file:/Users/azekyohe/part-00000-495c48e6-96d6-4650-aa65-3c36a3516ddd.c000.snappy.parquet
creator:           parquet-mr version 1.8.2 (build c6522788629e590a53eb79874b95f6c3ff11f16c)
extra:             org.apache.spark.sql.parquet.row.metadata = {"type":"struct","fields":[{"name":"marketplace","type":"string","nullable":true,"metadata":{}},{"name":"customer_id","type":"string","nullable":true,"metadata":{}},{"name":"review_id","type":"string","nullable":true,"metadata":{}},{"name":"product_id","type":"string","nullable":true,"metadata":{}},{"name":"product_parent","type":"string","nullable":true,"metadata":{}},{"name":"product_title","type":"string","nullable":true,"metadata":{}},{"name":"star_rating","type":"integer","nullable":true,"metadata":{}},{"name":"helpful_votes","type":"integer","nullable":true,"metadata":{}},{"name":"total_votes","type":"integer","nullable":true,"metadata":{}},{"name":"vine","type":"string","nullable":true,"metadata":{}},{"name":"verified_purchase","type":"string","nullable":true,"metadata":{}},{"name":"review_headline","type":"string","nullable":true,"metadata":{}},{"name":"review_body","type":"string","nullable":true,"metadata":{}},{"name":"review_date","type":"date","nullable":true,"metadata":{}},{"name":"year","type":"integer","nullable":true,"metadata":{}}]}

file schema:       spark_schema
--------------------------------------------------------------------------------
marketplace:       OPTIONAL BINARY O:UTF8 R:0 D:1
customer_id:       OPTIONAL BINARY O:UTF8 R:0 D:1
review_id:         OPTIONAL BINARY O:UTF8 R:0 D:1
product_id:        OPTIONAL BINARY O:UTF8 R:0 D:1
product_parent:    OPTIONAL BINARY O:UTF8 R:0 D:1
product_title:     OPTIONAL BINARY O:UTF8 R:0 D:1
star_rating:       OPTIONAL INT32 R:0 D:1
helpful_votes:     OPTIONAL INT32 R:0 D:1
total_votes:       OPTIONAL INT32 R:0 D:1
vine:              OPTIONAL BINARY O:UTF8 R:0 D:1
verified_purchase: OPTIONAL BINARY O:UTF8 R:0 D:1
review_headline:   OPTIONAL BINARY O:UTF8 R:0 D:1
review_body:       OPTIONAL BINARY O:UTF8 R:0 D:1 ★
review_date:       OPTIONAL INT32 O:DATE R:0 D:1
year:              OPTIONAL INT32 R:0 D:1 ★

row group 1:       RC:589900 TS:192293412 OFFSET:4
--------------------------------------------------------------------------------
marketplace:        BINARY SNAPPY DO:0 FPO:4 SZ:231/221/0.96 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
customer_id:        BINARY SNAPPY DO:0 FPO:235 SZ:4581545/6957912/1.52 VC:589900 ENC:RLE,PLAIN,BIT_PACKED
review_id:          BINARY SNAPPY DO:0 FPO:4581780 SZ:8637455/10463253/1.21 VC:589900 ENC:RLE,PLAIN,BIT_PACKED
product_id:         BINARY SNAPPY DO:0 FPO:13219235 SZ:5034158/8259079/1.64 VC:589900 ENC:RLE,PLAIN,BIT_PACKED
product_parent:     BINARY SNAPPY DO:0 FPO:18253393 SZ:5187236/7484331/1.44 VC:589900 ENC:RLE,PLAIN,BIT_PACKED,PLAIN_DICTIONARY
product_title:      BINARY SNAPPY DO:0 FPO:23440629 SZ:21585566/34792104/1.61 VC:589900 ENC:RLE,PLAIN,BIT_PACKED,PLAIN_DICTIONARY
star_rating:        INT32 SNAPPY DO:0 FPO:45026195 SZ:221797/221763/1.00 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
helpful_votes:      INT32 SNAPPY DO:0 FPO:45247992 SZ:276866/558457/2.02 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
total_votes:        INT32 SNAPPY DO:0 FPO:45524858 SZ:306153/590359/1.93 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
vine:               BINARY SNAPPY DO:0 FPO:45831011 SZ:962/1025/1.07 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
verified_purchase:  BINARY SNAPPY DO:0 FPO:45831973 SZ:62135/74471/1.20 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
review_headline:    BINARY SNAPPY DO:0 FPO:45894108 SZ:8309372/14205327/1.71 VC:589900 ENC:RLE,PLAIN,BIT_PACKED,PLAIN_DICTIONARY
review_body:        BINARY SNAPPY DO:0 FPO:54203480 SZ:66263112/107760057/1.63 VC:589900 ENC:RLE,PLAIN,BIT_PACKED
review_date:        INT32 SNAPPY DO:0 FPO:120466592 SZ:70391/738861/10.50 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY
year:               INT32 SNAPPY DO:0 FPO:120536983 SZ:9111/186192/20.44 VC:589900 ENC:RLE,BIT_PACKED,PLAIN_DICTIONARY

準備手順

データを S3 から HDFS にコピーする
$ ssh -i ~/mykey.pem hadoop@ec2-**-***-***-233.compute-1.amazonaws.com
  • hdfs ユーザーにスイッチする。
$ sudo su - hdfs
$ hadoop fs -mkdir /amazon-reviews-pds
  • データを S3 から HDFS にコピーする。
$ nohup s3-dist-cp --src  s3://amazon-reviews-pds/ --dest /amazon-reviews-pds  &
外部テーブルを定義する。
$ hive
> create database if not exists parquet;
^H> show databases;
> use parquet;
  • テーブルを作成する。
> CREATE EXTERNAL TABLE parquet.amazon_reviews_parquet(
  marketplace string, 
  customer_id string, 
  review_id string, 
  product_id string, 
  product_parent string, 
  product_title string, 
  star_rating int, 
  helpful_votes int, 
  total_votes int, 
  vine string, 
  verified_purchase string, 
  review_headline string, 
  review_body string, 
  review_date bigint, 
  year int)
PARTITIONED BY (product_category string)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
  'hdfs:///amazon-reviews-pds/parquet';
> MSCK REPAIR TABLE parquet.amazon_reviews_parquet;
> quit;
  • クエリを実行できることを確認する。
$ presto-cli
presto> use hive.parquet;
presto:parquet> select count(*) from amazon_reviews_parquet;
presto:parquet> select count(year) from amazon_reviews_parquet;
presto:parquet> select count(review_body) from amazon_reviews_parquet;

性能情報取得ツールインストール
$ sudo yum -y install htop sysstat dstat iotop ltrace strace perf blktrace gnuplot
$ sudo yum -y install cmake
$ git clone --depth=1 https://github.com/jrudolph/perf-map-agent
$ cd perf-map-agent
$ cmake .
$ make
  • FlameGraph
$ git clone https://github.com/brendangregg/FlameGraph
$ chmod +x FlameGraph/*.pl
$ vi ~/.bashrc
export FLAMEGRAPH_DIR=~/FlameGraph

*1VPN経由でアクセスできない

2018-10-29

KMSで別のキーマテリアルを CMK にインポートすることはできない

CMK を作成してインポートする
  • CMK を作成する。
$ aws kms create-key --origin EXTERNAL --description byok_key_test1
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "02c66c29-81b3-404b-beba-35355b4a56cc",
        "Description": "byok_key_test1",
        "KeyManager": "CUSTOMER",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1540823706.373,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/02c66c29-81b3-404b-beba-35355b4a56cc",
        "AWSAccountId": "123456789012"
    }
}
  • エイリアス名をつける。
$ aws kms create-alias --alias-name alias/byok-key-test1 --target-key-id 02c66c29-81b3-404b-beba-35355b4a56cc
  • PublicKey と ImportToken をダウンロードする。
$ aws kms get-parameters-for-import \
--key-id 02c66c29-81b3-404b-beba-35355b4a56cc \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048
  • 上記のPublicKey を PublicKey.b64、ImportToken を ImportToken.b64 というファイル名で保存する。
  • PublicKey と ImportToken をそれぞれbase64デコードして、新しいファイルで保存する。
$ openssl enc -d -a -A -in PublicKey.b64 -out PublicKey.bin
$ openssl enc -d -a -A -in ImportToken.b64 -out ImportToken.bin
  • KMS にインポートする CMK を作成する
$ openssl rand -out PlaintextKeyMaterial.bin 32
  • 生成した CMK を、デコードした PublicKey を使って暗号化する。
$ openssl rsautl -encrypt \
-in PlaintextKeyMaterial.bin \
-pkcs \
-inkey PublicKey.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial.bin
  • CMK を KMS にインポートする。
$ aws kms import-key-material --key-id 02c66c29-81b3-404b-beba-35355b4a56cc \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://ImportToken.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2018-11-01T00:00:00-00:00
  • キーの定義を確認する
$ aws kms describe-key --key-id 02c66c29-81b3-404b-beba-35355b4a56cc
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "02c66c29-81b3-404b-beba-35355b4a56cc",
        "Description": "byok_key_test1",
        "KeyManager": "CUSTOMER",
        "ExpirationModel": "KEY_MATERIAL_EXPIRES",
        "ValidTo": 1541030400.0,
        "Enabled": true,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1540823706.373,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/02c66c29-81b3-404b-beba-35355b4a56cc",
        "AWSAccountId": "123456789012"
    }
}
CMK を削除して再インポートする
  • キーマテリアルを削除する
$ aws kms delete-imported-key-material --key-id 02c66c29-81b3-404b-beba-35355b4a56cc
  • キーの定義を確認する
$ aws kms describe-key --key-id 02c66c29-81b3-404b-beba-35355b4a56cc
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "02c66c29-81b3-404b-beba-35355b4a56cc",
        "Description": "byok_key_test1",
        "KeyManager": "CUSTOMER",
        "Enabled": false, ★
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport", ★
        "CreationDate": 1540823706.373,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/02c66c29-81b3-404b-beba-35355b4a56cc",
        "AWSAccountId": "123456789012"
    }
}
  • PublicKey と ImportToken をダウンロードする。
aws kms get-parameters-for-import \
--key-id 02c66c29-81b3-404b-beba-35355b4a56cc \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048
  • 上記のPublicKey を PublicKey.b64、ImportToken を ImportToken.b64 というファイル名で保存する。
  • PublicKey と ImportToken をそれぞれbase64デコードして、新しいファイルで保存する。
$ openssl enc -d -a -A -in PublicKey.b64 -out PublicKey.bin
$ openssl enc -d -a -A -in ImportToken.b64 -out ImportToken.bin
  • KMS にインポートする CMK を作成する
$ openssl rand -out PlaintextKeyMaterial.bin 32
  • 生成した CMK を、デコードした PublicKey を使って暗号化する。
$ openssl rsautl -encrypt \
-in PlaintextKeyMaterial.bin \
-pkcs \
-inkey PublicKey.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial.bin
  • CMK を KMS にインポートする。
$ aws kms import-key-material --key-id 02c66c29-81b3-404b-beba-35355b4a56cc \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://ImportToken.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2018-11-01T00:00:00-00:00

An error occurred (IncorrectKeyMaterialException) when calling the ImportKeyMaterial operation: ★同じキーマテリアルでないため失敗する

S3 バケットのデフォルト暗号化に使う CMK を KMS で生成したものから BYOK に変えてみる

S3 バケットデフォルト暗号化に使う CMK(Customer Master Key) を KMS(Key Management Service) で生成したものから BYOK(Bring Your Own Key) に変えてみた。


手順

KMS に CMK を作成する
  • CMK を作成する
$ aws kms create-key
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "c3c1fb86-168d-40ca-9489-90cf2bd49dfa", ★
        "Description": "",
        "KeyManager": "CUSTOMER",
        "Enabled": true,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1540799362.916,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/c3c1fb86-168d-40ca-9489-90cf2bd49dfa",
        "AWSAccountId": "123456789012"
    }
}
  • エイリアス名をつける
$ aws kms create-alias --alias-name alias/kms-gen-key --target-key-id c3c1fb86-168d-40ca-9489-90cf2bd49dfa
S3バケットデフォルト暗号化を設定してファイルを Put する
$ aws s3 mb s3://kms-key-change-test
make_bucket: kms-key-change-test
$ aws s3api  put-bucket-encryption --bucket kms-key-change-test --server-side-encryption-configuration '{
  "Rules": [
    {
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "c3c1fb86-168d-40ca-9489-90cf2bd49dfa" 
      }
    }
  ]
}'
$ aws s3api get-bucket-encryption --bucket kms-key-change-test
{
    "ServerSideEncryptionConfiguration": {
        "Rules": [
            {
                "ApplyServerSideEncryptionByDefault": {
                    "KMSMasterKeyID": "c3c1fb86-168d-40ca-9489-90cf2bd49dfa", ★
                    "SSEAlgorithm": "aws:kms"
                }
            }
        ]
    }
}
  • ファイルを Put する
$ echo 'Test' > test1.txt
$ cp test1.txt test2.txt
$ cp test1.txt test3.txt
$ aws s3 cp test1.txt s3://kms-key-change-test/
upload: ./test1.txt to s3://kms-key-change-test/test1.txt
$ aws s3 cp test2.txt s3://kms-key-change-test/
upload: ./test2.txt to s3://kms-key-change-test/test2.txt
$ aws s3 cp test3.txt s3://kms-key-change-test/
upload: ./test3.txt to s3://kms-key-change-test/test3.txt
$ aws s3api head-object --bucket kms-key-change-test --key test1.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "text/plain",
    "LastModified": "Mon, 29 Oct 2018 08:01:00 GMT",
    "ContentLength": 5,
    "ETag": "\"028422466ea4c14965264d1666728a7c\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/c3c1fb86-168d-40ca-9489-90cf2bd49dfa", ★
    "Metadata": {}
}
KMS に BYOK する
  • CMK を作成する
$ aws kms create-key --origin EXTERNAL --description byok_key
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "2afa832b-d531-40fe-ac8c-4e34a578939a", ★
        "Description": "byok_key",
        "KeyManager": "CUSTOMER",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1540801553.271,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/2afa832b-d531-40fe-ac8c-4e34a578939a",
        "AWSAccountId": "123456789012"
    }
}
  • エイリアス名をつける
$ aws kms create-alias --alias-name alias/kms-byok-key --target-key-id 2afa832b-d531-40fe-ac8c-4e34a578939a
  • PublicKey と ImportToken をダウンロードする。
$ aws kms get-parameters-for-import \
--key-id 2afa832b-d531-40fe-ac8c-4e34a578939a \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048
  • 上記のPublicKey を PublicKey.b64、ImportToken を ImportToken.b64 というファイル名で保存する。
  • PublicKey と ImportToken をそれぞれbase64デコードして、新しいファイルで保存する。
$ openssl enc -d -a -A -in PublicKey.b64 -out PublicKey.bin
$ openssl enc -d -a -A -in ImportToken.b64 -out ImportToken.bin
  • KMS にインポートする CMK を作成する
$ openssl rand -out PlaintextKeyMaterial.bin 32
  • 生成した CMK を、デコードした PublicKey を使って暗号化する。
$ openssl rsautl -encrypt \
-in PlaintextKeyMaterial.bin \
-pkcs \
-inkey PublicKey.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial.bin
  • CMK を KMS にインポートする。
$ aws kms import-key-material --key-id 2afa832b-d531-40fe-ac8c-4e34a578939a \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://ImportToken.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2018-11-01T00:00:00-00:00
S3バケットデフォルト暗号化キーを BYOK した CMK に変更する
$ aws s3api put-bucket-encryption --bucket kms-key-change-test --server-side-encryption-configuration '{
  "Rules": [
    {
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "2afa832b-d531-40fe-ac8c-4e34a578939a" 
      }
    }
  ]
}'
  • デフォルト暗号化キーが変更されていることを確認する
$ aws s3api get-bucket-encryption --bucket kms-key-change-test
{
    "ServerSideEncryptionConfiguration": {
        "Rules": [
            {
                "ApplyServerSideEncryptionByDefault": {
                    "KMSMasterKeyID": "2afa832b-d531-40fe-ac8c-4e34a578939a", ★
                    "SSEAlgorithm": "aws:kms"
                }
            }
        ]
    }
}
S3のオブジェクトを Get/Put して BYOK した CMK で暗号化し直す
  • Get/Put して BYOK したキーで暗号化し直す
$ aws s3 cp s3://kms-key-change-test/test.txt ./
$ aws s3 cp test.txt s3://kms-key-change-test/
$ aws s3 cp s3://kms-key-change-test/test2.txt ./
$ aws s3 cp test2.txt s3://kms-key-change-test/
$ aws s3api head-object --bucket kms-key-change-test --key test1.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "text/plain",
    "LastModified": "Mon, 29 Oct 2018 08:37:32 GMT",
    "ContentLength": 5,
    "ETag": "\"f5b4a98e6bbdce444ebe6eaabbf5854b\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/2afa832b-d531-40fe-ac8c-4e34a578939a",
    "Metadata": {}
}
$ aws s3api head-object --bucket kms-key-change-test --key test1.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "text/plain",
    "LastModified": "Mon, 29 Oct 2018 08:37:32 GMT",
    "ContentLength": 5,
    "ETag": "\"f5b4a98e6bbdce444ebe6eaabbf5854b\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/2afa832b-d531-40fe-ac8c-4e34a578939a",
    "Metadata": {}
}
古い CMK を無効化する
  • 古いキーを無効化する
$ aws kms  disable-key --key-id c3c1fb86-168d-40ca-9489-90cf2bd49dfa
  • 無効化されていることを確認する。
$ aws kms describe-key --key-id c3c1fb86-168d-40ca-9489-90cf2bd49dfa
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "c3c1fb86-168d-40ca-9489-90cf2bd49dfa",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "Enabled": false, ★
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Disabled",
        "CreationDate": 1540799362.916,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/c3c1fb86-168d-40ca-9489-90cf2bd49dfa",
        "AWSAccountId": "123456789012"
    }
}
  • 新しいキーで暗号化し直したオブジェクトはダウンロードできる。
$ aws s3 cp s3://kms-key-change-test/test1.txt ./
download: s3://kms-key-change-test/test1.txt to ./test1.txt
$ aws s3 cp s3://kms-key-change-test/test3.txt ./
download failed: s3://kms-key-change-test/test3.txt to ./test3.txt An error occurred (KMS.DisabledException) when calling the GetObject operation: arn:aws:kms:ap-northeast-1: 123456789012:key/c3c1fb86-168d-40ca-9489-90cf2bd49dfa is disabled.
$ aws s3 ls --recursive s3://kms-key-change-test|perl -lane 'print $F[3]'|xargs -n1 aws s3api head-object --bucket kms-key-change-test --key|jq '.|@text "\(.SSEKMSKeyId)"'
"arn:aws:kms:ap-northeast-1:123456789012:key/2afa832b-d531-40fe-ac8c-4e34a578939a"
"arn:aws:kms:ap-northeast-1:123456789012:key/2afa832b-d531-40fe-ac8c-4e34a578939a"
"arn:aws:kms:ap-northeast-1:123456789012:key/c3c1fb86-168d-40ca-9489-90cf2bd49dfa"

S3のデフォルト暗号化キーはエイリアス名ではなくキーIDと紐付いてそう

AWSマネジメントコンソールでS3バケットデフォルト暗号化設定で、エイリアス名でキーを指定できるが、後で確認するとエイリアス名ではなくキーIDで表示される。


  • 設定時

f:id:yohei-a:20181029132624p:image:w360

  • 設定後に確認すると

f:id:yohei-a:20181029134347p:image:w360


AWS CLI からS3とKMSの設定を確認すると、S3バケットとエイリアス名ではなくキーIDと紐付いているように見える。

  • デフォルト暗号化キーはエイリアスではなくキーIDで指定されている。
$ aws s3api get-bucket-encryption --bucket az-test-bucket1
{
    "ServerSideEncryptionConfiguration": {
        "Rules": [
            {
                "ApplyServerSideEncryptionByDefault": {
                    "KMSMasterKeyID": "arn:aws:kms:ap-northeast-1:123456789012:key/608781a9-cf79-4e35-98dd-7efa5a109f72",
                    "SSEAlgorithm": "aws:kms"
                }
            }
        ]
    }
  • キーIDを指定してキーのメタデータを確認してもエイリアスはない。
$ aws kms describe-key --key-id 608781a9-cf79-4e35-98dd-7efa5a109f72
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "608781a9-cf79-4e35-98dd-7efa5a109f72",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "ExpirationModel": "KEY_MATERIAL_EXPIRES",
        "ValidTo": 1541059200.0,
        "Enabled": true,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1540447295.095,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/608781a9-cf79-4e35-98dd-7efa5a109f72",
        "AWSAccountId": "123456789012"
    }
}
  • エイリアス名とキーIDのマッピング表という形で持っていそうに見える。
$ aws kms list-aliases|jq '.Aliases[] | select(.AliasName=="alias/test-key")'
{
  "AliasArn": "arn:aws:kms:ap-northeast-1:123456789012:alias/test-key",
  "AliasName": "alias/test-key",
  "TargetKeyId": "608781a9-cf79-4e35-98dd-7efa5a109f72"
}

2018-10-27

EBS ボリュームの CMK を KMS で生成したものから BYOK に変更する

EBS ボリュームの CMK(Customer Master Key) を KMS で生成したものから BYOK(Bring Your Own Key) したものに変更してみた。EBS のスナップショットを取得して、スナップショットをコピーする際に CMK を変更し、EBS ボリュームを作成して EC2 にアタッチすることで CMK を変更できた。


手順

KMSにキーを作成する
  • CMK を作成する。
$ aws kms create-key
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "2ae86c99-8b8f-4bba-9998-005b2dd768ac",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "Enabled": true,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1540638331.395,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/2ae86c99-8b8f-4bba-9998-005b2dd768ac",
        "AWSAccountId": "123456789012"
    }
}
  • エイリアス名をつける。
$ aws kms create-alias --alias-name alias/ebs-kms-key --target-key-id 2ae86c99-8b8f-4bba-9998-005b2dd768ac
EC2インスタンスを作成する

f:id:yohei-a:20181027201557p:image

  • EBSのボリュームを初期化してマウントする
$ sudo mkfs -t ext4 /dev/sdb
$ sudo mkdir /ebs-enc
$ sudo chmod o+w /ebs-enc
$ sudo vi /etc/fstab
/dev/sdb    /ebs-enc    ext4    defaults        1   1 # 追記
$ sudo mount -a
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        3.9G   68K  3.9G   1% /dev
tmpfs           3.9G     0  3.9G   0% /dev/shm
/dev/xvda1      7.8G  1.1G  6.7G  14% /
/dev/xvdb        59G   52M   56G   1% /ebs-enc
EBSボリュームにデータを置く
$ aws s3 ls --recursive --human-readable --summarize s3://amazon-reviews-pds/tsv
(中略)
Total Objects: 55
   Total Size: 32.2 GiB
$ aws s3 cp --recursive s3://amazon-reviews-pds/tsv /ebs-enc/
$ ls -lh /ebs-enc|head -5
total 33G
-rw-rw-r-- 1 ec2-user ec2-user 231M Nov 24  2017 amazon_reviews_multilingual_DE_v1_00.tsv.gz
-rw-rw-r-- 1 ec2-user ec2-user  68M Nov 24  2017 amazon_reviews_multilingual_FR_v1_00.tsv.gz
-rw-rw-r-- 1 ec2-user ec2-user  91M Nov 24  2017 amazon_reviews_multilingual_JP_v1_00.tsv.gz
-rw-rw-r-- 1 ec2-user ec2-user 334M Nov 24  2017 amazon_reviews_multilingual_UK_v1_00.tsv.gz
KMSにCMKをBYOKする
  • KMS に CMK を空で作成する。
$ aws kms create-key --origin EXTERNAL --description byok_key
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "35e6c88a-0cd9-4614-9e7a-ec5782d7c1da",
        "Description": "byok_key",
        "KeyManager": "CUSTOMER",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1540639989.29,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/35e6c88a-0cd9-4614-9e7a-ec5782d7c1da",
        "AWSAccountId": "123456789012"
    }
}
  • 作成した CMK にエイリアス名をつける。
$ aws kms create-alias --alias-name alias/ebs-byok-key --target-key-id 35e6c88a-0cd9-4614-9e7a-ec5782d7c1da
  • PublicKey と ImportToken をダウンロードする。
$ aws kms get-parameters-for-import \
--key-id 35e6c88a-0cd9-4614-9e7a-ec5782d7c1da \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048
  • 上記のPublicKey を PublicKey.b64、ImportToken を ImportToken.b64 というファイル名で保存する。
  • PublicKey と ImportToken をそれぞれbase64デコードして、新しいファイルで保存する。
$ openssl enc -d -a -A -in PublicKey.b64 -out PublicKey.bin
$ openssl enc -d -a -A -in ImportToken.b64 -out ImportToken.bin
  • KMS にインポートする CMK を作成する
$ openssl rand -out PlaintextKeyMaterial.bin 32
  • 生成した CMK を、デコードした PublicKey を使って暗号化する。
$ openssl rsautl -encrypt \
-in PlaintextKeyMaterial.bin \
-pkcs \
-inkey PublicKey.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial.bin
  • 暗号化した CMK を KMS にインポートする。
$ aws kms import-key-material --key-id 35e6c88a-0cd9-4614-9e7a-ec5782d7c1da \
--encrypted-key-material fileb://EncryptedKeyMaterial.bin \
--import-token fileb://ImportToken.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2018-11-01T00:00:00-00:00

f:id:yohei-a:20181027204448p:image

EBSをBYOKしたCMKで暗号化し直す
  • アンマウントする。
$ sudo umount /ebs-enc
  • スナップショットを取得する。

f:id:yohei-a:20181027205349p:image

  • スナップショット取得完了を確認する。

f:id:yohei-a:20181027213441p:image

  • スナップショットを選択して、[アクション]-[コピー]を選択して[マスターキー]をBYOKしたCMKに変更して[コピー]をクリックする。

f:id:yohei-a:20181027213853p:image

  • スナップショットのコピーが完了したら、

f:id:yohei-a:20181027214959p:image

  • BYOKで暗号化したスナップショットを選択して、[アクション]-[ボリュームの作成]を選択して、スナップショットからEBSボリュームを作成する

f:id:yohei-a:20181027215058p:image

f:id:yohei-a:20181027215451p:image

  • 作成したEBSボリュームがBYOKしたCMKで暗号化されていることを確認する。

f:id:yohei-a:20181027220822p:image

  • EBSボリュームをマウントして確認する。
$ sudo mkdir /ebs-byok
$ sudo chmod o+w /ebs-byok
$ sudo vi /etc/fstab
/dev/sdf   /ebs-byok    ext4   defaults        1   1 #追記
$ sudo mount -a
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        3.9G   72K  3.9G   1% /dev
tmpfs           3.9G     0  3.9G   0% /dev/shm
/dev/xvda1      7.8G  1.1G  6.7G  14% /
/dev/xvdb        59G   33G   24G  58% /ebs-enc
/dev/xvdf        59G   33G   24G  58% /ebs-byok
$ cd /ebs-byok
$ ls -lh|head -5
total 33G
-rw-rw-r-- 1 ec2-user ec2-user 231M Nov 24  2017 amazon_reviews_multilingual_DE_v1_00.tsv.gz
-rw-rw-r-- 1 ec2-user ec2-user  68M Nov 24  2017 amazon_reviews_multilingual_FR_v1_00.tsv.gz
-rw-rw-r-- 1 ec2-user ec2-user  91M Nov 24  2017 amazon_reviews_multilingual_JP_v1_00.tsv.gz
-rw-rw-r-- 1 ec2-user ec2-user 334M Nov 24  2017 amazon_reviews_multilingual_UK_v1_00.tsv.gz
  • ファーストタッチペナルティを回避するためブロックデバイスのデータにアクセスする。
$ sudo dd if=/dev/xvdf of=/dev/null bs=1M

参考

S3 のデフォルト暗号化キーに使っている BYOK した CMK を入れ替える

KMS に BYOK(Bring Your Own Key) した CMK(Customer Master Key) で S3 バケットを SSE-KMS(Server-Side Encryption with AWS KMS) でデフォルト暗号化し、ファイルを S3 に Put した後、S3 のデフォルト暗号化キーを BYOK した別の CMK に変更して、S3 のオブジェクトを Get/Put して新しいキーで暗号化後に古い CMK を無効化してみた。


手順

KMS にCMKをインポートする
  • KMS に CMK を空で作成する。
$ aws kms create-key --origin EXTERNAL --description imported_key
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "d07a6b28-a314-44c0-899f-4c0b4fa18f23",
        "Description": "imported_key",
        "KeyManager": "CUSTOMER",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1540532700.471,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/d07a6b28-a314-44c0-899f-4c0b4fa18f23",
        "AWSAccountId": "123456789012"
    }
}
  • 作成した CMK にエイリアス名をつける。
$ aws kms create-alias --alias-name alias/rotation-test-key --target-key-id d07a6b28-a314-44c0-899f-4c0b4fa18f23
  • PublicKey と ImportToken をダウンロードする。
$ aws kms get-parameters-for-import \
--key-id d07a6b28-a314-44c0-899f-4c0b4fa18f23 \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048
{
    "ParametersValidTo": 1540625003.173,
    "PublicKey": "...",
    "ImportToken": "..."
}
  • 上記のPublicKey を PublicKey1.b64、ImportToken を ImportToken1.b64 というファイル名で保存する。
  • PublicKey と ImportToken をそれぞれbase64デコードして、新しいファイルで保存する。
$ openssl enc -d -a -A -in PublicKey1.b64 -out PublicKey1.bin
$ openssl enc -d -a -A -in ImportToken1.b64 -out ImportToken1.bin
  • KMS にインポートする CMK を作成する
$ openssl rand -out PlaintextKeyMaterial1.bin 32
  • 生成した CMK を、デコードした PublicKey を使って暗号化する。
$ openssl rsautl -encrypt \
-in PlaintextKeyMaterial1.bin \
-pkcs \
-inkey PublicKey1.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial1.bin
  • 暗号化した CMK を KMS にインポートする。
$ aws kms import-key-material --key-id d07a6b28-a314-44c0-899f-4c0b4fa18f23 \
--encrypted-key-material fileb://EncryptedKeyMaterial1.bin \
--import-token fileb://ImportToken1.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2018-11-01T00:00:00-00:00
S3バケットを作成し BYOK した CMK でデフォルト暗号化設定する
$ aws s3 mb s3://kms-key-rotation-test-bucket
make_bucket: kms-key-rotation-test-bucket
$ aws s3api put-bucket-encryption --bucket kms-key-rotation-test-bucket --server-side-encryption-configuration '{
   "Rules": [
     {
       "ApplyServerSideEncryptionByDefault": {
         "SSEAlgorithm": "aws:kms",
         "KMSMasterKeyID": "d07a6b28-a314-44c0-899f-4c0b4fa18f23"
       }
     }
   ]
}'
S3 にファイルを Put する
  • ファイルを S3 に Put する
$ echo 'kms key rotation test 1' > kms-key-rotation-test1.txt
$ aws s3 cp kms-key-rotation-test1.txt s3://kms-key-rotation-test-bucket/
$ echo 'kms key rotation test 2' > kms-key-rotation-test2.txt
$ aws s3 cp kms-key-rotation-test2.txt s3://kms-key-rotation-test-bucket/
$ aws s3api head-object --bucket kms-key-rotation-test-bucket --key kms-key-rotation-test1.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "text/plain",
    "LastModified": "Fri, 26 Oct 2018 07:47:48 GMT",
    "ContentLength": 24,
    "ETag": "\"97138b7a0ea21fd4607973bd6cbd83b5\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/d07a6b28-a314-44c0-899f-4c0b4fa18f23",
    "Metadata": {}
}
新しい CMK をインポートする
  • KMS に CMK を空で作成する。
$ aws kms create-key --origin EXTERNAL --description imported_key
{
    "KeyMetadata": {
        "Origin": "EXTERNAL",
        "KeyId": "1d3829b7-a35d-44fb-8f1d-41fc5ed229d8",
        "Description": "imported_key",
        "KeyManager": "CUSTOMER",
        "Enabled": false,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "PendingImport",
        "CreationDate": 1540540340.387,
        "Arn": "arn:aws:kms:ap-northeast-1:123456789012:key/1d3829b7-a35d-44fb-8f1d-41fc5ed229d8",
        "AWSAccountId": "123456789012"
    }
}
  • PublicKey と ImportToken をダウンロードする。
$ aws kms get-parameters-for-import \
--key-id 1d3829b7-a35d-44fb-8f1d-41fc5ed229d8 \
--wrapping-algorithm RSAES_PKCS1_V1_5 \
--wrapping-key-spec RSA_2048
{
    "ParametersValidTo": 1540626803.766,
    "PublicKey": "...",
    "ImportToken": "..."
}
  • 上記のPublicKey を PublicKey2.b64、ImportToken を ImportToken2.b64 というファイル名で保存する。
  • PublicKey と ImportToken をそれぞれbase64デコードして、新しいファイルで保存する。
$ openssl enc -d -a -A -in PublicKey2.b64 -out PublicKey2.bin
$ openssl enc -d -a -A -in ImportToken2.b64 -out ImportToken2.bin
  • KMSにインポートする CMK を作成する
$ openssl rand -out PlaintextKeyMaterial2.bin 32
  • 生成した CMK を、デコードした PublicKey を使って暗号化する。
$ openssl rsautl -encrypt \
-in PlaintextKeyMaterial2.bin \
-pkcs \
-inkey PublicKey2.bin \
-keyform DER \
-pubin \
-out EncryptedKeyMaterial2.bin
  • 暗号化した CMK を KMS にインポートする。
$ aws kms import-key-material --key-id 1d3829b7-a35d-44fb-8f1d-41fc5ed229d8 \
--encrypted-key-material fileb://EncryptedKeyMaterial2.bin \
--import-token fileb://ImportToken2.bin \
--expiration-model KEY_MATERIAL_EXPIRES \
--valid-to 2018-11-01T00:00:00-00:00
S3 のデフォルト暗号化キーを変更する
  • S3 のデフォルト暗号化キーを新しく作成した CMK に変更する。
$ aws s3api put-bucket-encryption --bucket kms-key-rotation-test-bucket --server-side-encryption-configuration '{
   "Rules": [
     {
       "ApplyServerSideEncryptionByDefault": {
         "SSEAlgorithm": "aws:kms",
         "KMSMasterKeyID": "1d3829b7-a35d-44fb-8f1d-41fc5ed229d8"
       }
     }
   ]
}'
  • エイリアス"rotation-test-key"のキーIDを確認する。
$ aws kms list-aliases | jq '.Aliases[] | select(.AliasName=="alias/rotation-test-key")'
{
  "AliasArn": "arn:aws:kms:ap-northeast-1:123456789012:alias/rotation-test-key",
  "AliasName": "alias/rotation-test-key",
  "TargetKeyId": "d07a6b28-a314-44c0-899f-4c0b4fa18f23"
}
  • エイリアスに紐づく CMK を変更する。
$ aws kms update-alias --alias-name alias/rotation-test-key --target-key-id 1d3829b7-a35d-44fb-8f1d-41fc5ed229d8
  • エイリアス"rotation-test-key"のキーIDが変わったことを確認する
$ aws kms list-aliases | jq '.Aliases[] | select(.AliasName=="alias/rotation-test-key")'
{
  "AliasArn": "arn:aws:kms:ap-northeast-1:123456789012:alias/rotation-test-key",
  "AliasName": "alias/rotation-test-key",
  "TargetKeyId": "1d3829b7-a35d-44fb-8f1d-41fc5ed229d8"
}
新しい CMK でオブジェクトを暗号化し直す
$ aws s3api head-object --bucket kms-key-rotation-test-bucket --key kms-key-rotation-test1.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "text/plain",
    "LastModified": "Fri, 26 Oct 2018 07:47:48 GMT",
    "ContentLength": 24,
    "ETag": "\"97138b7a0ea21fd4607973bd6cbd83b5\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/d07a6b28-a314-44c0-899f-4c0b4fa18f23",
    "Metadata": {}
}
$ aws s3 cp s3://kms-key-rotation-test-bucket/kms-key-rotation-test1.txt ./
download: s3://kms-key-rotation-test-bucket/kms-key-rotation-test1.txt to ./kms-key-rotation-test1.txt
$ aws s3 cp kms-key-rotation-test1.txt s3://kms-key-rotation-test-bucket/
upload: ./kms-key-rotation-test1.txt to s3://kms-key-rotation-test-bucket/kms-key-rotation-test1.txt
  • Put し直したオブジェクトが新しいキーで暗号化されていることを確認する
$ aws s3api head-object --bucket kms-key-rotation-test-bucket --key kms-key-rotation-test1.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "text/plain",
    "LastModified": "Fri, 26 Oct 2018 08:43:18 GMT",
    "ContentLength": 24,
    "ETag": "\"a66d75d4b8183e6d8475ec2da993e553\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/1d3829b7-a35d-44fb-8f1d-41fc5ed229d8",
    "Metadata": {}
}
古いキーを無効化する
  • 古いキーを無効化する
$ aws kms  disable-key --key-id d07a6b28-a314-44c0-899f-4c0b4fa18f23
  • 新しいキーで暗号化し直したオブジェクトはダウンロードできる。
$ aws s3 cp s3://kms-key-rotation-test-bucket/kms-key-rotation-test1.txt ./
download: s3://kms-key-rotation-test-bucket/kms-key-rotation-test1.txt to ./kms-key-rotation-test1.txt
$ aws s3 cp s3://kms-key-rotation-test-bucket/kms-key-rotation-test2.txt ./
download failed: s3://kms-key-rotation-test-bucket/kms-key-rotation-test2.txt to ./kms-key-rotation-test2.txt An error occurred (KMS.DisabledException) when calling the GetObject operation: arn:aws:kms:ap-northeast-1:123456789012:key/d07a6b28-a314-44c0-899f-4c0b4fa18f23 is disabled.

参考