.. prompt:: bash #
- ceph nfs export create cephfs --cluster-id <cluster_id> --pseudo-path <pseudo_path> --fsname <fsname> [--readonly] [--path=/path/in/cephfs] [--client_addr <value>...] [--squash <value>] [--sectype <value>...] [--cmount_path <value>]
+ ceph nfs export create cephfs --cluster-id <cluster_id> --pseudo-path <pseudo_path> --fsname <fsname> [--readonly] [--path=/path/in/cephfs] [--client_addr <value>...] [--squash <value>] [--sectype <value>...] [--cmount_path <value>] [--xprtsec <value>]
This creates export RADOS objects containing the export block, where
permissible values.
``<sectype>`` specifies which authentication methods will be used when
-connecting to the export. Valid values include "krb5p", "krb5i", "krb5", "sys", "tls", "mtls"
-and "none". More than one value can be supplied. The flag may be specified
+connecting to the export. Valid values include ``krb5p``, ``krb5i``, ``krb5``, ``sys``
+and ``none``. More than one value can be supplied. The flag may be specified
multiple times (example: ``--sectype=krb5p --sectype=krb5i``) or multiple
values may be separated by a comma (example: ``--sectype krb5p,krb5i``). The
server will negotatiate a supported security type with the client preferring
the supplied methods left-to-right.
+``<xprtsec>`` defines how traffic is secured at the transport layer.
+Valid values are ``tls``, ``mtls`` and ``none``.
+
``<cmount_path>`` specifies the path within the CephFS to mount this export on. It is
allowed to be any complete path hierarchy between ``/`` and the ``EXPORT {path}``. (i.e. if ``EXPORT { Path }`` parameter is ``/foo/bar`` then cmount_path could be ``/``, ``/foo`` or ``/foo/bar``).
.. prompt:: bash #
- ceph nfs export create rgw --cluster-id <cluster_id> --pseudo-path <pseudo_path> --bucket <bucket_name> [--user-id <user-id>] [--readonly] [--client_addr <value>...] [--squash <value>] [--sectype <value>...]
+ ceph nfs export create rgw --cluster-id <cluster_id> --pseudo-path <pseudo_path> --bucket <bucket_name> [--user-id <user-id>] [--readonly] [--client_addr <value>...] [--squash <value>] [--sectype <value>...] [--xprtsec <value>]
For example, to export ``mybucket`` via NFS cluster ``mynfs`` at the
pseudo-path ``/bucketdata`` to any host in the ``192.168.10.0/24`` network
permissible values.
``<sectype>`` specifies which authentication methods will be used when
-connecting to the export. Valid values include "krb5p", "krb5i", "krb5",
-"sys", and "none". More than one value can be supplied. The flag may be
+connecting to the export. Valid values include ``krb5p``, ``krb5i``, ``krb5``,
+``sys`` and ``none``. More than one value can be supplied. The flag may be
specified multiple times (example: ``--sectype=krb5p --sectype=krb5i``) or
multiple values may be separated by a comma (example: ``--sectype
krb5p,krb5i``). The server will negotatiate a supported security type with the
function on servers that are configured to support Kerberos. Setting up
NFS-Ganesha to support Kerberos is outside the scope of this document.
+``<xprtsec>`` defines how traffic is secured at the transport layer.
+Valid values are ``tls``, ``mtls`` and ``none``.
+
+
RGW user export
^^^^^^^^^^^^^^^
access_type: str,
clients: list = [],
sectype: Optional[List[str]] = None,
+ xprtsec: Optional[str] = None,
cmount_path: Optional[str] = "/",
earmark_resolver: Optional[CephFSEarmarkResolver] = None,
kmip_key_id: Optional[str] = None
},
"clients": clients,
"sectype": sectype,
- "kmip_key_id": kmip_key_id
+ "kmip_key_id": kmip_key_id,
+ "XprtSec": xprtsec,
},
earmark_resolver
)
user_id: Optional[str] = None,
clients: list = [],
sectype: Optional[List[str]] = None,
- kmip_key_id: Optional[str] = None) -> Dict[str, Any]:
+ kmip_key_id: Optional[str] = None,
+ xprtsec: Optional[str] = None) -> Dict[str, Any]:
pseudo_path = normalize_path(pseudo_path)
if not bucket and not user_id:
},
"clients": clients,
"sectype": sectype,
- "kmip_key_id": kmip_key_id
+ "kmip_key_id": kmip_key_id,
+ "XprtSec": xprtsec,
}
)
log.debug("creating rgw export %s", export)
def _validate_sec_type(sec_type: str) -> None:
- valid_sec_types = ["none", "sys", "krb5", "krb5i", "krb5p", "tls", "mtls"]
+ valid_sec_types = ["none", "sys", "krb5", "krb5i", "krb5p"]
if not isinstance(sec_type, str) or sec_type not in valid_sec_types:
raise NFSInvalidOperation(
f"SecType {sec_type} invalid, valid types are {valid_sec_types}")
+def _validate_xprtsec_type(xprtsec: str) -> None:
+ valid_xprtsec_types = ['none', 'tls', 'mtls']
+ if not isinstance(xprtsec, str) or xprtsec not in valid_xprtsec_types:
+ raise NFSInvalidOperation(
+ f"XprtSec {xprtsec} invalid, valid types are {valid_xprtsec_types}")
+
+
class GaneshaConfParser:
def __init__(self, raw_config: str):
self.pos = 0
clients: Optional[List[Client]] = None,
sectype: Optional[List[str]] = None,
qos_block: Optional[QOS] = None,
- kmip_key_id: Optional[str] = None) -> None:
+ kmip_key_id: Optional[str] = None,
+ xprtsec: Optional[str] = None) -> None:
self.export_id = export_id
self.path = path
self.fsal = fsal
self.sectype = sectype
self.qos_block = qos_block
self.kmip_key_id = kmip_key_id
+ self.xprtsec = xprtsec
@classmethod
def from_export_block(cls, export_block: RawBlock, cluster_id: str) -> 'Export':
# https://github.com/ceph/go-ceph/issues/1097
if sectype is not None and not isinstance(sectype, list):
sectype = [sectype]
+
+ xprtsec = export_block.values.get('XprtSec')
+
return cls(export_block.values['export_id'],
export_block.values['path'],
cluster_id,
for client in client_blocks],
sectype=sectype,
qos_block=qos_block,
- kmip_key_id=export_block.values.get('kmip_key_id')
- )
+ kmip_key_id=export_block.values.get('kmip_key_id'),
+ xprtsec=xprtsec)
def to_export_block(self) -> RawBlock:
# if kmip_key_id is present, it should be first line of export block
})
if self.sectype:
values['SecType'] = self.sectype
+ if self.xprtsec:
+ values['XprtSec'] = self.xprtsec
result = RawBlock("EXPORT", values=values)
result.blocks = [
self.fsal.to_fsal_block()
[Client.from_dict(client) for client in ex_dict.get('clients', [])],
sectype=ex_dict.get("sectype"),
qos_block=qos_block,
- kmip_key_id=ex_dict.get('kmip_key_id')
- )
+ kmip_key_id=ex_dict.get('kmip_key_id'),
+ xprtsec=ex_dict.get('XprtSec'))
def to_dict(self) -> Dict[str, Any]:
values = {
values['qos_block'] = self.qos_block.to_dict()
if self.kmip_key_id:
values['kmip_key_id'] = self.kmip_key_id
+ if self.xprtsec:
+ values['XprtSec'] = self.xprtsec
return values
def validate(self, mgr: 'Module') -> None:
for st in (self.sectype or []):
_validate_sec_type(st)
+ if self.xprtsec:
+ _validate_xprtsec_type(self.xprtsec)
def __eq__(self, other: Any) -> bool:
if not isinstance(other, Export):
sectype: Optional[List[str]] = None,
cmount_path: Optional[str] = "/",
skip_notify_nfs_server: bool = False,
- kmip_key_id: Optional[str] = None
+ kmip_key_id: Optional[str] = None,
+ xprtsec: Optional[str] = None
) -> Dict[str, Any]:
"""Create a CephFS export"""
self.export_mgr.skip_notify_nfs_server = skip_notify_nfs_server
squash=squash,
addr=client_addr,
sectype=sectype,
+ xprtsec=xprtsec,
cmount_path=cmount_path,
earmark_resolver=earmark_resolver,
kmip_key_id=kmip_key_id
squash: str = 'none',
sectype: Optional[List[str]] = None,
skip_notify_nfs_server: bool = False,
- kmip_key_id: Optional[str] = None
+ kmip_key_id: Optional[str] = None,
+ xprtsec: Optional[str] = None,
) -> Dict[str, Any]:
"""Create an RGW export"""
self.export_mgr.skip_notify_nfs_server = skip_notify_nfs_server
squash=squash,
addr=client_addr,
sectype=sectype,
- kmip_key_id=kmip_key_id
+ kmip_key_id=kmip_key_id,
+ xprtsec=xprtsec
)
@CLICommand('nfs export rm', perm='rw')
assert info["export_id"] == 2
assert info["path"] == "bucket"
assert "sectype" not in info
+ assert 'XprtSec' not in info
r = conf.apply_export(self.cluster_id, json.dumps({
'export_id': 2,
'access_type': None,
'squash': None
}],
- 'sectype': ["krb5p", "krb5i", "sys", "mtls", "tls"],
+ 'sectype': ["krb5p", "krb5i", "sys"],
+ 'XprtSec': 'tls',
'fsal': {
'name': 'RGW',
'user_id': 'nfs.foo.bucket',
info = conf._get_export_dict(self.cluster_id, "/rgw/bucket")
assert info["export_id"] == 2
assert info["path"] == "bucket"
- assert info["sectype"] == ["krb5p", "krb5i", "sys", "mtls", "tls"]
+ assert info["sectype"] == ["krb5p", "krb5i", "sys"]
+ assert info['XprtSec'] == 'tls'
def test_update_export_with_ganesha_conf(self):
self._do_mock_test(self._do_test_update_export_with_ganesha_conf)
pseudo_path='/mybucket',
read_only=False,
squash='root',
- addr=["192.168.0.0/16"]
+ addr=["192.168.0.0/16"],
+ xprtsec='tls'
)
assert r["bind"] == "/mybucket"
assert export.clients[0].access_type == 'rw'
assert export.clients[0].addresses == ["192.168.0.0/16"]
assert export.cluster_id == self.cluster_id
+ assert export.xprtsec == 'tls'
def test_create_export_rgw_bucket_user(self):
self._do_mock_test(self._do_test_create_export_rgw_bucket_user)