From 23207513ae5f5304b3f49484791cb1dc938e8c2a Mon Sep 17 00:00:00 2001 From: Raja Sharma Date: Fri, 6 Jun 2025 14:05:27 +0530 Subject: [PATCH] rgw/iam: getAccountSummary API Tracker: https://tracker.ceph.com/issues/72158 Signed-off-by: Raja Sharma --- src/rgw/CMakeLists.txt | 1 + src/rgw/rgw_auth_s3.cc | 1 + src/rgw/rgw_iam_policy.cc | 4 ++ src/rgw/rgw_iam_policy.h | 1 + src/rgw/rgw_op_type.h | 1 + src/rgw/rgw_rest_iam.cc | 2 + src/rgw/rgw_rest_iam_account.cc | 70 +++++++++++++++++++++++++++++ src/rgw/rgw_rest_iam_account.h | 16 +++++++ src/test/rgw/test_rgw_iam_policy.cc | 2 + 9 files changed, 98 insertions(+) create mode 100644 src/rgw/rgw_rest_iam_account.cc create mode 100644 src/rgw/rgw_rest_iam_account.h diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 18f1213f894..6071125edfc 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -97,6 +97,7 @@ set(librgw_common_srcs rgw_rest_metadata.cc rgw_rest_ratelimit.cc rgw_rest_role.cc + rgw_rest_iam_account.cc rgw_rest_iam_group.cc rgw_rest_iam_user.cc rgw_rest_s3.cc diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index ae573f4c23b..3cee81c97d2 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -511,6 +511,7 @@ bool is_non_s3_op(RGWOpType op_type) case RGW_OP_LIST_ROLE_TAGS: case RGW_OP_UNTAG_ROLE: case RGW_OP_UPDATE_ROLE: + case RGW_OP_GET_ACCOUNT_SUMMARY: case RGW_OP_CREATE_USER: case RGW_OP_GET_USER: diff --git a/src/rgw/rgw_iam_policy.cc b/src/rgw/rgw_iam_policy.cc index 356bd2384b8..ee7b1278fd2 100644 --- a/src/rgw/rgw_iam_policy.cc +++ b/src/rgw/rgw_iam_policy.cc @@ -202,6 +202,7 @@ static const actpair actpairs[] = { "iam:GenerateServiceLastAccessedDetails", iamGenerateServiceLastAccessedDetails}, { "iam:SimulateCustomPolicy", iamSimulateCustomPolicy}, { "iam:SimulatePrincipalPolicy", iamSimulatePrincipalPolicy}, + { "iam:GetAccountSummary", iamGetAccountSummary}, { "sts:AssumeRole", stsAssumeRole}, { "sts:AssumeRoleWithWebIdentity", stsAssumeRoleWithWebIdentity}, { "sts:GetSessionToken", stsGetSessionToken}, @@ -1704,6 +1705,9 @@ const char* action_bit_string(uint64_t action) { case iamSimulatePrincipalPolicy: return "iam:SimulatePrincipalPolicy"; + case iamGetAccountSummary: + return "iam:GetAccountSummary"; + case stsAssumeRole: return "sts:AssumeRole"; diff --git a/src/rgw/rgw_iam_policy.h b/src/rgw/rgw_iam_policy.h index 095937ee1c4..41f8bf90389 100644 --- a/src/rgw/rgw_iam_policy.h +++ b/src/rgw/rgw_iam_policy.h @@ -185,6 +185,7 @@ enum { iamGenerateServiceLastAccessedDetails, iamSimulateCustomPolicy, iamSimulatePrincipalPolicy, + iamGetAccountSummary, iamAll, stsAssumeRole, diff --git a/src/rgw/rgw_op_type.h b/src/rgw/rgw_op_type.h index ca8a71748ec..9721da13abb 100644 --- a/src/rgw/rgw_op_type.h +++ b/src/rgw/rgw_op_type.h @@ -119,6 +119,7 @@ enum RGWOpType { RGW_OP_LIST_ATTACHED_GROUP_POLICIES, RGW_OP_PUT_BUCKET_LOGGING, RGW_OP_POST_BUCKET_LOGGING, + RGW_OP_GET_ACCOUNT_SUMMARY, /* rgw specific */ RGW_OP_ADMIN_SET_METADATA, RGW_OP_GET_OBJ_LAYOUT, diff --git a/src/rgw/rgw_rest_iam.cc b/src/rgw/rgw_rest_iam.cc index 70d274946d2..8148a7f3f84 100644 --- a/src/rgw/rgw_rest_iam.cc +++ b/src/rgw/rgw_rest_iam.cc @@ -14,6 +14,7 @@ #include "rgw_rest_iam_user.h" #include "rgw_rest_conn.h" #include "rgw_zone.h" +#include "rgw_rest_iam_account.h" #define dout_context g_ceph_context #define dout_subsys ceph_subsys_rgw @@ -34,6 +35,7 @@ static const std::unordered_map op_generators = {"AttachRolePolicy", make_iam_attach_role_policy_op}, {"DetachRolePolicy", make_iam_detach_role_policy_op}, {"ListAttachedRolePolicies", make_iam_list_attached_role_policies_op}, + {"GetAccountSummary", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetAccountSummary;}}, {"PutUserPolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWPutUserPolicy(bl_post_body);}}, {"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_iam_account.cc b/src/rgw/rgw_rest_iam_account.cc new file mode 100644 index 00000000000..d011f39ce90 --- /dev/null +++ b/src/rgw/rgw_rest_iam_account.cc @@ -0,0 +1,70 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +#include "rgw_process_env.h" +#include "rgw_rest_iam_account.h" + +int RGWGetAccountSummary::verify_permission(optional_yield y) +{ + std::string account_id; + if (const auto& account = s->auth.identity->get_account(); account) { + account_id = account->id; + } else { + return -ERR_METHOD_NOT_ALLOWED; + } + const rgw::ARN arn{"", "root", account_id, true}; + if (verify_user_permission(this, s, arn, rgw::IAM::iamGetAccountSummary)) { + return 0; + } + return -EACCES; +} + +void RGWGetAccountSummary::add_entry(const std::string& type, int64_t value) +{ + s->formatter->open_object_section("entry"); + s->formatter->dump_string("key", type); + s->formatter->dump_int("value", value); + s->formatter->close_section(); +} + +void RGWGetAccountSummary::execute(optional_yield y) +{ + const auto& info = s->user->get_info(); + const auto& account = s->auth.identity->get_account(); + uint32_t users_count = 0; + uint32_t groups_count = 0; + + if (account->max_users >= 0) { + op_ret = driver->count_account_users(this, y, info.account_id, users_count); + if (op_ret < 0) { + ldpp_dout(this, 4) << "failed to count users for iam account " + << info.account_id << ": " << op_ret << dendl; + return; + } + } + + if (account->max_groups >= 0) { + op_ret = driver->count_account_groups(this, y, info.account_id, groups_count); + if (op_ret < 0) { + ldpp_dout(this, 4) << "failed to count groups for iam account " + << info.account_id << ": " << op_ret << dendl; + return; + } + } + + s->formatter->open_object_section("GetAccountSummaryResponse"); + s->formatter->open_object_section("ResponseMetadata"); + s->formatter->dump_string("RequestId", s->trans_id); + s->formatter->close_section(); + s->formatter->open_object_section("GetAccountSummaryResult"); + s->formatter->open_object_section("SummaryMap"); + add_entry("Users", users_count); + add_entry("Groups", groups_count); + add_entry("UsersQuota", account->max_users); + add_entry("GroupsQuota", account->max_groups); + add_entry("AccessKeysPerUserQuota", account->max_access_keys); + s->formatter->close_section(); + s->formatter->close_section(); + s->formatter->close_section(); +} + diff --git a/src/rgw/rgw_rest_iam_account.h b/src/rgw/rgw_rest_iam_account.h new file mode 100644 index 00000000000..44fc8eceec4 --- /dev/null +++ b/src/rgw/rgw_rest_iam_account.h @@ -0,0 +1,16 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +#pragma once + +#include "rgw_rest.h" +#include "rgw_op_type.h" + +class RGWGetAccountSummary : public RGWRESTOp { + void add_entry(const std::string& key, int64_t value); + public: + int verify_permission(optional_yield y) override; + void execute(optional_yield y) override; + const char* name() const override { return "get_account_summary"; } + RGWOpType get_type() override { return RGW_OP_GET_ACCOUNT_SUMMARY; } +}; diff --git a/src/test/rgw/test_rgw_iam_policy.cc b/src/test/rgw/test_rgw_iam_policy.cc index d3a285a14ca..7bc221dcd11 100644 --- a/src/test/rgw/test_rgw_iam_policy.cc +++ b/src/test/rgw/test_rgw_iam_policy.cc @@ -119,6 +119,7 @@ using rgw::IAM::iamListGroupPolicies; using rgw::IAM::iamListAttachedGroupPolicies; using rgw::IAM::iamSimulateCustomPolicy; using rgw::IAM::iamSimulatePrincipalPolicy; +using rgw::IAM::iamGetAccountSummary; using rgw::IAM::snsGetTopicAttributes; using rgw::IAM::snsListTopics; using rgw::Service; @@ -850,6 +851,7 @@ TEST_F(ManagedPolicyTest, IAMReadOnlyAccess) act[iamListAttachedGroupPolicies] = 1; act[iamSimulateCustomPolicy] = 1; act[iamSimulatePrincipalPolicy] = 1; + act[iamGetAccountSummary] = 1; EXPECT_EQ(act, p->statements[0].action); } -- 2.39.5