Study Notes - Key Management Service


整理 Key Management Service (KMS) 的學習筆記,包含以下:

  • 一、基本概念
  • 二、基本使用
  • 三、整合應用
  • 四、常見問答

KMS 需要有密碼學與資訊安全的概念,所以另外整理 摘要密碼學與資訊安全 的筆記。


一、基本概念

Customer Master Keys (CMKs)

  • Customer Master Keys (CMKs, 客戶主金鑰) 是 KMS 主金鑰 (Master Key) 的表示方式,它是個邏輯概念。
  • CMK 的 中繼資料 (metadata) 包含 Key ID, creation date, description, and key state.
  • KMS 的 CMK 支援對稱式與非對稱式加密演算法、也支援 橢圓曲線密碼學 ECC (Elliptic Curve Cryptography)
    • 對稱式 (Symmetric CMK): 256-bit key 加、解密。
    • 非對稱式 (Asymmetric CMK):使用 RSA key pair 做: 1) 加解密、2) 簽章驗證。
  • CMK 儲存在 AWS KMS,而且不會沒加密的離開 AWS KMS。
  • CMK 的使用政策 (Policy):
    • 分成 Key Administrators、Key Users、其他 AWS acccounts
    • 前兩者都是 IAM User / IAM Role,透過 IAM Policy 管理授權。
  • 限制:
    • CMK 可以加密的資料大小為 4KB
    • 如果要加密更大的資料,如放在 S3 裡的大型資料,那麼就透過 CMK 產生的 Data Key 加密資料。詳細後面 Data Key 描述。
  • CMK 有三種類型:Customer managed CMK (客戶管理的 CMK)、AWS managed CMK (AWS 管理的 CMK)、AWS owned CMK (AWS 擁有的 CMK),三種的 Metadata、可管理、使用範圍、Rotation 機制如下圖:

非對稱式 CMK

提供 公鑰 (Public Key)、私鑰 (Private Key) 的非對稱金鑰,可以用在 1) 加解密 和 2) 簽章驗證 兩種使用方式,只能擇一。

  • 加解密 (Encrypt and descrypt): 提供三種 Key spec: RSA_2048, RSA_3072, RSA_4096
  • 簽章驗證 (Sing and Verify): 提供以下 Key Spec:RSA_2048, RSA_3072, RSA_4096, ECC_NIST_P256, ECC_NIST_P384, ECC_NIST_P521, ECC_SECG_P256K1

Customer managed CMK

  • 可完全管理 CMK,包含建立、維護金鑰策略、IAM Policy、Alias、Tags、刪除排程 .. 等
  • 使用 DescribeKey 查詢 KeyManager 欄位會顯示 CUSTOMER
  • 包含管理和使用 CMK 的 IAM users
  • 允許跨 AWS 帳號授權
  • CM-CMK 每月會產生費用

AWS managed CMK

  • 你的 AWS 帳號裡受 AWS 管理的 CMK,他的管理政策由 AWS 管理。
  • 他的 alias 格式固定為: aws/service-name,例如 aws/s3
  • 使用 DescribeKey 查詢 KeyManager 欄位會顯示 AWS
  • AM-CMK 不需要支付管理費用,但是超過免費試用的要收錢。

AWS owned CMK

  • 由 AWS 擁有的、跨 AWS 帳號的。
  • 無法在 KMS 介面看到

Data Keys (資料金鑰)

資料金鑰 (Data Keys) 是個 加密密鑰 (encryption key),可以用來加密 大型資料。KMS 本身不會儲存、追蹤、管理 Data Key,使用者必須自己管理。Data Key 的使用情境有以下三種:

建立資料金鑰

使用 對稱式 CMK,選擇加密演算法,然後產生 Plaintext Data Key (明文資料金鑰)、或者 Encrypted data key (加密資料金鑰)。要注意的是,不能使用非對稱 CMK 產生 Data Key。其中加密演算法支援 AES_256, AES_128。使用流程如下圖(取自官方文件):

AWS CLI:

