Skip to content

Preliminary support for AWS Nitro Enclaves #325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 12, 2025
Merged

Conversation

tylerfanelli
Copy link
Member

@tylerfanelli tylerfanelli commented May 2, 2025

This PR adds a new flavor, libkrun-nitro. The nitro flavor is expected to be run on AWS EC2 instances that support AWS Nitro Enclaves.

AWS Nitro Enclaves are fully isolated and highly constrained virtual machines that run on the Nitro hypervisor. CPUs and memory of an enclave are completely isolated from a parent instance and other users of a system, significantly reducing the attack surface and helping to prevent the stealing/tampering of data.

Try for yourself

To demo on an AWS EC2 instance with Nitro Enclaves enabled:

  • Clone repo, checkout the nitro branch
$ git clone https://github.com/tylerfanelli/libkrun.git
$ cd libkrun
$ git checkout nitro
  • Build the libkrun-nitro flavor
$ make NITRO=1
$ make install NITRO=1
$ ln /usr/local/lib64/libkrun-nitro.so /usr/local/lib64/libkrun.so.1
  • Build the nitro example
$ cd examples
$ make nitro
  • Run the nitro example with an example EIF file found in examples/test_data
$ LD_LIBRARY_PATH=/usr/local/lib64 ./nitro test_data/hello.eif

This will run the enclave in debug mode, where you can examine debug output from the nitro enclave.

This will include Linux kernel logs:

[    0.000000] Booting Linux on physical CPU 0x0                                                                                                                                                                                                                                
.. snip ..

As well as a hello message from the enclave:

.. snip ..
[    0.062913] random: crng init done
[    0.063151] NSM RNG: returning rand bytes = 128
[    0.063450] NSM RNG: returning rand bytes = 128
Hello (from a nitro enclave!)
[    0.066406] reboot: Restarting system

@tylerfanelli
Copy link
Member Author

cc @slp

@tylerfanelli tylerfanelli force-pushed the nitro branch 3 times, most recently from e202171 to 299f3f9 Compare May 2, 2025 20:31
Copy link
Member

@jakecorrenti jakecorrenti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I haven't tested the code yet, but so far things are looking good. I added a couple nits here and there.

In general, I would prefer if the commits were ordered such that changes in src/ come first, then include/, then finally examples/. My thought process behind this is it prevents the use of the API before the functionality is fully baked. Then, once we have the "backend" code, we can add the UAPI, then finally the example when everything's in a state where a working solution is possible. I think that would be a pretty invasive change here so I'm not asking you to do that, but I'm not sure how others feel about commit ordering in that sense.

@tylerfanelli
Copy link
Member Author

tylerfanelli commented May 6, 2025

In general, I would prefer if the commits were ordered such that changes in src/ come first, then include/, then finally examples/. My thought process behind this is it prevents the use of the API before the functionality is fully baked. Then, once we have the "backend" code, we can add the UAPI, then finally the example when everything's in a state where a working solution is possible. I think that would be a pretty invasive change here so I'm not asking you to do that, but I'm not sure how others feel about commit ordering in that sense.

I would say this is up to personal preference. You could include the examples/ and include/ modifications along with the src/ modifications if it logically makes sense, or you could split them up.

However, this is not true if you make a change that would break a caller's use of an API. In that scenario, the changes to the caller must be also included (in examples/, for instance), as to not break the example/test.

@tylerfanelli tylerfanelli force-pushed the nitro branch 9 times, most recently from dd698c8 to 00be2da Compare May 12, 2025 22:03
@tylerfanelli tylerfanelli requested a review from slp as a code owner May 12, 2025 22:03
@@ -13,6 +13,7 @@ efi = ["blk", "net"]
gpu = ["rutabaga_gfx", "thiserror", "zerocopy", "zerocopy-derive"]
snd = ["pw", "thiserror"]
virgl_resource_map2 = []
nitro = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: do we want to follow some sort of naming convention with the TEE features? We currently have amd-sev which is prefixed by the manufacturer, intel-tdx which will follow that style as well. We also have nitro and in the future cca.

Should we come to some sort of consensus with regards to a manufacturer prefix or not? Does it matter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could. I prefer sev and tdx rather than amd-sev and intel-tdx FWIW.

jakecorrenti
jakecorrenti previously approved these changes May 14, 2025
Copy link
Member

@jakecorrenti jakecorrenti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM

@tylerfanelli
Copy link
Member Author

@slp Can you review when you have the chance?

@tylerfanelli
Copy link
Member Author

@jakecorrenti @slp After rebasing, I'm seeing a weird issue. Each test is failing with the following:


error[E0308]: mismatched types
   --> src/devices/src/legacy/ioapic.rs:141:28
    |
