Skip to content

Commit

Permalink
Allow signing EIFs with KMS while building
Browse files Browse the repository at this point in the history
This commit updates `nitro-cli` to use `aws-nitro-enclaves-image-format`
v0.4 which allows to sign EIF during build using a key from KMS. In
order to do so, user needs to specify KMS key ARN and region instead of
the local private key file.

Signed-off-by: Mark Kirichenko <[email protected]>
  • Loading branch information
atanzu committed Jan 20, 2025
1 parent 895a8c6 commit 8cd57f0
Show file tree
Hide file tree
Showing 11 changed files with 936 additions and 100 deletions.
839 changes: 761 additions & 78 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ page_size = "0.6"
signal-hook = "0.3"
ciborium = "0.2"
driver-bindings = { path = "./driver-bindings" }
aws-nitro-enclaves-image-format = "0.2"
aws-nitro-enclaves-image-format = "0.4"
eif_loader = { path = "./eif_loader" }
enclave_build = { path = "./enclave_build" }
openssl = "0.10.66"
Expand Down
2 changes: 1 addition & 1 deletion eif_loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ rust-version = "1.68"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aws-nitro-enclaves-image-format = "0.2"
aws-nitro-enclaves-image-format = "0.4"
nix = "0.26"
libc = "0.2"
vsock = "0.3"
Expand Down
2 changes: 1 addition & 1 deletion enclave_build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ url = "2.4"
sha2 = "0.9.5"
futures = "0.3.28"

aws-nitro-enclaves-image-format = "0.2"
aws-nitro-enclaves-image-format = "0.4"
tar = "0.4.40"
flate2 = "1.0.28"
41 changes: 33 additions & 8 deletions enclave_build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ mod yaml_generator;

use aws_nitro_enclaves_image_format::defs::{EifBuildInfo, EifIdentityInfo, EIF_HDR_ARCH_ARM64};
use aws_nitro_enclaves_image_format::utils::identity::parse_custom_metadata;
use aws_nitro_enclaves_image_format::utils::{EifBuilder, SignEnclaveInfo};
use aws_nitro_enclaves_image_format::utils::{
EifBuilder, SignKeyData, SignKeyDataInfo, SignKeyInfo,
};
use docker::DockerUtil;
use serde_json::json;
use sha2::Digest;
Expand All @@ -31,7 +33,7 @@ pub struct Docker2Eif<'a> {
linuxkit_path: String,
artifacts_prefix: String,
output: &'a mut File,
sign_info: Option<SignEnclaveInfo>,
sign_info: Option<SignKeyData>,
img_name: Option<String>,
img_version: Option<String>,
metadata_path: Option<String>,
Expand Down Expand Up @@ -70,6 +72,8 @@ impl<'a> Docker2Eif<'a> {
artifacts_prefix: String,
certificate_path: &Option<String>,
key_path: &Option<String>,
kms_key_id: &Option<String>,
kms_key_region: &Option<String>,
img_name: Option<String>,
img_version: Option<String>,
metadata_path: Option<String>,
Expand Down Expand Up @@ -98,15 +102,31 @@ impl<'a> Docker2Eif<'a> {
}
}

