Skip to content

Commit

Permalink
Merge PR ceph#22879 into master
Browse files Browse the repository at this point in the history
* refs/pull/22879/head:
	doc/rados/operations/user-management: document 'network' clause of moncap and osdcap
	mds/SessionMap: make Session::connection private
	mds/MDSAuthCaps: parse and enforce network restriction
	mds/MDSAuthCaps: pass addr to is_capable
	mds/SessionMap: track socket_addr for each Session
	osd/OSDCap: enforce network restriction
	osd/OSDCap: take addr arg to is_capable
	osd/OSDCap: parse 'network' clause in grant
	mon: adapt MonCap network checks to addrvecs
	mon/MonCap: enforce network constraint (if present)
	mon/MonCap: take addr for MonCap::is_capable
	mon/MonCap: parse 'network ...' suffix
	osd: add peer_socket_addr to Session
	mon: use addrvec for RoutedRequest and MForward
	msg/Connection: add get_peer_socket_addr()
	common/ipaddr: add network_contains() helper
	common/ipaddr: add parse_network helper
	common/ipaddr: expose netmask_ipv[46]

Reviewed-by: Gregory Farnum <[email protected]>
Reviewed-by: Greg Farnum <[email protected]>
  • Loading branch information
liewegas committed Aug 13, 2018
2 parents e2e6a77 + d7596a7 commit 8f3560d
Show file tree
Hide file tree
Showing 38 changed files with 1,501 additions and 994 deletions.
16 changes: 16 additions & 0 deletions doc/cephfs/client-auth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,19 @@ in the ``bar`` directory of filesystem ``cephfs_a``.


.. _User Management - Add a User to a Keyring: ../../rados/operations/user-management/#add-a-user-to-a-keyring

Network restriction
===================

::

client.foo
key: *key*
caps: [mds] allow r network 10.0.0.0/8, allow rw path=/bar network 10.0.0.0/8
caps: [mon] allow r network 10.0.0.0/8
caps: [osd] allow rw tag cephfs data=cephfs_a network 10.0.0.0/8

The optional ``{network/prefix}`` is a standard network name and
prefix length in CIDR notation (e.g., ``10.3.0.0/16``). If present,
the use of this capability is restricted to clients connecting from
this network.
16 changes: 13 additions & 3 deletions doc/rados/operations/user-management.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,26 @@ Capability syntax follows the form::
- **Monitor Caps:** Monitor capabilities include ``r``, ``w``, ``x`` access
settings or ``profile {name}``. For example::

mon 'allow {access-spec}'
mon 'allow {access-spec} [network {network/prefix}]'

mon 'profile {name}'

The ``{access-spec}`` syntax is as follows: ::

* | all | [r][w][x]

The optional ``{network/prefix}`` is a standard network name and
prefix length in CIDR notation (e.g., ``10.3.0.0/16``). If present,
the use of this capability is restricted to clients connecting from
this network.

- **OSD Caps:** OSD capabilities include ``r``, ``w``, ``x``, ``class-read``,
``class-write`` access settings or ``profile {name}``. Additionally, OSD
capabilities also allow for pool and namespace settings. ::

osd 'allow {access-spec} [{match-spec}]'
osd 'allow {access-spec} [{match-spec}] [network {network/prefix}]'

osd 'profile {name} [pool={pool-name} [namespace={namespace-name}]]'
osd 'profile {name} [pool={pool-name} [namespace={namespace-name}]] [network {network/prefix}]'

The ``{access-spec}`` syntax is either of the following: ::

Expand All @@ -132,6 +137,11 @@ Capability syntax follows the form::

[namespace={namespace-name}] tag {application} {key}={value}

The optional ``{network/prefix}`` is a standard network name and
prefix length in CIDR notation (e.g., ``10.3.0.0/16``). If present,
the use of this capability is restricted to clients connecting from
this network.

