Skip to content

Commit 108bc7a

Browse files
committed
cdh: add sealed secret signing
Add mechanism to serialize and deserialize secrets with signatures. When deserializing, use the KID in the JWS header to find the signing key. The signing key will either be retrieved from the KBS (if it is a resource URI) or it will be treated as a local credential. The second approach is used for testing (although sadly the tests do require sudo or some fiddling). The key should be an EC PS256 JWK. There are hooks to support more key types in the future. When serializing, a signature will be created. The JWK and KID must be provided. Note that the JWK has a KID field of its own, but we don't care about this. The KID in the JWS is what matters. Also update the secret_cli. Note that the CLI will no longer let you create a secret without a signature. Signed-off-by: Tobin Feldman-Fitzthum <tfeldmanfitz@nvidia.com>
1 parent 4be23c4 commit 108bc7a

File tree

5 files changed

+285
-27
lines changed

5 files changed

+285
-27
lines changed

Cargo.lock

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

confidential-data-hub/hub/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ env_logger = { workspace = true, optional = true }
4545
image-rs = { path = "../../image-rs", default-features = false, features = [
4646
"kata-cc-rustls-tls",
4747
] }
48+
jose-b64 = "0.1.2"
49+
jose-jwa = "0.1.2"
50+
jose-jwk = "0.1.2"
51+
jose-jws = "0.1.2"
4852
kms = { path = "../kms", default-features = false }
4953
log.workspace = true
54+
p256 = "0.13.2"
5055
prost = { workspace = true, optional = true }
5156
protos = { path = "../../protos", default-features = false, optional = true }
5257
rand.workspace = true

confidential-data-hub/hub/src/bin/secret_cli.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-License-Identifier: Apache-2.0
44
//
55

6+
use jose_jwk::Jwk;
67
use std::{env, path::Path};
78

89
use base64::{engine::general_purpose::STANDARD, Engine};
@@ -41,6 +42,16 @@ struct SealArgs {
4142
/// Type of the Secret, i.e. `vault` or `envelope`
4243
#[command(subcommand)]
4344
r#type: TypeArgs,
45+
46+
/// The kid of the signing key. This will be used when unsealing
47+
/// to find the key.
48+
#[arg(short, long)]
49+
signing_kid: String,
50+
51+
/// A path to a file containing a JWK (with a private component)
52+
/// for signing the sealed secret.
53+
#[arg(short, long)]
54+
signing_jwk_path: String,
4455
}
4556

4657
#[derive(Args)]
@@ -57,6 +68,10 @@ struct UnsealArgs {
5768
/// configuration for connecting to KBS provider
5869
#[arg(short, long)]
5970
aa_kbc_params: Option<String>,
71+
72+
/// Skip validating the signature of the sealed secret.
73+
#[arg(short, long)]
74+
skip_verification: Option<bool>,
6075
}
6176

6277
#[derive(Subcommand)]
@@ -164,7 +179,11 @@ async fn unseal_secret(unseal_args: &UnsealArgs) {
164179
let secret_string = fs::read_to_string(&unseal_args.file_path)
165180
.await
166181
.expect("failed to read sealed secret");
167-
let secret = Secret::from_signed_base64_string(secret_string).expect("Failed to parse secret.");
182+
let skip_verification = unseal_args.skip_verification.unwrap_or(false);
183+
184+
let secret = Secret::from_signed_base64_string(secret_string, skip_verification)
185+
.await
186+
.expect("Failed to parse secret.");
168187

169188
// Setup secret provider
170189
let secret_provider = match secret.r#type {
@@ -277,12 +296,16 @@ async fn seal_secret(seal_args: &SealArgs) {
277296
}
278297
};
279298

299+
let signing_jwk =
300+
std::fs::read_to_string(&seal_args.signing_jwk_path).expect("Could not find signing JWK");
301+
let signing_jwk: Jwk = serde_json::from_str(&signing_jwk).expect("Could not parse signing JWK");
302+
280303
let secret = Secret {
281304
version: VERSION.into(),
282305
r#type: sc,
283306
};
284307
let secret_string = secret
285-
.to_signed_base64_string()
308+
.to_signed_base64_string(signing_jwk, seal_args.signing_kid.clone())
286309
.expect("failed to serialize secret");
287310
println!("{secret_string}");
288311
}

confidential-data-hub/hub/src/secret/error.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,19 @@ pub enum SecretError {
2525

2626
#[error("parse SealedSecret failed: {0}")]
2727
ParseFailed(&'static str),
28+
29+
#[error("Signature Error: {0}")]
30+
SignatureError(#[from] p256::ecdsa::Error),
31+
32+
#[error("JSON Parsing Error: {0}")]
33+
JsonError(#[from] serde_json::Error),
34+
35+
#[error("Signing key error: {0}")]
36+
BadSigningKey(&'static str),
37+
38+
#[error("Failed to get key from KMS: {0}")]
39+
KmsError(#[from] kms::Error),
40+
41+
#[error("IO Operation Failed: {0}")]
42+
IoError(#[from] std::io::Error),
2843
}

0 commit comments

Comments
 (0)