From 57a4f6b43f3ccdcf0e7418a9a3417334ae6e9368 Mon Sep 17 00:00:00 2001 From: Pritha Srivastava Date: Mon, 23 May 2022 17:00:41 +0530 Subject: [PATCH] rgw/sts: adding code for UpdateRole REST API and radosgw-admin command that allows modification of max_session_duration of a role. fixes: https://tracker.ceph.com/issues/55751 Signed-off-by: Pritha Srivastava --- doc/radosgw/role.rst | 43 ++++++++++++++++++++ src/rgw/rgw_admin.cc | 32 ++++++++++++++- src/rgw/rgw_auth_s3.cc | 3 +- src/rgw/rgw_iam_policy.cc | 4 ++ src/rgw/rgw_iam_policy.h | 3 +- src/rgw/rgw_op_type.h | 1 + src/rgw/rgw_rest_iam.cc | 2 + src/rgw/rgw_rest_role.cc | 65 +++++++++++++++++++++++++++++++ src/rgw/rgw_rest_role.h | 11 ++++++ src/rgw/rgw_role.cc | 23 +++++++++-- src/rgw/rgw_role.h | 2 + src/test/cli/radosgw-admin/help.t | 1 + 12 files changed, 184 insertions(+), 6 deletions(-) diff --git a/doc/radosgw/role.rst b/doc/radosgw/role.rst index dbe8810a0b8..e974498722b 100644 --- a/doc/radosgw/role.rst +++ b/doc/radosgw/role.rst @@ -291,6 +291,32 @@ For example:: radosgw-admin role-policy delete --role-name=S3Access1 --policy-name=Policy1 +Update a role +------------- + +To update a role's max-session-duration, execute the following:: + + radosgw-admin role update --role-name={role-name} --max-session-duration={max-session-duration} + +Request Parameters +~~~~~~~~~~~~~~~~~~ + +``role-name`` + +:Description: Name of the role. +:Type: String + +``max-session-duration`` + +:Description: Maximum session duration for a role. +:Type: String + +For example:: + + radosgw-admin role update --role-name=S3Access1 --max-session-duration=43200 + +Note: This command currently can only be used to update max-session-duration. + REST APIs for Manipulating a Role ================================= @@ -470,6 +496,23 @@ Example:: +Update Role +----------- + +Example:: + POST "?Action=UpdateRole&RoleName=S3Access&MaxSessionDuration=43200" + +.. code-block:: XML + + + + + tx000000000000000000007-00611f337e-1027-default + + + + +Note: This API currently can only be used to update max-session-duration. Sample code for tagging, listing tags and untagging a role ---------------------------------------------------------- diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 506098a224c..d4bde231a9e 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -273,6 +273,7 @@ void usage() cout << " role-policy list list policies attached to a role\n"; cout << " role-policy get get the specified inline policy document embedded with the given role\n"; cout << " role-policy delete remove policy attached to a role\n"; + cout << " role update update max_session_duration of a role\n"; cout << " reshard add schedule a resharding of a bucket\n"; cout << " reshard list list all bucket resharding or scheduled to be resharded\n"; cout << " reshard status read bucket resharding status\n"; @@ -796,6 +797,7 @@ enum class OPT { ROLE_POLICY_LIST, ROLE_POLICY_GET, ROLE_POLICY_DELETE, + ROLE_UPDATE, RESHARD_ADD, RESHARD_LIST, RESHARD_STATUS, @@ -1027,6 +1029,7 @@ static SimpleCmd::Commands all_cmds = { { "role-policy get", OPT::ROLE_POLICY_GET }, { "role policy delete", OPT::ROLE_POLICY_DELETE }, { "role-policy delete", OPT::ROLE_POLICY_DELETE }, + { "role update", OPT::ROLE_UPDATE }, { "reshard bucket", OPT::BUCKET_RESHARD }, { "reshard add", OPT::RESHARD_ADD }, { "reshard list", OPT::RESHARD_LIST }, @@ -3456,7 +3459,7 @@ int main(int argc, const char **argv) std::string zonegroup_name, zonegroup_id, zonegroup_new_name; std::optional opt_zonegroup_name, opt_zonegroup_id; std::string api_name; - std::string role_name, path, assume_role_doc, policy_name, perm_policy_doc, path_prefix; + std::string role_name, path, assume_role_doc, policy_name, perm_policy_doc, path_prefix, max_session_duration; std::string redirect_zone; bool redirect_zone_set = false; list endpoints; @@ -4051,6 +4054,8 @@ int main(int argc, const char **argv) perm_policy_doc = val; } else if (ceph_argparse_witharg(args, i, &val, "--path-prefix", (char*)NULL)) { path_prefix = val; + } else if (ceph_argparse_witharg(args, i, &val, "--max-session-duration", (char*)NULL)) { + max_session_duration = val; } else if (ceph_argparse_witharg(args, i, &val, "--totp-serial", (char*)NULL)) { totp_serial = val; } else if (ceph_argparse_witharg(args, i, &val, "--totp-pin", (char*)NULL)) { @@ -4392,6 +4397,7 @@ int main(int argc, const char **argv) && opt_cmd != OPT::ROLE_POLICY_LIST && opt_cmd != OPT::ROLE_POLICY_GET && opt_cmd != OPT::ROLE_POLICY_DELETE + && opt_cmd != OPT::ROLE_UPDATE && opt_cmd != OPT::RESHARD_ADD && opt_cmd != OPT::RESHARD_CANCEL && opt_cmd != OPT::RESHARD_STATUS) { @@ -6770,6 +6776,30 @@ int main(int argc, const char **argv) << role_name << std::endl; return 0; } + case OPT::ROLE_UPDATE: + { + if (role_name.empty()) { + cerr << "ERROR: role name is empty" << std::endl; + return -EINVAL; + } + + std::unique_ptr role = store->get_role(role_name, tenant); + ret = role->get(dpp(), null_yield); + if (ret < 0) { + return -ret; + } + if (!role->validate_max_session_duration(dpp())) { + ret = -EINVAL; + return ret; + } + role->update_max_session_duration(max_session_duration); + ret = role->update(dpp(), null_yield); + if (ret < 0) { + return -ret; + } + cout << "Max session duration updated successfully for role: " << role_name << std::endl; + return 0; + } default: output_user_info = false; } diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index a48cc199ffc..faba2c071c8 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -479,7 +479,8 @@ bool is_non_s3_op(RGWOpType op_type) op_type == RGW_OP_PUBSUB_TOPIC_DELETE || op_type == RGW_OP_TAG_ROLE || op_type == RGW_OP_LIST_ROLE_TAGS || - op_type == RGW_OP_UNTAG_ROLE) { + op_type == RGW_OP_UNTAG_ROLE || + op_type == RGW_OP_UPDATE_ROLE) { return true; } return false; diff --git a/src/rgw/rgw_iam_policy.cc b/src/rgw/rgw_iam_policy.cc index 0ab1058d768..fb978cf97b0 100644 --- a/src/rgw/rgw_iam_policy.cc +++ b/src/rgw/rgw_iam_policy.cc @@ -156,6 +156,7 @@ static const actpair actpairs[] = { "iam:TagRole", iamTagRole}, { "iam:ListRoleTags", iamListRoleTags}, { "iam:UntagRole", iamUntagRole}, + { "iam:UpdateRole", iamUpdateRole}, { "sts:AssumeRole", stsAssumeRole}, { "sts:AssumeRoleWithWebIdentity", stsAssumeRoleWithWebIdentity}, { "sts:GetSessionToken", stsGetSessionToken}, @@ -1364,6 +1365,9 @@ const char* action_bit_string(uint64_t action) { case iamUntagRole: return "iam:UntagRole"; + case iamUpdateRole: + return "iam:UpdateRole"; + case stsAssumeRole: return "sts:AssumeRole"; diff --git a/src/rgw/rgw_iam_policy.h b/src/rgw/rgw_iam_policy.h index de8ba9297b4..1cc80d54d9a 100644 --- a/src/rgw/rgw_iam_policy.h +++ b/src/rgw/rgw_iam_policy.h @@ -131,7 +131,8 @@ static constexpr std::uint64_t iamListOIDCProviders = s3All + 17; static constexpr std::uint64_t iamTagRole = s3All + 18; static constexpr std::uint64_t iamListRoleTags = s3All + 19; static constexpr std::uint64_t iamUntagRole = s3All + 20; -static constexpr std::uint64_t iamAll = s3All + 21; +static constexpr std::uint64_t iamUpdateRole = s3All + 21; +static constexpr std::uint64_t iamAll = s3All + 22; static constexpr std::uint64_t stsAssumeRole = iamAll + 1; static constexpr std::uint64_t stsAssumeRoleWithWebIdentity = iamAll + 2; diff --git a/src/rgw/rgw_op_type.h b/src/rgw/rgw_op_type.h index e9b670ce283..375c7348b24 100644 --- a/src/rgw/rgw_op_type.h +++ b/src/rgw/rgw_op_type.h @@ -64,6 +64,7 @@ enum RGWOpType { RGW_OP_TAG_ROLE, RGW_OP_LIST_ROLE_TAGS, RGW_OP_UNTAG_ROLE, + RGW_OP_UPDATE_ROLE, RGW_OP_PUT_BUCKET_POLICY, RGW_OP_GET_BUCKET_POLICY, RGW_OP_DELETE_BUCKET_POLICY, diff --git a/src/rgw/rgw_rest_iam.cc b/src/rgw/rgw_rest_iam.cc index 35f1b367381..876f26f4e45 100644 --- a/src/rgw/rgw_rest_iam.cc +++ b/src/rgw/rgw_rest_iam.cc @@ -86,6 +86,8 @@ RGWOp *RGWHandler_REST_IAM::op_post() return new RGWListRoleTags; if (action.compare("UntagRole") == 0) return new RGWUntagRole(this->bl_post_body); + if (action.compare("UpdateRole") == 0) + return new RGWUpdateRole(this->bl_post_body); } return nullptr; diff --git a/src/rgw/rgw_rest_role.cc b/src/rgw/rgw_rest_role.cc index 71090c59c17..0fe6981cb27 100644 --- a/src/rgw/rgw_rest_role.cc +++ b/src/rgw/rgw_rest_role.cc @@ -948,4 +948,69 @@ void RGWUntagRole::execute(optional_yield y) s->formatter->close_section(); s->formatter->close_section(); } +} + +int RGWUpdateRole::get_params() +{ + role_name = s->info.args.get("RoleName"); + max_session_duration = s->info.args.get("MaxSessionDuration"); + + if (role_name.empty()) { + ldpp_dout(this, 20) << "ERROR: Role name is empty"<< dendl; + return -EINVAL; + } + + return 0; +} + +void RGWUpdateRole::execute(optional_yield y) +{ + op_ret = get_params(); + if (op_ret < 0) { + return; + } + + if (!store->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("MaxSessionDuration"); + s->info.args.remove("Action"); + s->info.args.remove("Version"); + + RGWUserInfo info = s->user->get_info(); + const auto& it = info.access_keys.begin(); + RGWAccessKey key; + if (it != info.access_keys.end()) { + key.id = it->first; + RGWAccessKey cred = it->second; + key.key = cred.key; + } + op_ret = store->forward_iam_request_to_master(s, key, nullptr, 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; + } + } + + if (!_role->validate_max_session_duration(this)) { + op_ret = -EINVAL; + return; + } + + _role->update_max_session_duration(max_session_duration); + op_ret = _role->update(this, y); + + s->formatter->open_object_section("UpdateRoleResponse"); + s->formatter->open_object_section("UpdateRoleResult"); + s->formatter->open_object_section("ResponseMetadata"); + s->formatter->dump_string("RequestId", s->trans_id); + s->formatter->close_section(); + s->formatter->close_section(); } \ No newline at end of file diff --git a/src/rgw/rgw_rest_role.h b/src/rgw/rgw_rest_role.h index 69e64306526..98a08833bf7 100644 --- a/src/rgw/rgw_rest_role.h +++ b/src/rgw/rgw_rest_role.h @@ -168,3 +168,14 @@ public: RGWOpType get_type() override { return RGW_OP_UNTAG_ROLE; } uint64_t get_op() override { return rgw::IAM::iamUntagRole; } }; + +class RGWUpdateRole : public RGWRoleWrite { + bufferlist bl_post_body; +public: + RGWUpdateRole(const bufferlist& bl_post_body) : bl_post_body(bl_post_body) {}; + void execute(optional_yield y) override; + int get_params(); + const char* name() const override { return "update_role"; } + RGWOpType get_type() override { return RGW_OP_UPDATE_ROLE; } + uint64_t get_op() override { return rgw::IAM::iamUpdateRole; } +}; \ No newline at end of file diff --git a/src/rgw/rgw_role.cc b/src/rgw/rgw_role.cc index 0188f422777..b6dde215f94 100644 --- a/src/rgw/rgw_role.cc +++ b/src/rgw/rgw_role.cc @@ -179,6 +179,16 @@ void RGWRole::decode_json(JSONObj *obj) info.decode_json(obj); } +bool RGWRole::validate_max_session_duration(const DoutPrefixProvider* dpp) +{ + if (info.max_session_duration < SESSION_DURATION_MIN || + info.max_session_duration > SESSION_DURATION_MAX) { + ldpp_dout(dpp, 0) << "ERROR: Invalid session duration, should be between 3600 and 43200 seconds " << dendl; + return false; + } + return true; +} + bool RGWRole::validate_input(const DoutPrefixProvider* dpp) { if (info.name.length() > MAX_ROLE_NAME_LEN) { @@ -203,9 +213,7 @@ bool RGWRole::validate_input(const DoutPrefixProvider* dpp) return false; } - if (info.max_session_duration < SESSION_DURATION_MIN || - info.max_session_duration > SESSION_DURATION_MAX) { - ldpp_dout(dpp, 0) << "ERROR: Invalid session duration, should be between 3600 and 43200 seconds " << dendl; + if (!validate_max_session_duration(dpp)) { return false; } return true; @@ -303,6 +311,15 @@ void RGWRole::erase_tags(const vector& tagKeys) } } +void RGWRole::update_max_session_duration(const std::string& max_session_duration_str) +{ + if (max_session_duration_str.empty()) { + info.max_session_duration = SESSION_DURATION_MIN; + } else { + info.max_session_duration = std::stoull(max_session_duration_str); + } +} + const string& RGWRole::get_names_oid_prefix() { return role_name_oid_prefix; diff --git a/src/rgw/rgw_role.h b/src/rgw/rgw_role.h index 6ea23e090e9..eda04ef714e 100644 --- a/src/rgw/rgw_role.h +++ b/src/rgw/rgw_role.h @@ -93,6 +93,7 @@ public: virtual int read_id(const DoutPrefixProvider *dpp, const std::string& role_name, const std::string& tenant, std::string& role_id, optional_yield y) = 0; virtual int read_name(const DoutPrefixProvider *dpp, optional_yield y) = 0; virtual int read_info(const DoutPrefixProvider *dpp, optional_yield y) = 0; + bool validate_max_session_duration(const DoutPrefixProvider* dpp); bool validate_input(const DoutPrefixProvider* dpp); void extract_name_tenant(const std::string& str); @@ -139,6 +140,7 @@ public: int set_tags(const DoutPrefixProvider* dpp, const std::multimap& tags_map); boost::optional> get_tags(); void erase_tags(const std::vector& tagKeys); + void update_max_session_duration(const std::string& max_session_duration_str); void dump(Formatter *f) const; void decode_json(JSONObj *obj); diff --git a/src/test/cli/radosgw-admin/help.t b/src/test/cli/radosgw-admin/help.t index a70eb5ba0a5..f9137f58ab5 100644 --- a/src/test/cli/radosgw-admin/help.t +++ b/src/test/cli/radosgw-admin/help.t @@ -162,6 +162,7 @@ role-policy list list policies attached to a role role-policy get get the specified inline policy document embedded with the given role role-policy delete remove policy attached to a role + role update update max_session_duration of a role reshard add schedule a resharding of a bucket reshard list list all bucket resharding or scheduled to be resharded reshard status read bucket resharding status -- 2.39.5