From 390cdaa45ee923dde2de3e5b8077537c741fe5d9 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Fri, 2 Feb 2024 10:53:14 -0500 Subject: [PATCH] rgw/iam: AttachRolePolicy adds managed role policy Signed-off-by: Casey Bodley --- src/rgw/driver/rados/rgw_sal_rados.cc | 3 +- src/rgw/rgw_auth.cc | 23 ++- src/rgw/rgw_auth.h | 3 +- src/rgw/rgw_auth_s3.cc | 3 + src/rgw/rgw_iam_policy.cc | 12 ++ src/rgw/rgw_iam_policy.h | 3 + src/rgw/rgw_op_type.h | 17 +- src/rgw/rgw_rest_iam.cc | 3 + src/rgw/rgw_rest_role.cc | 263 ++++++++++++++++++++++++++ src/rgw/rgw_rest_role.h | 4 + src/rgw/rgw_rest_s3.cc | 11 +- src/rgw/rgw_role.cc | 18 +- src/rgw/rgw_role.h | 6 + src/test/rgw/test_rgw_iam_policy.cc | 2 + 14 files changed, 352 insertions(+), 19 deletions(-) diff --git a/src/rgw/driver/rados/rgw_sal_rados.cc b/src/rgw/driver/rados/rgw_sal_rados.cc index 51bdaa2a91a..fd9d6f90ad3 100644 --- a/src/rgw/driver/rados/rgw_sal_rados.cc +++ b/src/rgw/driver/rados/rgw_sal_rados.cc @@ -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; } diff --git a/src/rgw/rgw_auth.cc b/src/rgw/rgw_auth.cc index 9da2f6afc94..5692f9ae2f5 100644 --- a/src/rgw/rgw_auth.cc +++ b/src/rgw/rgw_auth.cc @@ -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 { diff --git a/src/rgw/rgw_auth.h b/src/rgw/rgw_auth.h index ddca72f84e4..3c3dd5ebe7c 100644 --- a/src/rgw/rgw_auth.h +++ b/src/rgw/rgw_auth.h @@ -727,7 +727,8 @@ public: std::string id; std::string name; std::string tenant; - std::vector role_policies; + std::vector inline_policies; + std::vector managed_policies; }; struct TokenAttrs { rgw_user user_id; diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index dd90925f04a..e43fe24c5eb 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -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: diff --git a/src/rgw/rgw_iam_policy.cc b/src/rgw/rgw_iam_policy.cc index c0a081054fa..f00cbfeac36 100644 --- a/src/rgw/rgw_iam_policy.cc +++ b/src/rgw/rgw_iam_policy.cc @@ -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"; diff --git a/src/rgw/rgw_iam_policy.h b/src/rgw/rgw_iam_policy.h index a8aa88dca7b..cf5310bfc6f 100644 --- a/src/rgw/rgw_iam_policy.h +++ b/src/rgw/rgw_iam_policy.h @@ -136,6 +136,9 @@ enum { iamGetRolePolicy, iamListRolePolicies, iamDeleteRolePolicy, + iamAttachRolePolicy, + iamDetachRolePolicy, + iamListAttachedRolePolicies, iamCreateOIDCProvider, iamDeleteOIDCProvider, iamGetOIDCProvider, diff --git a/src/rgw/rgw_op_type.h b/src/rgw/rgw_op_type.h index d71f174c37c..79edf3f2f50 100644 --- a/src/rgw/rgw_op_type.h +++ b/src/rgw/rgw_op_type.h @@ -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, diff --git a/src/rgw/rgw_rest_iam.cc b/src/rgw/rgw_rest_iam.cc index cbd692f7914..80b4228b513 100644 --- a/src/rgw/rgw_rest_iam.cc +++ b/src/rgw/rgw_rest_iam.cc @@ -30,6 +30,9 @@ static const std::unordered_map 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;}}, diff --git a/src/rgw/rgw_rest_role.cc b/src/rgw/rgw_rest_role.cc index f9580b206ff..d9def5cb520 100644 --- a/src/rgw/rgw_rest_role.cc +++ b/src/rgw/rgw_rest_role.cc @@ -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 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(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 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(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 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(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(); +} diff --git a/src/rgw/rgw_rest_role.h b/src/rgw/rgw_rest_role.h index bc3897acfcd..b7c662c02c6 100644 --- a/src/rgw/rgw_rest_role.h +++ b/src/rgw/rgw_rest_role.h @@ -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); diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 97c70befcce..ee5b21bd259 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -6469,12 +6469,11 @@ rgw::auth::s3::STSEngine::authenticate( r.name = role->get_name(); r.tenant = role->get_tenant(); - vector 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)); } } diff --git a/src/rgw/rgw_role.cc b/src/rgw/rgw_role.cc index c5116398788..9520a7ff746 100644 --- a/src/rgw/rgw_role.cc +++ b/src/rgw/rgw_role.cc @@ -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); diff --git a/src/rgw/rgw_role.h b/src/rgw/rgw_role.h index 3b5fa039f52..9f49351d6e6 100644 --- a/src/rgw/rgw_role.h +++ b/src/rgw/rgw_role.h @@ -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 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); } diff --git a/src/test/rgw/test_rgw_iam_policy.cc b/src/test/rgw/test_rgw_iam_policy.cc index d929afa4b4d..26a644625b1 100644 --- a/src/test/rgw/test_rgw_iam_policy.cc +++ b/src/test/rgw/test_rgw_iam_policy.cc @@ -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; -- 2.39.5