Skip to content

Utilities to reproducibly build images for AWS Nitro Enclaves

License

Notifications You must be signed in to change notification settings

monzo/aws-nitro-util

Repository files navigation

AWS Nitro utilities

This repo contains a Nix flake with some helpers to reproducibly build AWS Nitro Enclave image files.

You can think of it as an alternative to nitro-cli build-enclave for building EIFs. The idea is to:

  • have a more secure EIF-building process, by having the tool that builds them also be bit-by-bit reproducible, thus reducing the surface for supply-chain attacks as well as removing some implicit trust on AWS.
  • remove the dependency on containers completely, while still allowing their use
  • give users complete control over their enclave images, providing additional options like BYOK (Bring Your Own Kernel)
  • easily build EIFs on systems other than Amazon Linux, including M1+ Macs (e.g, it's possible to build an x86_64 Linux EIF on an ARM Mac)

We wrote a blog post about our motivation for building this tooling at Monzo. We recommend you read it if you use AWS Nitro Enclaves and you are wondering why you might want to use it. We also recommend this other excellent blog post to learn more about the EIF Nitro image format in general.

The tradeoffs between using this repo and AWS' nitro-cli are:

Feature nitro-cli build-enclave monzo/aws-nitro-util
EIF userspace input Docker container plain files, including nix packages and unpacked OCI images
EIF bootstrap input pre-compiled kernel binary provided by AWS use pre-compiled kernel by AWS or bring your own kernel (see example)
dependencies Docker, linuxkit fork, aws/aws-nitro-enclaves-image-format Nix, aws/aws-nitro-enclaves-image-format
Source-reproducible no, uses pre-compiled blobs provided by AWS yes, can be built entirely from source
Bit-by-bit reproducible EIFs no, EIFs are timestamped yes, building the same EIF will result in the same SHA256
cross-architecture EIFs yes, if you provide a container for the right architecture yes, if you provide binaries for the right architecture
OS* Amazon Linux unless you compile nitro-cli from source for other Linux. No MacOS. any Linux or MacOS with a Nix installation

(*): OS for building EIFs. Note that

  • to make EIFs on a Mac, you have to be able to cross-compile the userspace binaries from Darwin to Linux
  • even if you make an EIF on a Mac, it can still only run on Linux.

Examples

You can find examples in examples/.

Note that you need to install Nix and enable flakes to use this repo.

Design

monzo/aws-nitro-util compiles a CLI from aws/aws-nitro-enclaves-image-format (which allows building an EIF from a specific file structure) and of Nix utilities to reproducibly build AWS' tooling, the EIF, and its dependencies.

A typical EIF build would look like the following:

%%{init: {"flowchart": {"htmlLabels": false}} }%%

graph TD
	style yourRepo stroke:#C802E5
	style yourRepo stroke-width:4

	style initBin stroke:#018E01
	style initBin stroke-width:4

	style nsm stroke:#9B6201
	style nsm stroke-width:4

	style kernel stroke:#9B6201
	style kernel stroke-width:4



	subgraph The internet
		eifFormatRepo("📦 github repo \n aws/ \n aws-nitro-enclaves-\nimage-format")
		nitroCliRepo("📦 github repo \n aws/ \n aws-nitro-enclaves-\n cli")
		bootstrapRepo("📦 github repo \n aws/ \n aws-nitro-enclaves-\nsdk-bootstrap")
		yourRepo("your source code \n or OCI image")
	end
	initBin("init \n compiled init.c \n (or bring your own)")
	eifCli("📦 eif_build CLI \n")
	nsm("nsm.ko \n compiled Nitro \n kernel module \n (or bring your own)")

    subgraph PCR1
        kernel("Kernel binary \n (or bring your own)")
        sysInit("system-initramfs \n (app-agnositc) \n PCR1")
	end
    userInit("user-initramfs \n (app-specific)\n PCR2")
	
	rootfs("rootfs \n folder containing \n filesystem \n (eg, compiled main.go)")

	doEif(("package \n EIF..."))
	doSysInit(("package sys \n initramfs..."))
	doUserInit(("package user \n initramfs..."))
	
	yourRepo -->|compile \n from source|main("main \n compiled \n binary")
	main --> rootfs
	bootstrapRepo -->|compile \nfrom source|initBin

	nitroCliRepo -.->|has under blobs/|nsm
	nitroCliRepo -.->|has under blobs/|kernel

	rootfs --> doUserInit
	doUserInit==> userInit

	initBin --->doSysInit
	nsm-->doSysInit
	doSysInit ==> sysInit

	eifFormatRepo ---> |compile \n from source|eifCli
	eifCli -->doEif
	kernel -->doEif
	sysInit ==>doEif
	userInit ==>doEif


	doEif -->eif("image.eif \n enclave image")
	doEif -->pcr("pcr.json \n PCR signatures")
Loading
  • Pink outline: your build input (what will run on the enclave after it boots)
  • Green outline: by AWS, compiled from source
  • Brown outline: by AWS, downloaded trusted binary (that you can choose to replace with your own)