]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_iam_policy.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_iam_policy.h
CommitLineData
31f18b77
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#ifndef CEPH_RGW_IAM_POLICY_H
5#define CEPH_RGW_IAM_POLICY_H
6
7#include <bitset>
8#include <chrono>
9#include <cstdint>
10#include <iostream>
11#include <string>
11fdf7f2 12#include <bitset>
31f18b77
FG
13
14#include <boost/algorithm/string/predicate.hpp>
15#include <boost/container/flat_map.hpp>
16#include <boost/container/flat_set.hpp>
17#include <boost/optional.hpp>
18#include <boost/thread/shared_mutex.hpp>
19#include <boost/utility/string_ref.hpp>
20#include <boost/variant.hpp>
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
c07f9fc5 28#include "rgw_acl.h"
31f18b77
FG
29#include "rgw_basic_types.h"
30#include "rgw_iam_policy_keywords.h"
d2e6a577 31#include "rgw_string.h"
31f18b77 32
31f18b77
FG
33class RGWRados;
34namespace rgw {
35namespace auth {
36class Identity;
37}
38}
39struct rgw_obj;
40struct rgw_bucket;
41
42namespace rgw {
43namespace IAM {
11fdf7f2
TL
44
45static constexpr std::uint64_t s3GetObject = 0;
46static constexpr std::uint64_t s3GetObjectVersion = 1;
47static constexpr std::uint64_t s3PutObject = 2;
48static constexpr std::uint64_t s3GetObjectAcl = 3;
49static constexpr std::uint64_t s3GetObjectVersionAcl = 4;
50static constexpr std::uint64_t s3PutObjectAcl = 5;
51static constexpr std::uint64_t s3PutObjectVersionAcl = 6;
52static constexpr std::uint64_t s3DeleteObject = 7;
53static constexpr std::uint64_t s3DeleteObjectVersion = 8;
54static constexpr std::uint64_t s3ListMultipartUploadParts = 9;
55static constexpr std::uint64_t s3AbortMultipartUpload = 10;
56static constexpr std::uint64_t s3GetObjectTorrent = 11;
57static constexpr std::uint64_t s3GetObjectVersionTorrent = 12;
58static constexpr std::uint64_t s3RestoreObject = 13;
59static constexpr std::uint64_t s3CreateBucket = 14;
60static constexpr std::uint64_t s3DeleteBucket = 15;
61static constexpr std::uint64_t s3ListBucket = 16;
62static constexpr std::uint64_t s3ListBucketVersions = 17;
63static constexpr std::uint64_t s3ListAllMyBuckets = 18;
64static constexpr std::uint64_t s3ListBucketMultipartUploads = 19;
65static constexpr std::uint64_t s3GetAccelerateConfiguration = 20;
66static constexpr std::uint64_t s3PutAccelerateConfiguration = 21;
67static constexpr std::uint64_t s3GetBucketAcl = 22;
68static constexpr std::uint64_t s3PutBucketAcl = 23;
69static constexpr std::uint64_t s3GetBucketCORS = 24;
70static constexpr std::uint64_t s3PutBucketCORS = 25;
71static constexpr std::uint64_t s3GetBucketVersioning = 26;
72static constexpr std::uint64_t s3PutBucketVersioning = 27;
73static constexpr std::uint64_t s3GetBucketRequestPayment = 28;
74static constexpr std::uint64_t s3PutBucketRequestPayment = 29;
75static constexpr std::uint64_t s3GetBucketLocation = 30;
76static constexpr std::uint64_t s3GetBucketPolicy = 31;
77static constexpr std::uint64_t s3DeleteBucketPolicy = 32;
78static constexpr std::uint64_t s3PutBucketPolicy = 33;
79static constexpr std::uint64_t s3GetBucketNotification = 34;
80static constexpr std::uint64_t s3PutBucketNotification = 35;
81static constexpr std::uint64_t s3GetBucketLogging = 36;
82static constexpr std::uint64_t s3PutBucketLogging = 37;
83static constexpr std::uint64_t s3GetBucketTagging = 38;
84static constexpr std::uint64_t s3PutBucketTagging = 39;
85static constexpr std::uint64_t s3GetBucketWebsite = 40;
86static constexpr std::uint64_t s3PutBucketWebsite = 41;
87static constexpr std::uint64_t s3DeleteBucketWebsite = 42;
88static constexpr std::uint64_t s3GetLifecycleConfiguration = 43;
89static constexpr std::uint64_t s3PutLifecycleConfiguration = 44;
90static constexpr std::uint64_t s3PutReplicationConfiguration = 45;
91static constexpr std::uint64_t s3GetReplicationConfiguration = 46;
92static constexpr std::uint64_t s3DeleteReplicationConfiguration = 47;
93static constexpr std::uint64_t s3GetObjectTagging = 48;
94static constexpr std::uint64_t s3PutObjectTagging = 49;
95static constexpr std::uint64_t s3DeleteObjectTagging = 50;
96static constexpr std::uint64_t s3GetObjectVersionTagging = 51;
97static constexpr std::uint64_t s3PutObjectVersionTagging = 52;
98static constexpr std::uint64_t s3DeleteObjectVersionTagging = 53;
99static constexpr std::uint64_t s3All = 54;
100
101static constexpr std::uint64_t iamPutUserPolicy = 55;
102static constexpr std::uint64_t iamGetUserPolicy = 56;
103static constexpr std::uint64_t iamDeleteUserPolicy = 57;
104static constexpr std::uint64_t iamListUserPolicies = 58;
105static constexpr std::uint64_t iamCreateRole = 59;
106static constexpr std::uint64_t iamDeleteRole = 60;
107static constexpr std::uint64_t iamModifyRole = 61;
108static constexpr std::uint64_t iamGetRole = 62;
109static constexpr std::uint64_t iamListRoles = 63;
110static constexpr std::uint64_t iamPutRolePolicy = 64;
111static constexpr std::uint64_t iamGetRolePolicy = 65;
112static constexpr std::uint64_t iamListRolePolicies = 66;
113static constexpr std::uint64_t iamDeleteRolePolicy = 67;
114static constexpr std::uint64_t iamAll = 68;
115static constexpr std::uint64_t stsAssumeRole = 69;
116static constexpr std::uint64_t stsAssumeRoleWithWebIdentity = 70;
117static constexpr std::uint64_t stsGetSessionToken = 71;
118static constexpr std::uint64_t stsAll = 72;
119
120static constexpr std::uint64_t s3Count = s3DeleteObjectVersionTagging + 1;
121static constexpr std::uint64_t allCount = stsAll + 1;
122
123using Action_t = bitset<allCount>;
124using NotAction_t = Action_t;
125
126static const Action_t None(0);
127static const Action_t s3AllValue("111111111111111111111111111111111111111111111111111111");
128static const Action_t iamAllValue("11111111111110000000000000000000000000000000000000000000000000000000");
129static const Action_t stsAllValue("111000000000000000000000000000000000000000000000000000000000000000000000");
130//Modify allValue if more Actions are added
131static const Action_t allValue("1111111111111111111111111111111111111111111111111111111111111111111111111");
31f18b77
FG
132
133namespace {
a8e16298
TL
134// Please update the table in doc/radosgw/s3/authentication.rst if you
135// modify this function.
31f18b77
FG
136inline int op_to_perm(std::uint64_t op) {
137 switch (op) {
138 case s3GetObject:
139 case s3GetObjectTorrent:
140 case s3GetObjectVersion:
141 case s3GetObjectVersionTorrent:
224ce89b
WB
142 case s3GetObjectTagging:
143 case s3GetObjectVersionTagging:
31f18b77
FG
144 case s3ListAllMyBuckets:
145 case s3ListBucket:
28e407b8 146 case s3ListBucketMultipartUploads:
31f18b77
FG
147 case s3ListBucketVersions:
148 case s3ListMultipartUploadParts:
149 return RGW_PERM_READ;
150
151 case s3AbortMultipartUpload:
152 case s3CreateBucket:
153 case s3DeleteBucket:
154 case s3DeleteObject:
155 case s3DeleteObjectVersion:
156 case s3PutObject:
224ce89b
WB
157 case s3PutObjectTagging:
158 case s3PutObjectVersionTagging:
159 case s3DeleteObjectTagging:
160 case s3DeleteObjectVersionTagging:
31f18b77
FG
161 case s3RestoreObject:
162 return RGW_PERM_WRITE;
163
164 case s3GetAccelerateConfiguration:
165 case s3GetBucketAcl:
166 case s3GetBucketCORS:
167 case s3GetBucketLocation:
168 case s3GetBucketLogging:
169 case s3GetBucketNotification:
170 case s3GetBucketPolicy:
171 case s3GetBucketRequestPayment:
172 case s3GetBucketTagging:
173 case s3GetBucketVersioning:
174 case s3GetBucketWebsite:
175 case s3GetLifecycleConfiguration:
176 case s3GetObjectAcl:
177 case s3GetObjectVersionAcl:
178 case s3GetReplicationConfiguration:
179 return RGW_PERM_READ_ACP;
180
181 case s3DeleteBucketPolicy:
182 case s3DeleteBucketWebsite:
183 case s3DeleteReplicationConfiguration:
184 case s3PutAccelerateConfiguration:
185 case s3PutBucketAcl:
186 case s3PutBucketCORS:
187 case s3PutBucketLogging:
188 case s3PutBucketNotification:
189 case s3PutBucketPolicy:
190 case s3PutBucketRequestPayment:
191 case s3PutBucketTagging:
192 case s3PutBucketVersioning:
193 case s3PutBucketWebsite:
194 case s3PutLifecycleConfiguration:
195 case s3PutObjectAcl:
196 case s3PutObjectVersionAcl:
197 case s3PutReplicationConfiguration:
198 return RGW_PERM_WRITE_ACP;
199
200 case s3All:
201 return RGW_PERM_FULL_CONTROL;
202 }
203 return RGW_PERM_INVALID;
204}
205}
206
207using Environment = boost::container::flat_map<std::string, std::string>;
208
209enum struct Partition {
210 aws, aws_cn, aws_us_gov, wildcard
211 // If we wanted our own ARNs for principal type unique to us
212 // (maybe to integrate better with Swift) or for anything else we
213 // provide that doesn't map onto S3, we could add an 'rgw'
214 // partition type.
215};
216
217enum struct Service {
218 apigateway, appstream, artifact, autoscaling, aws_portal, acm,
219 cloudformation, cloudfront, cloudhsm, cloudsearch, cloudtrail,
220 cloudwatch, events, logs, codebuild, codecommit, codedeploy,
221 codepipeline, cognito_idp, cognito_identity, cognito_sync,
222 config, datapipeline, dms, devicefarm, directconnect,
223 ds, dynamodb, ec2, ecr, ecs, ssm, elasticbeanstalk, elasticfilesystem,
224 elasticloadbalancing, elasticmapreduce, elastictranscoder, elasticache,
225 es, gamelift, glacier, health, iam, importexport, inspector, iot,
226 kms, kinesisanalytics, firehose, kinesis, lambda, lightsail,
227 machinelearning, aws_marketplace, aws_marketplace_management,
228 mobileanalytics, mobilehub, opsworks, opsworks_cm, polly,
229 redshift, rds, route53, route53domains, sts, servicecatalog,
230 ses, sns, sqs, s3, swf, sdb, states, storagegateway, support,
231 trustedadvisor, waf, workmail, workspaces, wildcard
232};
233
234struct ARN {
235 Partition partition;
236 Service service;
237 std::string region;
11fdf7f2 238 // Once we refit tenant, we should probably use that instead of a
31f18b77
FG
239 // string.
240 std::string account;
241 std::string resource;
242
243 ARN()
244 : partition(Partition::wildcard), service(Service::wildcard) {}
245 ARN(Partition partition, Service service, std::string region,
246 std::string account, std::string resource)
247 : partition(partition), service(service), region(std::move(region)),
248 account(std::move(account)), resource(std::move(resource)) {}
249 ARN(const rgw_obj& o);
250 ARN(const rgw_bucket& b);
251 ARN(const rgw_bucket& b, const std::string& o);
11fdf7f2 252 ARN(const string& resource_name, const string& type, const string& tenant, bool has_path=false);
31f18b77
FG
253
254 static boost::optional<ARN> parse(const std::string& s,
255 bool wildcard = false);
256 std::string to_string() const;
257
258 // `this` is the pattern
259 bool match(const ARN& candidate) const;
260};
261
262inline std::string to_string(const ARN& a) {
263 return a.to_string();
264}
265
266inline std::ostream& operator <<(std::ostream& m, const ARN& a) {
267 return m << to_string(a);
268}
269
270bool operator ==(const ARN& l, const ARN& r);
271bool operator <(const ARN& l, const ARN& r);
272
273using Address = std::bitset<128>;
274struct MaskedIP {
275 bool v6;
276 Address addr;
277 // Since we're mapping IPv6 to IPv4 addresses, we may want to
278 // consider making the prefix always be in terms of a v6 address
279 // and just use the v6 bit to rewrite it as a v4 prefix for
280 // output.
281 unsigned int prefix;
282};
283
284std::ostream& operator <<(std::ostream& m, const MaskedIP& ip);
31f18b77
FG
285
286inline bool operator ==(const MaskedIP& l, const MaskedIP& r) {
b32b8144
FG
287 auto shift = std::max((l.v6 ? 128 : 32) - ((int) l.prefix),
288 (r.v6 ? 128 : 32) - ((int) r.prefix));
289 ceph_assert(shift >= 0);
31f18b77
FG
290 return (l.addr >> shift) == (r.addr >> shift);
291}
292
293struct Condition {
294 TokenID op;
295 // Originally I was going to use a perfect hash table, but Marcus
296 // says keys are to be added at run-time not compile time.
297
298 // In future development, use symbol internment.
299 std::string key;
300 bool ifexists = false;
301 // Much to my annoyance there is no actual way to do this in a
302 // typed way that is compatible with AWS. I know this because I've
303 // seen examples where the same value is used as a string in one
304 // context and a date in another.
305 std::vector<std::string> vals;
306
307 Condition() = default;
c07f9fc5
FG
308 Condition(TokenID op, const char* s, std::size_t len, bool ifexists)
309 : op(op), key(s, len), ifexists(ifexists) {}
31f18b77
FG
310
311 bool eval(const Environment& e) const;
312
313 static boost::optional<double> as_number(const std::string& s) {
314 std::size_t p = 0;
315
316 try {
317 double d = std::stod(s, &p);
318 if (p < s.length()) {
319 return boost::none;
320 }
321
322 return d;
323 } catch (const std::logic_error& e) {
324 return boost::none;
325 }
326 }
327
328 static boost::optional<ceph::real_time> as_date(const std::string& s) {
329 std::size_t p = 0;
330
331 try {
332 double d = std::stod(s, &p);
333 if (p == s.length()) {
334 return ceph::real_time(
335 std::chrono::seconds(static_cast<uint64_t>(d)) +
336 std::chrono::nanoseconds(
337 static_cast<uint64_t>((d - static_cast<uint64_t>(d))
338 * 1000000000)));
339 }
340
341 return from_iso_8601(boost::string_ref(s), false);
342 } catch (const std::logic_error& e) {
343 return boost::none;
344 }
345 }
346
347 static boost::optional<bool> as_bool(const std::string& s) {
348 std::size_t p = 0;
349
350 if (s.empty() || boost::iequals(s, "false")) {
351 return false;
352 }
353
354 try {
355 double d = std::stod(s, &p);
356 if (p == s.length()) {
c07f9fc5 357 return !((d == +0.0) || (d == -0.0) || std::isnan(d));
31f18b77
FG
358 }
359 } catch (const std::logic_error& e) {
360 // Fallthrough
361 }
362
363 return true;
364 }
365
366 static boost::optional<ceph::bufferlist> as_binary(const std::string& s) {
367 // In a just world
368 ceph::bufferlist base64;
369 // I could populate a bufferlist
370 base64.push_back(buffer::create_static(
371 s.length(),
372 const_cast<char*>(s.data()))); // Yuck
373 // From a base64 encoded std::string.
374 ceph::bufferlist bin;
375
376 try {
377 base64.decode_base64(bin);
378 } catch (const ceph::buffer::malformed_input& e) {
379 return boost::none;
380 }
381 return bin;
382 }
383
384 static boost::optional<MaskedIP> as_network(const std::string& s);
385
386
d2e6a577 387 struct ci_equal_to {
31f18b77
FG
388 bool operator ()(const std::string& s1,
389 const std::string& s2) const {
390 return boost::iequals(s1, s2);
391 }
392 };
393
d2e6a577
FG
394 struct string_like {
395 bool operator ()(const std::string& input,
396 const std::string& pattern) const {
397 return match_wildcards(pattern, input, 0);
398 }
399 };
31f18b77 400
11fdf7f2
TL
401 struct ci_starts_with {
402 bool operator()(const std::string& s1,
403 const std::string& s2) const {
404 return boost::istarts_with(s1, s2);
405 }
406 };
407
31f18b77
FG
408 template<typename F>
409 static bool orrible(F&& f, const std::string& c,
410 const std::vector<std::string>& v) {
411 for (const auto& d : v) {
412 if (std::forward<F>(f)(c, d)) {
413 return true;
414 }
415 }
416 return false;
417 }
418
419 template<typename F, typename X>
420 static bool shortible(F&& f, X& x, const std::string& c,
421 const std::vector<std::string>& v) {
422 auto xc = std::forward<X>(x)(c);
423 if (!xc) {
424 return false;
425 }
426
427 for (const auto& d : v) {
428 auto xd = std::forward<X>(x)(d);
429 if (!xd) {
430 continue;
431 }
432
433 if (std::forward<F>(f)(*xc, *xd)) {
434 return true;
435 }
436 }
437 return false;
438 }
11fdf7f2
TL
439
440 template <typename F>
441 bool has_key_p(const std::string& _key, F p) const {
442 return p(key, _key);
443 }
31f18b77
FG
444};
445
446std::ostream& operator <<(std::ostream& m, const Condition& c);
447
31f18b77
FG
448struct Statement {
449 boost::optional<std::string> sid = boost::none;
450
451 boost::container::flat_set<rgw::auth::Principal> princ;
452 boost::container::flat_set<rgw::auth::Principal> noprinc;
453
454 // Every statement MUST provide an effect. I just initialize it to
455 // deny as defensive programming.
456 Effect effect = Effect::Deny;
457
11fdf7f2
TL
458 Action_t action = 0;
459 NotAction_t notaction = 0;
31f18b77
FG
460
461 boost::container::flat_set<ARN> resource;
462 boost::container::flat_set<ARN> notresource;
463
464 std::vector<Condition> conditions;
465
466 Effect eval(const Environment& e,
467 boost::optional<const rgw::auth::Identity&> ida,
468 std::uint64_t action, const ARN& resource) const;
11fdf7f2
TL
469
470 Effect eval_principal(const Environment& e,
471 boost::optional<const rgw::auth::Identity&> ida) const;
472
473 Effect eval_conditions(const Environment& e) const;
31f18b77
FG
474};
475
476std::ostream& operator <<(ostream& m, const Statement& s);
31f18b77
FG
477
478struct PolicyParseException : public std::exception {
479 rapidjson::ParseResult pr;
480
11fdf7f2 481 explicit PolicyParseException(rapidjson::ParseResult&& pr)
31f18b77
FG
482 : pr(pr) { }
483 const char* what() const noexcept override {
484 return rapidjson::GetParseError_En(pr.Code());
485 }
486};
487
488struct Policy {
489 std::string text;
490 Version version = Version::v2008_10_17;
491 boost::optional<std::string> id = boost::none;
492
493 std::vector<Statement> statements;
494
495 Policy(CephContext* cct, const std::string& tenant,
496 const bufferlist& text);
497
498 Effect eval(const Environment& e,
499 boost::optional<const rgw::auth::Identity&> ida,
500 std::uint64_t action, const ARN& resource) const;
11fdf7f2
TL
501
502 Effect eval_principal(const Environment& e,
503 boost::optional<const rgw::auth::Identity&> ida) const;
504
505 Effect eval_conditions(const Environment& e) const;
506
507 template <typename F>
508 bool has_conditional(const string& conditional, F p) const {
509 for (const auto&s: statements){
510 if (std::any_of(s.conditions.begin(), s.conditions.end(),
511 [&](const Condition& c) { return c.has_key_p(conditional, p);}))
512 return true;
513 }
514 return false;
515 }
516
517 bool has_conditional(const string& c) const {
518 return has_conditional(c, Condition::ci_equal_to());
519 }
520
521 bool has_partial_conditional(const string& c) const {
522 return has_conditional(c, Condition::ci_starts_with());
523 }
31f18b77
FG
524};
525
526std::ostream& operator <<(ostream& m, const Policy& p);
31f18b77
FG
527}
528}
529
530namespace std {
531template<>
532struct hash<::rgw::IAM::Service> {
533 size_t operator()(const ::rgw::IAM::Service& s) const noexcept {
534 // Invoke a default-constructed hash object for int.
535 return hash<int>()(static_cast<int>(s));
536 }
537};
538}
539
540#endif