使用資料金鑰 加密 資料

資料金鑰主要是讓使用者可以在沒有 KMS 的環境進行加密動作,可以使用 OpenSSL 或者 AWS Encryption SDK 產生 Ciphertext Data (密文資料)Data KeyCiphertext Data 即使被竊取,也無法解開加密資料。其流程圖如下(取自官方文件):

使用資料金鑰解密

解密則需要透過 encrypt,這時候需要 CMK 才能解開加密資料,流程圖如下(取自官方文件):

AWS CLI: encrypt


二、基本使用

使用 CMK

下圖是我整理的 CMK 狀態機,也是整個運作的生命週期圖,圖中主要的狀態有:1) Creating, 2) Enabled, 3) Disabled, 4) Pending Delteion, 5) Deleted

註記:這圖是我自己畫了,建議 AWS 應該都要有這種狀態機流程圖,比較容易理解。類似的案例,在 Study Notes - CloudFomration Stack 我也自己整理的狀態機。

底下依照狀態改變過程的使用情境,以 CLI 整理。

建立

先準備一個 IAM Policy 檔案,建議先從 Console 複製一份修改,底下是建立 對稱式 CMK

1
2
3
4
aws kms create-key \
--key-usage "ENCRYPT_DECRYPT" \
--description "symmetric key" \
--policy "$(cat policy.json)"

使用 CLI 要注意 Policy 的準備,確立 admin / user 都有指定正確,否則後續會無法操作,建議先從 Console 建立一個,然後複製 policy 來改。否則會出現如下圖的狀況:

為了方便識別 CMK,KMS 提供以下的識別格式:

  1. CMK ID: 123456-1234-1234-1234-abcdefghijk
  2. ARN with CMK ID: arn:aws:kms:us-west-2:123456789012:alias/test-key
  3. Alias: alias/test-key
  4. ARN with Alias: arn:aws:kms:us-west-2:123456789012:key/123456-1234-1234-1234-abcdefghijk

底下是建立 Alias 方式:

1
2
3
4
CMK_ID="aabbccdd-4444-5555-6666-778899001122"
aws kms create-alias \
--alias-name "alias/test-encryption-key" \
--target-key-id ${CMK_ID}

查詢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
## Customer Managed CMK
aws kms describe-key \
--key-id ${CMK_ID}
{
"KeyMetadata": {
"AWSAccountId": "123456789012",
"KeyId": "a23456-1234-1234-1234-abcdefghijk",
"Arn": "arn:aws:kms:us-west-2:123456789012:key/a23456-1234-1234-1234-abcdefghijk",
"CreationDate": "2020-03-03T22:29:40.426000+08:00",
"Enabled": true,
"Description": "",
"KeyUsage": "ENCRYPT_DECRYPT",
"KeyState": "Enabled",
"Origin": "AWS_KMS",
"KeyManager": "CUSTOMER",
"CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
"EncryptionAlgorithms": [
"SYMMETRIC_DEFAULT"
]
}
}

## AWS Managed CMK
aws kms describe-key \
--key-id ${CMK_ID}
{
"KeyMetadata": {
"AWSAccountId": "123456789012",
"KeyId": "123456-1234-1234-1234-abcdefghijk",
"Arn": "arn:aws:kms:us-west-2:123456789012:key/123456-1234-1234-1234-abcdefghijk",
"CreationDate": "2019-06-03T23:17:42.544000+08:00",
"Enabled": true,
"Description": "Default master key that protects my S3 objects when no other key is defined",
"KeyUsage": "ENCRYPT_DECRYPT",
"KeyState": "Enabled",
"Origin": "AWS_KMS",
"KeyManager": "AWS",
"CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
"EncryptionAlgorithms": [
"SYMMETRIC_DEFAULT"
]
}
}

加密資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## 大小在 4KiB 以內
PLAINTEXT_PATH="plain_data.txt"
CIPHERTEXT_PATH="encrypted_data.bin"

