]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/iam: add policy evaluation for Arn-based Conditions 62285/head
authorCasey Bodley <cbodley@redhat.com>
Thu, 13 Mar 2025 19:14:39 +0000 (15:14 -0400)
committerCasey Bodley <cbodley@redhat.com>
Fri, 14 Mar 2025 14:23:36 +0000 (10:23 -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>
PendingReleaseNotes
src/rgw/rgw_iam_policy.cc
src/test/rgw/test_rgw_iam_policy.cc

index c86dbd74267fe886a75c9bfe0a14f1165e5928fe..c4b892d8ae5b0975d0e04d9ef92401c11e896112 100644 (file)
@@ -14,6 +14,8 @@
 * RGW: For compatibility with AWS S3, LastModified timestamps are now truncated
   to the second. Note that during upgrade, users may observe these timestamps
   moving backwards as a result.
+* 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 db7d634e48533c291fd4df9adc42525f9b9f55d6..bcd89d7f87733b3e96e752e24ae6782716cbbe26 100644 (file)
@@ -852,6 +852,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);
@@ -992,11 +1004,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 bacf517d3f5a823078926da5a43866e56576fc6d..143229eb5d537bfce82100037c0b3483e3196242 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;
@@ -1492,3 +1493,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"}}));
+  }
+}