let sign_info = match (certificate_path, key_path) {
let sign_key_info = match (kms_key_id, key_path) {
(None, None) => None,
(Some(cert_path), Some(key_path)) => Some(
SignEnclaveInfo::new(cert_path, key_path)
.map_err(|err| Docker2EifError::SignImageError(format!("{err:?}")))?,
),
(Some(kms_id), None) => Some(SignKeyInfo::KmsKeyInfo {
id: kms_id.into(),
region: kms_key_region.clone(),
}),
(None, Some(key_path)) => Some(SignKeyInfo::LocalPrivateKeyInfo {
path: key_path.into(),
}),
_ => return Err(Docker2EifError::SignArgsError),
};

let sign_info = sign_key_info
.map(|key_info| {
SignKeyData::new(&SignKeyDataInfo {
cert_path: certificate_path
.as_ref()
.ok_or(Docker2EifError::SignArgsError)?
.into(),
key_info,
})
.map_err(|_| Docker2EifError::SignArgsError)
})
.transpose()?;

Ok(Docker2Eif {
docker_image,
docker,
Expand Down Expand Up @@ -275,10 +295,15 @@ impl<'a> Docker2Eif<'a> {
_ => return Err(Docker2EifError::UnsupportedArchError),
};

// We cannot clone `sign_info` because it might contain a KmsKey object
// which is not copyable. Since `create` is the last method called, we can
// move it out of the struct.
let sign_info = self.sign_info.take();

let mut build = EifBuilder::new(
Path::new(&self.kernel_img_path),
self.cmdline.clone(),
self.sign_info.clone(),
sign_info,
sha2::Sha384::new(),
flags,
self.generate_identity_info()?,
Expand Down
25 changes: 24 additions & 1 deletion enclave_build/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use clap::{Arg, ArgAction, Command};
use clap::{Arg, ArgAction, ArgGroup, Command};
use std::fs::OpenOptions;

use aws_nitro_enclaves_image_format::generate_build_info;
Expand Down Expand Up @@ -75,6 +75,23 @@ fn main() {
.long("private-key")
.help("Specify the path to the private-key"),
)
.arg(
Arg::new("kms-key-id")
.long("kms-key-id")
.help("Specify unique id of the KMS key")
)
.arg(
Arg::new("kms-key-region")
.long("kms-key-region")
.help("Specify region in which the KMS key resides")
.requires("kms-key-id")
)
.group(
ArgGroup::new("signing-key")
.args(["kms-key-id", "private-key"])
.multiple(false)
.requires("signing-certificate")
)
.arg(
Arg::new("build")
.short('b')
Expand Down Expand Up @@ -122,6 +139,10 @@ fn main() {
let img_name = matches.get_one::<String>("image_name").map(String::from);
let img_version = matches.get_one::<String>("image_version").map(String::from);
let metadata = matches.get_one::<String>("metadata").map(String::from);
let kms_key_id = matches.get_one::<String>("kms-key-id").map(String::from);
let kms_key_region = matches
.get_one::<String>("kms-key-region")
.map(String::from);

let mut output = OpenOptions::new()
.read(true)
Expand All @@ -142,6 +163,8 @@ fn main() {
".".to_string(),
&signing_certificate,
&private_key,
&kms_key_id,
&kms_key_region,
img_name,
img_version,
metadata,
Expand Down
32 changes: 24 additions & 8 deletions src/common/commands_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ pub struct BuildEnclavesArgs {
pub signing_certificate: Option<String>,
/// The path to the private key for signed enclaves.
pub private_key: Option<String>,
/// ID of the KMS key for signed enclaves.
pub kms_key_id: Option<String>,
/// Region of the KMS key for signed enclaves.
pub kms_key_region: Option<String>,
/// The name of the enclave image.
pub img_name: Option<String>,
/// The version of the enclave image.
Expand All @@ -121,16 +125,18 @@ impl BuildEnclavesArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
let signing_certificate = parse_signing_certificate(args);
let private_key = parse_private_key(args);
let kms_key_id = parse_kms_key_id(args);
let kms_key_region = parse_kms_key_region(args);

match (&signing_certificate, &private_key) {
(Some(_), None) => {
match (&signing_certificate, &private_key, &kms_key_id) {
(_, Some(_), Some(_)) => {
return Err(new_nitro_cli_failure!(
"`private-key` argument not found",
NitroCliErrorEnum::MissingArgument
)
.add_info(vec!["private-key"]))
"Cannot use both `private-key` and `kms-key-id`",
NitroCliErrorEnum::ConflictingArgument
))
}
(None, Some(_)) => {
(None, None, None) => (),
(None, _, _) => {
return Err(new_nitro_cli_failure!(
"`signing-certificate` argument not found",
NitroCliErrorEnum::MissingArgument
Expand Down Expand Up @@ -158,6 +164,8 @@ impl BuildEnclavesArgs {
})?,
signing_certificate,
private_key,
kms_key_id,
kms_key_region,
img_name: parse_image_name(args),
img_version: parse_image_version(args),
metadata: parse_metadata(args),
Expand Down Expand Up @@ -543,6 +551,14 @@ fn parse_private_key(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("private-key").map(String::from)
}

fn parse_kms_key_id(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("kms-key-id").map(String::from)
}

fn parse_kms_key_region(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("kms-key-region").map(String::from)
}

fn parse_image_name(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("image_name").map(String::from)
}
Expand Down Expand Up @@ -572,7 +588,7 @@ mod tests {
use crate::common::construct_error_message;
use crate::create_app;

use clap::{Arg, Command};
use clap::{Arg, ArgGroup, Command};

/// Parse the path of the JSON config file
fn parse_config_file(args: &ArgMatches) -> NitroCliResult<String> {
Expand Down
23 changes: 23 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub fn build_enclaves(args: BuildEnclavesArgs) -> NitroCliResult<()> {
&args.output,
&args.signing_certificate,
&args.private_key,
&args.kms_key_id,
&args.kms_key_region,
&args.img_name,
&args.img_version,
&args.metadata,
Expand All @@ -73,6 +75,8 @@ pub fn build_from_docker(
output_path: &str,
signing_certificate: &Option<String>,
private_key: &Option<String>,
kms_key_id: &Option<String>,
kms_key_region: &Option<String>,
img_name: &Option<String>,
img_version: &Option<String>,
metadata_path: &Option<String>,
Expand Down Expand Up @@ -136,6 +140,8 @@ pub fn build_from_docker(
artifacts_path()?,
signing_certificate,
private_key,
kms_key_id,
kms_key_region,
img_name.clone(),
img_version.clone(),
metadata_path.clone(),
Expand Down Expand Up @@ -714,6 +720,23 @@ macro_rules! create_app {
.long("private-key")
.help("Local path to developer's Eliptic Curve private key."),
)
.arg(
Arg::new("kms-key-id")
.long("kms-key-id")
.help("Specify unique id of the KMS key")
)
.arg(
Arg::new("kms-key-region")
.long("kms-key-region")
.help("Specify region in which the KMS key resides")
.requires("kms-key-id")
)
.group(
ArgGroup::new("signing-key")
.args(&["kms-key-id", "private-key"])
.multiple(false)
.requires("signing-certificate")
)
.arg(
Arg::new("image_name")
.long("name")
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
extern crate lazy_static;

use clap::{Arg, Command};
use clap::{Arg, ArgGroup, Command};
use log::info;
use std::os::unix::net::UnixStream;

Expand Down
2 changes: 1 addition & 1 deletion tests/test_nitro_cli_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#[cfg(test)]
mod test_nitro_cli_args {
use clap::{Arg, Command};
use clap::{Arg, ArgGroup, Command};
use nitro_cli::create_app;

#[test]
Expand Down
Loading

0 comments on commit 8cd57f0

Please sign in to comment.