so they have permissions to add keys, etc. when bootstrapping
a metadata server.
+``profile bootstrap-rbd`` (Monitor only)
+
+:Description: Gives a user permissions to bootstrap an RBD user.
+ Conferred on deployment tools such as ``ceph-deploy``, etc.
+ so they have permissions to add keys, etc. when bootstrapping
+ an RBD user.
+
+``profile bootstrap-rbd-mirror`` (Monitor only)
+
+:Description: Gives a user permissions to bootstrap an ``rbd-mirror`` daemon
+ user. Conferred on deployment tools such as ``ceph-deploy``, etc.
+ so they have permissions to add keys, etc. when bootstrapping
+ an ``rbd-mirror`` daemon.
+
``profile rbd`` (Monitor and OSD)
:Description: Gives a user permissions to manipulate RBD images. When used
by an RBD client application. When used as an OSD cap, it
provides read-write access to an RBD client application.
+``profile rbd-mirror`` (Monitor only)
+
+:Description: Gives a user permissions to manipulate RBD images and retrieve
+ RBD mirroring config-key secrets. It provides the minimal
+ privileges required for the ``rbd-mirror`` daemon.
+
``profile rbd-read-only`` (OSD only)
:Description: Gives a user read-only permissions to RBD images.
- ``ceph.bootstrap-mds.keyring``
- ``ceph.bootstrap-rgw.keyring``
- ``ceph.bootstrap-rbd.keyring``
+ - ``ceph.bootstrap-rbd-mirror.keyring``
.. note:: If this process fails with a message similar to "Unable to
find /etc/ceph/ceph.client.admin.keyring", please ensure that the
} },
{ "bootstrap-rbd", {
{ "mon", _encode_cap("allow profile bootstrap-rbd") }
+ } },
+ { "bootstrap-rbd-mirror", {
+ { "mon", _encode_cap("allow profile bootstrap-rbd-mirror") }
} }
};
profile_grants.back().command_args["caps_osd"] = StringConstraint(
StringConstraint::MATCH_TYPE_EQUAL, "allow rwx");
}
- if (profile == "bootstrap-rbd") {
+ if (profile == "bootstrap-rbd" || profile == "bootstrap-rbd-mirror") {
profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); // read monmap
- profile_grants.push_back(MonCapGrant("auth get-or-create")); // FIXME: this can expose other mds keys
+ profile_grants.push_back(MonCapGrant("auth get-or-create")); // FIXME: this can expose other rbd keys
profile_grants.back().command_args["entity"] = StringConstraint(
StringConstraint::MATCH_TYPE_PREFIX, "client.");
profile_grants.back().command_args["caps_mon"] = StringConstraint(
- StringConstraint::MATCH_TYPE_EQUAL, "profile rbd");
+ StringConstraint::MATCH_TYPE_EQUAL,
+ (profile == "bootstrap-rbd-mirror" ? "profile rbd-mirror" :
+ "profile rbd"));
profile_grants.back().command_args["caps_osd"] = StringConstraint(
StringConstraint::MATCH_TYPE_REGEX,
"^([ ,]*profile(=|[ ]+)['\"]?rbd[^ ,'\"]*['\"]?([ ]+pool(=|[ ]+)['\"]?[^,'\"]+['\"]?)?)+$");
profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));
profile_grants.push_back(MonCapGrant("pg", MON_CAP_R));
}
- if (profile == "rbd") {
+ if (profile == "rbd" || profile == "rbd-mirror") {
profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));
profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));
profile_grants.push_back(MonCapGrant("pg", MON_CAP_R));
StringConstraint::MATCH_TYPE_EQUAL, "add");
profile_grants.back().command_args["addr"] = StringConstraint(
StringConstraint::MATCH_TYPE_REGEX, "^[^/]+/[0-9]+$");
+
+ }
+ if (profile == "rbd-mirror") {
+ StringConstraint constraint(StringConstraint::MATCH_TYPE_PREFIX,
+ "rbd/mirror/");
+ profile_grants.push_back(MonCapGrant("config-key get", "key", constraint));
}
if (profile == "role-definer") {
}, true, true, true,
entity_addr_t()));
}
+
+TEST(MonCap, ProfileBootstrapRBDMirror) {
+ MonCap cap;
+ ASSERT_FALSE(cap.is_allow_all());
+ ASSERT_TRUE(cap.parse("profile bootstrap-rbd-mirror", NULL));
+
+ EntityName name;
+ name.from_str("mon.a");
+ ASSERT_TRUE(cap.is_capable(nullptr, CEPH_ENTITY_TYPE_MON, name, "",
+ "auth get-or-create", {
+ {"entity", "client.rbd"},
+ {"caps_mon", "profile rbd-mirror"},
+ {"caps_osd", "profile rbd pool=foo, profile rbd-read-only"},
+ }, true, true, true,
+ entity_addr_t()));
+ ASSERT_FALSE(cap.is_capable(nullptr, CEPH_ENTITY_TYPE_MON, name, "",
+ "auth get-or-create", {
+ {"entity", "client.rbd"},
+ {"caps_mon", "profile rbd"},
+ {"caps_osd", "profile rbd pool=foo, profile rbd-read-only"},
+ }, true, true, true,
+ entity_addr_t()));
+ ASSERT_FALSE(cap.is_capable(nullptr, CEPH_ENTITY_TYPE_MON, name, "",
+ "auth get-or-create", {
+ {"entity", "client.rbd"},
+ {"caps_mon", "allow *"},
+ {"caps_osd", "profile rbd"},
+ }, true, true, true,
+ entity_addr_t()));
+ ASSERT_FALSE(cap.is_capable(nullptr, CEPH_ENTITY_TYPE_MON, name, "",
+ "auth get-or-create", {
+ {"entity", "client.rbd"},
+ {"caps_mon", "profile rbd-mirror"},
+ {"caps_osd", "profile rbd pool=foo, allow *, profile rbd-read-only"},
+ }, true, true, true,
+ entity_addr_t()));
+}
+
+TEST(MonCap, ProfileRBD) {
+ MonCap cap;
+ ASSERT_FALSE(cap.is_allow_all());
+ ASSERT_TRUE(cap.parse("profile rbd", NULL));
+
+ EntityName name;
+ name.from_str("mon.a");
+ ASSERT_FALSE(cap.is_capable(nullptr, CEPH_ENTITY_TYPE_MON, name, "config-key",
+ "config-key get", {
+ {"key", "rbd/mirror/peer/1/1234"},
+ }, true, false, false, entity_addr_t()));
+}
+
+TEST(MonCap, ProfileRBDMirror) {
+ MonCap cap;
+ ASSERT_FALSE(cap.is_allow_all());
+ ASSERT_TRUE(cap.parse("profile rbd-mirror", NULL));
+
+ EntityName name;
+ name.from_str("mon.a");
+ ASSERT_TRUE(cap.is_capable(nullptr, CEPH_ENTITY_TYPE_MON, name, "config-key",
+ "config-key get", {
+ {"key", "rbd/mirror/peer/1/1234"},
+ }, true, false, false, entity_addr_t()));
+}