141 |         vm.set_gsi_routing(&irq_routing[0])?;
    |            --------------- ^^^^^^^^^^^^^^^ expected `&FamStructWrapper<kvm_irq_routing>`, found `&kvm_irq_routing`
    |            |
    |            arguments to this method are incorrect
    |
    = note: expected reference `&vmm_sys_util::fam::FamStructWrapper<kvm_bindings::kvm_irq_routing>`
               found reference `&kvm_bindings::kvm_irq_routing`
note: method defined here
   --> /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/kvm-ioctls-0.22.0/src/ioctls/vm.rs:633:12
    |
633 |     pub fn set_gsi_routing(&self, irq_routing: &KvmIrqRouting) -> Result<()> {
    |            ^^^^^^^^^^^^^^^

I didn't change any of the kvm-bindings, kvm-ioctls, or vmm-sys-utils dependencies, and this is not an issue in the main branch (with the same dependency versions). Do you have any idea what could cause this?

@jakecorrenti
Copy link
Member

jakecorrenti commented Jun 6, 2025

@jakecorrenti @slp After rebasing, I'm seeing a weird issue. Each test is failing with the following:


error[E0308]: mismatched types
   --> src/devices/src/legacy/ioapic.rs:141:28
    |
141 |         vm.set_gsi_routing(&irq_routing[0])?;
    |            --------------- ^^^^^^^^^^^^^^^ expected `&FamStructWrapper<kvm_irq_routing>`, found `&kvm_irq_routing`
    |            |
    |            arguments to this method are incorrect
    |
    = note: expected reference `&vmm_sys_util::fam::FamStructWrapper<kvm_bindings::kvm_irq_routing>`
               found reference `&kvm_bindings::kvm_irq_routing`
note: method defined here
   --> /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/kvm-ioctls-0.22.0/src/ioctls/vm.rs:633:12
    |
633 |     pub fn set_gsi_routing(&self, irq_routing: &KvmIrqRouting) -> Result<()> {
    |            ^^^^^^^^^^^^^^^

I didn't change any of the kvm-bindings, kvm-ioctls, or vmm-sys-utils dependencies, and this is not an issue in the main branch (with the same dependency versions). Do you have any idea what could cause this?

upstream kvm-bindings wrapped kvm_irq_routing in a FamStructWrapper as of this PR rust-vmm/kvm#325. I can work on a fix right now

@tylerfanelli
Copy link
Member Author

Yes, but I never updated those dependencies? Regardless, it seems that #348 fixed it. Thanks!

The nitro flavor introduces support for libkrun acting as a "driver" and
manager for AWS Nitro Enclaves.

Signed-off-by: Tyler Fanelli <[email protected]>
Nitro enclaves' memory regions are defined by enclave image files.
Introduce a libkrun API to set an enclave's image from a file path as
well as the type of enclave image it is.

Currently, only Enclave Image Format (EIF) files are supported for nitro
enclaves.

Signed-off-by: Tyler Fanelli <[email protected]>
The guest/libkrun process will initiate the communication of vsock data
from a nitro enclave.

Signed-off-by: Tyler Fanelli <[email protected]>
@jakecorrenti
Copy link
Member

Yes, but I never updated those dependencies? Regardless, it seems that #348 fixed it. Thanks!

You changed src/utils/Cargo.toml to use kvm-bindings >= 0.10 instead of 0.11 which probably triggered the update if I had to guess

@tylerfanelli
Copy link
Member Author

Yes, but I never updated those dependencies? Regardless, it seems that #348 fixed it. Thanks!

You changed src/utils/Cargo.toml to use kvm-bindings >= 0.10 instead of 0.11 which probably triggered the update if I had to guess

Yea, that must've been a mistake. Removed that change.

The nitro module/crate will serve as the main management layer for nitro
enclaves. Collecting enclave resources from a krun context will allow us
to re-use the existing libkrun APIs for nitro enclaves.

Signed-off-by: Tyler Fanelli <[email protected]>
The nitro example will run a nitro enclave in debug mode and print the
vsock data from the enclave to the console.

Signed-off-by: Tyler Fanelli <[email protected]>
Uses the nitro-enclaves crate to create and run an enclave in debug mode.

Signed-off-by: Tyler Fanelli <[email protected]>
To give more control to the user, allow for the krun_add_vsock_port API
to forward enclave data to/from and IPC socket set up by a consumer of
the library.

Signed-off-by: Tyler Fanelli <[email protected]>
The nitro workspace member is not supported on macOS and has
Linux-exclusive dependencies. Exclude the crate when running
clippy on macOS.

Signed-off-by: Tyler Fanelli <[email protected]>
Copy link
Collaborator

@slp slp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@slp slp merged commit 885d642 into containers:main Jun 12, 2025
6 checks passed
@tylerfanelli tylerfanelli deleted the nitro branch June 12, 2025 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants