Skip to content

Commit d7221a8

Browse files
committed
Allow signing EIFs with KMS while building
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]>
1 parent 895a8c6 commit d7221a8

File tree

11 files changed

+936
-100
lines changed

11 files changed

+936
-100
lines changed

Cargo.lock

Lines changed: 761 additions & 78 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ page_size = "0.6"
2020
signal-hook = "0.3"
2121
ciborium = "0.2"
2222
driver-bindings = { path = "./driver-bindings" }
23-
aws-nitro-enclaves-image-format = "0.2"
23+
aws-nitro-enclaves-image-format = "0.4"
2424
eif_loader = { path = "./eif_loader" }
2525
enclave_build = { path = "./enclave_build" }
2626
openssl = "0.10.66"

eif_loader/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ rust-version = "1.68"
88
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
99

1010
[dependencies]
11-
aws-nitro-enclaves-image-format = "0.2"
11+
aws-nitro-enclaves-image-format = "0.4"
1212
nix = "0.26"
1313
libc = "0.2"
1414
vsock = "0.3"

enclave_build/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ url = "2.4"
2121
sha2 = "0.9.5"
2222
futures = "0.3.28"
2323

24-
aws-nitro-enclaves-image-format = "0.2"
24+
aws-nitro-enclaves-image-format = "0.4"
2525
tar = "0.4.40"
2626
flate2 = "1.0.28"

enclave_build/src/lib.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ mod yaml_generator;
1212

1313
use aws_nitro_enclaves_image_format::defs::{EifBuildInfo, EifIdentityInfo, EIF_HDR_ARCH_ARM64};
1414
use aws_nitro_enclaves_image_format::utils::identity::parse_custom_metadata;
15-
use aws_nitro_enclaves_image_format::utils::{EifBuilder, SignEnclaveInfo};
15+
use aws_nitro_enclaves_image_format::utils::{
16+
EifBuilder, SignKeyData, SignKeyDataInfo, SignKeyInfo,
17+
};
1618
use docker::DockerUtil;
1719
use serde_json::json;
1820
use sha2::Digest;
@@ -31,7 +33,7 @@ pub struct Docker2Eif<'a> {
3133
linuxkit_path: String,
3234
artifacts_prefix: String,
3335
output: &'a mut File,
34-
sign_info: Option<SignEnclaveInfo>,
36+
sign_info: Option<SignKeyData>,
3537
img_name: Option<String>,
3638
img_version: Option<String>,
3739
metadata_path: Option<String>,
@@ -70,6 +72,8 @@ impl<'a> Docker2Eif<'a> {
7072
artifacts_prefix: String,
7173
certificate_path: &Option<String>,
7274
key_path: &Option<String>,
75+
kms_key_id: &Option<String>,
76+
kms_key_region: &Option<String>,
7377
img_name: Option<String>,
7478
img_version: Option<String>,
7579
metadata_path: Option<String>,
@@ -98,15 +102,31 @@ impl<'a> Docker2Eif<'a> {
98102
}
99103
}
100104

