

# カスタム UEFI 安全ブート キーを使用して Linux AMI を作成する
<a name="create-ami-with-uefi-secure-boot"></a>

この手順では、UEFI 安全ブートとカスタムメイドのプライベートキーを使用して Linux AMI を作成する方法を示します。Amazon Linux は、AL2023 リリース 2023.1 から UEFI セキュアブートをサポートしています。詳細については、「Amazon Linux 2023 ユーザーガイド」の「[UEFI Secure Boot on AL2023](https://docs.aws.amazon.com/linux/al2023/ug/uefi-secure-boot.html)」を参照してください。

**重要**  
次の手順は、**上級ユーザーのみ**を対象としています。これらの手順を使用するには、SSL および Linux ディストリビューションのブートフローに関する十分な知識が必要です。

**前提条件**
+ 以下のツールを使用します。
  + OpenSSL – [https://www.openssl.org/](https://www.openssl.org/)
  + efivar – [https://github.com/rhboot/efivar](https://github.com/rhboot/efivar)
  + efitools – [https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/](https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/)
  + [get-instance-uefi-data](https://docs.aws.amazon.com/cli/latest/reference/ec2/get-instance-uefi-data.html) コマンド
+ Linux インスタンスは、UEFI ブートモードをサポートする Linux AMI で起動され、不揮発性データを使用している必要があります。

UEFI 安全ブート キーを使用せずに新規で作成されたインスタンスには、`SetupMode` が適用されます。この状態で、独自のキーを登録することが可能です。一部の AMI では UEFI 安全ブート が事前設定されており、既定のキーを変更することはできません。AMI のキーを変更する場合は、その AMI をベースに、新らたな AMI を作成する必要があります。

変数ストア内のキーを伝達するには 2 つの方法があり、それぞれを、以下の オプション A とオプション B の中で説明します。オプション A では、実際のハードウェアのフローを模倣することで、インスタンス内からこれを行う方法について説明します。オプション B では、AMI の作成時に base64 でエンコードされたファイルとして渡される、バイナリ BLOB を作成する方法について説明します。どちらのオプションでも、最初に、信頼チェーンに使用するためのキーペアを 3 つ作成する必要があります。

**Topics**
+ [タスク 1: キーペアを作成する](#uefi-secure-boot-create-three-key-pairs)
+ [タスク 2 – オプション A: インスタンス内から変数ストアにキーを追加する](#uefi-secure-boot-optionA)
+ [タスク 2 – オプション B: 値が事前に設定済みの変数ストアを含むバイナリ BLOB を作成する](#uefi-secure-boot-optionB)

## タスク 1: キーペアを作成する
<a name="uefi-secure-boot-create-three-key-pairs"></a>

UEFI 安全ブート は、プラットフォームキー (PK)、キー交換キー (KEK)、署名データベース (db) という 3 つのキーデータベースに基づいおり、これらのデータベースは信頼チェーンで使用されます。

インスタンスでは、これらの各キーを作成する必要があります。UEFI 安全ブート 標準が有効な形式でパブリックキーの準備を行うには、それぞれのキー用に証明書を作成します。`DER` では SSL 形式 (バイナリエンコード用の形式) を定義しています。その後、各証明書を UEFI 署名リストに変換します。このリストはバイナリ形式で、UEFI 安全ブート による解析が可能です。最後に、関連するキーで各証明書に署名します。

**Topics**
+ [キーペアの作成を準備するには](#uefisb-prepare-to-create-key-pairs)
+ [キーペア 1: プラットフォームキー (PK) を作成します。](#uefisb-create-key-pair-1)
+ [キーペア 2: キー交換キー (KEK) を作成します](#uefisb-create-key-pair-2)
+ [キーペア 3: 署名データベース (db) を作成します](#uefisb-create-key-pair-3)
+ [ブートイメージ (カーネル) にプライベートキーで署名する](#uefi-secure-boot-sign-kernel)

### キーペアの作成を準備するには
<a name="uefisb-prepare-to-create-key-pairs"></a>

キーペアを作成する前に、キー生成処理で使用するための、グローバルで一意の識別子 (GUID) を作成します。

1. [インスタンスに接続します。](connect.md)

1. シェルプロンプトで、次のコマンドを実行します。

   ```
   uuidgen --random > GUID.txt
   ```

### キーペア 1: プラットフォームキー (PK) を作成します。
<a name="uefisb-create-key-pair-1"></a>

PK は UEFI 安全ブート インスタンスの信頼のルートです。プライベート PK は KEK を更新するために使用されます。このキーはその後、認証されたキーを署名データベース (db) に追加するためにも使用されます。

キーペアの作成には、X.509 標準が適用されます。標準の詳細については、*ウィキペディア*の「[X.509](https://en.wikipedia.org/wiki/X.509)」を参照してください。

**PK を作成するには**

1. キーを作成します。変数 `PK` に名前を付ける必要があります

   ```
   openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN={{Platform key}}/" -out PK.crt
   ```

   以下の各パラメータが指定されます。
   + `-keyout PK.key` – プライベートキーファイル。
   + `-days 3650` – 証明書が有効な日数。
   + `-out PK.crt` – UEFI 変数の作成に使用される証明書。
   + `CN={{Platform key}}` – キーの共通名 (CN)。ここでは、{{プラットフォームキー}} の代わりに組織の独自の名前を入力できます。

1. 証明書を作成します。

   ```
   openssl x509 -outform DER -in PK.crt -out PK.cer
   ```

1. 証明書を UEFI 署名リストに変換します。

   ```
   cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
   ```

1. UEFI 署名リストに (自己署名の) プライベート PKで署名します。

   ```
   sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth
   ```

### キーペア 2: キー交換キー (KEK) を作成します
<a name="uefisb-create-key-pair-2"></a>

プライベート KEK は db にキーを追加するために使用されます。このデータベースは、システム上で起動が許可された署名のリストです。

**KEK を作成するには**

1. キーを作成します。

   ```
   openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=Key Exchange Key/" -out KEK.crt
   ```

1. 証明書を作成します。

   ```
   openssl x509 -outform DER -in KEK.crt -out KEK.cer
   ```

1. 証明書を UEFI 署名リストに変換します。

   ```
   cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl
   ```

1. プライベート PK で署名リストに署名します。

   ```
   sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth
   ```

### キーペア 3: 署名データベース (db) を作成します
<a name="uefisb-create-key-pair-3"></a>

db リストには、システム上で起動することが認証されているキーが記載されています。このリストを変更する場合は、プライベート KEK が必要です。ブートイメージは、このステップで作成したプライベートキーで署名されます。

**db を作成するには**

1. キーを作成します。

   ```
   openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=Signature Database key/" -out db.crt
   ```

1. 証明書を作成します。

   ```
   openssl x509 -outform DER -in db.crt -out db.cer
   ```

1. 証明書を UEFI 署名リストに変換します。

   ```
   cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl
   ```

1. プライベート KEK を使用して署名リストに署名します。

   ```
   sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth
   ```

### ブートイメージ (カーネル) にプライベートキーで署名する
<a name="uefi-secure-boot-sign-kernel"></a>

Ubuntu 22.04 の場合、以下のイメージに署名が必要です。

```
/boot/efi/EFI/ubuntu/shimx64.efi
/boot/efi/EFI/ubuntu/mmx64.efi
/boot/efi/EFI/ubuntu/grubx64.efi
/boot/vmlinuz
```

**イメージに署名するには**  
イメージに署名するには、以下の構文を使用します。

```
sbsign --key db.key --cert db.crt --output {{/boot/vmlinuz}} {{/boot/vmlinuz}}
```

**注記**  
署名は、すべての新しいカーネルに対して行う必要があります。通常、{{`/boot/vmlinuz`}} は、最近インストールしたカーネルへのシンボリックリンクとなります。

ブートチェーンおよび必要なイメージは、ディストリビューションのドキュメントで確認してください。

¹ ArchWiki コミュニティの皆さんから提供された、すべての作業に感謝します。PK の作成、KEK の作成、DB の作成、およびイメージへの署名のためのコマンドは、[Creating keys](https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys) から提供されており、ArchWiki メンテナンスチームおよび (または) ArchWiki のコントリビューターによって作成されたものです。

## タスク 2 – オプション A: インスタンス内から変数ストアにキーを追加する
<a name="uefi-secure-boot-optionA"></a>

[3 つのキーペア](#uefi-secure-boot-create-three-key-pairs)の作成が完了すると、以下のステップにより、インスタンスに接続し、インスタンス内から変数ストアにキーを追加できるようになります。または、[タスク 2 – オプション B: 値が事前に設定済みの変数ストアを含むバイナリ BLOB を作成する](#uefi-secure-boot-optionB) の手順を完了します。

**Topics**
+ [ステップ 1: UEFI 安全ブート をサポートするインスタンスを起動する](#step1-launch-uefi-sb)
+ [ステップ 2: UEFI 安全ブート をサポートするようにインスタンスを設定する](#step2-launch-uefi-sb)
+ [ステップ 3: インスタンスから AMI を作成する](#step3-launch-uefi-sb)

### ステップ 1: UEFI 安全ブート をサポートするインスタンスを起動する
<a name="step1-launch-uefi-sb"></a>

次の前提条件の下で‭[‭‬インスタンスを起動‭](LaunchingAndUsingInstances.md)‬することで、UEFI 安全ブート をサポートするようにインスタンスを構成する準備が整います。インスタンスでの UEFI 安全ブート のサポートは、起動時にみ有効化が可能で、その後に有効にすることはできません。

**前提条件**
+ **AMI** - Linux AMI では、UEFI ブートモードをサポートする必要があります。AMI が UEFI ブートモードをサポートしていることを確認するには、AMI ブートモードパラメータで **uefi** を指定する必要があります。詳細については、「[Amazon EC2 AMI のブートモードパラメータを確認する](ami-boot-mode.md)」を参照してください。

  AWS では、重力子 ベースのインスタンスタイプ向けに UEFI をサポートするように構成された Linux AMI のみを提供します。AWS では、UEFI ブートモードをサポートする x86\_64 Linux AMI を提供していません。すべてのアーキテクチャで UEFI ブートモードをサポートするように独自の AMI を構成できます。UEFI ブートモードをサポートするように AMI を設定するには、独自の AMI に対して、複数の設定ステップを実行する必要があります。詳細については、「[Amazon EC2 AMI のブートモードを設定する](set-ami-boot-mode.md)」を参照してください。
+ **インスタンスタイプ** — UEFI をサポートするすべての仮想インスタンスタイプは、UEFI 安全ブート もサポートします。ベアメタルインスタンスタイプは UEFI 安全ブート をサポートしていません。UEFI 安全ブート をサポートするインスタンスタイプについては、[UEFI ブートモードの要件](launch-instance-boot-mode.md) を参照してください。
+ UEFI 安全ブート の立ち上げ後に、インスタンスの起動を行います。UEFI 安全ブート のサポートが可能なのは、2022 年 5 月 10 日 (UEFI 安全ブート リリース日) より後に起動されたインスタンスのみです。

インスタンスを起動したら、UEFI データが存在するかどうかを調べ、UEFI 安全ブート のサポートを設定できる状態であることを確認します ([ステップ 2](#step2-launch-uefi-sb)‬ に進みます)。UEFI データが見つかれば、不揮発性データが保持されていることになります。

**インスタンスがステップ 2 に進める状態かどうかを確認するには**  
[https://docs.aws.amazon.com/cli/latest/reference/ec2/get-instance-uefi-data.html](https://docs.aws.amazon.com/cli/latest/reference/ec2/get-instance-uefi-data.html) コマンドを使用して、インスタンス ID を指定します。

```
aws ec2 get-instance-uefi-data --instance-id {{i-1234567890abcdef0}}
```

出力に UEFI データが含まれていれば、そのインスタンスはステップ 2 に進める状態です。空の出力が表示される場合、そのインスタンスで UEFI 安全ブート をサポートする設定は行えません。この状態は、UEFI 安全ブート サポートが利用可能になる前に起動されたインスタンスで発生します。この場合、新しいインスタンスを起動して再試行します。

### ステップ 2: UEFI 安全ブート をサポートするようにインスタンスを設定する
<a name="step2-launch-uefi-sb"></a>

#### インスタンスの UEFI 変数ストアにキーペアを登録します。
<a name="step2a-launch-uefi-sb"></a>

**警告**  
ブートイメージへの署名は、キーの登録*後*に行う必要があります。そうしないと、インスタンスを起動できなくなります。

署名済みの UEFI 署名リスト (`PK`、`KEK`、および `db`) は、作成後に UEFI ファームウェアに登録する必要があります。

`PK` 変数に対する書き込みは、以下の場合にのみ行うことができます。
+ `SetupMode`変数が`1`の場合、PKはまだ登録されていない。これは、次のコマンドを使用して確認します。`1` または `0` のどちらかが出力されている。

  ```
  efivar -d -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-SetupMode 
  ```
+ 新しい PK が、既存の PK のプライベートキーによって署名されている。

**UEFI 変数ストアにキーを登録するには**  
インスタンスで以下のコマンドを実行する必要があります。

SetupMode が有効 (値が `1`) になっていれば、インスタンスで以下のコマンドを実行することでキーを登録できます。

```
[ec2-user ~]$ efi-updatevar -f db.auth db
```

```
[ec2-user ~]$ efi-updatevar -f KEK.auth KEK
```

```
[ec2-user ~]$ efi-updatevar -f PK.auth PK
```

**UEFI 安全ブート が有効になっていることを確認するには**  
UEFI 安全ブート が有効であることを確認するには、「[Amazon EC2 インスタンスで UEFI 安全ブート が有効化されているかどうかを確認する](verify-uefi-secure-boot.md)」に示したステップに従います。

この段階で、[https://docs.aws.amazon.com/cli/latest/reference/ec2/get-instance-uefi-data.html](https://docs.aws.amazon.com/cli/latest/reference/ec2/get-instance-uefi-data.html) CLI コマンドにより UEFI 変数ストアをエクスポートすることが可能です。あるいは、次のステップに進みブートイメージに署名して、それを UEFI 安全ブート-対応のインスタンスで再起動できます。

### ステップ 3: インスタンスから AMI を作成する
<a name="step3-launch-uefi-sb"></a>

インスタンスから AMI を作成するには、コンソールまたは `CreateImage` API、CLI、または SDK を使用します。コンソールでのステップについては、「[Amazon EBS-backed AMI を作成する](creating-an-ami-ebs.md)」を参照してください。API でのステップについては、「[CreateImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateImage.html)」を参照してください。

**注記**  
`CreateImage` API は、インスタンスの UEFI 変数ストアを AMI に自動的にコピーします。コンソールは `CreateImage` API を使用します。この AMI を使用してインスタンスを起動した場合、インスタンスにも AMI と同じ UEFI 変数ストアが含まれます。

## タスク 2 – オプション B: 値が事前に設定済みの変数ストアを含むバイナリ BLOB を作成する
<a name="uefi-secure-boot-optionB"></a>

[3 つのキーペア](#uefi-secure-boot-create-three-key-pairs)の作成後、事前に値が設定され UEFI 安全ブート キーが指定された変数ストアを含む、バイナリ BLOB を作成できます。または、[タスク 2 – オプション A: インスタンス内から変数ストアにキーを追加する](#uefi-secure-boot-optionA) の手順を完了します。

**警告**  
ブートイメージへの署名は、キーの登録*前*に行う必要があります。そうしないと、インスタンスを起動できなくなります。

**Topics**
+ [ステップ 1: 変数ストアを新規で作成するか既存の変数ストアを更新する](#uefi-secure-boot-create-or-update-variable)
+ [ステップ 2: AMI の作成時にバイナリ BLOB をアップロードする](#uefi-secure-boot-upload-binary-blob-on-ami-creation)

### ステップ 1: 変数ストアを新規で作成するか既存の変数ストアを更新する
<a name="uefi-secure-boot-create-or-update-variable"></a>

python-uefivars ツールを使用すれば、インスタンスを実行しなくても*オフラインで*変数ストアを作成できます。このツールでは、キーから新しい変数ストアを作成できます。現在、このスクリプトでは、EDK2 形式、AWS 形式、および上位レベルのツールで編集しやすい JSON 表現がサポートされています。

**インスタンスを実行せずに変数ストアをオフラインで作成するには**

1. 次のリンクからツールをダウンロードします。

   ```
   https://github.com/awslabs/python-uefivars
   ```

1. 次のコマンドを実行して、キーから新しい変数ストアを作成します。これにより、base64 でエンコードされたバイナリ BLOB が、{{your\_binary\_blob}} bin として作成されます。このツールでは、`-I` パラメータ経由でバイナリ BLOB を更新することもできます。

   ```
   ./uefivars.py -i none -o aws -O {{your_binary_blob}}.bin -P PK.esl -K KEK.esl --db db.esl --dbx dbx.esl
   ```

### ステップ 2: AMI の作成時にバイナリ BLOB をアップロードする
<a name="uefi-secure-boot-upload-binary-blob-on-ami-creation"></a>

[https://docs.aws.amazon.com/cli/latest/reference/ec2/register-image.html](https://docs.aws.amazon.com/cli/latest/reference/ec2/register-image.html) により、UEFI 変数ストアデータを渡します。`--uefi-data` パラメータではバイナリ BLOB を指定し、また `--boot-mode` パラメータでは `uefi` を指定します。

```
aws ec2 register-image \
    --name uefi_sb_tpm_register_image_test \
    --uefi-data $(cat {{your_binary_blob}}.bin) \
    --block-device-mappings "DeviceName=/dev/sda1,Ebs= {SnapshotId={{snap-0123456789example}},DeleteOnTermination=true}" \
    --architecture x86_64 \
    --root-device-name /dev/sda1 \
    --virtualization-type hvm \
    --ena-support \
    --boot-mode uefi
```