]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_iam_policy.h
c0a7e51b5fd7e8f7fdce253f97e89575c2b2f0ab
[ceph.git] / ceph / src / rgw / rgw_iam_policy.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 #pragma once
5
6 #include <bitset>
7 #include <chrono>
8 #include <cstdint>
9 #include <iostream>
10 #include <string>
11 #include <string_view>
12
13 #include <boost/algorithm/string/predicate.hpp>
14 #include <boost/container/flat_map.hpp>
15 #include <boost/container/flat_set.hpp>
16 #include <boost/optional.hpp>
17 #include <boost/thread/shared_mutex.hpp>
18 #include <boost/variant.hpp>
19
20 #include <fmt/format.h>
21
22 #include "common/ceph_time.h"
23 #include "common/iso_8601.h"
24
25 #include "rapidjson/error/error.h"
26 #include "rapidjson/error/en.h"
27
28 #include "rgw_acl.h"
29 #include "rgw_basic_types.h"
30 #include "rgw_iam_policy_keywords.h"
31 #include "rgw_string.h"
32 #include "rgw_arn.h"
33
34 namespace rgw {
35 namespace auth {
36 class Identity;
37 }
38 }
39
40 namespace rgw {
41 namespace IAM {
42
43 static constexpr std::uint64_t s3GetObject = 0;
44 static constexpr std::uint64_t s3GetObjectVersion = 1;
45 static constexpr std::uint64_t s3PutObject = 2;
46 static constexpr std::uint64_t s3GetObjectAcl = 3;
47 static constexpr std::uint64_t s3GetObjectVersionAcl = 4;
48 static constexpr std::uint64_t s3PutObjectAcl = 5;
49 static constexpr std::uint64_t s3PutObjectVersionAcl = 6;
50 static constexpr std::uint64_t s3DeleteObject = 7;
51 static constexpr std::uint64_t s3DeleteObjectVersion = 8;
52 static constexpr std::uint64_t s3ListMultipartUploadParts = 9;
53 static constexpr std::uint64_t s3AbortMultipartUpload = 10;
54 static constexpr std::uint64_t s3GetObjectTorrent = 11;
55 static constexpr std::uint64_t s3GetObjectVersionTorrent = 12;
56 static constexpr std::uint64_t s3RestoreObject = 13;
57 static constexpr std::uint64_t s3CreateBucket = 14;
58 static constexpr std::uint64_t s3DeleteBucket = 15;
59 static constexpr std::uint64_t s3ListBucket = 16;
60 static constexpr std::uint64_t s3ListBucketVersions = 17;
61 static constexpr std::uint64_t s3ListAllMyBuckets = 18;
62 static constexpr std::uint64_t s3ListBucketMultipartUploads = 19;
63 static constexpr std::uint64_t s3GetAccelerateConfiguration = 20;
64 static constexpr std::uint64_t s3PutAccelerateConfiguration = 21;
65 static constexpr std::uint64_t s3GetBucketAcl = 22;
66 static constexpr std::uint64_t s3PutBucketAcl = 23;
67 static constexpr std::uint64_t s3GetBucketCORS = 24;
68 static constexpr std::uint64_t s3PutBucketCORS = 25;
69 static constexpr std::uint64_t s3GetBucketVersioning = 26;
70 static constexpr std::uint64_t s3PutBucketVersioning = 27;
71 static constexpr std::uint64_t s3GetBucketRequestPayment = 28;
72 static constexpr std::uint64_t s3PutBucketRequestPayment = 29;
73 static constexpr std::uint64_t s3GetBucketLocation = 30;
74 static constexpr std::uint64_t s3GetBucketPolicy = 31;
75 static constexpr std::uint64_t s3DeleteBucketPolicy = 32;
76 static constexpr std::uint64_t s3PutBucketPolicy = 33;
77 static constexpr std::uint64_t s3GetBucketNotification = 34;
78 static constexpr std::uint64_t s3PutBucketNotification = 35;
79 static constexpr std::uint64_t s3GetBucketLogging = 36;
80 static constexpr std::uint64_t s3PutBucketLogging = 37;
81 static constexpr std::uint64_t s3GetBucketTagging = 38;
82 static constexpr std::uint64_t s3PutBucketTagging = 39;
83 static constexpr std::uint64_t s3GetBucketWebsite = 40;
84 static constexpr std::uint64_t s3PutBucketWebsite = 41;
85 static constexpr std::uint64_t s3DeleteBucketWebsite = 42;
86 static constexpr std::uint64_t s3GetLifecycleConfiguration = 43;
87 static constexpr std::uint64_t s3PutLifecycleConfiguration = 44;
88 static constexpr std::uint64_t s3PutReplicationConfiguration = 45;
89 static constexpr std::uint64_t s3GetReplicationConfiguration = 46;
90 static constexpr std::uint64_t s3DeleteReplicationConfiguration = 47;
91 static constexpr std::uint64_t s3GetObjectTagging = 48;
92 static constexpr std::uint64_t s3PutObjectTagging = 49;
93 static constexpr std::uint64_t s3DeleteObjectTagging = 50;
94 static constexpr std::uint64_t s3GetObjectVersionTagging = 51;
95 static constexpr std::uint64_t s3PutObjectVersionTagging = 52;
96 static constexpr std::uint64_t s3DeleteObjectVersionTagging = 53;
97 static constexpr std::uint64_t s3PutBucketObjectLockConfiguration = 54;
98 static constexpr std::uint64_t s3GetBucketObjectLockConfiguration = 55;
99 static constexpr std::uint64_t s3PutObjectRetention = 56;
100 static constexpr std::uint64_t s3GetObjectRetention = 57;
101 static constexpr std::uint64_t s3PutObjectLegalHold = 58;
102 static constexpr std::uint64_t s3GetObjectLegalHold = 59;
103 static constexpr std::uint64_t s3BypassGovernanceRetention = 60;
104 static constexpr std::uint64_t s3GetBucketPolicyStatus = 61;
105 static constexpr std::uint64_t s3PutPublicAccessBlock = 62;
106 static constexpr std::uint64_t s3GetPublicAccessBlock = 63;
107 static constexpr std::uint64_t s3DeletePublicAccessBlock = 64;
108 static constexpr std::uint64_t s3GetBucketPublicAccessBlock = 65;
109 static constexpr std::uint64_t s3PutBucketPublicAccessBlock = 66;
110 static constexpr std::uint64_t s3DeleteBucketPublicAccessBlock = 67;
111 static constexpr std::uint64_t s3GetBucketEncryption = 68;
112 static constexpr std::uint64_t s3PutBucketEncryption = 69;
113 static constexpr std::uint64_t s3All = 70;
114
115 static constexpr std::uint64_t iamPutUserPolicy = s3All + 1;
116 static constexpr std::uint64_t iamGetUserPolicy = s3All + 2;
117 static constexpr std::uint64_t iamDeleteUserPolicy = s3All + 3;
118 static constexpr std::uint64_t iamListUserPolicies = s3All + 4;
119 static constexpr std::uint64_t iamCreateRole = s3All + 5;
120 static constexpr std::uint64_t iamDeleteRole = s3All + 6;
121 static constexpr std::uint64_t iamModifyRoleTrustPolicy = s3All + 7;
122 static constexpr std::uint64_t iamGetRole = s3All + 8;
123 static constexpr std::uint64_t iamListRoles = s3All + 9;
124 static constexpr std::uint64_t iamPutRolePolicy = s3All + 10;
125 static constexpr std::uint64_t iamGetRolePolicy = s3All + 11;
126 static constexpr std::uint64_t iamListRolePolicies = s3All + 12;
127 static constexpr std::uint64_t iamDeleteRolePolicy = s3All + 13;
128 static constexpr std::uint64_t iamCreateOIDCProvider = s3All + 14;
129 static constexpr std::uint64_t iamDeleteOIDCProvider = s3All + 15;
130 static constexpr std::uint64_t iamGetOIDCProvider = s3All + 16;
131 static constexpr std::uint64_t iamListOIDCProviders = s3All + 17;
132 static constexpr std::uint64_t iamTagRole = s3All + 18;
133 static constexpr std::uint64_t iamListRoleTags = s3All + 19;
134 static constexpr std::uint64_t iamUntagRole = s3All + 20;
135 static constexpr std::uint64_t iamUpdateRole = s3All + 21;
136 static constexpr std::uint64_t iamAll = s3All + 22;
137
138 static constexpr std::uint64_t stsAssumeRole = iamAll + 1;
139 static constexpr std::uint64_t stsAssumeRoleWithWebIdentity = iamAll + 2;
140 static constexpr std::uint64_t stsGetSessionToken = iamAll + 3;
141 static constexpr std::uint64_t stsTagSession = iamAll + 4;
142 static constexpr std::uint64_t stsAll = iamAll + 5;
143
144 static constexpr std::uint64_t s3Count = s3All;
145 static constexpr std::uint64_t allCount = stsAll + 1;
146
147 using Action_t = std::bitset<allCount>;
148 using NotAction_t = Action_t;
149
150 template <size_t N>
151 constexpr std::bitset<N> make_bitmask(size_t s) {
152 // unfortunately none of the shift/logic operators of std::bitset have a constexpr variation
153 return s < 64 ? std::bitset<N> ((1ULL << s) - 1) :
154 std::bitset<N>((1ULL << 63) - 1) | make_bitmask<N> (s - 63) << 63;
155 }
156
157 template <size_t N>
158 constexpr std::bitset<N> set_cont_bits(size_t start, size_t end)
159 {
160 return (make_bitmask<N>(end - start)) << start;
161 }
162
163 static const Action_t None(0);
164 static const Action_t s3AllValue = set_cont_bits<allCount>(0,s3All);
165 static const Action_t iamAllValue = set_cont_bits<allCount>(s3All+1,iamAll);
166 static const Action_t stsAllValue = set_cont_bits<allCount>(iamAll+1,stsAll);
167 static const Action_t allValue = set_cont_bits<allCount>(0,allCount);
168
169 namespace {
170 // Please update the table in doc/radosgw/s3/authentication.rst if you
171 // modify this function.
172 inline int op_to_perm(std::uint64_t op) {
173 switch (op) {
174 case s3GetObject:
175 case s3GetObjectTorrent:
176 case s3GetObjectVersion:
177 case s3GetObjectVersionTorrent:
178 case s3GetObjectTagging:
179 case s3GetObjectVersionTagging:
180 case s3GetObjectRetention:
181 case s3GetObjectLegalHold:
182 case s3ListAllMyBuckets:
183 case s3ListBucket:
184 case s3ListBucketMultipartUploads:
185 case s3ListBucketVersions:
186 case s3ListMultipartUploadParts:
187 return RGW_PERM_READ;
188
189 case s3AbortMultipartUpload:
190 case s3CreateBucket:
191 case s3DeleteBucket:
192 case s3DeleteObject:
193 case s3DeleteObjectVersion:
194 case s3PutObject:
195 case s3PutObjectTagging:
196 case s3PutObjectVersionTagging:
197 case s3DeleteObjectTagging:
198 case s3DeleteObjectVersionTagging:
199 case s3RestoreObject:
200 case s3PutObjectRetention:
201 case s3PutObjectLegalHold:
202 case s3BypassGovernanceRetention:
203 return RGW_PERM_WRITE;
204
205 case s3GetAccelerateConfiguration:
206 case s3GetBucketAcl:
207 case s3GetBucketCORS:
208 case s3GetBucketEncryption:
209 case s3GetBucketLocation:
210 case s3GetBucketLogging:
211 case s3GetBucketNotification:
212 case s3GetBucketPolicy:
213 case s3GetBucketPolicyStatus:
214 case s3GetBucketRequestPayment:
215 case s3GetBucketTagging:
216 case s3GetBucketVersioning:
217 case s3GetBucketWebsite:
218 case s3GetLifecycleConfiguration:
219 case s3GetObjectAcl:
220 case s3GetObjectVersionAcl:
221 case s3GetReplicationConfiguration:
222 case s3GetBucketObjectLockConfiguration:
223 case s3GetBucketPublicAccessBlock:
224 return RGW_PERM_READ_ACP;
225
226 case s3DeleteBucketPolicy:
227 case s3DeleteBucketWebsite:
228 case s3DeleteReplicationConfiguration:
229 case s3PutAccelerateConfiguration:
230 case s3PutBucketAcl:
231 case s3PutBucketCORS:
232 case s3PutBucketEncryption:
233 case s3PutBucketLogging:
234 case s3PutBucketNotification:
235 case s3PutBucketPolicy:
236 case s3PutBucketRequestPayment:
237 case s3PutBucketTagging:
238 case s3PutBucketVersioning:
239 case s3PutBucketWebsite:
240 case s3PutLifecycleConfiguration:
241 case s3PutObjectAcl:
242 case s3PutObjectVersionAcl:
243 case s3PutReplicationConfiguration:
244 case s3PutBucketObjectLockConfiguration:
245 case s3PutBucketPublicAccessBlock:
246 return RGW_PERM_WRITE_ACP;
247
248 case s3All:
249 return RGW_PERM_FULL_CONTROL;
250 }
251 return RGW_PERM_INVALID;
252 }
253 }
254
255 enum class PolicyPrincipal {
256 Role,
257 Session,
258 Other
259 };
260
261 using Environment = std::unordered_multimap<std::string, std::string>;
262
263 using Address = std::bitset<128>;
264 struct MaskedIP {
265 bool v6;
266 Address addr;
267 // Since we're mapping IPv6 to IPv4 addresses, we may want to
268 // consider making the prefix always be in terms of a v6 address
269 // and just use the v6 bit to rewrite it as a v4 prefix for
270 // output.
271 unsigned int prefix;
272 };
273
274 std::ostream& operator <<(std::ostream& m, const MaskedIP& ip);
275
276 inline bool operator ==(const MaskedIP& l, const MaskedIP& r) {
277 auto shift = std::max((l.v6 ? 128 : 32) - ((int) l.prefix),
278 (r.v6 ? 128 : 32) - ((int) r.prefix));
279 ceph_assert(shift >= 0);
280 return (l.addr >> shift) == (r.addr >> shift);
281 }
282
283 struct Condition {
284 TokenID op;
285 // Originally I was going to use a perfect hash table, but Marcus
286 // says keys are to be added at run-time not compile time.
287
288 // In future development, use symbol internment.
289 std::string key;
290 bool ifexists = false;
291 bool isruntime = false; //Is evaluated during run-time
292 // Much to my annoyance there is no actual way to do this in a
293 // typed way that is compatible with AWS. I know this because I've
294 // seen examples where the same value is used as a string in one
295 // context and a date in another.
296 std::vector<std::string> vals;
297
298 Condition() = default;
299 Condition(TokenID op, const char* s, std::size_t len, bool ifexists)
300 : op(op), key(s, len), ifexists(ifexists) {}
301
302 bool eval(const Environment& e) const;
303
304 static boost::optional<double> as_number(const std::string& s) {
305 std::size_t p = 0;
306
307 try {
308 double d = std::stod(s, &p);
309 if (p < s.length()) {
310 return boost::none;
311 }
312
313 return d;
314 } catch (const std::logic_error& e) {
315 return boost::none;
316 }
317 }
318
319 static boost::optional<ceph::real_time> as_date(const std::string& s) {
320 std::size_t p = 0;
321
322 try {
323 double d = std::stod(s, &p);
324 if (p == s.length()) {
325 return ceph::real_time(
326 std::chrono::seconds(static_cast<uint64_t>(d)) +
327 std::chrono::nanoseconds(
328 static_cast<uint64_t>((d - static_cast<uint64_t>(d))
329 * 1000000000)));
330 }
331
332 return from_iso_8601(std::string_view(s), false);
333 } catch (const std::logic_error& e) {
334 return boost::none;
335 }
336 }
337
338 static boost::optional<bool> as_bool(const std::string& s) {
339 std::size_t p = 0;
340
341 if (s.empty() || boost::iequals(s, "false")) {
342 return false;
343 }
344
345 try {
346 double d = std::stod(s, &p);
347 if (p == s.length()) {
348 return !((d == +0.0) || (d == -0.0) || std::isnan(d));
349 }
350 } catch (const std::logic_error& e) {
351 // Fallthrough
352 }
353
354 return true;
355 }
356
357 static boost::optional<ceph::bufferlist> as_binary(const std::string& s) {
358 // In a just world
359 ceph::bufferlist base64;
360 // I could populate a bufferlist
361 base64.push_back(buffer::create_static(
362 s.length(),
363 const_cast<char*>(s.data()))); // Yuck
364 // From a base64 encoded std::string.
365 ceph::bufferlist bin;
366
367 try {
368 bin.decode_base64(base64);
369 } catch (const ceph::buffer::malformed_input& e) {
370 return boost::none;
371 }
372 return bin;
373 }
374
375 static boost::optional<MaskedIP> as_network(const std::string& s);
376
377
378 struct ci_equal_to {
379 bool operator ()(const std::string& s1,
380 const std::string& s2) const {
381 return boost::iequals(s1, s2);
382 }
383 };
384
385 struct string_like {
386 bool operator ()(const std::string& input,
387 const std::string& pattern) const {
388 return match_wildcards(pattern, input, 0);
389 }
390 };
391
392 struct ci_starts_with {
393 bool operator()(const std::string& s1,
394 const std::string& s2) const {
395 return boost::istarts_with(s1, s2);
396 }
397 };
398
399 using unordered_multimap_it_pair = std::pair <std::unordered_multimap<std::string,std::string>::const_iterator, std::unordered_multimap<std::string,std::string>::const_iterator>;
400
401 template<typename F>
402 static bool andible(F&& f, const unordered_multimap_it_pair& it,
403 const std::vector<std::string>& v) {
404 for (auto itr = it.first; itr != it.second; itr++) {
405 bool matched = false;
406 for (const auto& d : v) {
407 if (std::forward<F>(f)(itr->second, d)) {
408 matched = true;
409 }
410 }
411 if (!matched)
412 return false;
413 }
414 return true;
415 }
416
417 template<typename F>
418 static bool orrible(F&& f, const unordered_multimap_it_pair& it,
419 const std::vector<std::string>& v) {
420 for (auto itr = it.first; itr != it.second; itr++) {
421 for (const auto& d : v) {
422 if (std::forward<F>(f)(itr->second, d)) {
423 return true;
424 }
425 }
426 }
427 return false;
428 }
429
430 template<typename F, typename X>
431 static bool shortible(F&& f, X& x, const std::string& c,
432 const std::vector<std::string>& v) {
433 auto xc = std::forward<X>(x)(c);
434 if (!xc) {
435 return false;
436 }
437
438 for (const auto& d : v) {
439 auto xd = std::forward<X>(x)(d);
440 if (!xd) {
441 continue;
442 }
443
444 if (std::forward<F>(f)(*xc, *xd)) {
445 return true;
446 }
447 }
448 return false;
449 }
450
451 template <typename F>
452 bool has_key_p(const std::string& _key, F p) const {
453 return p(key, _key);
454 }
455
456 template <typename F>
457 bool has_val_p(const std::string& _val, F p) const {
458 for (auto val : vals) {
459 if (p(val, _val))
460 return true;
461 }
462 return false;
463 }
464 };
465
466 std::ostream& operator <<(std::ostream& m, const Condition& c);
467
468 struct Statement {
469 boost::optional<std::string> sid = boost::none;
470
471 boost::container::flat_set<rgw::auth::Principal> princ;
472 boost::container::flat_set<rgw::auth::Principal> noprinc;
473
474 // Every statement MUST provide an effect. I just initialize it to
475 // deny as defensive programming.
476 Effect effect = Effect::Deny;
477
478 Action_t action = 0;
479 NotAction_t notaction = 0;
480
481 boost::container::flat_set<ARN> resource;
482 boost::container::flat_set<ARN> notresource;
483
484 std::vector<Condition> conditions;
485
486 Effect eval(const Environment& e,
487 boost::optional<const rgw::auth::Identity&> ida,
488 std::uint64_t action, boost::optional<const ARN&> resource, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
489
490 Effect eval_principal(const Environment& e,
491 boost::optional<const rgw::auth::Identity&> ida, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
492
493 Effect eval_conditions(const Environment& e) const;
494 };
495
496 std::ostream& operator <<(std::ostream& m, const Statement& s);
497
498 struct PolicyParseException : public std::exception {
499 rapidjson::ParseResult pr;
500 std::string msg;
501
502 explicit PolicyParseException(const rapidjson::ParseResult pr,
503 const std::string& annotation)
504 : pr(pr),
505 msg(fmt::format("At character offset {}, {}",
506 pr.Offset(),
507 (pr.Code() == rapidjson::kParseErrorTermination ?
508 annotation :
509 rapidjson::GetParseError_En(pr.Code())))) {}
510
511 const char* what() const noexcept override {
512 return msg.c_str();
513 }
514 };
515
516 struct Policy {
517 std::string text;
518 Version version = Version::v2008_10_17;
519 boost::optional<std::string> id = boost::none;
520
521 std::vector<Statement> statements;
522
523 // reject_invalid_principals should be set to
524 // `cct->_conf.get_val<bool>("rgw_policy_reject_invalid_principals")`
525 // when executing operations that *set* a bucket policy, but should
526 // be false when reading a stored bucket policy so as not to break
527 // backwards configuration.
528 Policy(CephContext* cct, const std::string& tenant,
529 const bufferlist& text,
530 bool reject_invalid_principals);
531
532 Effect eval(const Environment& e,
533 boost::optional<const rgw::auth::Identity&> ida,
534 std::uint64_t action, boost::optional<const ARN&> resource, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
535
536 Effect eval_principal(const Environment& e,
537 boost::optional<const rgw::auth::Identity&> ida, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
538
539 Effect eval_conditions(const Environment& e) const;
540
541 template <typename F>
542 bool has_conditional(const std::string& conditional, F p) const {
543 for (const auto&s: statements){
544 if (std::any_of(s.conditions.begin(), s.conditions.end(),
545 [&](const Condition& c) { return c.has_key_p(conditional, p);}))
546 return true;
547 }
548 return false;
549 }
550
551 template <typename F>
552 bool has_conditional_value(const std::string& conditional, F p) const {
553 for (const auto&s: statements){
554 if (std::any_of(s.conditions.begin(), s.conditions.end(),
555 [&](const Condition& c) { return c.has_val_p(conditional, p);}))
556 return true;
557 }
558 return false;
559 }
560
561 bool has_conditional(const std::string& c) const {
562 return has_conditional(c, Condition::ci_equal_to());
563 }
564
565 bool has_partial_conditional(const std::string& c) const {
566 return has_conditional(c, Condition::ci_starts_with());
567 }
568
569 // Example: ${s3:ResourceTag}
570 bool has_partial_conditional_value(const std::string& c) const {
571 return has_conditional_value(c, Condition::ci_starts_with());
572 }
573 };
574
575 std::ostream& operator <<(std::ostream& m, const Policy& p);
576 bool is_public(const Policy& p);
577
578 }
579 }