101-
let sign_info = match (certificate_path, key_path) {
105+
let sign_key_info = match (kms_key_id, key_path) {
102106
(None, None) => None,
103-
(Some(cert_path), Some(key_path)) => Some(
104-
SignEnclaveInfo::new(cert_path, key_path)
105-
.map_err(|err| Docker2EifError::SignImageError(format!("{err:?}")))?,
106-
),
107+
(Some(kms_id), None) => Some(SignKeyInfo::KmsKeyInfo {
108+
id: kms_id.into(),
109+
region: kms_key_region.clone(),
110+
}),
111+
(None, Some(key_path)) => Some(SignKeyInfo::LocalPrivateKeyInfo {
112+
path: key_path.into(),
113+
}),
107114
_ => return Err(Docker2EifError::SignArgsError),
108115
};
109116

117+
let sign_info = sign_key_info
118+
.map(|key_info| {
119+
SignKeyData::new(&SignKeyDataInfo {
120+
cert_path: certificate_path
121+
.as_ref()
122+
.ok_or(Docker2EifError::SignArgsError)?
123+
.into(),
124+
key_info,
125+
})
126+
.map_err(|_| Docker2EifError::SignArgsError)
127+
})
128+
.transpose()?;
129+
110130
Ok(Docker2Eif {
111131
docker_image,
112132
docker,
@@ -275,10 +295,15 @@ impl<'a> Docker2Eif<'a> {
275295
_ => return Err(Docker2EifError::UnsupportedArchError),
276296
};
277297

298+
// We cannot clone `sign_info` because it might contain a KmsKey object
299+
// which is not copyable. Since `create` is the last method called, we can
300+
// move it out of the struct.
301+
let sign_info = self.sign_info.take();
302+
278303
let mut build = EifBuilder::new(
279304
Path::new(&self.kernel_img_path),
280305
self.cmdline.clone(),
281-
self.sign_info.clone(),
306+
sign_info,
282307
sha2::Sha384::new(),
283308
flags,
284309
self.generate_identity_info()?,

enclave_build/src/main.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use clap::{Arg, ArgAction, Command};
4+
use clap::{Arg, ArgAction, ArgGroup, Command};
55
use std::fs::OpenOptions;
66

77
use aws_nitro_enclaves_image_format::generate_build_info;
@@ -75,6 +75,23 @@ fn main() {
7575
.long("private-key")
7676
.help("Specify the path to the private-key"),
7777
)
78+
.arg(
79+
Arg::new("kms-key-id")
80+
.long("kms-key-id")
81+
.help("Specify unique id of the KMS key")
82+
)
83+
.arg(
84+
Arg::new("kms-key-region")
85+
.long("kms-key-region")
86+
.help("Specify region in which the KMS key resides")
87+
.requires("kms-key-id")
88+
)
89+
.group(
90+
ArgGroup::new("signing-key")
91+
.args(&["kms-key-id", "private-key"])
92+
.multiple(false)
93+
.requires("signing-certificate")
94+
)
7895
.arg(
7996
Arg::new("build")
8097
.short('b')
@@ -122,6 +139,10 @@ fn main() {
122139
let img_name = matches.get_one::<String>("image_name").map(String::from);
123140
let img_version = matches.get_one::<String>("image_version").map(String::from);
124141
let metadata = matches.get_one::<String>("metadata").map(String::from);
142+
let kms_key_id = matches.get_one::<String>("kms-key-id").map(String::from);
143+
let kms_key_region = matches
144+
.get_one::<String>("kms-key-region")
145+
.map(String::from);
125146

126147
let mut output = OpenOptions::new()
127148
.read(true)
@@ -142,6 +163,8 @@ fn main() {
142163
".".to_string(),
143164
&signing_certificate,
144165
&private_key,
166+
&kms_key_id,
167+
&kms_key_region,
145168
img_name,
146169
img_version,
147170
metadata,

src/common/commands_parser.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ pub struct BuildEnclavesArgs {
108108
pub signing_certificate: Option<String>,
109109
/// The path to the private key for signed enclaves.
110110
pub private_key: Option<String>,
111+
/// ID of the KMS key for signed enclaves.
112+
pub kms_key_id: Option<String>,
113+
/// Region of the KMS key for signed enclaves.
114+
pub kms_key_region: Option<String>,
111115
/// The name of the enclave image.
112116
pub img_name: Option<String>,
113117
/// The version of the enclave image.
@@ -121,16 +125,18 @@ impl BuildEnclavesArgs {
121125
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
122126
let signing_certificate = parse_signing_certificate(args);
123127
let private_key = parse_private_key(args);
128+
let kms_key_id = parse_kms_key_id(args);
129+
let kms_key_region = parse_kms_key_region(args);
124130

125-
match (&signing_certificate, &private_key) {
126-
(Some(_), None) => {
131+
match (&signing_certificate, &private_key, &kms_key_id) {
132+
(_, Some(_), Some(_)) => {
127133
return Err(new_nitro_cli_failure!(
128-
"`private-key` argument not found",
129-
NitroCliErrorEnum::MissingArgument
130-
)
131-
.add_info(vec!["private-key"]))
134+
"Cannot use both `private-key` and `kms-key-id`",
135+
NitroCliErrorEnum::ConflictingArgument
136+
))
132137
}
133-
(None, Some(_)) => {
138+
(None, None, None) => (),
139+
(None, _, _) => {
134140
return Err(new_nitro_cli_failure!(
135141
"`signing-certificate` argument not found",
136142
NitroCliErrorEnum::MissingArgument
@@ -158,6 +164,8 @@ impl BuildEnclavesArgs {
158164
})?,
159165
signing_certificate,
160166
private_key,
167+
kms_key_id,
168+
kms_key_region,
161169
img_name: parse_image_name(args),
162170
img_version: parse_image_version(args),
163171
metadata: parse_metadata(args),
@@ -543,6 +551,14 @@ fn parse_private_key(args: &ArgMatches) -> Option<String> {
543551
args.get_one::<String>("private-key").map(String::from)
544552
}
545553

554+
fn parse_kms_key_id(args: &ArgMatches) -> Option<String> {
555+
args.get_one::<String>("kms-key-id").map(String::from)
556+
}
557+
558+
fn parse_kms_key_region(args: &ArgMatches) -> Option<String> {
559+
args.get_one::<String>("kms-key-region").map(String::from)
560+
}
561+
546562
fn parse_image_name(args: &ArgMatches) -> Option<String> {
547563
args.get_one::<String>("image_name").map(String::from)
548564
}
@@ -572,7 +588,7 @@ mod tests {
572588
use crate::common::construct_error_message;
573589
use crate::create_app;
574590

575-
use clap::{Arg, Command};
591+
use clap::{Arg, ArgGroup, Command};
576592

577593
/// Parse the path of the JSON config file
578594
fn parse_config_file(args: &ArgMatches) -> NitroCliResult<String> {

src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ pub fn build_enclaves(args: BuildEnclavesArgs) -> NitroCliResult<()> {
5858
&args.output,
5959
&args.signing_certificate,
6060
&args.private_key,
61+
&args.kms_key_id,
62+
&args.kms_key_region,
6163
&args.img_name,
6264
&args.img_version,
6365
&args.metadata,
@@ -73,6 +75,8 @@ pub fn build_from_docker(
7375
output_path: &str,
7476
signing_certificate: &Option<String>,
7577
private_key: &Option<String>,
78+
kms_key_id: &Option<String>,
79+
kms_key_region: &Option<String>,
7680
img_name: &Option<String>,
7781
img_version: &Option<String>,
7882
metadata_path: &Option<String>,
@@ -136,6 +140,8 @@ pub fn build_from_docker(
136140
artifacts_path()?,
137141
signing_certificate,
138142
private_key,
143+
kms_key_id,
144+
kms_key_region,
139145
img_name.clone(),
140146
img_version.clone(),
141147
metadata_path.clone(),
@@ -714,6 +720,23 @@ macro_rules! create_app {
714720
.long("private-key")
715721
.help("Local path to developer's Eliptic Curve private key."),
716722
)
723+
.arg(
724+
Arg::new("kms-key-id")
725+
.long("kms-key-id")
726+
.help("Specify unique id of the KMS key")
727+
)
728+
.arg(
729+
Arg::new("kms-key-region")
730+
.long("kms-key-region")
731+
.help("Specify region in which the KMS key resides")
732+
.requires("kms-key-id")
733+
)
734+
.group(
735+
ArgGroup::new("signing-key")
736+
.args(&["kms-key-id", "private-key"])
737+
.multiple(false)
738+
.requires("signing-certificate")
739+
)
717740
.arg(
718741
Arg::new("image_name")
719742
.long("name")

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
99
extern crate lazy_static;
1010

11-
use clap::{Arg, Command};
11+
use clap::{Arg, ArgGroup, Command};
1212
use log::info;
1313
use std::os::unix::net::UnixStream;
1414

tests/test_nitro_cli_args.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#[cfg(test)]
66
mod test_nitro_cli_args {
7-
use clap::{Arg, Command};
7+
use clap::{Arg, ArgGroup, Command};
88
use nitro_cli::create_app;
99

1010
#[test]

0 commit comments

Comments
 (0)