}
std::unique_ptr<RGWRole> DaosStore::get_role(
- std::string name, std::string tenant, std::string path,
+ std::string name, std::string tenant, rgw_account_id account_id, std::string path,
std::string trust_policy, std::string max_session_duration_str,
std::multimap<std::string, std::string> tags) {
RGWRole* p = nullptr;
std::unique_ptr<LuaManager> get_lua_manager(const DoutPrefixProvider *dpp = nullptr, const std::string& luarocks_path = "") override;
virtual std::unique_ptr<RGWRole> get_role(
- std::string name, std::string tenant, std::string path = "",
+ std::string name, std::string tenant, rgw_account_id account_id, std::string path = "",
std::string trust_policy = "", std::string max_session_duration_str = "",
std::multimap<std::string, std::string> tags = {}) override;
virtual std::unique_ptr<RGWRole> get_role(const RGWRoleInfo& info) override;
std::unique_ptr<RGWRole> MotrStore::get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path,
std::string trust_policy,
std::string max_session_duration_str,
std::unique_ptr<LuaManager> get_lua_manager(const DoutPrefixProvider *dpp = nullptr, const std::string& luarocks_path = "") override;
virtual std::unique_ptr<RGWRole> get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path="",
std::string trust_policy="",
std::string max_session_duration_str="",
std::string_view rolename,
std::unique_ptr<RGWRole>* role)
{
- std::string id;
- librados::Rados& rados = *getRados()->get_rados_handle();
- const RGWZoneParams& zone = svc()->zone->get_zone_params();
- const rgw_raw_obj& obj = rgwrados::account::get_roles_obj(zone, account_id);
- int r = rgwrados::roles::get(dpp, y, rados, obj, rolename, id);
+ RGWRoleInfo info;
+ info.account_id = account_id;
+ info.name = rolename;
+ auto p = get_role(info);
+ int r = p->get(dpp, y);
if (r < 0) {
- ldpp_dout(dpp, 20) << "failed to find account rolename " << rolename
- << ": " << cpp_strerror(r) << dendl;
- return r;
- }
-
- std::unique_ptr<RGWRole> p = get_role(id);
- r = p->read_info(dpp, y);
- if (r < 0) {
- ldpp_dout(dpp, 20) << "failed to load account role " << id
+ ldpp_dout(dpp, 20) << "failed to load account role " << rolename
<< ": " << cpp_strerror(r) << dendl;
return r;
}
std::unique_ptr<RGWRole> RadosStore::get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path,
std::string trust_policy,
std::string max_session_duration_str,
std::multimap<std::string,std::string> tags)
{
- return std::make_unique<RadosRole>(this, name, tenant, path, trust_policy, max_session_duration_str, tags);
+ return std::make_unique<RadosRole>(this, name, tenant, std::move(account_id), path, trust_policy, max_session_duration_str, tags);
}
std::unique_ptr<RGWRole> RadosStore::get_role(std::string id)
}
}
+static std::string role_name_oid(const RGWRoleInfo& r, std::string_view prefix)
+{
+ if (!r.account_id.empty()) {
+ // names are case-insensitive, so store them in lower case
+ std::string lower_name = r.name;
+ boost::algorithm::to_lower(lower_name);
+ // use account id as prefix
+ return string_cat_reserve(r.account_id, prefix, lower_name);
+ } else {
+ // use tenant as prefix
+ return string_cat_reserve(r.tenant, prefix, r.name);
+ }
+}
+
int RadosRole::store_name(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y)
{
auto sysobj = store->svc()->sysobj;
RGWNameToId nameToId;
nameToId.obj_id = info.id;
- std::string oid = info.tenant + get_names_oid_prefix() + info.name;
+ std::string oid = role_name_oid(info, get_names_oid_prefix());
bufferlist bl;
using ceph::encode;
int RadosRole::store_path(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y)
{
+ if (!info.account_id.empty()) {
+ librados::Rados& rados = *store->getRados()->get_rados_handle();
+ const RGWZoneParams& zone = store->svc()->zone->get_zone_params();
+ const rgw_raw_obj& obj = rgwrados::account::get_roles_obj(zone, info.account_id);
+ constexpr uint32_t no_limit = std::numeric_limits<uint32_t>::max();
+ return rgwrados::roles::add(dpp, y, rados, obj, info, false, no_limit);
+ }
+
auto sysobj = store->svc()->sysobj;
std::string oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id;
int RadosRole::read_name(const DoutPrefixProvider *dpp, optional_yield y)
{
auto sysobj = store->svc()->sysobj;
- std::string oid = info.tenant + get_names_oid_prefix() + info.name;
+ std::string oid = role_name_oid(info, get_names_oid_prefix());
bufferlist bl;
int ret = rgw_get_system_obj(sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, nullptr, nullptr, y, dpp);
}
//arn
- info.arn = role_arn_prefix + info.tenant + ":role" + info.path + info.name;
+ std::string_view account = !info.account_id.empty() ? info.account_id : info.tenant;
+ info.arn = string_cat_reserve(role_arn_prefix, account, ":role", info.path, info.name);
// Creation time
real_clock::time_point t = real_clock::now();
<< info.id << ": " << cpp_strerror(-info_ret) << dendl;
}
//Delete role name that was stored in previous call
- oid = info.tenant + get_names_oid_prefix() + info.name;
+ oid = role_name_oid(info, get_names_oid_prefix());
int name_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
if (name_ret < 0) {
ldpp_dout(dpp, 0) << "ERROR: cleanup of role name from Role pool: "
}
// Delete name
- std::string oid = info.tenant + get_names_oid_prefix() + info.name;
+ std::string oid = role_name_oid(info, get_names_oid_prefix());
ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
if (ret < 0) {
ldpp_dout(dpp, 0) << "ERROR: deleting role name from Role pool: "
}
// Delete path
- oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id;
- ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
- if (ret < 0) {
- ldpp_dout(dpp, 0) << "ERROR: deleting role path from Role pool: "
- << info.path << ": " << cpp_strerror(-ret) << dendl;
+ if (!info.account_id.empty()) {
+ librados::Rados& rados = *store->getRados()->get_rados_handle();
+ const RGWZoneParams& zone = store->svc()->zone->get_zone_params();
+ const rgw_raw_obj& obj = rgwrados::account::get_roles_obj(zone, info.account_id);
+ ret = rgwrados::roles::remove(dpp, y, rados, obj, info.name);
+ if (ret < 0) {
+ ldpp_dout(dpp, 4) << "ERROR: deleting role path from account list: "
+ << info.path << ": " << cpp_strerror(-ret) << dendl;
+ }
+ } else {
+ oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id;
+ ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 4) << "ERROR: deleting role path from Role pool: "
+ << info.path << ": " << cpp_strerror(-ret) << dendl;
+ }
}
- return ret;
+ return 0;
}
} // namespace rgw::sal
std::unique_ptr<LuaManager> get_lua_manager(const std::string& luarocks_path) override;
virtual std::unique_ptr<RGWRole> get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path="",
std::string trust_policy="",
std::string max_session_duration_str="",
public:
RadosRole(RadosStore* _store, std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path,
std::string trust_policy,
std::string max_session_duration,
- std::multimap<std::string,std::string> tags) : RGWRole(name, tenant, path, trust_policy, max_session_duration, tags), store(_store) {}
+ std::multimap<std::string,std::string> tags)
+ : RGWRole(name, tenant, std::move(account_id), path, trust_policy, max_session_duration, tags), store(_store) {}
RadosRole(RadosStore* _store, std::string id) : RGWRole(id), store(_store) {}
RadosRole(RadosStore* _store, const RGWRoleInfo& info) : RGWRole(info), store(_store) {}
RadosRole(RadosStore* _store) : store(_store) {}
string tenant;
string user_ns;
string account_name;
- string account_id;
+ rgw_account_id account_id;
rgw_user new_user_id;
std::string access_key, secret_key, user_email, display_name;
std::string bucket_name, pool_name, object;
cerr << "failed to parse policy: " << e.what() << std::endl;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, path,
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id, path,
assume_role_doc, max_session_duration);
ret = role->create(dpp(), true, "", null_yield);
if (ret < 0) {
cerr << "ERROR: empty role name" << std::endl;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->delete_obj(dpp(), null_yield);
if (ret < 0) {
return -ret;
cerr << "ERROR: empty role name" << std::endl;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
constexpr int32_t max_chunk = 100;
int32_t count = std::min(max_chunk, remaining);
- ret = driver->list_roles(dpp(), null_yield, tenant, path_prefix,
- listing.next_marker, count, listing);
+ if (!account_id.empty()) {
+ // list roles in the account
+ ret = driver->list_account_roles(dpp(), null_yield, account_id,
+ path_prefix, listing.next_marker,
+ count, listing);
+ } else {
+ // list roles in the tenant
+ ret = driver->list_roles(dpp(), null_yield, tenant, path_prefix,
+ listing.next_marker, count, listing);
+ }
if (ret < 0) {
return -ret;
}
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
cerr << "ERROR: Role name is empty" << std::endl;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
cerr << "ERROR: policy name is empty" << std::endl;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
int ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
cerr << "ERROR: policy name is empty" << std::endl;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
return -EINVAL;
}
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, account_id);
ret = role->get(dpp(), null_yield);
if (ret < 0) {
return -ret;
std::unique_ptr<rgw::sal::RGWRole>& role,
rgw::ARN& resource, std::string& message)
{
+ auto arn_account = std::ref(tenant);
if (const auto* id = std::get_if<rgw_account_id>(&owner); id) {
account_id = *id;
-
- // look up account role by RoleName
- int r = driver->load_account_role_by_name(dpp, y, account_id, name, &role);
- if (r == -ENOENT) {
- message = "No such RoleName in the account";
- return -ERR_NO_ROLE_FOUND;
- }
- if (r >= 0) {
- resource = make_role_arn(role->get_path(), role->get_name(), account_id);
- }
- return r;
+ arn_account = std::ref(account_id);
}
- role = driver->get_role(name, tenant);
+ role = driver->get_role(name, tenant, account_id);
const int r = role->get(dpp, y);
if (r == -ENOENT) {
message = "No such RoleName in the tenant";
return -ERR_NO_ROLE_FOUND;
}
if (r >= 0) {
+ // construct the ARN once we know the path
resource = make_role_arn(role->get_path(),
role->get_name(),
- role->get_tenant());
+ arn_account);
}
return r;
}
+// check the current role count against account limit
+int check_role_limit(const DoutPrefixProvider* dpp, optional_yield y,
+ rgw::sal::Driver* driver, std::string_view account_id,
+ std::string& err)
+{
+ RGWAccountInfo account;
+ rgw::sal::Attrs attrs; // unused
+ RGWObjVersionTracker objv; // unused
+ int r = driver->load_account_by_id(dpp, y, account_id, account, attrs, objv);
+ if (r < 0) {
+ ldpp_dout(dpp, 4) << "failed to load iam account "
+ << account_id << ": " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ if (account.max_roles < 0) { // max_roles < 0 means unlimited
+ return 0;
+ }
+
+ uint32_t count = 0;
+ r = driver->count_account_roles(dpp, y, account_id, count);
+ if (r < 0) {
+ ldpp_dout(dpp, 4) << "failed to count roles for iam account "
+ << account_id << ": " << cpp_strerror(r) << dendl;
+ return r;
+ }
+ if (std::cmp_greater_equal(count, account.max_roles)) {
+ err = fmt::format("Role limit {} exceeded", account.max_roles);
+ return -ERR_LIMIT_EXCEEDED;
+ }
+ return 0;
+}
+
int RGWCreateRole::init_processing(optional_yield y)
{
if (const auto* id = std::get_if<rgw_account_id>(&s->owner.id); id) {
+ account_id = *id;
resource = make_role_arn(role_path, role_name, *id);
+
+ ret = check_role_limit(this, y, driver, account_id, s->err.message);
+ if (ret < 0) {
+ return ret;
+ }
} else {
resource = make_role_arn(role_path, role_name, s->user->get_tenant());
}
std::string user_tenant = s->user->get_tenant();
std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name,
user_tenant,
+ account_id,
role_path,
trust_policy,
max_session_duration,
return -EINVAL;
}
+ if (const auto* id = std::get_if<rgw_account_id>(&s->owner.id); id) {
+ account_id = *id;
+ }
return 0;
}
void RGWListRoles::execute(optional_yield y)
{
- // TODO: list_account_roles() for account owner
rgw::sal::RoleList listing;
- op_ret = driver->list_roles(s, y, s->user->get_tenant(), path_prefix,
- marker, max_items, listing);
+ if (!account_id.empty()) {
+ // list roles from the account
+ op_ret = driver->list_account_roles(this, y, account_id, path_prefix,
+ marker, max_items, listing);
+ } else {
+ // list roles from the tenant
+ op_ret = driver->list_roles(this, y, s->auth.identity->get_tenant(),
+ path_prefix, marker, max_items, listing);
+ }
if (op_ret == 0) {
s->formatter->open_object_section("ListRolesResponse");
#include "common/ceph_json.h"
#include "rgw_rest.h"
+#include "rgw_account.h"
#include "rgw_auth.h"
#include "rgw_auth_registry.h"
#include "jwt-cpp/jwt.h"
string role_arn = s->info.args.get("RoleArn");
string role_tenant = get_role_tenant(role_arn);
string role_name = get_role_name(role_arn);
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, role_tenant);
+
+ rgw_account_id role_account;
+ if (rgw::account::validate_id(role_tenant)) {
+ role_account = std::move(role_tenant);
+ role_tenant.clear();
+ }
+
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, role_tenant, role_account);
int ret = role->get(dpp, y);
if (ret < 0) {
ldpp_dout(dpp, 0) << "Role not found: name:" << role_name << " tenant: " << role_tenant << dendl;
return result_t::deny(-EACCES);
}
boost::optional<multimap<string,string>> role_tags = role->get_tags();
- auto apl = apl_factory->create_apl_web_identity(cct, s, role_session, role_tenant, *t, role_tags, princ_tags);
+ auto apl = apl_factory->create_apl_web_identity(cct, s, role_session, role->get_tenant(), *t, role_tags, princ_tags);
return result_t::grant(std::move(apl));
}
return result_t::deny(-EACCES);
encode_json("CreateDate", creation_date, f);
encode_json("MaxSessionDuration", max_session_duration, f);
encode_json("AssumeRolePolicyDocument", trust_policy, f);
+ encode_json("AccountId", account_id, f);
if (!perm_policy_map.empty()) {
f->open_array_section("PermissionPolicies");
for (const auto& it : perm_policy_map) {
JSONDecoder::decode_json("CreateDate", creation_date, obj);
JSONDecoder::decode_json("MaxSessionDuration", max_session_duration, obj);
JSONDecoder::decode_json("AssumeRolePolicyDocument", trust_policy, obj);
+ JSONDecoder::decode_json("AccountId", account_id, obj);
auto tags_iter = obj->find_first("Tags");
if (!tags_iter.end()) {
RGWRole::RGWRole(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path,
std::string trust_policy,
std::string max_session_duration_str,
std::multimap<std::string,std::string> tags)
{
info.name = std::move(name);
+ info.account_id = std::move(account_id);
info.path = std::move(path);
info.trust_policy = std::move(trust_policy);
info.tenant = std::move(tenant);
std::map<std::string, bufferlist> attrs;
RGWObjVersionTracker objv_tracker;
real_time mtime;
+ rgw_account_id account_id;
RGWRoleInfo() = default;
~RGWRoleInfo() = default;
void encode(bufferlist& bl) const {
- ENCODE_START(3, 1, bl);
+ ENCODE_START(4, 1, bl);
encode(id, bl);
encode(name, bl);
encode(path, bl);
encode(perm_policy_map, bl);
encode(tenant, bl);
encode(max_session_duration, bl);
+ encode(account_id, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::const_iterator& bl) {
- DECODE_START(3, bl);
+ DECODE_START(4, bl);
decode(id, bl);
decode(name, bl);
decode(path, bl);
if (struct_v >= 3) {
decode(max_session_duration, bl);
}
+ if (struct_v >= 4) {
+ decode(account_id, bl);
+ }
DECODE_FINISH(bl);
}
RGWRole(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path="",
std::string trust_policy="",
std::string max_session_duration_str="",
const std::string& get_id() const { return info.id; }
const std::string& get_name() const { return info.name; }
const std::string& get_tenant() const { return info.tenant; }
+ const rgw_account_id& get_account_id() const { return info.account_id; }
const std::string& get_path() const { return info.path; }
const std::string& get_create_date() const { return info.creation_date; }
const std::string& get_assume_role_policy() const { return info.trust_policy;}
/** Get an IAM Role by name etc. */
virtual std::unique_ptr<RGWRole> get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path="",
std::string trust_policy="",
std::string max_session_duration_str="",
std::unique_ptr<RGWRole> DBStore::get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path,
std::string trust_policy,
std::string max_session_duration_str,
std::unique_ptr<LuaManager> get_lua_manager(const std::string& luarocks_path) override;
virtual std::unique_ptr<RGWRole> get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path="",
std::string trust_policy="",
std::string max_session_duration_str="",
std::unique_ptr<RGWRole> FilterDriver::get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path,
std::string trust_policy,
std::string max_session_duration_str,
std::multimap<std::string,std::string> tags)
{
- return next->get_role(name, tenant, path, trust_policy, max_session_duration_str, tags);
+ return next->get_role(name, tenant, std::move(account_id), path, trust_policy, max_session_duration_str, tags);
}
std::unique_ptr<RGWRole> FilterDriver::get_role(std::string id)
virtual std::unique_ptr<LuaManager> get_lua_manager(const std::string& luarocks_path) override;
virtual std::unique_ptr<RGWRole> get_role(std::string name,
std::string tenant,
+ rgw_account_id account_id,
std::string path="",
std::string trust_policy="",
std::string
#include "include/types.h"
#include "rgw_string.h"
+#include "rgw_account.h"
#include "rgw_b64.h"
#include "rgw_common.h"
#include "rgw_tools.h"
if (auto r_arn = rgw::ARN::parse(arn); r_arn) {
auto pos = r_arn->resource.find_last_of('/');
string roleName = r_arn->resource.substr(pos + 1);
- std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(roleName, r_arn->account);
+ string tenant = r_arn->account;
+
+ rgw_account_id account;
+ if (rgw::account::validate_id(tenant)) {
+ account = std::move(tenant);
+ tenant.clear();
+ }
+
+ std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(roleName, tenant, account);
if (int ret = role->get(dpp, y); ret < 0) {
if (ret == -ENOENT) {
ldpp_dout(dpp, 0) << "Role doesn't exist: " << roleName << dendl;