EC2で稼働するアプリケーションにさらなる環境分離を提供!!Nitro Enclavesを試してみた

個人情報、医療、金融、知的財産データといった機密性の高いデータを安全に処理するための新機能Nitro Enclavesを試してみました
2020.11.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部@大阪の岩田です。re:invenvt2019で発表されたNitro Enclavesが先日GAされました。

どんなサービスか概要を掴むためにGetting startedの内容を試してみたので、内容を簡単にご紹介します。

Nitro Enclavesとは?

AWS Nitro EnclavesはEC2インスタンス内にEnclaveと呼ばれる分離されたアプリケーション環境を作成するための機能です。各Enclaveは独立したカーネルを実行し、メモリとCPUリソースへの排他的アクセス権を持ちます。Enclaveには、外部ネットワーク接続、永続ストレージ、ユーザーアクセスは提供されず、vsockを介した親EC2インスタンスとの通信のみが許可されます。Enclaveを利用することで、個人情報、医療、金融、知的財産データといった機密性の高いデータを保護および安全に処理できます。

以下の画像は上記AWSブログから引用した画像です。EC2インスタンス内の隔離された環境でEnclaveが実行されることがイメージできると思います。

OS上での環境分離というとDockerのようなコンテナ技術が思い浮かびますが、Dockerであれば親のEC2インスタンスからdocker exec等のコマンドを使って、いわゆる「コンテナの中に入る」ことでコンテナ内で任意のコマンドを実行できますが、Enclaveではこういった操作ができないような設計になっているのがポイントです。

さらに、Nitro EnclavesはAttestationという機能をサポートしており、この機能を使うことで承認されたコードのみがEnclave内で実行されていることを確認できます。 Nitro EnclavesはKMSと統合されており、KSMによるAttestationのサポートが組み込まれています。

Nitro Enclavesの要件

Nitro Enclavesを利用するにはEC2インスタンスに以下の要件が必要です

  • Nitroベースのインスタンスであること
    • ただしt3, t3a, t4g, a1, c6g, c6gd, m6g, m6gd, r6g, r6gdを除く
  • 4つ以上のvCPUを持っていること
  • Linux OSであること

やってみる

では、早速Nitro Enclavesを試してみましょう。今回は公式ドキュメントの「Getting started: Hello enclave」の内容に沿って進めて行きます。

EC2インスタンスの起動

まずはNitro Enclavesを動作させるためのEC2インスタンスを起動します。前述の要件を考慮し、以下のEC2インスタンスを起動しました。

  • インスタンスタイプ:m5.xlarge
  • OS:Amazon Linux2
  • AMI ID:ami-0ce107ae7af2e92b5
  • カーネルバージョン:4.14.193-149.317.amzn2.x86_64

いつの間にかEC2起動時のウィザードにEnclaveを有効化するためのオプションが追加されていますね。

Nitro Enclaves CLIのインストール

EC2が起動したらNitro CLIをインストールします

$ sudo  amazon-linux-extras install aws-nitro-enclaves-cli -y
Installing aws-nitro-enclaves-cli
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Cleaning repos: amzn2-core amzn2extra-aws-nitro-enclaves-cli amzn2extra-docker
12 metadata files removed
4 sqlite files removed
0 metadata files removed
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core                                                                                                                                                                                                                    

...略
 
 47  aws-nitro-enclaves-cli=latest  enabled      [ =stable ]
 48  R4                             available    [ =stable ]

Nitro Enclaves development toolsのインストール

$ sudo yum install aws-nitro-enclaves-cli-devel -y

Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Resolving Dependencies
--> Running transaction check
---> Package aws-nitro-enclaves-cli-devel.x86_64 0:1.0-5.amzn2 will be installed
--> Finished Dependency Resolution

...略

Installed:
  aws-nitro-enclaves-cli-devel.x86_64 0:1.0-5.amzn2

Complete!