- **Metadata Server Caps:** For administrators, use ``allow *``. For all
other users, such as CephFS clients, consult :doc:`/cephfs/client-auth`

Expand Down
59 changes: 55 additions & 4 deletions src/common/ipaddr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
#endif

#include "include/ipaddr.h"
#include "msg/msg_types.h"

static void netmask_ipv4(const struct in_addr *addr,
void netmask_ipv4(const struct in_addr *addr,
unsigned int prefix_len,
struct in_addr *out) {
uint32_t mask;
Expand Down Expand Up @@ -57,9 +58,9 @@ const struct ifaddrs *find_ipv4_in_subnet(const struct ifaddrs *addrs,
}


static void netmask_ipv6(const struct in6_addr *addr,
unsigned int prefix_len,
struct in6_addr *out) {
void netmask_ipv6(const struct in6_addr *addr,
unsigned int prefix_len,
struct in6_addr *out) {
if (prefix_len > 128)
prefix_len = 128;

Expand Down Expand Up @@ -164,3 +165,53 @@ bool parse_network(const char *s, struct sockaddr_storage *network, unsigned int

return false;
}

bool parse_network(const char *s,
entity_addr_t *network,
unsigned int *prefix_len)
{
sockaddr_storage ss;
bool ret = parse_network(s, &ss, prefix_len);
if (ret) {
network->set_type(entity_addr_t::TYPE_LEGACY);
network->set_sockaddr((sockaddr *)&ss);
}
return ret;
}

bool network_contains(
const struct entity_addr_t& network,
unsigned int prefix_len,
const struct entity_addr_t& addr)
{
if (addr.get_family() != network.get_family()) {
return false;
}
switch (network.get_family()) {
case AF_INET:
{
struct in_addr a, b;
netmask_ipv4(
&((const sockaddr_in*)network.get_sockaddr())->sin_addr, prefix_len, &a);
netmask_ipv4(
&((const sockaddr_in*)addr.get_sockaddr())->sin_addr, prefix_len, &b);
if (memcmp(&a, &b, sizeof(a)) == 0) {
return true;
}
}
break;
case AF_INET6:
{
struct in6_addr a, b;
netmask_ipv6(
&((const sockaddr_in6*)network.get_sockaddr())->sin6_addr, prefix_len, &a);
netmask_ipv6(
&((const sockaddr_in6*)addr.get_sockaddr())->sin6_addr, prefix_len, &b);
if (memcmp(&a, &b, sizeof(a)) == 0) {
return true;
}
}
break;
}
return false;
}
22 changes: 21 additions & 1 deletion src/include/ipaddr.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef CEPH_IPADDR_H
#define CEPH_IPADDR_H

class entity_addr_t;

/*
* Find an IP address that is in the wanted subnet.
*
Expand All @@ -22,6 +24,24 @@ const struct ifaddrs *find_ip_in_subnet(const struct ifaddrs *addrs,
*
* if the network string is invalid, return false.
*/
bool parse_network(const char *s, struct sockaddr_storage *network, unsigned int *prefix_len);
bool parse_network(const char *s,
struct sockaddr_storage *network,
unsigned int *prefix_len);
bool parse_network(const char *s,
entity_addr_t *network,
unsigned int *prefix_len);

void netmask_ipv6(const struct in6_addr *addr,
unsigned int prefix_len,
struct in6_addr *out);

void netmask_ipv4(const struct in_addr *addr,
unsigned int prefix_len,
struct in_addr *out);

bool network_contains(
const struct entity_addr_t& network,
unsigned int prefix_len,
const struct entity_addr_t& addr);

#endif
18 changes: 10 additions & 8 deletions src/mds/CInode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3209,9 +3209,11 @@ int CInode::get_caps_allowed_for_client(Session *session, mempool_inode *file_i)

if (!is_dir()) {
if ((file_i->inline_data.version != CEPH_INLINE_NONE &&
!session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) ||
!session->get_connection()->has_feature(
CEPH_FEATURE_MDS_INLINE_DATA)) ||
(!file_i->layout.pool_ns.empty() &&
!session->connection->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2)))
!session->get_connection()->has_feature(
CEPH_FEATURE_FS_FILE_LAYOUT_V2)))
allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR);
}
return allowed;
Expand Down Expand Up @@ -3622,7 +3624,7 @@ int CInode::encode_inodestat(bufferlist& bl, Session *session,
ENCODE_FINISH(bl);
}
else {
assert(session->connection);
assert(session->get_connection());

encode(oi->ino, bl);
encode(snapid, bl);
Expand Down Expand Up @@ -3655,22 +3657,22 @@ int CInode::encode_inodestat(bufferlist& bl, Session *session,
encode(file_i->rstat.rctime, bl);
dirfragtree.encode(bl);
encode(symlink, bl);
if (session->connection->has_feature(CEPH_FEATURE_DIRLAYOUTHASH)) {
if (session->get_connection()->has_feature(CEPH_FEATURE_DIRLAYOUTHASH)) {
encode(file_i->dir_layout, bl);
}
encode(xbl, bl);
if (session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) {
if (session->get_connection()->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) {
encode(inline_version, bl);
encode(inline_data, bl);
}
if (session->connection->has_feature(CEPH_FEATURE_MDS_QUOTA)) {
if (session->get_connection()->has_feature(CEPH_FEATURE_MDS_QUOTA)) {
mempool_inode *policy_i = ppolicy ? pi : oi;
encode(policy_i->quota, bl);
}
if (session->connection->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2)) {
if (session->get_connection()->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2)) {
encode(layout.pool_ns, bl);
}
if (session->connection->has_feature(CEPH_FEATURE_FS_BTIME)) {
if (session->get_connection()->has_feature(CEPH_FEATURE_FS_BTIME)) {
encode(any_i->btime, bl);
encode(any_i->change_attr, bl);
}
Expand Down
5 changes: 3 additions & 2 deletions src/mds/Locker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2027,8 +2027,9 @@ bool Locker::issue_caps(CInode *in, Capability *only_cap)

Session *session = mds->get_session(it->first);
if (in->inode.inline_data.version != CEPH_INLINE_NONE &&
!(session && session->connection &&
session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)))
!(session &&
session->get_connection() &&
session->get_connection()->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)))
allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR);

int pending = cap->pending();
Expand Down
7 changes: 4 additions & 3 deletions src/mds/MDCache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2038,8 +2038,9 @@ void MDCache::broadcast_quota_to_client(CInode *in, client_t exclude_ct)

for (auto &p : in->client_caps) {
Session *session = mds->get_session(p.first);
if (!session || !session->connection ||
!session->connection->has_feature(CEPH_FEATURE_MDS_QUOTA))
if (!session ||
!session->get_connection() ||
!session->get_connection()->has_feature(CEPH_FEATURE_MDS_QUOTA))
continue;

Capability *cap = &p.second;
Expand Down Expand Up @@ -2079,7 +2080,7 @@ void MDCache::broadcast_quota_to_client(CInode *in, client_t exclude_ct)
msg->ino = in->ino();
msg->rstat = i->rstat;
msg->quota = i->quota;
mds->send_message_client_counted(msg, session->connection);
mds->send_message_client_counted(msg, session->get_connection());
}
for (const auto &it : in->get_replicas()) {
MGatherCaps *msg = new MGatherCaps;
Expand Down
35 changes: 29 additions & 6 deletions src/mds/MDSAuthCaps.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "common/debug.h"
#include "MDSAuthCaps.h"
#include "include/ipaddr.h"

#define dout_subsys ceph_subsys_mds

Expand Down Expand Up @@ -58,6 +59,7 @@ struct MDSCapParser : qi::grammar<Iterator, MDSAuthCaps()>
lexeme[lit("\"") >> *(char_ - '"') >> '"'] |
lexeme[lit("'") >> *(char_ - '\'') >> '\''];
unquoted_path %= +char_("a-zA-Z0-9_./-");
network_str %= +char_("/.:a-fA-F0-9][");

// match := [path=<path>] [uid=<uid> [gids=<gid>[,<gid>...]]
path %= (spaces >> lit("path") >> lit('=') >> (quoted_path | unquoted_path));
Expand Down Expand Up @@ -86,12 +88,14 @@ struct MDSCapParser : qi::grammar<Iterator, MDSAuthCaps()>
(lit("r"))[_val = MDSCapSpec(MDSCapSpec::READ)]
);

grant = lit("allow") >> (capspec >> match)[_val = phoenix::construct<MDSCapGrant>(_1, _2)];
grant = lit("allow") >> (capspec >> match >>
-(spaces >> lit("network") >> spaces >> network_str))
[_val = phoenix::construct<MDSCapGrant>(_1, _2, _3)];
grants %= (grant % (*lit(' ') >> (lit(';') | lit(',')) >> *lit(' ')));
mdscaps = grants [_val = phoenix::construct<MDSAuthCaps>(_1)];
}
qi::rule<Iterator> spaces;
qi::rule<Iterator, string()> quoted_path, unquoted_path;
qi::rule<Iterator, string()> quoted_path, unquoted_path, network_str;
qi::rule<Iterator, MDSCapSpec()> capspec;
qi::rule<Iterator, string()> path;
qi::rule<Iterator, uint32_t()> uid;
Expand Down Expand Up @@ -163,6 +167,12 @@ bool MDSCapMatch::match_path(std::string_view target_path) const
return true;
}

