diff --git a/bottlecap/src/secrets/decrypt.rs b/bottlecap/src/secrets/decrypt.rs index eb96612f7..de0376e09 100644 --- a/bottlecap/src/secrets/decrypt.rs +++ b/bottlecap/src/secrets/decrypt.rs @@ -107,6 +107,7 @@ async fn decrypt_aws_kms( let headers = build_get_secret_signed_headers( aws_config, + aws_config.region.clone(), RequestArgs { service: "kms".to_string(), body: json_body, @@ -128,6 +129,7 @@ async fn decrypt_aws_kms( let headers = build_get_secret_signed_headers( aws_config, + aws_config.region.clone(), RequestArgs { service: "kms".to_string(), body: json_body, @@ -153,9 +155,15 @@ async fn decrypt_aws_sm( aws_config: &AwsConfig, ) -> Result> { let json_body = &serde_json::json!({ "SecretId": secret_arn}); - + // Supports cross-region secrets + let secret_region = secret_arn + .split(':') + .nth(3) + .unwrap_or(&aws_config.region) + .to_string(); let headers = build_get_secret_signed_headers( aws_config, + secret_region, RequestArgs { service: "secretsmanager".to_string(), body: json_body, @@ -211,6 +219,7 @@ async fn request( fn build_get_secret_signed_headers( aws_config: &AwsConfig, + region: String, header_values: RequestArgs, ) -> Result> { let amz_date = header_values.time.format("%Y%m%dT%H%M%SZ").to_string(); @@ -222,7 +231,7 @@ fn build_get_secret_signed_headers( "amazonaws.com" }; - let host = format!("{}.{}.{}", header_values.service, aws_config.region, domain); + let host = format!("{}.{}.{}", header_values.service, region, domain); let canonical_uri = "/"; let canonical_querystring = ""; @@ -240,7 +249,7 @@ fn build_get_secret_signed_headers( let algorithm = "AWS4-HMAC-SHA256"; let credential_scope = format!( "{}/{}/{}/aws4_request", - date_stamp, aws_config.region, header_values.service + date_stamp, region, header_values.service ); let string_to_sign = format!( "{}\n{}\n{}\n{}", @@ -253,7 +262,7 @@ fn build_get_secret_signed_headers( let signing_key = get_aws4_signature_key( &aws_config.aws_secret_access_key, &date_stamp, - aws_config.region.as_str(), + region.as_str(), header_values.service.as_str(), )?; @@ -338,6 +347,7 @@ mod tests { function_name: "arn:some-function".to_string(), sandbox_init_time: Instant::now(), }, + "us-east-1".to_string(), RequestArgs { service: "secretsmanager".to_string(), body: &serde_json::json!({ "SecretId": "arn:aws:secretsmanager:region:account-id:secret:secret-name"}), @@ -373,4 +383,58 @@ mod tests { assert_eq!(headers.get(k).expect("cannot get header"), v); } } + + #[test] + #[allow(clippy::unwrap_used)] + fn test_cross_region_secret() { + let time = Utc.from_utc_datetime( + &NaiveDateTime::parse_from_str("2024-05-30 09:10:11", "%Y-%m-%d %H:%M:%S").unwrap(), + ); + let headers = build_get_secret_signed_headers( + &AwsConfig{ + region: "us-east-1".to_string(), + aws_access_key_id: "AKIDEXAMPLE".to_string(), + aws_secret_access_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY".to_string(), + aws_session_token: "AQoDYXdzEJr...".to_string(), + aws_container_authorization_token: String::new(), + aws_container_credentials_full_uri: String::new(), + function_name: "arn:some-function".to_string(), + sandbox_init_time: Instant::now(), + }, + "us-west-2".to_string(), + RequestArgs { + service: "secretsmanager".to_string(), + body: &serde_json::json!({ "SecretId": "arn:aws:secretsmanager:us-west-2:account-id:secret:secret-name"}), + time, + x_amz_target: "secretsmanager.GetSecretValue".to_string(), + }, + ).unwrap(); + + let mut expected_headers = HeaderMap::new(); + expected_headers.insert("authorization", HeaderValue::from_str("AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20240530/us-west-2/secretsmanager/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token;x-amz-target, Signature=bd77112dd24d7a35566b29a39861f7421660c49b065964212f966db509e90813").unwrap()); + expected_headers.insert( + "host", + HeaderValue::from_str("secretsmanager.us-west-2.amazonaws.com").unwrap(), + ); + expected_headers.insert( + "content-type", + HeaderValue::from_str("application/x-amz-json-1.1").unwrap(), + ); + expected_headers.insert( + "x-amz-date", + HeaderValue::from_str("20240530T091011Z").unwrap(), + ); + expected_headers.insert( + "x-amz-target", + HeaderValue::from_str("secretsmanager.GetSecretValue").unwrap(), + ); + expected_headers.insert( + "x-amz-security-token", + HeaderValue::from_str("AQoDYXdzEJr...").unwrap(), + ); + + for (k, v) in &expected_headers { + assert_eq!(headers.get(k).expect("cannot get header"), v); + } + } }