커스텀 UEFI Secure Boot 키로 Linux AMI 만들기
커스텀 UEFI Secure Boot 키로 Linux AMI 만들기
이 지침은 UEFI Secure Boot와 커스텀 제작 개인 키로 Linux AMI를 만드는 방법을 보여줘요. 이 절에서 세 개의 키 페어 생성, 인스턴스 내부에서 변수 저장소에 키 추가, 사전 채워진 변수 저장소가 포함된 바이너리 blob 만들기를 살펴볼게요.
출처: 문서
본문
이 지침은 UEFI Secure Boot와 커스텀 제작 개인 키로 Linux AMI를 만드는 방법을 보여줘요. Amazon Linux는 AL2023 릴리스 2023.1부터 UEFI Secure Boot를 지원해요. 자세한 내용은 Amazon Linux 2023 User Guide의 UEFI Secure Boot on AL2023을 참고하세요.
중요
다음 절차는 고급 사용자 전용입니다. 이 절차를 사용하려면 SSL과 Linux 배포판 부팅 흐름에 대한 충분한 지식이 있어야 해요.
사전 요구 사항
- 다음 도구가 사용됩니다.
- OpenSSL – https://www.openssl.org/
- efivar – https://github.com/rhboot/efivar
- efitools – https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/
- get-instance-uefi-data 명령
- 내 Linux 인스턴스가 UEFI 부트 모드를 지원하는 Linux AMI로 시작되었고 비휘발성 데이터가 있어야 해요.
UEFI Secure Boot 키 없이 새로 만든 인스턴스는 SetupMode로 생성되며, 이를 통해 내 키를 등록할 수 있어요. 일부 AMI는 UEFI Secure Boot가 사전 구성되어 있어 기존 키를 변경할 수 없어요. 키를 변경하려면 원래 AMI를 기반으로 새 AMI를 만들어야 해요.
변수 저장소에 키를 전파하는 두 가지 방법이 있으며, 이는 이어지는 Option A와 Option B에 설명되어 있어요. Option A는 인스턴스 내부에서, 실제 하드웨어의 흐름을 모방해 수행하는 방법을 설명해요. Option B는 AMI를 만들 때 base64 인코딩 파일로 전달되는 바이너리 blob을 만드는 방법을 설명해요. 두 옵션 모두 먼저 신뢰 체인(chain of trust)에 사용되는 세 개의 키 페어를 만들어야 해요.
UEFI Secure Boot를 지원하는 Linux AMI를 만들려면, 먼저 세 개의 키 페어를 만든 다음 Option A 또는 Option B 중 하나만 완료하세요.
- 작업 1: 키 페어 만들기
- 작업 2 – Option A: 인스턴스 내부에서 변수 저장소에 키 추가
- 작업 2 – Option B: 사전 채워진 변수 저장소가 포함된 바이너리 blob 만들기
작업 1: 키 페어 만들기
UEFI Secure Boot는 신뢰 체인에 사용되는 다음 세 가지 키 데이터베이스를 기반으로 해요: 플랫폼 키(platform key, PK), 키 교환 키(key exchange key, KEK), 서명 데이터베이스(signature database, db).¹
각 키를 인스턴스에서 만듭니다. 공개 키를 UEFI Secure Boot 표준에 유효한 형식으로 준비하려면 각 키에 대한 인증서를 만듭니다. DER은 SSL 형식을 정의해요(형식의 이진 인코딩). 그런 다음 각 인증서를 UEFI Secure Boot가 이해하는 이진 형식인 UEFI 서명 목록으로 변환합니다. 마지막으로 각 인증서를 관련 키로 서명합니다.
작업
- 키 페어 생성 준비
- 키 페어 1: 플랫폼 키(PK) 만들기
- 키 페어 2: 키 교환 키(KEK) 만들기
- 키 페어 3: 서명 데이터베이스(db) 만들기
- 개인 키로 부팅 이미지(커널) 서명
키 페어 생성 준비
키 페어를 만들기 전에 키 생성에 사용할 전역 고유 식별자(GUID)를 만듭니다.
- 인스턴스에 연결합니다.
- 셸 프롬프트에서 다음 명령을 실행합니다.
uuidgen --random > GUID.txt
키 페어 1: 플랫폼 키(PK) 만들기
PK는 UEFI Secure Boot 인스턴스의 신뢰 루트예요. 개인 PK는 KEK를 업데이트하는 데 사용되며, KEK는 다시 서명 데이터베이스(db)에 인증된 키를 추가하는 데 사용될 수 있어요.
키 페어 생성에는 X.509 표준이 사용됩니다. 이 표준에 대한 자세한 내용은 Wikipedia의 X.509를 참고하세요.
PK 만들기
- 키를 만듭니다. 변수 이름은
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– 키의 common name(CN)입니다.Platform key대신 내 조직의 이름을 입력할 수 있어요. -
인증서를 만듭니다.
openssl x509 -outform DER -in PK.crt -out PK.cer
- 인증서를 UEFI 서명 목록으로 변환합니다.
cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
- UEFI 서명 목록을 개인 PK로 서명합니다(자체 서명).
sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth
키 페어 2: 키 교환 키(KEK) 만들기
개인 KEK는 시스템에서 부팅하도록 인증된 서명 목록인 db에 키를 추가하는 데 사용됩니다.
KEK 만들기
- 키를 만듭니다.
openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=Key Exchange Key/" -out KEK.crt
- 인증서를 만듭니다.
openssl x509 -outform DER -in KEK.crt -out KEK.cer
- 인증서를 UEFI 서명 목록으로 변환합니다.
cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl
- 서명 목록을 개인 PK로 서명합니다.
sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth
키 페어 3: 서명 데이터베이스(db) 만들기
db 목록에는 시스템에서 부팅하도록 인증된 인증된 키가 포함됩니다. 목록을 수정하려면 개인 KEK가 필요해요. 부팅 이미지는 이 단계에서 만든 개인 키로 서명됩니다.
db 만들기
- 키를 만듭니다.
openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=Signature Database key/" -out db.crt
- 인증서를 만듭니다.
openssl x509 -outform DER -in db.crt -out db.cer
- 인증서를 UEFI 서명 목록으로 변환합니다.
cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl
- 서명 목록을 개인 KEK로 서명합니다.
sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth
개인 키로 부팅 이미지(커널) 서명
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 기여자가 작성한 Creating keys에서 가져왔습니다.
작업 2 – Option A: 인스턴스 내부에서 변수 저장소에 키 추가
세 개의 키 페어를 만든 후에는 인스턴스에 연결해 다음 단계를 완료함으로써 인스턴스 내부에서 변수 저장소에 키를 추가할 수 있어요. 또는 작업 2 – Option B: 사전 채워진 변수 저장소가 포함된 바이너리 blob 만들기의 단계를 완료할 수도 있어요.
Option A 단계:
1단계: UEFI Secure Boot를 지원할 인스턴스 시작
다음 사전 요구 사항으로 인스턴스를 시작하면 인스턴스가 UEFI Secure Boot를 지원하도록 구성될 준비가 됩니다. UEFI Secure Boot 지원은 시작 시에만 인스턴스에서 활성화할 수 있어요; 나중에는 활성화할 수 없어요.
사전 요구 사항
-
AMI – Linux AMI가 UEFI 부트 모드를 지원해야 해요. AMI가 UEFI 부트 모드를 지원하는지 확인하려면 AMI 부트 모드 매개 변수가 uefi여야 해요. 자세한 내용은 Determine the boot mode parameter of an Amazon EC2 AMI를 참고하세요.
AWS는 Graviton 기반 인스턴스 유형에 대해서만 UEFI를 지원하도록 구성된 Linux AMI를 제공한다는 점에 유의하세요. AWS는 현재 UEFI 부트 모드를 지원하는 x86_64 Linux AMI를 제공하지 않아요. 모든 아키텍처에 대해 UEFI 부트 모드를 지원하도록 내 AMI를 구성할 수 있어요. UEFI 부트 모드를 지원하도록 내 AMI를 구성하려면 내 AMI에서 여러 구성 단계를 수행해야 해요. 자세한 내용은 Set the boot mode of an Amazon EC2 AMI를 참고하세요.
-
인스턴스 유형 – UEFI를 지원하는 모든 가상화 인스턴스 유형은 UEFI Secure Boot도 지원해요. 베어 메탈 인스턴스 유형은 UEFI Secure Boot를 지원하지 않아요. UEFI Secure Boot를 지원하는 인스턴스 유형은 Requirements for UEFI boot mode를 참고하세요.
-
UEFI Secure Boot가 출시된 후 인스턴스를 시작하세요. 2022년 5월 10일(UEFI Secure Boot 출시일) 이후에 시작된 인스턴스만 UEFI Secure Boot를 지원할 수 있어요.
인스턴스를 시작한 후 UEFI 데이터가 있는지 확인해 UEFI Secure Boot를 지원하도록 구성될 준비가 되었는지(2단계로 진행할 수 있는지) 확인할 수 있어요. UEFI 데이터가 있다는 것은 비휘발성 데이터가 유지되었음을 나타냅니다.
2단계 준비 여부 확인
get-instance-uefi-data 명령을 사용하고 인스턴스 ID를 지정합니다.
aws ec2 get-instance-uefi-data --instance-id i-1234567890abcdef0
출력에 UEFI 데이터가 있으면 인스턴스가 2단계 준비가 된 것입니다. 출력이 비어 있으면 인스턴스를 UEFI Secure Boot를 지원하도록 구성할 수 없어요. 이는 인스턴스가 UEFI Secure Boot 지원이 제공되기 전에 시작된 경우 발생할 수 있어요. 새 인스턴스를 시작하고 다시 시도하세요.
2단계: UEFI Secure Boot를 지원하도록 인스턴스 구성
인스턴스의 UEFI 변수 저장소에 키 페어 등록
경고
키를 등록한 후에 부팅 이미지를 서명해야 합니다. 그렇지 않으면 인스턴스를 부팅할 수 없게 돼요.
서명된 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 Secure Boot가 활성화되었는지 확인
UEFI Secure Boot가 활성화되었는지 확인하려면 Verify whether an Amazon EC2 instance is enabled for UEFI Secure Boot의 단계를 따르세요.
이제 get-instance-uefi-data CLI 명령으로 UEFI 변수 저장소를 내보낼 수 있으며, 또는 다음 단계로 계속해 UEFI Secure Boot가 활성화된 인스턴스로 재부팅하도록 부팅 이미지를 서명할 수 있습니다.
3단계: 인스턴스에서 AMI 만들기
인스턴스에서 AMI를 만들려면 콘솔이나 CreateImage API, CLI, SDK를 사용할 수 있어요. 콘솔 지침은 Create an Amazon EBS-backed AMI를 참고하세요. API 지침은 CreateImage를 참고하세요.
참고
CreateImage API는 인스턴스의 UEFI 변수 저장소를 AMI에 자동으로 복사합니다. 콘솔은 CreateImage API를 사용해요. 이 AMI로 인스턴스를 시작하면 인스턴스는 같은 UEFI 변수 저장소를 가지게 돼요.
작업 2 – Option B: 사전 채워진 변수 저장소가 포함된 바이너리 blob 만들기
세 개의 키 페어를 만든 후에는 UEFI Secure Boot 키가 포함된 사전 채워진 변수 저장소가 포함된 바이너리 blob을 만들 수 있어요. 또는 작업 2 – Option A: 인스턴스 내부에서 변수 저장소에 키 추가의 단계를 완료할 수도 있어요.
경고
키를 등록하기 전에 부팅 이미지를 서명해야 합니다. 그렇지 않으면 인스턴스를 부팅할 수 없게 돼요.
Option B 단계:
1단계: 새 변수 저장소를 만들거나 기존 변수 저장소 업데이트
python-uefivars 도구를 사용해 실행 중인 인스턴스 없이 오프라인으로 변수 저장소를 만들 수 있어요. 이 도구는 내 키로 새 변수 저장소를 만들 수 있어요. 스크립트는 현재 EDK2 형식, AWS 형식, 그리고 더 높은 수준의 도구로 편집하기 쉬운 JSON 표현을 지원해요.
실행 중인 인스턴스 없이 오프라인으로 변수 저장소 만들기
- 다음 링크에서 도구를 다운로드합니다.
https://github.com/awslabs/python-uefivars
- 다음 명령을 실행해 내 키로 새 변수 저장소를 만듭니다. 이렇게 하면
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 업로드
register-image를 사용해 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