]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: SSE-KMS: Handle Testing Key Per Object 61256/head
authorMarcel Lauhoff <marcel.lauhoff@clyso.com>
Tue, 5 May 2026 12:21:03 +0000 (14:21 +0200)
committerMarcel Lauhoff <marcel.lauhoff@clyso.com>
Mon, 1 Jun 2026 17:04:12 +0000 (19:04 +0200)
The testing backend uses a 'keysel' attribute to derive a per object
key from the KEK in the config. A single key_id with distinct keysel
has different keys and need to be cached as such.

Add the keysel to the cache key id to handle these collisions.

Signed-off-by: Marcel Lauhoff <marcel.lauhoff@clyso.com>
On-behalf-of: SAP marcel.lauhoff@sap.com

src/rgw/rgw_kms.cc
src/test/rgw/test_rgw_kms.cc
src/test/rgw/test_rgw_kms_cache.cc

index c35459d0d85b2b28fd42870a5b5f4bfd6440953d..1961d256123bc6535be1659c5f85c6da118fb6d0 100644 (file)
@@ -1223,6 +1223,15 @@ int reconstitute_actual_key_from_kms(
       cache_key_id = string_cat_reserve(
           key_id, "T", calc_hash_sha256(wrapped_key).to_str());
     }
+  } else if (RGW_SSE_KMS_BACKEND_TESTING == kms_backend) {
+    // The testing backend uses keysel to derive per-object keys with
+    // the same keyid.
+    const std::string key_selector =
+        get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
+    if (!key_selector.empty()) {
+      cache_key_id = string_cat_reserve(
+          key_id, "S", calc_hash_sha256(key_selector).to_str());
+    }
   }
 
   const auto fetch = [&](std::string& out_secret) -> int {
index e47348419dead7f49b3316fcf57435a5acf1dc2d..f32c0e648e88164ade9939a741226f244153781b 100644 (file)
@@ -2,6 +2,7 @@
 // vim: ts=8 sw=2 sts=2 expandtab
 
 #include "gtest/gtest.h"
+#include <common/random_string.h>
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
 #include "common/ceph_context.h"
@@ -316,3 +317,14 @@ TEST_F(TestSSEKMS, test_transit_backend_empty_response)
   ASSERT_EQ(res, -EINVAL);
   ASSERT_EQ(actual_key, from_base64(""));
 }
+
+TEST_F(TestSSEKMS, TestingBackendDifferentKeyselSameKeyIdDoNotCollide) {
+  map<string, bufferlist> attrs;
+  const NoDoutPrefix no_dpp(cct, 1);
+  cct->_conf->rgw_crypt_s3_kms_encryption_keys =
+      "foo=IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM=";
+  std::string out_a, out_b;
+  ASSERT_EQ(0, get_actual_key_from_conf(&no_dpp, "foo", gen_rand_alphanumeric(cct, AES_256_KEYSIZE), out_a));
+  ASSERT_EQ(0, get_actual_key_from_conf(&no_dpp, "foo", gen_rand_alphanumeric(cct, AES_256_KEYSIZE), out_b));
+  ASSERT_NE(out_a, out_b);
+}
index 15004a02e5f09e7f339a664829f3e8700be3e33a..7fc3f18fc3412ddd5d829f528ebf76163143da60 100644 (file)
@@ -8,6 +8,7 @@
 #include <global/global_context.h>
 #include <global/global_init.h>
 #include <gtest/gtest.h>
+#include <rgw_crypt.h>
 
 #include <boost/asio/cancellation_signal.hpp>
 #include <boost/asio/co_spawn.hpp>
@@ -351,6 +352,37 @@ TEST_F(TestSSEKMSWithTestingKMS, TestRuntimeEnableDisable) {
   EXPECT_EQ(cache_perf->get(static_cast<int>(webcache::Metric::size)), 0);
 }
 
+TEST_F(TestSSEKMSWithTestingKMS, KeyselCollisionAfterClearCache) {
+  cct->_conf.set_val("rgw_crypt_s3_kms_cache_enabled", "true");
+  auto attrs_A = attrs;
+  auto attrs_B = attrs;
+  set_attr(attrs_B, RGW_ATTR_CRYPT_KEYSEL,
+      "\x3a\xa8\x16\xc2\x48\x0e\xb4\x3e\x9b\xff\xab\x7b\xfc\xc2\xc7\xfd"
+      "\x3a\xa8\x16\xc2\x48\x0e\xb4\x3e\x9b\xff\xab\x7b\xfc\xc2\xc7\xfd");
+
+  std::string out_A1;
+  ASSERT_EQ(reconstitute_actual_key_from_kms(
+                &no_dpp, attrs_A, uut, null_yield, out_A1),
+      0);
+  EXPECT_EQ(out_A1, std::string(32, '*'));
+
+  uut->clear_cache();
+  EXPECT_EQ(cache_perf->get(static_cast<int>(webcache::Metric::size)), 0);
+
+  std::string out_B1;
+  ASSERT_EQ(reconstitute_actual_key_from_kms(
+                &no_dpp, attrs_B, uut, null_yield, out_B1),
+      0);
+  EXPECT_EQ(out_B1, std::string(32, '+'));
+
+  std::string out_A2;
+  ASSERT_EQ(reconstitute_actual_key_from_kms(
+                &no_dpp, attrs_A, uut, null_yield, out_A2),
+      0);
+  EXPECT_EQ(out_A2, out_A1);
+  EXPECT_NE(out_A2, out_B1);
+}
+
 int main(int argc, char** argv) {
   auto args = argv_to_vec(argc, argv);
   std::map<std::string, std::string> defaults{