Request that authenticate with Keystone also include:
- keystone:role
+- keystone:userid
We support certain S3 condition keys for bucket and object requests.
use keystone`` option is set. For details, see
:doc:`s3/authentication`.
-Requests authenticated via Keystone expose the Keystone role names in the
-IAM policy environment as the condition key ``keystone:role``. It can be
-used in bucket policies and idenitity policies to allow or deny access by
-role (e.g. ``StringEquals`` on ``keystone:role``).
+Requests authenticated via Keystone (Swift tokens or S3 with Keystone-managed
+credentials) expose the Keystone idenitity in the IAM policy environment
+as the condition keys: ``keystone:role`` (role names) and
+``keystone:userid`` (user UUID). These conditions can be used in bucket
+policies and idenitity policies with ``StringEquals``, ``StringNotEquals`` etc.
+
+- **keystone:role** - Allow or deny by *role* (e.g only users with role
+ ``reader`` get read access). Use for RBAC.
+- **keystone:userid** - Restrict to specific *user*. Use when policy
+ depends on a specific user, not just their role.
+
See :doc:`bucketpolicy` for list of supported condition keys.
Service Token Support
s->env.emplace("keystone:role", std::move(role));
}
+ if (!info.keystone_user_id.empty()) {
+ s->env.emplace("keystone:userid", info.keystone_user_id);
+ }
}
std::optional<rgw::ARN> rgw::auth::RemoteApplier::get_caller_identity() const
const std::string keystone_user;
const std::optional<rgw::keystone::ScopeInfo> keystone_scope;
const std::vector<std::string> keystone_roles;
+ const std::string keystone_user_id;
public:
enum class acct_privilege_t {
const std::string keystone_user,
const uint32_t acct_type=TYPE_NONE,
std::optional<rgw::keystone::ScopeInfo> keystone_scope=std::nullopt,
- std::vector<std::string> keystone_roles = {})
+ std::vector<std::string> keystone_roles = {},
+ const std::string keystone_user_id = {}
+ )
: acct_user(acct_user),
acct_name(acct_name),
perm_mask(perm_mask),
subuser(subuser),
keystone_user(keystone_user),
keystone_scope(std::move(keystone_scope)),
- keystone_roles(std::move(keystone_roles)) {
+ keystone_roles(std::move(keystone_roles)),
+ keystone_user_id(keystone_user_id) {
}
};
token.get_user_name(),
TYPE_KEYSTONE,
std::move(keystone_scope),
- std::move(role_names)
+ std::move(role_names),
+ token.get_user_id()
};
}
token.get_user_name(),
TYPE_KEYSTONE,
std::move(keystone_scope),
- std::move(role_names)
+ std::move(role_names),
+ token.get_user_id()
};
}
multi_env.emplace("keystone:role", "member");
multi_env.emplace("keystone:role", "testrole");
EXPECT_TRUE(p->statements[0].conditions[0].eval(multi_env));
+}
+
+TEST_F(ConditionTest, KeystoneUserIdStringEquals)
+{
+ const std::string key = "keystone:userid";
+ Condition cond{TokenID::StringEquals, key.data(), key.size(), false};
+ cond.vals.push_back("user-123");
+
+ EXPECT_FALSE(cond.eval({}));
+ EXPECT_TRUE(cond.eval({{key, "user-123"}}));
+ EXPECT_FALSE(cond.eval({{key, "user-456"}}));
}
\ No newline at end of file