

# 사용자 지정 UEFI 보안 부팅 키를 사용하여 Linux AMI 생성
<a name="create-ami-with-uefi-secure-boot"></a>

이 지침은 UEFI 보안 부팅과 사용자 지정 프라이빗 키를 사용하여 Linux AMI를 생성하는 방법을 보여줍니다. Amazon Linux는 AL2023 릴리스 2023.1부터 UEFI 보안 부팅을 지원합니다. 자세한 정보는 *Amazon Linux 2023 사용 설명서*의 [AL2023의 UEFI 보안 부팅](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-dat](https://docs.aws.amazon.com/cli/latest/reference/ec2/get-instance-uefi-data.html) 명령
+ Linux 인스턴스는 UEFI 부팅 모드를 지원하는 Linux AMI로 시작되고 비휘발성 데이터가 있어야 합니다.

UEFI 보안 부팅 키 없이 새로 생성된 인스턴스는 `SetupMode`에 생성됩니다. 이를 통해 자체 키를 등록할 수 있습니다. 일부 AMI는 UEFI 보안 부팅으로 사전 구성되어 제공되며 기존 키를 변경할 수 없습니다. 키를 변경하려면 원래 AMI를 기반으로 새 AMI를 생성해야 합니다.

변수 스토어에 키를 전파하는 방법에는 두 가지가 있습니다. 이들 방법은 다음에 나오는 옵션 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)의 세 가지 키 데이터베이스를 기반으로 합니다.¹

인스턴스에서 각 키를 생성합니다. 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를 업데이트하는 데 사용되며, KEK는 승인된 키를 서명 데이터베이스(db)에 추가하는 데 사용할 수 있습니다.

X.509 표준은 키 페어를 생성하는 데 사용됩니다. 표준에 대한 자세한 내용은 *Wikipedia*의 [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. 프라이빗 PK(자체 서명)로 UEFI 서명 목록에 서명합니다.

   ```
   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 생성 및 이미지 서명을 위한 명령은 ArchWiki 유지 관리 팀 및/또는 ArchWiki 기고자가 작성한 [키 생성](https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_keys)에서 가져왔습니다.

## 작업 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에서는 Graviton 기반 인스턴스 유형의 UEFI를 지원하도록 구성된 Linux AMI만 제공합니다. AWS에서는 현재 UEFI 부팅 모드를 지원하는 x86\_64 Linux AMI를 제공하지 않습니다. 모든 아키텍처의 UEFI 부팅 모드를 지원하도록 자체 AMI를 구성할 수 있습니다. UEFI 부팅 모드를 지원하도록 자체 AMI를 구성하려면 자체 AMI에서 여러 구성 단계를 수행해야 합니다. 자세한 내용은 [Amazon EC2 AMI의 부팅 모드 설정](set-ami-boot-mode.md) 섹션을 참조하세요.
+ **인스턴스 유형(Instance type)** - 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` 변수에 쓸 수 있습니다.
+ 아직 등록된 PK가 없으며 이는 `SetupMode` 변수가 `1`인 경우 표시됩니다. 다음 명령을 사용하여 이를 확인합니다. 출력은 `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 보안 부팅이 활성화되었는지 확인하려면 [UEFI 보안 부팅에 대해 Amazon EC2 인스턴스가 활성화되어 있는지 확인](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 지원 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를 사용하여 인스턴스를 시작하면 인스턴스는 동일한 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. 다음 명령을 실행하여 키에서 새 변수 스토어를 생성합니다. 그러면 {{your\_binary\_blob}}.bin에 base64로 인코딩된 바이너리 blob이 생성됩니다. 이 도구는 `-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
```