]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/iam: AttachRolePolicy adds managed role policy
authorCasey Bodley <cbodley@redhat.com>
Fri, 2 Feb 2024 15:53:14 +0000 (10:53 -0500)
committerCasey Bodley <cbodley@redhat.com>
Fri, 12 Apr 2024 19:34:28 +0000 (15:34 -0400)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
(cherry picked from commit 390cdaa45ee923dde2de3e5b8077537c741fe5d9)

14 files changed:
src/rgw/driver/rados/rgw_sal_rados.cc
src/rgw/rgw_auth.cc
src/rgw/rgw_auth.h
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_iam_policy.cc
src/rgw/rgw_iam_policy.h
src/rgw/rgw_op_type.h
src/rgw/rgw_rest_iam.cc
src/rgw/rgw_rest_role.cc
src/rgw/rgw_rest_role.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_role.cc
src/rgw/rgw_role.h
src/test/rgw/test_rgw_iam_policy.cc

index 51bdaa2a91a5ab2182b8cb3875116ca3501857cc..fd9d6f90ad3748221dceca93daa844e970a31863 100644 (file)
@@ -4243,7 +4243,8 @@ int RadosRole::delete_obj(const DoutPrefixProvider *dpp, optional_yield y)
     return ret;
   }
 
-  if (! info.perm_policy_map.empty()) {
+  if (!info.perm_policy_map.empty() ||
+      !info.managed_policies.arns.empty()) {
     return -ERR_DELETE_CONFLICT;
   }
 
index 9da2f6afc949613996f67d3d0cba91f4685d4bfc..5692f9ae2f5bee2ad5227ad78367a811875d6742 100644 (file)
@@ -10,6 +10,7 @@
 #include "rgw_quota.h"
 #include "rgw_user.h"
 #include "rgw_http_client.h"
+#include "rgw_iam_managed_policy.h"
 #include "rgw_keystone.h"
 #include "rgw_sal.h"
 #include "rgw_log.h"
@@ -949,9 +950,16 @@ ACLOwner rgw::auth::RoleApplier::get_aclowner() const
 
 void rgw::auth::RoleApplier::to_str(std::ostream& out) const {
   out << "rgw::auth::RoleApplier(role name =" << role.name;
-  for (auto& policy: role.role_policies) {
+  for (auto& policy: role.inline_policies) {
     out << ", role policy =" << policy;
   }
+  for (std::string_view arn : role.managed_policies) {
+    if (auto p = arn.find('/'); p != arn.npos) {
+      out << ", managed policy =" << arn.substr(p + 1);
+    } else {
+      out << ", managed policy =" << arn;
+    }
+  }
   out << ", token policy =" << token_attrs.token_policy;
   out << ")";
 }
@@ -987,7 +995,7 @@ void rgw::auth::RoleApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUs
 
 void rgw::auth::RoleApplier::modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const
 {
-  for (const auto& policy : role.role_policies) {
+  for (const auto& policy : role.inline_policies) {
     try {
       const rgw::IAM::Policy p(s->cct, role.tenant, policy, false);
       s->iam_user_policies.push_back(std::move(p));
@@ -997,6 +1005,17 @@ void rgw::auth::RoleApplier::modify_request_state(const DoutPrefixProvider *dpp,
       ldpp_dout(dpp, 20) << "failed to parse role policy: " << e.what() << dendl;
     }
   }
+  for (const auto& arn : role.managed_policies) {
+    try {
+      if (auto p = rgw::IAM::get_managed_policy(s->cct, arn); p) {
+        s->iam_user_policies.push_back(std::move(*p));
+      }
+    } catch (rgw::IAM::PolicyParseException& e) {
+      //Control shouldn't reach here as the policy has already been
+      //verified earlier
+      ldpp_dout(dpp, 20) << "failed to parse role policy: " << e.what() << dendl;
+    }
+  }
 
   if (!this->token_attrs.token_policy.empty()) {
     try {
index ddca72f84e4aeb7eb10a4665281756d52f838436..3c3dd5ebe7c86b143b0545f831a9a3544a41da29 100644 (file)
@@ -727,7 +727,8 @@ public:
     std::string id;
     std::string name;
     std::string tenant;
-    std::vector<std::string> role_policies;
+    std::vector<std::string> inline_policies;
+    std::vector<std::string> managed_policies;
   };
   struct TokenAttrs {
     rgw_user user_id;
index dd90925f04a2501d8cb634172743355e3ef53289..e43fe24c5eb162390100edeeb235ed1f58510134 100644 (file)
@@ -481,6 +481,9 @@ bool is_non_s3_op(RGWOpType op_type)
   case RGW_OP_GET_ROLE_POLICY:
   case RGW_OP_LIST_ROLE_POLICIES:
   case RGW_OP_DELETE_ROLE_POLICY:
+  case RGW_OP_ATTACH_ROLE_POLICY:
+  case RGW_OP_DETACH_ROLE_POLICY:
+  case RGW_OP_LIST_ATTACHED_ROLE_POLICIES:
   case RGW_OP_PUT_USER_POLICY:
   case RGW_OP_GET_USER_POLICY:
   case RGW_OP_LIST_USER_POLICIES:
index c0a081054fa81e425b468fb5dccaacadff23c4d3..f00cbfeac3662ff7ad4be2357ddb434c55c597d4 100644 (file)
@@ -153,6 +153,9 @@ static const actpair actpairs[] =
  { "iam:GetRolePolicy", iamGetRolePolicy},
  { "iam:ListRolePolicies", iamListRolePolicies},
  { "iam:DeleteRolePolicy", iamDeleteRolePolicy},
+ { "iam:AttachRolePolicy", iamAttachRolePolicy },
+ { "iam:DetachRolePolicy", iamDetachRolePolicy },
+ { "iam:ListAttachedRolePolicies", iamListAttachedRolePolicies },
  { "iam:CreateOIDCProvider", iamCreateOIDCProvider},
  { "iam:DeleteOIDCProvider", iamDeleteOIDCProvider},
  { "iam:GetOIDCProvider", iamGetOIDCProvider},
@@ -1505,6 +1508,15 @@ const char* action_bit_string(uint64_t action) {
   case iamDeleteRolePolicy:
     return "iam:DeleteRolePolicy";
 
+  case iamAttachRolePolicy:
+    return "iam:AttachRolePolicy";
+
+  case iamDetachRolePolicy:
+    return "iam:DetachRolePolicy";
+
+  case iamListAttachedRolePolicies:
+    return "iam:ListAttachedRolePolicies";
+
   case iamCreateOIDCProvider:
     return "iam:CreateOIDCProvider";
 
index a8aa88dca7b025791e0a88ac491b1814b255fdbf..cf5310bfc6f4b9ce4f018879649d87815d7db124 100644 (file)
@@ -136,6 +136,9 @@ enum {
   iamGetRolePolicy,
   iamListRolePolicies,
   iamDeleteRolePolicy,
+  iamAttachRolePolicy,
+  iamDetachRolePolicy,
+  iamListAttachedRolePolicies,
   iamCreateOIDCProvider,
   iamDeleteOIDCProvider,
   iamGetOIDCProvider,
index d71f174c37c264c4f6c416fa0cdde0e32f564b36..79edf3f2f506d3ea863f0b5c29aa9043dd78b35b 100644 (file)
@@ -61,13 +61,6 @@ enum RGWOpType {
   RGW_OP_PUT_LC,
   RGW_OP_GET_LC,
   RGW_OP_DELETE_LC,
-  RGW_OP_PUT_USER_POLICY,
-  RGW_OP_GET_USER_POLICY,
-  RGW_OP_LIST_USER_POLICIES,
-  RGW_OP_DELETE_USER_POLICY,
-  RGW_OP_ATTACH_USER_POLICY,
-  RGW_OP_DETACH_USER_POLICY,
-  RGW_OP_LIST_ATTACHED_USER_POLICIES,
   RGW_OP_PUT_BUCKET_OBJ_LOCK,
   RGW_OP_GET_BUCKET_OBJ_LOCK,
   RGW_OP_PUT_OBJ_RETENTION,
@@ -75,6 +68,13 @@ enum RGWOpType {
   RGW_OP_PUT_OBJ_LEGAL_HOLD,
   RGW_OP_GET_OBJ_LEGAL_HOLD,
   // IAM
+  RGW_OP_PUT_USER_POLICY,
+  RGW_OP_GET_USER_POLICY,
+  RGW_OP_LIST_USER_POLICIES,
+  RGW_OP_DELETE_USER_POLICY,
+  RGW_OP_ATTACH_USER_POLICY,
+  RGW_OP_DETACH_USER_POLICY,
+  RGW_OP_LIST_ATTACHED_USER_POLICIES,
   RGW_OP_CREATE_ROLE,
   RGW_OP_DELETE_ROLE,
   RGW_OP_GET_ROLE,
@@ -84,6 +84,9 @@ enum RGWOpType {
   RGW_OP_GET_ROLE_POLICY,
   RGW_OP_LIST_ROLE_POLICIES,
   RGW_OP_DELETE_ROLE_POLICY,
+  RGW_OP_ATTACH_ROLE_POLICY,
+  RGW_OP_DETACH_ROLE_POLICY,
+  RGW_OP_LIST_ATTACHED_ROLE_POLICIES,
   RGW_OP_TAG_ROLE,
   RGW_OP_LIST_ROLE_TAGS,
   RGW_OP_UNTAG_ROLE,
index cbd692f7914bff7018650fbee37170597aaeec3e..80b4228b513f53413028aa0afc906892c100fe2c 100644 (file)
@@ -30,6 +30,9 @@ static const std::unordered_map<std::string_view, op_generator> op_generators =
   {"GetRolePolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetRolePolicy;}},
   {"ListRolePolicies", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListRolePolicies;}},
   {"DeleteRolePolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWDeleteRolePolicy(bl_post_body);}},
+  {"AttachRolePolicy", make_iam_attach_role_policy_op},
+  {"DetachRolePolicy", make_iam_detach_role_policy_op},
+  {"ListAttachedRolePolicies", make_iam_list_attached_role_policies_op},
   {"PutUserPolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWPutUserPolicy;}},
   {"GetUserPolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetUserPolicy;}},
   {"ListUserPolicies", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListUserPolicies;}},
index f9580b206ffcc8b7159ffe58388a1a02752ebe15..d9def5cb520cc899897e95759bb33e0dc41f02af 100644 (file)
@@ -956,3 +956,266 @@ void RGWUpdateRole::execute(optional_yield y)
   s->formatter->close_section();
   s->formatter->close_section();
 }
+
+static bool validate_policy_arn(const std::string& arn, std::string& err)
+{
+  if (arn.empty()) {
+    err = "Missing required element PolicyArn";
+    return false;
+  }
+
+  if (arn.size() > 2048) {
+    err = "PolicyArn must be at most 2048 characters long";
+    return false;
+  }
+
+  if (arn.size() < 20) {
+    err = "PolicyArn must be at least 20 characters long";
+    return false;
+  }
+
+  return true;
+}
+
+class RGWAttachRolePolicy_IAM : public RGWRestRole {
+  bufferlist bl_post_body;
+  std::string role_name;
+  std::string policy_arn;
+  std::unique_ptr<rgw::sal::RGWRole> role;
+public:
+  explicit RGWAttachRolePolicy_IAM(const bufferlist& bl_post_body)
+    : RGWRestRole(rgw::IAM::iamAttachRolePolicy, RGW_CAP_WRITE),
+      bl_post_body(bl_post_body) {}
+  int init_processing(optional_yield y) override;
+  void execute(optional_yield y) override;
+  const char* name() const override { return "attach_role_policy"; }
+  RGWOpType get_type() override { return RGW_OP_ATTACH_ROLE_POLICY; }
+};
+
+int RGWAttachRolePolicy_IAM::init_processing(optional_yield y)
+{
+  // managed policy is only supported for account users. adding them to
+  // non-account users would give blanket permissions to all buckets
+  if (!std::holds_alternative<rgw_account_id>(s->owner.id)) {
+    s->err.message = "Managed policies are only supported for account users";
+    return -ERR_METHOD_NOT_ALLOWED;
+  }
+
+  role_name = s->info.args.get("RoleName");
+  if (!validate_iam_role_name(role_name, s->err.message)) {
+    return -EINVAL;
+  }
+
+  policy_arn = s->info.args.get("PolicyArn");
+  if (!validate_policy_arn(policy_arn, s->err.message)) {
+    return -EINVAL;
+  }
+
+  return load_role(this, y, driver, s->owner.id, account_id,
+                   s->user->get_tenant(), role_name, role, resource,
+                   s->err.message);
+}
+
+void RGWAttachRolePolicy_IAM::execute(optional_yield y)
+{
+  const rgw::SiteConfig& site = *s->penv.site;
+  if (!site.is_meta_master()) {
+    RGWXMLDecoder::XMLParser parser;
+    if (!parser.init()) {
+      ldpp_dout(this, 0) << "ERROR: failed to initialize xml parser" << dendl;
+      op_ret = -EINVAL;
+      return;
+    }
+
+    bufferlist data;
+    s->info.args.remove("RoleName");
+    s->info.args.remove("PolicyArn");
+    s->info.args.remove("Action");
+    s->info.args.remove("Version");
+
+    op_ret = forward_iam_request_to_master(this, site, s->user->get_info(),
+                                           bl_post_body, parser, s->info, y);
+    if (op_ret < 0) {
+      ldpp_dout(this, 20) << "ERROR: forward_iam_request_to_master failed with error code: " << op_ret << dendl;
+      return;
+    }
+  }
+
+  try {
+    // make sure the policy exists
+    if (!rgw::IAM::get_managed_policy(s->cct, policy_arn)) {
+      op_ret = ERR_NO_SUCH_ENTITY;
+      s->err.message = "The requested PolicyArn is not recognized";
+      return;
+    }
+  } catch (rgw::IAM::PolicyParseException& e) {
+    ldpp_dout(this, 5) << "failed to parse policy: " << e.what() << dendl;
+    s->err.message = e.what();
+    op_ret = -ERR_MALFORMED_DOC;
+    return;
+  }
+
+  // insert the policy arn. if it's already there, just return success
+  auto &policies = role->get_info().managed_policies;
+  const bool inserted = policies.arns.insert(policy_arn).second;
+  if (inserted) {
+    op_ret = role->update(this, y);
+  }
+
+  if (op_ret == 0) {
+    s->formatter->open_object_section_in_ns("AttachRolePolicyResponse", RGW_REST_IAM_XMLNS);
+    s->formatter->open_object_section("ResponseMetadata");
+    s->formatter->dump_string("RequestId", s->trans_id);
+    s->formatter->close_section();
+    s->formatter->close_section();
+  }
+}
+
+class RGWDetachRolePolicy_IAM : public RGWRestRole {
+  bufferlist bl_post_body;
+  std::string role_name;
+  std::string policy_arn;
+  std::unique_ptr<rgw::sal::RGWRole> role;
+public:
+  explicit RGWDetachRolePolicy_IAM(const bufferlist& bl_post_body)
+    : RGWRestRole(rgw::IAM::iamDetachRolePolicy, RGW_CAP_WRITE),
+      bl_post_body(bl_post_body) {}
+  int init_processing(optional_yield y) override;
+  void execute(optional_yield y) override;
+  const char* name() const override { return "detach_role_policy"; }
+  RGWOpType get_type() override { return RGW_OP_DETACH_ROLE_POLICY; }
+};
+
+int RGWDetachRolePolicy_IAM::init_processing(optional_yield y)
+{
+  // managed policy is only supported for account users. adding them to
+  // non-account users would give blanket permissions to all buckets
+  if (!std::holds_alternative<rgw_account_id>(s->owner.id)) {
+    s->err.message = "Managed policies are only supported for account users";
+    return -ERR_METHOD_NOT_ALLOWED;
+  }
+
+  role_name = s->info.args.get("RoleName");
+  if (!validate_iam_role_name(role_name, s->err.message)) {
+    return -EINVAL;
+  }
+
+  policy_arn = s->info.args.get("PolicyArn");
+  if (!validate_policy_arn(policy_arn, s->err.message)) {
+    return -EINVAL;
+  }
+
+  return load_role(this, y, driver, s->owner.id, account_id,
+                   s->user->get_tenant(), role_name, role, resource,
+                   s->err.message);
+}
+
+void RGWDetachRolePolicy_IAM::execute(optional_yield y)
+{
+  const rgw::SiteConfig& site = *s->penv.site;
+  if (!site.is_meta_master()) {
+    RGWXMLDecoder::XMLParser parser;
+    if (!parser.init()) {
+      ldpp_dout(this, 0) << "ERROR: failed to initialize xml parser" << dendl;
+      op_ret = -EINVAL;
+      return;
+    }
+
+    bufferlist data;
+    s->info.args.remove("RoleName");
+    s->info.args.remove("PolicyArn");
+    s->info.args.remove("Action");
+    s->info.args.remove("Version");
+
+    op_ret = forward_iam_request_to_master(this, site, s->user->get_info(),
+                                           bl_post_body, parser, s->info, y);
+    if (op_ret < 0) {
+      ldpp_dout(this, 20) << "ERROR: forward_iam_request_to_master failed with error code: " << op_ret << dendl;
+      return;
+    }
+  }
+
+  auto &policies = role->get_info().managed_policies;
+  auto p = policies.arns.find(policy_arn);
+  if (p == policies.arns.end()) {
+    op_ret = -ERR_NO_SUCH_ENTITY;
+    s->err.message = "The requested PolicyArn is not attached to the role";
+    return;
+  }
+  policies.arns.erase(p);
+  op_ret = role->update(this, y);
+
+  if (op_ret == 0) {
+    s->formatter->open_object_section_in_ns("DetachRolePolicyResponse", RGW_REST_IAM_XMLNS);
+    s->formatter->open_object_section("ResponseMetadata");
+    s->formatter->dump_string("RequestId", s->trans_id);
+    s->formatter->close_section();
+    s->formatter->close_section();
+  }
+}
+
+class RGWListAttachedRolePolicies_IAM : public RGWRestRole {
+  std::string role_name;
+  std::unique_ptr<rgw::sal::RGWRole> role;
+public:
+  RGWListAttachedRolePolicies_IAM()
+    : RGWRestRole(rgw::IAM::iamListAttachedRolePolicies, RGW_CAP_WRITE)
+  {}
+  int init_processing(optional_yield y) override;
+  void execute(optional_yield y) override;
+  const char* name() const override { return "list_attached_role_policies"; }
+  RGWOpType get_type() override { return RGW_OP_LIST_ATTACHED_ROLE_POLICIES; }
+};
+
+int RGWListAttachedRolePolicies_IAM::init_processing(optional_yield y)
+{
+  // managed policy is only supported for account roles. adding them to
+  // non-account roles would give blanket permissions to all buckets
+  if (!std::holds_alternative<rgw_account_id>(s->owner.id)) {
+    s->err.message = "Managed policies are only supported for account roles";
+    return -ERR_METHOD_NOT_ALLOWED;
+  }
+
+  role_name = s->info.args.get("RoleName");
+  if (!validate_iam_role_name(role_name, s->err.message)) {
+    return -EINVAL;
+  }
+
+  return load_role(this, y, driver, s->owner.id, account_id,
+                   s->user->get_tenant(), role_name, role, resource,
+                   s->err.message);
+}
+
+void RGWListAttachedRolePolicies_IAM::execute(optional_yield y)
+{
+  s->formatter->open_object_section_in_ns("ListAttachedRolePoliciesResponse", RGW_REST_IAM_XMLNS);
+  s->formatter->open_object_section("ResponseMetadata");
+  s->formatter->dump_string("RequestId", s->trans_id);
+  s->formatter->close_section(); // ResponseMetadata
+  s->formatter->open_object_section("ListAttachedRolePoliciesResult");
+  s->formatter->open_array_section("AttachedPolicies");
+  for (const auto& policy : role->get_info().managed_policies.arns) {
+    s->formatter->open_object_section("member");
+    std::string_view arn = policy;
+    if (auto p = arn.find('/'); p != arn.npos) {
+      s->formatter->dump_string("PolicyName", arn.substr(p + 1));
+    }
+    s->formatter->dump_string("PolicyArn", arn);
+    s->formatter->close_section(); // member
+  }
+  s->formatter->close_section(); // AttachedPolicies
+  s->formatter->close_section(); // ListAttachedRolePoliciesResult
+  s->formatter->close_section(); // ListAttachedRolePoliciesResponse
+}
+
+RGWOp* make_iam_attach_role_policy_op(const ceph::bufferlist& post_body) {
+  return new RGWAttachRolePolicy_IAM(post_body);
+}
+
+RGWOp* make_iam_detach_role_policy_op(const ceph::bufferlist& post_body) {
+  return new RGWDetachRolePolicy_IAM(post_body);
+}
+
+RGWOp* make_iam_list_attached_role_policies_op(const ceph::bufferlist& unused) {
+  return new RGWListAttachedRolePolicies_IAM();
+}
index bc3897acfcd317b371a0c123fa4bb9fa1bc725d4..b7c662c02c66fb5bf6b66a6df6384bb42de94b22 100644 (file)
@@ -206,3 +206,7 @@ public:
   const char* name() const override { return "update_role"; }
   RGWOpType get_type() override { return RGW_OP_UPDATE_ROLE; }
 };
+
+RGWOp* make_iam_attach_role_policy_op(const ceph::bufferlist& post_body);
+RGWOp* make_iam_detach_role_policy_op(const ceph::bufferlist& post_body);
+RGWOp* make_iam_list_attached_role_policies_op(const ceph::bufferlist& unused);
index 9c6ed1552d1fa4ee4a093096ab0aba53652dfb52..37cabde9e6b20e3a6979ea67280c6d1adfebce31 100644 (file)
@@ -6458,12 +6458,11 @@ rgw::auth::s3::STSEngine::authenticate(
     r.name = role->get_name();
     r.tenant = role->get_tenant();
 
-    vector<string> role_policy_names = role->get_role_policy_names();
-    for (auto& policy_name : role_policy_names) {
-      string perm_policy;
-      if (int ret = role->get_role_policy(dpp, policy_name, perm_policy); ret == 0) {
-        r.role_policies.push_back(std::move(perm_policy));
-      }
+    for (auto& [name, policy] : role->get_info().perm_policy_map) {
+      r.inline_policies.push_back(std::move(policy));
+    }
+    for (auto& arn : role->get_info().managed_policies.arns) {
+      r.managed_policies.push_back(std::move(arn));
     }
   }
 
index c5116398788c63e86f60dfb38840929b0e9a9893..9520a7ff7467e86513d37fe01fe9f2e154e56051 100644 (file)
@@ -64,6 +64,13 @@ void RGWRoleInfo::dump(Formatter *f) const
     }
     f->close_section();
   }
+  if (!managed_policies.arns.empty()) {
+    f->open_array_section("ManagedPermissionPolicies");
+    for (const auto& arn : managed_policies.arns) {
+      encode_json("PolicyArn", arn, f);
+    }
+    f->close_section();
+  }
   if (!tags.empty()) {
     f->open_array_section("Tags");
     for (const auto& it : tags) {
@@ -101,8 +108,8 @@ void RGWRoleInfo::decode_json(JSONObj *obj)
     }
   }
 
-  auto perm_policy_iter = obj->find_first("PermissionPolicies");
-  if (!perm_policy_iter.end()) {
+  if (auto perm_policy_iter = obj->find_first("PermissionPolicies");
+      !perm_policy_iter.end()) {
     JSONObj* perm_policies = *perm_policy_iter;
     auto iter = perm_policies->find_first();
 
@@ -114,6 +121,13 @@ void RGWRoleInfo::decode_json(JSONObj *obj)
     }
   }
 
+  if (auto p = obj->find_first("ManagedPermissionPolicies"); !p.end()) {
+    for (auto iter = (*p)->find_first(); !iter.end(); ++iter) {
+      std::string arn = (*iter)->get_data();
+      this->managed_policies.arns.insert(std::move(arn));
+    }
+  }
+
   if (auto pos = name.find('$'); pos != std::string::npos) {
     tenant = name.substr(0, pos);
     name = name.substr(pos+1);
index 3b5fa039f529ab05881350b51a99635f663b022b..9f49351d6e643949f8cc58aa44a73518ceee12ea 100644 (file)
@@ -11,6 +11,7 @@
 #include "common/ceph_context.h"
 #include "rgw_rados.h"
 #include "rgw_metadata.h"
+#include "rgw_iam_managed_policy.h"
 
 class RGWRados;
 
@@ -23,7 +24,10 @@ struct RGWRoleInfo
   std::string arn;
   std::string creation_date;
   std::string trust_policy;
+  // map from PolicyName to an inline policy document from PutRolePolicy
   std::map<std::string, std::string> perm_policy_map;
+  // set of managed policy arns from AttachRolePolicy
+  rgw::IAM::ManagedPolicies managed_policies;
   std::string tenant;
   std::string description;
   uint64_t max_session_duration = 0;
@@ -50,6 +54,7 @@ struct RGWRoleInfo
     encode(max_session_duration, bl);
     encode(account_id, bl);
     encode(description, bl);
+    encode(managed_policies, bl);
     ENCODE_FINISH(bl);
   }
 
@@ -71,6 +76,7 @@ struct RGWRoleInfo
     if (struct_v >= 4) {
       decode(account_id, bl);
       decode(description, bl);
+      decode(managed_policies, bl);
     }
     DECODE_FINISH(bl);
   }
index 6bdfd081b25363dab92117d6b639e7e1328501de..f03762422e1a54424f7a050d0dab774092aac416 100644 (file)
@@ -102,6 +102,7 @@ using rgw::IAM::iamListUserPolicies;
 using rgw::IAM::iamListAttachedUserPolicies;
 using rgw::IAM::iamListRoles;
 using rgw::IAM::iamListRolePolicies;
+using rgw::IAM::iamListAttachedRolePolicies;
 using rgw::IAM::iamListOIDCProviders;
 using rgw::IAM::iamListRoleTags;
 using rgw::IAM::iamListUsers;
@@ -803,6 +804,7 @@ TEST_F(ManagedPolicyTest, IAMReadOnlyAccess)
   act[iamListAttachedUserPolicies] = 1;
   act[iamListRoles] = 1;
   act[iamListRolePolicies] = 1;
+  act[iamListAttachedRolePolicies] = 1;
   act[iamListOIDCProviders] = 1;
   act[iamListRoleTags] = 1;
   act[iamListUsers] = 1;