続いてec-userをneグループとdockerグループに追加します

$ sudo usermod -aG ne ec2-user
$ sudo usermod -aG docker ec2-user

追加できたら一度ログアウト、再ログインしておきましょう。

Nitro CLIのバージョンを確認してみます。

$ nitro-cli --version
Nitro CLI 0.1.0

続いてnitro-enclaves-allocatorの起動&自動起動を有効化します。このサービスはEC2インスタンス起動時にEnclave向けにメモリとvCPUを予約してくれるサービスです。

$ sudo systemctl start nitro-enclaves-allocator.service && sudo systemctl enable nitro-enclaves-allocator.service
Created symlink from /etc/systemd/system/multi-user.target.wants/nitro-enclaves-allocator.service to /usr/lib/systemd/system/nitro-enclaves-allocator.service.

予約するメモリ、vCPUは/etc/nitro_enclaves/allocator.yamlで設定します。今回はデフォルト値のまま進めました。

/etc/nitro_enclaves/allocator.yaml

---
# Enclave configuration file.
#
# How much memory to allocate for enclaves (in MiB).
memory_mib: 512
#
# How many CPUs to reserve for enclaves.
cpu_count: 2
#
# Alternatively, the exact CPUs to be reserved for the enclave can be explicitely
# configured by using `cpu_pool` (like below), instead of `cpu_count`.
# Note: cpu_count and cpu_pool conflict with each other. Only use exactly one of them.
# Example of reserving CPUs 2, 3, and 6 through 9:
# cpu_pool: 2,3,6-9

最後にDockerサービスを起動しつつ、自動起動を有効化しておきます

$ sudo systemctl start docker && sudo systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.

Enclaveイメージファイルのビルド

続いてEnclave用のイメージファイルをビルドします。Enclave用のイメージはDockerイメージからビルドするので、まずはDockerイメージのビルドから行います。/usr/share/nitro_enclaves/examples/helloにサンプルのDockerfileがあるので、これを利用します

$ docker build /usr/share/nitro_enclaves/examples/hello -t hello

Sending build context to Docker daemon   5.12kB
Step 1/4 : FROM busybox
latest: Pulling from library/busybox
9758c28807f2: Pull complete
Digest: sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d
Status: Downloaded newer image for busybox:latest
 ---> f0b02e9d092d
Step 2/4 : ENV HELLO="Hello from the enclave side!"
 ---> Running in 1934e2701fa1
Removing intermediate container 1934e2701fa1
 ---> 8671ef6a13b1
Step 3/4 : COPY hello.sh /bin/hello.sh
 ---> 2beae393bde7
Step 4/4 : CMD ["/bin/hello.sh"]
 ---> Running in 45bddf6dcc6a
Removing intermediate container 45bddf6dcc6a
 ---> 27eb8d7bf0ac
Successfully built 27eb8d7bf0ac
Successfully tagged hello:latest

ビルドできたことを確認します

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              27eb8d7bf0ac        3 minutes ago       1.23MB
busybox             latest              f0b02e9d092d        2 weeks ago         1.23MB

Dockerイメージが準備できたので、DocerkイメージをEnclaveイメージに変換します。

$ nitro-cli build-enclave --docker-uri hello:latest --output-file hello.eif
Start building the Enclave Image...
Enclave Image successfully created.
{
  "Measurements": {
    "HashAlgorithm": "Sha384 { ... }",
    "PCR0": "d5af17bde7ce1853f0142e7dc9993a4a8631c7c98c28c22652fa19a8ed3399626cb3eba32487a21e137a985c9ecdb0ac",
    "PCR1": "ef5b4f1f63c3fe666bdf4a096bae53439d28a9fa70c33241c0e1479a1b6f17cff6d100accbe01d766a19e8116b0a2c70",
    "PCR2": "bf3957c730d97ed1da544c454afd85eba663b2822047de3a832f0f4805f3f75271220c1a33c2836d217798b9a3ca9249"
  }
}