## 加密:測試加密結果
aws kms encrypt \
--key-id ${CMK_ID} \
--plaintext fileb://${PLAINTEXT_PATH} \
--output text \
--query CiphertextBlob

## 加密:轉成 Base64
aws kms encrypt \
--key-id ${CMK_ID} \
--plaintext fileb://${PLAINTEXT_PATH} \
--output text \
--query CiphertextBlob | base64 --decode > ${CIPHERTEXT_PATH}

解密

解密 (Decrypt),不需要指定 CMK_ID。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CIPHERTEXT_PATH="encrypted_data.bin"
PLAINTEXT_PATH="plaintext.data"

## 解密:測試解密,直接輸出
aws kms decrypt \
--ciphertext-blob fileb://${CIPHERTEXT_PATH} \
--output text \
--query Plaintext

## 解密:解 Base64 encoding
aws kms decrypt \
--ciphertext-blob fileb://${CIPHERTEXT_PATH} \
--output text \
--query Plaintext | base64 --decode > ${PLAINTEXT_PATH}

刪除

CMK 可以被刪除,但是為了避免因為刪除,造成資料永久無法解密,所以流程是:

  1. 必須先 Disable,這時候無法用這把 CMK 加密、解密,會出現類似這樣的訊息:
    • 加密:An error occurred (DisabledException) when calling the Encrypt operation: arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab is disabled.
    • 解密:An error occurred (DisabledException) when calling the Decrypt operation: arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab is disabled.
    • 如果反悔,只要重新 Enable 即可,馬上會生效。
  2. 再執行 Schedule Key deletion (至少是七天後),這時候如果執行 encrypt 會出現這樣的錯誤訊息:
    • 加密:An error occurred (KMSInvalidStateException) when calling the Encrypt operation: arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab is pending deletion.
    • 解密:An error occurred (KMSInvalidStateException) when calling the Decrypt operation: arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab is pending deletion.
    • 如果反悔可以 Cancel Key Deletion,然後要再 Enable 才可以使用。

官方文件針對 CMK 狀態,可以執行那一些動作整理了一份列表,主要是針對 CMK 狀態 與 Action 的排列組合,詳細參閱 Key State Affects。這列表基本上跟 Redmine Workflow 的狀態與角色切換列表差不多概念。

使用 Data Key

底下紀錄使用 Data Key 的情境,包含:

  1. 產生 Data Key,取得 CiphertextBlob, Plaintext
  2. 透過 openssl 使用 Data Key 加密
  3. 使用 CMK 解密

產生 Data Key

要注意的是,Data Key 並不會被 AWS KMS 保管,所以產生出來之後,要自己存好。

底下例子會建立 Data Key,過程中需要把 CiphertextBlobPlaintext 用 Base64 解開。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
STEP01_DATA_KEY="01_data-key.json"
STEP01_CIPHERTEXT_BLOB_DEC="01_ciphertext_blob.dec"
STEP01_PLAINTEXT_DEC="01_plaintext_key.dec"

## 01-1. 產生 Data Key
aws kms generate-data-key \
--key-id ${CMK_ID} \
--key-spec AES_256 \
--output json > ${STEP01_DATA_KEY}

## 01-2. 確認 Data Key 內容,資料結構如下:
cat ${STEP01_DATA_KEY}
{
"CiphertextBlob": "AQIDAHgVetQ51Hwjs ... 略 ... st7WseW4zyHcCNA==",
"Plaintext": "AfBepF8/h ... 略 ... RgyQMR/WXenU=",
"KeyId": "arn:aws:kms:us-west-2:123456789012:key/123456-1234-1234-1234-abcdefghijk"
}

## 01-3. 解開 CiphertextBlob
cat ${STEP01_DATA_KEY} | jq -r .CiphertextBlob | base64 --decode > ${STEP01_CIPHERTEXT_BLOB_DEC}

## 01-4. 解開 Plaintext
cat ${STEP01_DATA_KEY} | jq -r .Plaintext | base64 --decode > ${STEP01_PLAINTEXT_DEC}