void MDSCapGrant::parse_network()
{
network_valid = ::parse_network(network.c_str(), &network_parsed,
&network_prefix);
}

/**
* Is the client *potentially* able to access this path? Actual
* permission will depend on uids/modes in the full is_capable.
Expand Down Expand Up @@ -191,7 +201,8 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
uid_t caller_uid, gid_t caller_gid,
const vector<uint64_t> *caller_gid_list,
unsigned mask,
uid_t new_uid, gid_t new_gid) const
uid_t new_uid, gid_t new_gid,
const entity_addr_t& addr) const
{
if (cct)
ldout(cct, 10) << __func__ << " inode(path /" << inode_path
Expand All @@ -206,6 +217,13 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
for (std::vector<MDSCapGrant>::const_iterator i = grants.begin();
i != grants.end();
++i) {
if (i->network.size() &&
(!i->network_valid ||
!network_contains(i->network_parsed,
i->network_prefix,
addr))) {
continue;
}

if (i->match.match(inode_path, caller_uid, caller_gid, caller_gid_list) &&
i->spec.allows(mask & (MAY_READ|MAY_EXECUTE), mask & MAY_WRITE)) {
Expand Down Expand Up @@ -286,15 +304,17 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
void MDSAuthCaps::set_allow_all()
{
grants.clear();
grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::ALL), MDSCapMatch()));
grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::ALL), MDSCapMatch(),
{}));
}

bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
{
// Special case for legacy caps
if (str == "allow") {
grants.clear();
grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::RWPS), MDSCapMatch()));
grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::RWPS), MDSCapMatch(),
{}));
return true;
}

Expand All @@ -307,6 +327,7 @@ bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
if (r && iter == end) {
for (auto& grant : grants) {
std::sort(grant.match.gids.begin(), grant.match.gids.end());
grant.parse_network();
}
return true;
} else {
Expand Down Expand Up @@ -389,7 +410,9 @@ ostream &operator<<(ostream &out, const MDSCapGrant &grant)
if (!grant.match.is_match_all()) {
out << " " << grant.match;
}

if (grant.network.size()) {
out << " network " << grant.network;
}
return out;
}

Expand Down
Loading

0 comments on commit 8f3560d

Please sign in to comment.