Enclaveの起動

Enclaveイメージが準備できたので、Enclaveを起動します

$ nitro-cli run-enclave --cpu-count 2 --memory 512 --eif-path hello.eif --debug-mode
Start allocating memory...
Started enclave with enclave-cid: 16, memory: 512 MiB, cpu-ids: [1, 3]
{
  "EnclaveID": "i-0478b502a88c70dfd-enc1758247c92dfb6b",
  "ProcessID": 13280,
  "EnclaveCID": 16,
  "NumberOfCPUs": 2,
  "CPUIDs": [
    1,
    3
  ],
  "MemoryMiB": 512
}

起動完了時に出力されるEnclaveIDを控えておきましょう

Enclaveの確認

起動中のEnclave一覧を確認してみましょう

$ nitro-cli describe-enclaves
[
  {
    "EnclaveID": "i-0478b502a88c70dfd-enc1758247c92dfb6b",
    "ProcessID": 13280,
    "EnclaveCID": 16,
    "NumberOfCPUs": 2,
    "CPUIDs": [
      1,
      3
    ],
    "MemoryMiB": 512,
    "State": "RUNNING",
    "Flags": "DEBUG_MODE"
  }
]

先程起動したEnclavei-0478b502a88c70dfd-enc1758247c92dfb6bが起動していることが分かります。

最後にEnclaveのコンソールを確認してみます

