AWS Nitro EnclavesのKMSとの連携 Hands-On

# Overview

この記事は [Getting started with cryptographic attestation: KMS Tool sample application](https://docs.aws.amazon.com/enclaves/latest/user/hello-kms.html)をより一層わかりやすく理解することを目的としています。

チュートリアルだと以下の理解で時間が必要でした

- チュートリアルのため親インスタンスにすべての権限をつけて1台のインスタンスでテストできる構成をとっている
- そのため[Enclaves workflow](https://docs.aws.amazon.com/enclaves/latest/user/using.html)との整合性が犠牲になっており、各種権限周りの理解が難しくなっている
- Debugのセクションがかえって全体の見通しを悪くしているように感じた(必要性は理解できるが付録でもよいかも)

ここではインスタンス2台分必要ですが、分かりやすさを重視してこのように進めます。


## 登場人物

[Enclaves workflow](https://docs.aws.amazon.com/enclaves/latest/user/using.html)を参考に、3人の登場人物とその権限周りを明らかにします。

- データ所有者用: KMSのマスターキーの管理者。今回はCustomer Managed Key(CMK)を作成する
- 親インスタンスを管理者: 親インスタンスを所有しenclaveのライフサイクルを管理する
- アプリケーション管理者: enclaveと親インスタンスで実行されるアプリケーションを開発する

| 登場人物               | Users Guide 記載の役割                                                                                                                                                                                                                                                                                                      | このHands-Onで何を行うか？                                                                                                                                                                                                                              | 
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 
| データ所有者           | 秘密データを暗号化し、暗号化データと暗号化データキーを利用可能にする責任がある<br><br>**必要な権限**<br>- CMK作成権限/削除権限<br>- kms-encrypt権限                                                                                                                                                                         | (1) データを暗号化するインスタンスt2.microを起動しデータの暗号化を行う<br>(2) 以下の情報をCMKのキーポリシーに登録する<br>- 親インスタンスにアタッチするIAM RoleのARNを登録する<br>- EnclaveのPCR0の情報をキーポリシーに登録する                         | 
| 親インスタンス管理者   | 親インスタンスを起動し環境を起動する<br><br>**必要な権限**<br>- kms-decrypt を呼び出す権限<br>ただし、このリクエストはenclaveの内部から行われ、KMS キーポリシーの条件キーに一致する値を含んでいる場合のみ成功する<br><br>**持ってはいけない権限**<br>- KMS鍵を使った暗号化操作を行う権限<br>- KMS鍵のポリシーを変更する権限 | (1) 親インスタンスを起動し、Enclaveを起動する<br>(2) IAM RoleのARNとPCR0の情報をデータ所有者に提供する<br>(3) vsock-proxyを起動する<br>(4) 暗号化されたメッセージを受け取りEnclaveに送る。<br>(5) Enclaveから復号化された結果を標準出力から得る<br><br> | 
| アプリケーション管理者 | アプリケーションをenclaveのイメージファイルまたはDockerイメージにパッケージして親インスタンス管理者に提供する<br><br>アプリケーション開発者は、親インスタンス自体で動作するアプリケーションを開発することもある                                                                                                             | 今回は作業はありません。親インスタンスにDocker Imageをすでに提供済みという前提で進めます                                                                                                                                                                | 

## Hands-Onの概要

### Hands-Onでやりたいこと

下の図は主に以下の3つで構成されています。

- 親インスタンスとEncloveがあるインスタンス
- データ暗号化用のインスタンス
- KMS

やりたいこととしては以下です。

- 基本的には、エンベロープ暗号化のデータキーをわかりやすさのため "Hello, KMS\!" とし、このデータキーがEnclave内でPlaneに戻るまでを模擬することを目的とします
- エンベロープ暗号化でいう実際のデータの暗号化/復号化に関しては議論していないことに注意してください
- [aws-nitro-enclaves-sdk-c](https://github.com/aws/aws-nitro-enclaves-sdk-c)を詳細に見られていないので、実際のデータキーのPlane状態はKMS内で得られているのか？もう一度Enclave内でPrivateKeyを使って復号化しているのか？そこまでは分析できていません。わかり次第記載したいと思います。


![](https://docs.google.com/drawings/d/e/2PACX-1vTt5JsPHsCXF0fMjg7uaVlJKkexownVWyqVpqDYa1Z2ng9j2t6mNr2iiYntRKV11wxR4Sbyzwhienbp/pub?w=1036&h=622)

### Hands-Onの流れ

このHans-Onの構成図と全体の流れを以下に示します。

![](https://docs.google.com/drawings/d/e/2PACX-1vQxIbVopdRTAQ6n_tyPtv3TqWb2fNNMoNcM38rOot-Wq1pCe4Y5EEqU8Y5HvdmHz13tuiCfakX0si6-/pub?w=1036&h=622)

### 親インスタンスとEnclaveで動作するアプリケーション

KMS Tool sample application に含まれる２つのアプリケーションが親インスタンスで起動します。

- `kmstool-enclave`
    - Enclaveで動作します
    - 認証を使ってKMSを呼び出し、インスタンス側から受け取ったメッセージを復号化するアプリケーションです
- `kmstool-instance`
    - 親インスタンス上で実行され、kmstool-enclaveに接続します
    - kmstool-enclaveに接続し、資格情報をenclaveに渡し次にEnclaveにbase64でエンコードされたメッセージの復号を要求します


### 親インスタンスとEnclave間の通信

親インスタンスで動作する`kmstool-enclave`とEnclaveで動作する`kmstool-instance`間の通信

- vsock-proxyを介して通信
- 通信プロトコル: 標準的な `AF_VSOCK`ソケット(posixのSOCK_STREAMソケットに似ている)
- Format: JSONスキーマ

### CMK(Customer Managed Key)のキーポリシー

- AWS Keymanagement Serviceの機能の一つ
- 必要なARNと`nitro-cli`でenclaveイメージ`kmstool.eif`作成時に得られる`PCR0`の情報を登録する
- データ提供者に設定する

### 補足: システム管理者について

今回は上記表にない、システム管理者ロールを儲けています。UserGuideへの記載はありませんが、公式のチュートリアルで、その存在を確認できます。閲覧/変更/削除など暗号化/復号化以外のCMKに対する操作権限を持っています。
システムによっては、データ所有者に代わってシステム管理者がCMK作成とキーポリシーの設定を行うほうが自然な場合もあると推測されます。

Hands-on
===========================

STEP1 [データ提供者] encryption用インスタンスの起動 (t2.micro)
-------------------------------------------

### 1.1 IAM Roleの作成

まず始めにアタッチするIAM ROLEを作成します。
1. IAM > [Roles](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/roles)の画面の操作
    - `Create Role` ボタンをクリック
2. Select trusted entity の画面での操作
    - `AWS service` を選択
    -  Use Caseとして`EC2`を選択
    -  `Next` をクリック
3. Add permissionsの画面
    - 何でもよいですが、今回は `AmazonSSMManagedInstanceCore`を選択します。インスタンスの接続が便利になります。
    - `Next`をクリック
4. Name, review, and create
    - 今回は、`20230115_EncryptionForEnclaveTest`という名前にします。
    - その他はデフォルトとし`Create Role`のボタンをクリックします。

### 1.2 Instanceの起動

Encryption用インスタンスを以下のように起動します。その他はデフォルトでOKです。

1. **EC2 > [Incetances](https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#Instances:v=3;$case=tags:true%5C,client:false;$regex=tags:false%5C,client:false)**
    - Instancesのメニュを開き、`Launch Instances` のボタンをクリックします
2. **Launch an instance**
    - Name and tags
        - Nameに`EncryptionForDataProvider`を入力します。任意の名前でOKです。
    - Application and OS Images (Amazon Machine Image)
        - `Amazon Linux`を選択します。現時点におけるAMIは`ami-0b5eea76982371e91`でした
    - Instance type
        - `t2.micro`を選択します。
    - Key pair (login)
        - 適当なキーを選択します。無ければ作成してもOKです
    - Advance Details
        - `AM instance profile` で先程作成した、`20230115_EncryptionForEnclaveTest` を選択します。
    - 設定が終わったら、`Launch Instance`のボタンをクリックします。
        - その他はデフォルト設定でOKです。

設定が終わったら作成したRoleの画面を開いて`ARN`の情報をメモして起きましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73207/3605bff2-ede0-ec11-ea16-ec3d4f265e9a.png)

```bash
arn:aws:iam::<Account ID>:role/20230115_EncryptionForEnclaveTest
```

### 1.3 Instanceの起動確認

1. 以下の図のように起動したInstanceの`Connect to Instance`の画面を開きます
2. `Session Manager`のタブから`Connect`のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73207/fa9eac2e-ff04-fcda-1958-5d9f42c7a95f.png)

うまくいけば、ブラウザー上にTerminalが開きます。以下を実施しユーザを`ec2-user`に変更します。

```bash
sudo su - ec2-user
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73207/b4ddc4af-ca1b-3954-9d01-5a99649c2134.png)

これで正しくロールがアタッチできていることを確認しました。またこのインスタンスの接続はsshでも良いですし、このSession Managerを通じた方法でも良いです。

STEP2: [親インスタンス管理者] 親インスタンスの起動 (m5.xlarge)
-----------------------------------------------------------------

### 2.1 IAM Roleの作成 (親インスタンス用)

まず始めにアタッチするIAM ROLEを作成します。

1. IAM > [Roles](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/roles)の画面の操作
    - `Create Role` ボタンをクリック
2. Select trusted entity の画面での操作
    - `AWS service` を選択
    -  Use Caseとして`EC2`を選択
    -  `Next` をクリック
3. Add permissionsの画面
    - 何でもよいですが、今回は `AmazonSSMManagedInstanceCore`を選択します。インスタンスの接続が便利になります。
    - `Next`をクリック
4. Name, review, and create
    - 今回は、`20230115_DecryptionForEnclaveTest`という名前にします。
    - その他はデフォルトとし`Create Role`のボタンをクリックします。
   
親インスタンスも同様に設定が終わったら作成したRoleの画面を開いて`ARN`の情報をメモして起きましょう。

```bash
arn:aws:iam::<Account ID>:role/20230115_DecryptionForEnclaveTest
```

### 2.2 Instanceの起動 (m5.xlarge)

Encryption用インスタンスを以下のように起動します。その他はデフォルトでOKです。

1. **EC2 > [Incetances](https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#Instances:v=3;$case=tags:true%5C,client:false;$regex=tags:false%5C,client:false)**
    - Instancesのメニュを開き、`Launch Instances` のボタンをクリックします
2. **Launch an instance**
    - Name and tags
        - Nameに`EnclaveTest`を入力します。任意の名前でOKです。
    - Application and OS Images (Amazon Machine Image)
        - `Amazon Linux`を選択します。現時点におけるAMIは`ami-0b5eea76982371e91`でした
    - Instance type
        - `m5.xlarge`を選択します。Nitro Enclaveを有効化できるインスタンスには制限があります。このインスタンスはEnclave環境を有効化できます。
    - Key pair (login)
        - 適当なキーを選択します。無ければ作成してもOKです
    - Advance Details
        - `AM instance profile` で先程作成した、`20230115_DecryptionForEnclaveTest` を選択します。
        - `Nitro Enclave`のSelect Menuから`Enable`を選択します。
    - 設定が終わったら、`Launch Instance`のボタンをクリックします。


### 2.3 Instanceの起動確認

先程と同様に、

1. 以下の図のように起動したInstanceの`Connect to Instance`の画面を開きます
2. `Session Manager`のタブから`Connect`のボタンをクリックします。

ブラウザー上にTerminalが開いたら、ユーザを`ec2-user`に変更してみましょう。

```bash
sudo su - ec2-user
```

これで正しくロールがアタッチできていることを確認しました。またこのインスタンスの接続はsshでも良いですし、このSession Managerを通じた方法でも良いです。

STEP3: [親インスタンス管理者] 各種インストールおよびEnclaveイメージファイル作成
---------------------------------------------------------------------

### 3.1 nitro-cliおよび必要なパッケージのインストール

#### 3.1.1 親インスタンスへのログイン

STEP2の最後に示した方法で、親インスタンスにログインします。Session Managerを使用した場合はユーザをec2-userにしてください。

```bash
sudo su - ec2-user
```

#### 3.1.2 git installation

```bash:command
sudo yum install git -y
```

#### 3.1.3 docker installation

```bash:command
sudo amazon-linux-extras install docker -y
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker ec2-user
```

#### 3.1.4 nitro-cli installation

```bash:command
sudo amazon-linux-extras enable aws-nitro-enclaves-cli
yum clean metadata
sudo yum install -y aws-nitro-enclaves-cli aws-nitro-enclaves-cli-devel
sudo usermod -aG ne ec2-user
```

#### 3.1.5 デーモンの起動

```bash:command
sudo systemctl start nitro-enclaves-allocator.service
sudo systemctl status nitro-enclaves-allocator.service
sudo systemctl enable nitro-enclaves-allocator.service
```

#### 3.1.6 Terinalの再起動

一度ターミナルを再起動しておきます。`exit`して入り直してください


### 3.2 Enclave環境のリソース割当の変更(`allocator.yaml`の編集)

#### 3.2.1 yamlの編集

いったん、メモリを1024MBまで使えるように編集します

```bash:command
sudo vim /etc/nitro_enclaves/allocator.yaml
```

#### 3.2.2 デーモンの再起動

nitro-enclaves-allocatorのデーモンを再起動します。

```bash:command
sudo systemctl restart nitro-enclaves-allocator.service
sudo systemctl status nitro-enclaves-allocator.service
```

### 3.3 使用するアプリケーションのdocker build

Enclaveを構築するために、既に提供されている Dockerfile: Dockerfile.al2 があります。このリポジトリのルートから次を実行します。

#### 3.3.1 Sampleアプリのgit clone

```bash:command
git clone https://github.com/aws/aws-nitro-enclaves-sdk-c.git
cd aws-nitro-enclaves-sdk-c/
```

#### 3.3.2 kmstool-instanceのビルド(親インスタンスで動作するコンテナー)

```bash:command
docker build --target kmstool-instance -t kmstool-instance -f containers/Dockerfile.al2 .
```

#### 3.3.3 kmstool-enclaveのビルド (Enclaveイメージに変換予定のコンテナー)

```bash:command
docker build --target kmstool-enclave -t kmstool-enclave -f containers/Dockerfile.al2 .
```

### 3.4 Nitro enclave イメージファイルのビルド (`kmstool.eif`)

以下のコマンドを実行し、上記で作成した`kmstool-enclave`をNitro enclaveのイメージファイルに変換します。
作成時得られる、`PCR0` の値を保存します。これは、「KMS のセットアップ」セクションで作成される KMS ポリシーに関連するためです。

```bash:command
cd ~/
nitro-cli build-enclave --docker-uri kmstool-enclave --output-file kmstool.eif
```

```terminal
Start building the Enclave Image...
Using the locally available Docker image...
Enclave Image successfully created.
{
  "Measurements": {
    "HashAlgorithm": "Sha384 { ... }",
    "PCR0": "309e2d2e699327a2684fddf345908a0e44bc829fd162b6abac3140fb1ace27c2e3b5aca01ff802d10fedc38a6cf12c8d",
    "PCR1": "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f",
    "PCR2": "c0b51dd99a22ff02d00169dabc7ae28dedd79b0bb747f9b374092749c5c7476e8638a322aab267f4cfd342b3f4c18724"
  }
}
```

STEP4: [データ提供者] KMS上でCustom Managed Key を作成
---------------------------------------------------------

### Customer Managed Keyの作成

1. [Customer Managed Key](https://us-east-1.console.aws.amazon.com/kms/home?region=us-east-1#/kms/keys)の画面を開き、`Create Key`のボタンをクリックします。
2. Configure keyの画面で以下のように項目を選択します
    - `Key type`: `Symetric`
    - `Key usage`: `Encrypt and decrypt` 
    - その他はDefaultで`Next`のボタンをクリック
3. Add labels の画面
    - `Alias`: `TestEnclave`
    - `Next`のボタンをクリック
4. Define key administrative permissions の画面
    - このHands-Onでは今操作中のIAM USERを選択します。本番はData Provider or/and システム管理者のIAM USERを登録をするのが良いでしょう
5. Define key usage permissions
     - 何も操作せず、`Next`のボタンを押します
6. Review
    - Key polycy をマニュアルで編集します。Statementの中のAdminの部分はすでにできています。それ以外を以下のようになるように編集してください
    - また`<Account ID>`, `<PCR0 from Enclave>`, `<現在使用中のIAM USER>` を正しい値に変更します
    - Encryptはt2.microにアタッチしたロールを許可しています。
    - Decryptはm5.xlargeにアタッチしたロールを許可しています。またPCR0の情報を付与しています。

```json
{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Enable decrypt from enclave",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<Account ID>:role/20230115_DecryptionForEnclaveTest"
            },
            "Action": "kms:Decrypt",
            "Resource": "*",
            "Condition": {
                "StringEqualsIgnoreCase": {
                    "kms:RecipientAttestation:ImageSha384": "<PCR0 from Enclave>"
                }
            }
        },
        {
            "Sid": "Enable encrypt from instance",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<Account ID>:role/20230115_EncryptionForEnclaveTest"
            },
            "Action": "kms:Encrypt",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<Account ID>:user/<現在使用中のIAM USER>"
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        }
    ]
}
```

STEP5 [データプロバイダー] データの暗号化 (On t2.micro)
--------------------------------------------------------------------------------

STEP4の動作確認を兼ねて、シンプルなメッセージを暗号化できるかテストしてみます。

### 5.1 作成したキーのArn情報の取得

```bash
KMS_KEY_ARN="arn:aws:kms:us-east-1:<Account ID>:key/<Key ID>"
```

KEY IDが分かっている場合、以下のようにCLIで取得しても良いでしょう。

```bash
KEY_ID="73a41f61-d869-484a-8e1f-3a33e834fc6c"
KMS_KEY_ARN=$(aws kms describe-key --key-id ${KEY_ID} | jq -r .KeyMetadata.Arn) \
    && echo "KMS_KEY_ARN=\"${KMS_KEY_ARN}\""
```

### 5.2 暗号化のテスト

先程の作成したCMKのテストも兼ねて、シンプルなテキストメッセージを暗号化します。

```bash
MESSAGE="Hello, KMS\!"
CIPHERTEXT=$(aws kms encrypt \
                --key-id "$KMS_KEY_ARN" \
                --plaintext "$MESSAGE" \
                --region "us-east-1" \
                --query CiphertextBlob --output text) && echo $CIPHERTEXT
```

以下のような結果が得られれは成功です。これをどこかにメモしておきます。

```terminal
AQICAHhCGziCzvenEaSgqMuJN4tg+uhqwBxjg0gUiZ/4K/W3ZAHAW1zocOfQk8gdI3MiXd3sAAAAajBoBgkqhkiG9w0BBwagWzBZAgEAMFQGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM5TrAppNou6LT3ZfyAgEQgCeY6EL8FNEgQYLzvzQPIzHSG8AlpL4awWY5rhhgTyoZ0ey0vlPUHGo=
```


STEP6: [親インスタンス管理者] Enclaveの起動
-----------------------------------------

### 6.1 親インスタンスへのログイン

STEP2.3同様にブラウザー上にTerminalが開いたら、ユーザを`ec2-user`に変更してみましょう。

```bash
sudo su - ec2-user
```

### 6.2 ProductionとしてEnclaveを起動

#### 6.2.1 `nitro-cli run-enclave` コマンドの実行

以下のコマンドでEnclaveをスタートし、以下のような結果が得られれば起動成功です。

```bash
nitro-cli run-enclave \
    --eif-path kmstool.eif \
    --memory 1024 \
    --cpu-count 2
    # debug modeのときは下記オプションを有効にする
    # --debug-mode
```

```terminal
Start allocating memory...
Started enclave with enclave-cid: 16, memory: 1024 MiB, cpu-ids: [1, 3]
{
  "EnclaveName": "kmstool",
  "EnclaveID": "i-0b61db7edb7713c3e-enc185b47a2a0ded78",
  "ProcessID": 13573,
  "EnclaveCID": 16,
  "NumberOfCPUs": 2,
  "CPUIDs": [
    1,
    3
  ],
  "MemoryMiB": 1024
}
```

#### 6.2.2  起動したEnclaveのPCR0の再確認方法

```bash:command
ENCLAVE_PCR0=$(nitro-cli describe-enclaves \
                | jq -r .[0].Measurements.PCR0) \
            && echo $ENCLAVE_PCR0
```

```terminal
af2df3f00dc2f2462ebce2119cb6639524921ab115806313eb20465869c33600827ddf0e65a2116c366a8f6df0b2ca56
```

#### 6.2.3  Consoleに接続できないことの確認

`nitro-cli run-enclave`実行時に`--debug-mode`オプションをつけず、本番環境と起動した場合Enclaveのコンソールにも接続できないことに注意しましょう

```bash:command
ENCLAVE_ID=$(nitro-cli describe-enclaves | jq -r .[0].EnclaveID) && echo $ENCLAVE_ID
nitro-cli console --enclave-id $ENCLAVE_ID
```

```terminal
[ E44 ] Enclave console connection failure. Such error appears when the Nitro CLI process fails to establish a connection to a running enclave's console.

For more details, please visit https://docs.aws.amazon.com/enclaves/latest/user/cli-errors.html#E44

If you open a support ticket, please provide the error log found at "/var/log/nitro_enclaves/err2023-01-01T06:58:38.598485783+00:00.log"
```

STEP7: [親インスタンス管理者] vsock-proxyの起動 (別のターミナル実行)
-----------------------------------------------------------------

vsockを通じた通信を確立します。別のターミナルを開き、ポート`8000`でvsock-proxyを起動します
親インスタンスへログインし、ユーザをec2-userに変更

```bash
sudo su - ec2-user
```

プロキシーを起動します。

```bash
# The region where you created your AWS KMS CMK
CMK_REGION=us-east-1
vsock-proxy 8000 kms.$CMK_REGION.amazonaws.com 443
```

```
(プロンプトがかえってこない状態でOK)
```

STEP8: [親インスタンス管理者] 暗号化データの送信と、Enclave内での復号化
-----------------------------------------------------------

### 8.1 動作テスト1 (正常動作確認)

#### 8.1.1 CMKのArn情報と暗号化されたメッセージの入力

STEP5.2で得られた暗号されたメッセージを親インスタンスの変数に定義します。これは後ほど`kmstool-instance`を実行する際の引数として与えられます。

```bash:command
CIPHERTEXT="AQICAHhCGziCzvenEaSgqMuJN4tg+uhqwBxjg0gUiZ/4K/W3ZAHAW1zocOfQk8gdI3MiXd3sAAAAajBoBgkqhkiG9w0BBwagWzBZAgEAMFQGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM5TrAppNou6LT3ZfyAgEQgCeY6EL8FNEgQYLzvzQPIzHSG8AlpL4awWY5rhhgTyoZ0ey0vlPUHGo="
```

#### 8.1.2 EnclaveのCID情報を取得

```bash:command
CMK_REGION=us-east-1
ENCLAVE_CID=$(nitro-cli describe-enclaves | jq -r .[0].EnclaveCID) \
            && echo "$ENCLAVE_CID"
```

#### 8.1.3 変数の確認

```bash:command
cat << ETX

ENCLAVE_CID: "$ENCLAVE_CID"
CMK_REGION: "$CMK_REGION"
CIPHERTEXT: "$CIPHERTEXT"

ETX
```

#### 8.1.4 kmstool-instanceツールによるメッセージ送信

```bash:command
docker run --network host -it kmstool-instance \
    /kmstool_instance --cid "$ENCLAVE_CID" --region "$CMK_REGION" "$CIPHERTEXT"
```

```json
Object = { "Operation": "SetClient", "AwsAccessKeyId": "XXXXXXXXXXXXXXX", "AwsSecretAccessKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "AwsSessionToken": "IQo...(省略)...qmSmWg==", "AwsRegion": "us-east-1" }
Object = { "Status": "Ok" }
Object = { "Operation": "Decrypt", "Ciphertext": "AQICAHg...(省略)...l68=" }
Object = { "Status": "Ok", "Message": "SGVsbG8sIEtNU1wh" }
Hello, KMS\!
```

### 8.2 動作テスト2 (vsock切断)

vsockを切断した状態でテストしエラーが得られることを確認します。

#### 8.2.1 vsock-proxyの切断

先程確立した、vsock-proxyを切断してください

#### 8.2.2 kmstool-instanceツールによるメッセージ送信

今回は以下のようにエラーが得られることを確認します。

```bash:command
docker run --network host -it kmstool-instance \
    /kmstool_instance --cid "$ENCLAVE_CID" --region "$CMK_REGION" "$CIPHERTEXT"
```

```json
(省略)
Object = { "Status": "Error", "Message": "Could not create new client" }
Error: Could not create new client
```


STEP9: [親インスタンス管理者] Enclaveの停止
--------------------------------------------

```bash
ENCLAVE_CID=$(nitro-cli describe-enclaves | jq -r .[0].EnclaveCID) \
            && echo "$ENCLAVE_CID"
nitro-cli terminate-enclave --enclave-id ${ENCLAVE_ID}
```

# 付録

## 親インスタンスとEnclave間の通信プロトコルに関する説明

両者間の通信プロトコルは、標準的な `AF_VSOCK` ソケット(posixのSOCK_STREAMソケットに似ている)とシンプルなJSONスキーマに基づいています。メッセージは 0 バイトで区切られます。

メッセージのタイプは2つあります。

### (1) command

これはkmstool-instanceがEnclaveに送信するメッセージで、`SetClient`または`Decrypt`となるOperationフィールドが含まれています

- `SetClient` オペレーションは `AwsAccessKeyId` と `AwsSecretAccessId` を必要とします
- `AwsSecretAccessKey` フィールドに、対応する IAM クレデンシャルを設定する必要があります
- `AwsSessionToken` がある場合は、`AwsAccessKeyId` と `AwsSecretAccessKey` フィールドに対応する IAM クレデンシャルを設定します
- さらに、`AwsRegion` を指定して、クライアントがリージョンを変更できるようにすることができます。
    - Enclaveに特定のリージョンが設定されていない場合。どちらにも特定の地域が設定されていない場合、"us-east-1" が使用されます


```json:sample
{"Operation": "SetClient"、"AwsAccessKeyId": "akiaiosfodnn7example",
"AwsSecretAccessKey": "XXXXXXXXXXXX/XXXXXX/XXXXXXXXXXXXX"、"AwsRegion": "us-east-1"}
```

- `Decrypt` 操作には、`Ciphertext` フィールドの設定が必要です
- 暗号文は KMS Encrypt オペレーションの結果を base64 でエンコードしたバイトストリームで送信します

```json:sample
{"Operation": "Decrypt", "Ciphertext": "AQICAHiFvOgLomqhXP8y..NkRa4CGQ=="}
```
 
### (2) reply

このメッセージは、コマンドの実行後に**kmstool-enclave**によって設定されます。このメッセージは常に `Ok` か `Error` のどちらかの `Status` を含み、オプションで `Message` を含むことができます。

- `Status` が `Ok` で、コマンドが`Decrypt` の場合、 `Message` にはその結果が表示されます
- もし `Status` が `Error` ならば、 `Message` にはエラーの説明が含まれます

この例は `Status`が`Ok`のケースです。`SGVsbG8sIEtNU1wh` はbase64でエンコードされており、そのデコード結果が`Hello, KMS\!`です。

```json:sample
Object = { "Status": "Ok", "Message": "SGVsbG8sIEtNU1wh" }
Hello, KMS\!
```

この例は、`Status`が`Error`の例です。`Message`にはエラー内容 `Could not create new client` とPlane Textの状態で表示されています。

```json:sample
Object = { "Status": "Error", "Message": "Could not create new client" }
Error: Could not create new client
```