## 01-5. 銷毀 Data Key
shred \
--iterations=100 \
--remove=wipesync \
--zero ${STEP01_DATA_KEY}

加密資料

使用 OpenSSL 加密資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
STEP2_ORIGIN_DATA="./02_origin-data/database-0000.sql"
STEP2_ENC_DATA="./02_enc-data/database-0000.sql.enc"

## 02-1. 使用 OpenSSL,透過 Plaintext 加密資料。
openssl enc -aes-256-cbc \
-kfile ${STEP01_PLAINTEXT_DEC} \
-in ${STEP2_ORIGIN_DATA} \
-out ${STEP2_ENC_DATA}

## 02-2. 檢查
head ${STEP2_ENC_DATA}
Salted__iN>s�����1I1-]U��O��X�&?�

## 02-3. 銷毀 plaintext key
shred \
--iterations=100 \
--remove=wipesync \
--zero ${STEP01_PLAINTEXT_DEC}

解密資料

流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
STEP03_PLAINTEXT_DEC="03_plaintext_key.dec"
STEP03_DEC_DATA="./03_dec-data/database-0000.sql"

## 03-1. 使用 CiphertextBlob 取得 Plaintext
aws kms decrypt \
--ciphertext-blob fileb://./${STEP01_CIPHERTEXT_BLOB_DEC}
{
"CiphertextBlob": "AQIDAHgVetQ51Hwjs ... 略 ... st7WseW4zyHcCNA==",
"Plaintext": "AfBepF8/h ... 略 ... RgyQMR/WXenU=",
"KeyId": "arn:aws:kms:us-west-2:123456789012:key/123456-1234-1234-1234-abcdefghijk"
}

## 03-2. 取得 Plaintext,並且用 Base64 還原
aws kms decrypt \
--ciphertext-blob fileb://./${STEP01_CIPHERTEXT_BLOB_DEC} \
--query 'Plaintext' \
--output text | base64 -d > ${STEP03_PLAINTEXT_DEC}

## 03-3. 用 OpenSSL 解密檔案
openssl aes-256-cbc -d \
-kfile ${STEP03_PLAINTEXT_DEC} \
-in ${STEP2_ENC_DATA} \
-out ${STEP03_DEC_DATA}

## 03-4. 確認資料已經還原
head ${STEP03_DEC_DATA}
-- MySQL dump 10.13 Distrib 5.1.66, for redhat-linux-gnu (x86_64)
--
-- Host: localhost Database: QoO
-- ------------------------------------------------------
-- Server version 8.0.66
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;

三、整合應用

KMS 整合很多 AWS Services,簡單列舉如下:

  1. S3
  2. Secrets Manager
  3. SSM Parameter Store
  4. EBS
  5. SES
  6. RDS
  7. DynamoDB
  8. CloudTrail
  9. Lambda
  10. EMR
  11. Transcoder
  12. Redshift

四、常見問答

Q: 每個 CMK 有自己的 Admin / User 清單,那麼還需要授權給個別的 IAM User?

實測過,IAM User encrypt / decrypt 的權限由 CMK 的 Key Policy 管理。

Q: API Operation (e.g., Encrypt, Decrypt, GenerateDataKey) 有沒有 Rate Limit?

依照官方文件 KMS - Limits 的描述,主要的動作 (Decrypt, Encrypt, Generate*, ReEncrypt),在大部分的 Region RPS 都是 5000,us-east-1 / us-west-2 / eu-west-1 為 10,000。這些 RPS 是 Shared.

Q: Key Rotation 時,CMK 的 key ID, ARN, Region … 會改變嗎?

不會。

Q: 如何知道 KMS 的使用狀況?

用 CloudWatch,Namespace: AWS/KMS,相關文件 Monitoring with Amazon CloudWatch

Q: 什麼時候用 CMK?什麼時候要用 Data Key?

Data Key 可以在沒有 KMS 的環境加密資料、也可以加密大型檔案。


延伸閱讀

站內延伸

參考資料:官方文件

AWS CLI

參考資料




Comments