nitro-cli console --enclave-id <先程確認したEnclaveID>
Connecting to the console for enclave 16...
Successfully connected to the console.
[    0.000000] Linux version 4.14.177-104.253.amzn2.x86_64 (mockbuild@ip-10-0-1-32) (gcc version 7.3.1 20180712 (Red Hat 7.3.1-6) (GCC)) #1 SMP Fri May 1 02:01:13 UTC 2020
[    0.000000] Command line: reboot=k panic=30 pci=off nomodules console=ttyS0 i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd random.trust_cpu=on virtio_mmio.device=4K@0xd0000000:5 virtio_mmio.device=4K@0xd0001000:6
[    0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x008: 'MPX bounds registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x010: 'MPX CSR'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x020: 'AVX-512 opmask'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x040: 'AVX-512 Hi256'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x080: 'AVX-512 ZMM_Hi256'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x200: 'Protection Keys User registers'
[    0.000000] x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256
[    0.000000] x86/fpu: xstate_offset[3]:  832, xstate_sizes[3]:   64
[    0.000000] x86/fpu: xstate_offset[4]:  896, xstate_sizes[4]:   64
[    0.000000] x86/fpu: xstate_offset[5]:  960, xstate_sizes[5]:   64
[    0.000000] x86/fpu: xstate_offset[6]: 1024, xstate_sizes[6]:  512
[    0.000000] x86/fpu: xstate_offset[7]: 1536, xstate_sizes[7]: 1024
[    0.000000] x86/fpu: xstate_offset[9]: 2560, xstate_sizes[9]:    8
[    0.000000] x86/fpu: Enabled xstate features 0x2ff, context size is 2568 bytes, using 'compacted' format.
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000001f7fffff] usable
[    0.000000] NX (Execute Disable) protection: active
[    0.000000] DMI not present or invalid.
[    0.000000] Hypervisor detected: KVM
[    0.000000] tsc: Fast TSC calibration using PIT
[    0.000000] e820: last_pfn = 0x1f800 max_arch_pfn = 0x400000000
[    0.000000] MTRR: Disabled
[    0.000000] x86/PAT: MTRRs disabled, skipping PAT initialization too.
[    0.000000] CPU MTRRs all blank - virtualized system.
[    0.000000] x86/PAT: Configuration [0-7]: WB  WT  UC- UC  WB  WT  UC- UC
[    0.000000] found SMP MP-table at [mem 0x0009fc00-0x0009fc0f]
[    0.000000] Scanning 1 areas for low memory corruption
[    0.000000] Using GB pages for direct mapping
[    0.000000] RAMDISK: [mem 0x02447000-0x02665fff]
[    0.000000] No NUMA configuration found
[    0.000000] Faking a node at [mem 0x0000000000000000-0x000000001f7fffff]
[    0.000000] NODE_DATA(0) allocated [mem 0x1f7de000-0x1f7fffff]
[    0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00
[    0.000000] kvm-clock: cpu 0, msr 0:1f7dc001, primary cpu clock
[    0.000000] kvm-clock: using sched offset of 329297422 cycles
[    0.000000] clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000000001000-0x0000000000ffffff]
[    0.000000]   DMA32    [mem 0x0000000001000000-0x000000001f7fffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000001000-0x000000000009efff]
[    0.000000]   node   0: [mem 0x0000000000100000-0x000000001f7fffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000001000-0x000000001f7fffff]
[    0.000000] Intel MultiProcessor Specification v1.4
[    0.000000] MPTABLE: OEM ID: FC
[    0.000000] MPTABLE: Product ID: 000000000000
[    0.000000] MPTABLE: APIC at: 0xFEE00000
[    0.000000] Processor #0 (Bootup-CPU)
[    0.000000] Processor #1
[    0.000000] IOAPIC[0]: apic_id 3, version 17, address 0xfec00000, GSI 0-23
[    0.000000] Processors: 2
[    0.000000] smpboot: Allowing 2 CPUs, 0 hotplug CPUs
[    0.000000] PM: Registered nosave memory: [mem 0x00000000-0x00000fff]
[    0.000000] PM: Registered nosave memory: [mem 0x0009f000-0x000fffff]
[    0.000000] e820: [mem 0x1f800000-0xffffffff] available for PCI devices
[    0.000000] Booting paravirtualized kernel on KVM
[    0.000000] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645519600211568 ns
[    0.000000] random: get_random_bytes called from start_kernel+0x94/0x486 with crng_init=0
[    0.000000] setup_percpu: NR_CPUS:128 nr_cpumask_bits:128 nr_cpu_ids:2 nr_node_ids:1
[    0.000000] percpu: Embedded 41 pages/cpu s128600 r8192 d31144 u1048576
[    0.000000] KVM setup async PF for cpu 0
[    0.000000] kvm-stealtime: cpu 0, msr 1f415040
[    0.000000] PV qspinlock hash table entries: 256 (order: 0, 4096 bytes)
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 126889
[    0.000000] Policy zone: DMA32
[    0.000000] Kernel command line: reboot=k panic=30 pci=off nomodules console=ttyS0 i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd random.trust_cpu=on virtio_mmio.device=4K@0xd0000000:5 virtio_mmio.device=4K@0xd0001000:6
[    0.000000] PID hash table entries: 2048 (order: 2, 16384 bytes)
[    0.000000] Memory: 485488K/515704K available (10252K kernel code, 653K rwdata, 1572K rodata, 1300K init, 2808K bss, 30216K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
[    0.004000] Hierarchical RCU implementation.
[    0.004000] 	RCU restricting CPUs from NR_CPUS=128 to nr_cpu_ids=2.
[    0.004000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
[    0.004000] NR_IRQS: 4352, nr_irqs: 56, preallocated irqs: 16
[    0.004000] Console: colour dummy device 80x25
[    0.004000] console [ttyS0] enabled
[    0.004000] tsc: Detected 2499.998 MHz processor
[    0.004000] Calibrating delay loop (skipped) preset value.. 4999.99 BogoMIPS (lpj=9999992)
[    0.004000] pid_max: default: 32768 minimum: 301
[    0.004000] Security Framework initialized
[    0.004000] SELinux:  Initializing.
[    0.004000] Dentry cache hash table entries: 65536 (order: 7, 524288 bytes)
[    0.004000] Inode-cache hash table entries: 32768 (order: 6, 262144 bytes)
[    0.004000] Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)
[    0.004017] Mountpoint-cache hash table entries: 1024 (order: 1, 8192 bytes)
[    0.004961] Last level iTLB entries: 4KB 64, 2MB 8, 4MB 8
[    0.005396] Last level dTLB entries: 4KB 64, 2MB 0, 4MB 0, 1GB 4
[    0.005899] unchecked MSR access error: RDMSR from 0x122 at rIP: 0xffffffff81038c76 (native_read_msr+0x6/0x20)
[    0.006693] Call Trace:
[    0.006910]  tsx_disable+0x14/0x40
[    0.007196]  tsx_init+0xdf/0x134
[    0.007448]  identify_boot_cpu+0x78/0x7a
[    0.007748]  check_bugs+0x25/0x954
[    0.008013]  ? kmem_cache_alloc+0x132/0x140
[    0.008355]  start_kernel+0x45b/0x486
[    0.008655]  x86_64_start_reservations+0x2a/0x2c
[    0.009031]  x86_64_start_kernel+0x72/0x75
[    0.009364]  secondary_startup_64+0xa5/0xb0
[    0.009708] unchecked MSR access error: WRMSR to 0x122 (tried to write 0x0000000000000003) at rIP: 0xffffffff81038cb8 (native_write_msr+0x8/0x10)
[    0.010670] Call Trace:
[    0.010861]  tsx_disable+0x2e/0x40
[    0.011121]  tsx_init+0xdf/0x134
[    0.011368]  identify_boot_cpu+0x78/0x7a
[    0.011667]  check_bugs+0x25/0x954
[    0.012004]  ? kmem_cache_alloc+0x132/0x140
[    0.012376]  start_kernel+0x45b/0x486
[    0.012676]  x86_64_start_reservations+0x2a/0x2c
[    0.013052]  x86_64_start_kernel+0x72/0x75
[    0.013387]  secondary_startup_64+0xa5/0xb0
[    0.013733] Spectre V1 : Mitigation: usercopy/swapgs barriers and __user pointer sanitization
[    0.014412] Spectre V2 : Mitigation: Enhanced IBRS
[    0.014778] Spectre V2 : Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch
[    0.015403] Spectre V2 : mitigation: Enabling conditional Indirect Branch Prediction Barrier
[    0.016004] Speculative Store Bypass: Mitigation: Speculative Store Bypass disabled via prctl and seccomp
[    0.016722] TAA: Mitigation: TSX disabled
[    0.017270] Freeing SMP alternatives memory: 32K
[    0.019489] smpboot: Max logical packages: 2
[    0.020131] x2apic enabled
[    0.020522] Switched APIC routing to physical x2apic.
[    0.021693] ..TIMER: vector=0x30 apic1=0 pin1=0 apic2=-1 pin2=-1
[    0.022190] smpboot: CPU0: Intel(R) Xeon(R) Processor @ 2.50GHz (family: 0x6, model: 0x55, stepping: 0x7)
[    0.023006] Performance Events: unsupported p6 CPU model 85 no PMU driver, software events only.
[    0.023735] Hierarchical SRCU implementation.
[    0.024000] smp: Bringing up secondary CPUs ...
[    0.024000] x86: Booting SMP configuration:
[    0.024000] .... node  #0, CPUs:      #1
[    0.004000] kvm-clock: cpu 1, msr 0:1f7dc041, secondary cpu clock
[    0.024272] KVM setup async PF for cpu 1
[    0.024295] kvm-stealtime: cpu 1, msr 1f515040
[    0.024776] smp: Brought up 1 node, 2 CPUs
[    0.024776] smpboot: Total of 2 processors activated (9999.99 BogoMIPS)
[    0.024986] devtmpfs: initialized
[    0.024986] x86/mm: Memory block size: 128MB
[    0.024986] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.024986] futex hash table entries: 512 (order: 3, 32768 bytes)
[    0.028261] NET: Registered protocol family 16
[    0.028795] cpuidle: using governor ladder
[    0.028795] cpuidle: using governor menu
[    0.033536] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
[    0.033536] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[    0.033536] SCSI subsystem initialized
[    0.033536] pps_core: LinuxPPS API ver. 1 registered
[    0.033536] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.036018] PTP clock support registered
[    0.036335] dmi: Firmware registration failed.
[    0.036811] NetLabel: Initializing
[    0.037082] NetLabel:  domain hash size = 128
[    0.037421] NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO
[    0.037878] NetLabel:  unlabeled traffic allowed by default
[    0.038351] clocksource: Switched to clocksource kvm-clock
[    0.038802] VFS: Disk quotas dquot_6.6.0
[    0.039117] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    0.039716] NET: Registered protocol family 2
[    0.039788] TCP established hash table entries: 4096 (order: 3, 32768 bytes)
[    0.040350] TCP bind hash table entries: 4096 (order: 4, 65536 bytes)
[    0.040852] TCP: Hash tables configured (established 4096 bind 4096)
[    0.041358] UDP hash table entries: 256 (order: 1, 8192 bytes)
[    0.041811] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[    0.042331] NET: Registered protocol family 1
[    0.042754] RPC: Registered named UNIX socket transport module.
[    0.043207] RPC: Registered udp transport module.
[    0.043574] RPC: Registered tcp transport module.
[    0.043936] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.044479] Unpacking initramfs...
[    0.049019] Freeing initrd memory: 2172K
[    0.049373] virtio-mmio: Registering device virtio-mmio.0 at 0xd0000000-0xd0000fff, IRQ 5.
[    0.050026] virtio-mmio: Registering device virtio-mmio.1 at 0xd0001000-0xd0001fff, IRQ 6.
[    0.050685] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x240937b9988, max_idle_ns: 440795218083 ns
[    0.051469] platform rtc_cmos: registered platform RTC device (no PNP device found)
[    0.052300] Scanning for low memory corruption every 60 seconds
[    0.052977] audit: initializing netlink subsys (disabled)
[    0.053435] audit: type=2000 audit(1604208544.673:1): state=initialized audit_enabled=0 res=1
[    0.053559] Initialise system trusted keyrings
[    0.054537] Key type blacklist registered
[    0.054897] workingset: timestamp_bits=36 max_order=17 bucket_order=0
[    0.056638] zbud: loaded
[    0.057273] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.057866] NFS: Registering the id_resolver key type
[    0.058261] Key type id_resolver registered
[    0.058584] Key type id_legacy registered
[    0.058898] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[    0.060982] Key type asymmetric registered
[    0.061315] Asymmetric key parser 'x509' registered
[    0.061699] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
[    0.062290] io scheduler noop registered (default)
[    0.062693] io scheduler cfq registered
[    0.063069] virtio-mmio virtio-mmio.0: Failed to enable 64-bit or 32-bit DMA.  Trying to continue, but this might not work.
[    0.063969] virtio-mmio virtio-mmio.1: Failed to enable 64-bit or 32-bit DMA.  Trying to continue, but this might not work.
[    0.064917] Serial: 8250/16550 driver, 1 ports, IRQ sharing disabled
[    0.086720] serial8250: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a U6_16550A
[    0.088885] loop: module loaded
[    0.089183] Loading iSCSI transport class v2.0-870.
[    0.089682] iscsi: registered transport (tcp)
[    0.090027] tun: Universal TUN/TAP device driver, 1.6
[    0.090541] hidraw: raw HID events driver (C) Jiri Kosina
[    0.091023] nf_conntrack version 0.5.0 (4096 buckets, 16384 max)
[    0.091647] ip_tables: (C) 2000-2006 Netfilter Core Team
[    0.092259] Initializing XFRM netlink socket
[    0.092706] NET: Registered protocol family 10
[    0.093582] Segment Routing with IPv6
[    0.093917] NET: Registered protocol family 17
[    0.094276] Bridge firewalling registered
[    0.094626] Key type dns_resolver registered
[    0.095032] NET: Registered protocol family 40
[    0.095894] sched_clock: Marking stable (94994540, 0)->(153974421, -58979881)
[    0.096725] registered taskstats version 1
[    0.097050] Loading compiled-in X.509 certificates
[    0.098113] Loaded X.509 cert 'Build time autogenerated kernel key: c582bb2a1fdabdd195bbc9c8840fff8158852907'
[    0.098863] zswap: loaded using pool lzo/zbud
[    0.099400] Key type encrypted registered
[    0.100820] Freeing unused kernel memory: 1300K
[    0.120095] Write protecting the kernel read-only data: 14336k
[    0.121957] Freeing unused kernel memory: 2016K
[    0.123239] Freeing unused kernel memory: 476K
[    0.123806] nsm: loading out-of-tree module taints kernel.
[    0.124279] nsm: module verification failed: signature and/or required key missing - tainting kernel
[   1] Hello from the enclave side!
[   2] Hello from the enclave side!
[   3] Hello from the enclave side!
[   4] Hello from the enclave side!

