]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/iam: add policy evaluation for Arn-based Conditions 62434/head
authorCasey Bodley <cbodley@redhat.com>
Thu, 13 Mar 2025 19:14:39 +0000 (15:14 -0400)
committerCasey Bodley <cbodley@redhat.com>
Tue, 27 May 2025 20:08:27 +0000 (16:08 -0400)
arn-based conditions like ArnEquals etc are recognized by the policy
parser, but not enforced during policy evaluation

Fixes: https://tracker.ceph.com/issues/70481
Signed-off-by: Casey Bodley <cbodley@redhat.com>
(cherry picked from commit 62c3e5ec69f115c6991e632f6f27f4f295e3741a)

PendingReleaseNotes
src/rgw/rgw_iam_policy.cc
src/test/rgw/test_rgw_iam_policy.cc

index 6aaa4ffb30f57022ce433e572d0c3ffd2ee894c9..c1fd3b941e04683fab50877d9bed42355b8f0a06 100644 (file)
@@ -19,6 +19,8 @@
   Related trackers:
    - https://tracker.ceph.com/issues/67179
    - https://tracker.ceph.com/issues/66867
+* RGW: IAM policy evaluation now supports conditions ArnEquals and ArnLike, along
+  with their Not and IfExists variants.
 
 >=18.2.4
 --------
index cf56f0f5572887a30be3617d1c8386ec0aa70970..8f6bb5b83c26f13cb4c6b4958facd48f3611d0e1 100644 (file)
@@ -764,6 +764,18 @@ ostream& operator <<(ostream& m, const MaskedIP& ip) {
   return m;
 }
 
+// Case-sensitive matching of the ARN. Each of the six colon-delimited
+// components of the ARN is checked separately and each can include multi-
+// character match wildcards (*) or single-character match wildcards (?).
+static bool arn_like(const std::string& input, const std::string& pattern)
+{
+  constexpr auto delim = [] (char c) { return c == ':'; };
+  if (std::count_if(input.begin(), input.end(), delim) != 5) {
+    return false;
+  }
+  return match_policy(pattern, input, MATCH_POLICY_ARN);
+}
+
 bool Condition::eval(const Environment& env) const {
   std::vector<std::string> runtime_vals;
   auto i = env.find(key);
@@ -904,11 +916,14 @@ bool Condition::eval(const Environment& env) const {
       return true;
     }
 
-#if 0
-    // Amazon Resource Names! (Does S3 need this?)
-    TokenID::ArnEquals, TokenID::ArnNotEquals, TokenID::ArnLike,
-      TokenID::ArnNotLike,
-#endif
+    // Amazon Resource Names!
+    // The ArnEquals and ArnLike condition operators behave identically.
+  case TokenID::ArnEquals:
+  case TokenID::ArnLike:
+    return orrible(arn_like, itr, isruntime? runtime_vals : vals);
+  case TokenID::ArnNotEquals:
+  case TokenID::ArnNotLike:
+    return orrible(std::not_fn(arn_like), itr, isruntime? runtime_vals : vals);
 
   default:
     return false;
index a79d20849da30a88b0252be8ca0e14b3d4e3ef74..4f2467f0cc8bc489b6e0edf4c5f5261c6d92aca1 100644 (file)
@@ -47,6 +47,7 @@ using rgw::IAM::Effect;
 using rgw::IAM::Environment;
 using rgw::Partition;
 using rgw::IAM::Policy;
+using rgw::IAM::Condition;
 using rgw::IAM::s3All;
 using rgw::IAM::s3Count;
 using rgw::IAM::s3GetAccelerateConfiguration;
@@ -1300,3 +1301,27 @@ TEST(set_cont_bits, iamconsts)
   EXPECT_EQ(stsAllValue, set_range_bits(iamAll+1, stsAll));
   EXPECT_EQ(allValue , set_range_bits(0, allCount));
 }
+
+TEST(Condition, ArnLike)
+{
+  const std::string key = "aws:SourceArn";
+  {
+    Condition ArnLike{TokenID::ArnLike, key.data(), key.size(), false};
+    ArnLike.vals.push_back("arn:aws:s3:::bucket");
+
+    EXPECT_FALSE(ArnLike.eval({}));
+    EXPECT_TRUE(ArnLike.eval({{key, "arn:aws:s3:::bucket"}}));
+    EXPECT_FALSE(ArnLike.eval({{key, "arn:aws:s3:::BUCKET"}}));
+    EXPECT_FALSE(ArnLike.eval({{key, "arn:aws:s3:::user"}}));
+  }
+  {
+    Condition ArnLike{TokenID::ArnLike, key.data(), key.size(), false};
+    ArnLike.vals.push_back("arn:aws:s3:::b*");
+
+    EXPECT_FALSE(ArnLike.eval({}));
+    EXPECT_TRUE(ArnLike.eval({{key, "arn:aws:s3:::b"}}));
+    EXPECT_TRUE(ArnLike.eval({{key, "arn:aws:s3:::bucket"}}));
+    EXPECT_FALSE(ArnLike.eval({{key, "arn:aws:s3:::BUCKET"}}));
+    EXPECT_FALSE(ArnLike.eval({{key, "arn:aws:s3:::user"}}));
+  }
+}