diff --git a/crates/kms/tests/vault_approle_live.rs b/crates/kms/tests/vault_approle_live.rs index 441ce8107..b36434218 100644 --- a/crates/kms/tests/vault_approle_live.rs +++ b/crates/kms/tests/vault_approle_live.rs @@ -29,6 +29,8 @@ use rustfs_kms::{ }; use std::collections::HashMap; +const LIVE_KEY_DESCRIPTION: &str = "AppRole live metadata"; + fn assert_approle_config(config: &KmsConfig, expected_backend: KmsBackend) { assert_eq!(config.backend, expected_backend); let auth_method = match &config.backend_config { @@ -42,12 +44,13 @@ fn assert_approle_config(config: &KmsConfig, expected_backend: KmsBackend) { ); } -async fn exercise_backend(backend: &B, key_prefix: &str) -> rustfs_kms::Result<()> { +async fn exercise_backend(backend: &B, key_prefix: &str) -> rustfs_kms::Result { let key_id = format!("{key_prefix}-{}", uuid::Uuid::new_v4()); let created = backend .create_key(CreateKeyRequest { key_name: Some(key_id.clone()), key_usage: KeyUsage::EncryptDecrypt, + description: Some(LIVE_KEY_DESCRIPTION.to_string()), ..Default::default() }) .await?; @@ -57,6 +60,7 @@ async fn exercise_backend(backend: &B, key_prefix: .describe_key(rustfs_kms::DescribeKeyRequest { key_id: key_id.clone() }) .await?; assert_eq!(described.key_metadata.key_id, key_id); + assert_eq!(described.key_metadata.description.as_deref(), Some(LIVE_KEY_DESCRIPTION)); let listed = backend .list_keys(ListKeysRequest { @@ -88,7 +92,7 @@ async fn exercise_backend(backend: &B, key_prefix: }) .await?; assert_eq!(unwrapped.plaintext, generated.plaintext_key); - Ok(()) + Ok(key_id) } #[tokio::test] @@ -97,7 +101,7 @@ async fn vault_kv2_approle_auth_live() -> rustfs_kms::Result<()> { let config = KmsConfig::from_env()?; assert_approle_config(&config, KmsBackend::VaultKv2); let backend = VaultKmsBackend::new(config).await?; - exercise_backend(&backend, "rustfs-approle-kv2").await + exercise_backend(&backend, "rustfs-approle-kv2").await.map(|_| ()) } #[tokio::test] @@ -109,9 +113,34 @@ async fn vault_transit_approle_auth_live() -> rustfs_kms::Result<()> { BackendConfig::VaultTransit(vault) => vault, _ => panic!("expected Vault Transit configuration"), }; + assert_eq!(transit.mount_path, "transit"); assert_eq!(transit.metadata_kv_mount, DEFAULT_VAULT_TRANSIT_METADATA_KV_MOUNT); assert_eq!(transit.metadata_key_prefix, DEFAULT_VAULT_TRANSIT_METADATA_KEY_PREFIX); let backend = VaultTransitKmsBackend::new(config).await?; - exercise_backend(&backend, "rustfs-approle-transit").await + exercise_backend(&backend, "rustfs-approle-transit").await.map(|_| ()) +} + +#[tokio::test] +#[ignore = "requires a real Vault AppRole; run scripts/test/vault_approle_kms_live.sh"] +async fn vault_transit_approle_custom_paths_live() -> rustfs_kms::Result<()> { + let config = KmsConfig::from_env()?; + assert_approle_config(&config, KmsBackend::VaultTransit); + let BackendConfig::VaultTransit(transit) = &config.backend_config else { + panic!("expected Vault Transit configuration"); + }; + assert_eq!(transit.mount_path, "kms-test/transit"); + assert_eq!(transit.metadata_kv_mount, "kms-test/metadata"); + assert_eq!(transit.metadata_key_prefix, "custom/transit-metadata"); + + let backend = VaultTransitKmsBackend::new(config.clone()).await?; + let key_id = exercise_backend(&backend, "rustfs-approle-custom-transit").await?; + drop(backend); + + // A fresh backend must read the stored record, not synthesize Enabled + // metadata or reuse a record cached during key creation. + let restarted = VaultTransitKmsBackend::new(config).await?; + let described = restarted.describe_key(rustfs_kms::DescribeKeyRequest { key_id }).await?; + assert_eq!(described.key_metadata.description.as_deref(), Some(LIVE_KEY_DESCRIPTION)); + Ok(()) } diff --git a/scripts/test/vault_approle_kms_live.sh b/scripts/test/vault_approle_kms_live.sh index 398daffd4..ada1f0e2f 100755 --- a/scripts/test/vault_approle_kms_live.sh +++ b/scripts/test/vault_approle_kms_live.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -# Start an ephemeral Vault, issue a least-privilege AppRole, and run the two +# Start an ephemeral Vault, issue a least-privilege AppRole, and run the # ignored RustFS KMS checks without ever exposing the generated credentials. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -77,6 +77,8 @@ if [[ "$ready" != 1 ]]; then fi vault_cli secrets enable -path=transit transit >/dev/null +vault_cli secrets enable -path=kms-test/transit transit >/dev/null +vault_cli secrets enable -path=kms-test/metadata kv-v2 >/dev/null vault_cli auth enable approle >/dev/null POLICY_NAME="rustfs-kms-live-$$" @@ -105,6 +107,11 @@ path "secret/metadata/rustfs/kms/transit-metadata" { capabilities = ["list"] } +# Non-default Transit metadata mount and prefix, both containing slashes. +path "kms-test/metadata/data/custom/transit-metadata/*" { + capabilities = ["create", "read", "update"] +} + # Transit key lifecycle and data-path operations. path "transit/keys" { capabilities = ["list"] @@ -118,6 +125,20 @@ path "transit/encrypt/*" { path "transit/decrypt/*" { capabilities = ["update"] } + +# The same operations under a non-default, nested Transit mount. +path "kms-test/transit/keys" { + capabilities = ["list"] +} +path "kms-test/transit/keys/*" { + capabilities = ["create", "read", "update"] +} +path "kms-test/transit/encrypt/*" { + capabilities = ["update"] +} +path "kms-test/transit/decrypt/*" { + capabilities = ["update"] +} EOF vault_cli policy write "$POLICY_NAME" "$POLICY_FILE" >/dev/null @@ -135,6 +156,9 @@ SECRET_ID="$(vault_cli write -f -field=secret_id "auth/approle/role/${ROLE_NAME} run_live_test() { local backend="$1" local test_name="$2" + local transit_mount="${3:-transit}" + local metadata_mount="${4:-secret}" + local metadata_prefix="${5:-rustfs/kms/transit-metadata}" local -a backend_env=( -u RUSTFS_KMS_BACKEND @@ -178,9 +202,9 @@ run_live_test() { ) else backend_env+=( - RUSTFS_KMS_VAULT_MOUNT_PATH=transit - RUSTFS_KMS_VAULT_TRANSIT_METADATA_KV_MOUNT=secret - RUSTFS_KMS_VAULT_TRANSIT_METADATA_PREFIX=rustfs/kms/transit-metadata + RUSTFS_KMS_VAULT_MOUNT_PATH="$transit_mount" + RUSTFS_KMS_VAULT_TRANSIT_METADATA_KV_MOUNT="$metadata_mount" + RUSTFS_KMS_VAULT_TRANSIT_METADATA_PREFIX="$metadata_prefix" ) fi @@ -193,4 +217,9 @@ run_live_test() { cd "$PROJECT_ROOT" run_live_test vault vault_kv2_approle_auth_live run_live_test vault-transit vault_transit_approle_auth_live +# Remove the default mounts so a fallback to transit or secret cannot pass. +vault_cli secrets disable transit >/dev/null +vault_cli secrets disable secret >/dev/null +run_live_test vault-transit vault_transit_approle_custom_paths_live \ + kms-test/transit kms-test/metadata custom/transit-metadata echo "Vault AppRole KV2 and Transit live checks passed"