注目したいのがEnclaveのコンソール出力の1行目Linux version 4.14.177-104.253.amzn2.x86_64の部分です。今回利用したEC2インスタンスのカーネルバージョン4.14.200-155.322.amzn2.x86_64とは異なります。EnclaveとホストOSでは別のカーネルが動作していることが分かります。この4.14.177-104.253.amzn2.x86_64というバージョンはどこから来たのでしょうか??Nitro Enclaves development toolsに内包されてるのかなー?と考え、それらしきディレクトリを漁ってみたところ見つかりました。

$ file /usr/share/nitro_enclaves/blobs/bzImage
/usr/share/nitro_enclaves/blobs/bzImage: Linux kernel x86 boot executable bzImage, version 4.14.177-104.253.amzn2.x86_64 (mockbuild@ip-10-0-1-32) #1 SMP F, RO-rootFS, swap_dev 0x4, Normal VGA

Enclaveイメージファイルをビルドする際に/usr/share/nitro_enclaves/blobs/bzImageを利用してイメージファイルをビルドしているようですね。他にも/usr/share/nitro_enclaves/blobs/配下にはいくつかのファイルが保存されていました。

$ tree /usr/share/nitro_enclaves/blobs/
/usr/share/nitro_enclaves/blobs/
├── bzImage
├── bzImage.config
├── cmdline
├── init
├── linuxkit
└── nsm.ko

名前から大体役割が想像できますね。このあたりのファイルを編集すればEnclaveを細かくカスタマイズできるのかもしれません。※こんなカスタマイズ方法はドキュメントのどこにも記載されていないので、もし試される場合は自己責任でお願いしますm(_ _)m

確認できたので、Enclaveを停止します

$ nitro-cli terminate-enclave --enclave-id i-0478b502a88c70dfd-enc1758247c92dfb6b
Successfully terminated enclave i-0478b502a88c70dfd-enc1758247c92dfb6b.
{
  "EnclaveID": "i-0478b502a88c70dfd-enc1758247c92dfb6b",
  "Terminated": true
}

以上。簡単ですがEnclaveイメージのビルド~起動までの一連の流れが確認できました。

まとめ

Nitro Enclavesについてご紹介しました。セキュリィ要件の厳しいワークロードを実行している環境ではNitro Enclavesの利用を検討してみるのも良いのではないでしょうか?

今回は簡単なGetting startedを試してみただけなので、後日改めてKMSとの連携やEnclave アプリを開発するためのNitro Enclaves SDKなども試してみようと思います。