]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/iam: add policy evaluation for Arn-based Conditions 62435/head
authorCasey Bodley <cbodley@redhat.com>
Thu, 13 Mar 2025 19:14:39 +0000 (15:14 -0400)
committerCasey Bodley <cbodley@redhat.com>
Mon, 28 Apr 2025 19:00:01 +0000 (15:00 -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 e9c37a59e202c5515d7696d1f60b53d2c16e6631..fb73dd1fe6f7731a2446282534d75a2c7ad00ce3 100644 (file)
@@ -3,6 +3,8 @@
 * RGW: Lua scripts will not run against health checks.
 * RGW: Adding missing quotes to the ETag values returned by S3 CopyPart,
   PostObject and CompleteMultipartUpload responses.
+* RGW: IAM policy evaluation now supports conditions ArnEquals and ArnLike, along
+  with their Not and IfExists variants.
 
 * RBD: All Python APIs that produce timestamps now return "aware" `datetime`
   objects instead of "naive" ones (i.e. those including time zone information
index bef4b587a666ecb99a5c6df5c8238ffa5d8f0a46..f8d27ba62eb48803b16253cab83bdefa525018cb 100644 (file)
@@ -839,6 +839,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);
@@ -979,11 +991,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 aa97fb8767243019f8ef676879d6e875c3b277fc..4267f184fd2ac71d96fcbf437fd2c5b504434fc3 100644 (file)
@@ -49,6 +49,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::s3objectlambdaAll;
 using rgw::IAM::s3GetAccelerateConfiguration;
@@ -1482,3 +1483,27 @@ TEST(set_cont_bits, iamconsts)
   EXPECT_EQ(organizationsAllValue, set_range_bits(snsAll+1, organizationsAll));
   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"}}));
+  }
+}