From b141fdf6e7b145a660f412b4f8992de097c4d34e Mon Sep 17 00:00:00 2001 From: subhamkrai Date: Wed, 17 Nov 2021 10:09:47 +0530 Subject: [PATCH] security: add read-only mode for external cluster script Adding read-only mode for external cluster script. This will add cli argument `--read-only` or `-r` which will enable/disable read-only mode for the external script. By default `read-only` option will be `True` which means it will only generate `get` output, will not able to create something unless `--read-only` if `False`. If `read-only` is `true` and user is trying `write/create` operation it will raise ``` raise ExecutionFailureException( "Read-only mode is enabled. Pass '--read-only' or '-r' as False") ``` Signed-off-by: subhamkrai --- .../ceph/create-external-cluster-resources.py | 54 +++++++++++++++---- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/cluster/examples/kubernetes/ceph/create-external-cluster-resources.py b/cluster/examples/kubernetes/ceph/create-external-cluster-resources.py index 465ccab2218bd..07c06663c1b0a 100644 --- a/cluster/examples/kubernetes/ceph/create-external-cluster-resources.py +++ b/cluster/examples/kubernetes/ceph/create-external-cluster-resources.py @@ -193,6 +193,8 @@ def gen_arg_parser(cls, args_to_parse=None): help="Ceph Manager prometheus exporter endpoints (comma separated list of entries of active and standby mgrs)") output_group.add_argument("--monitoring-endpoint-port", default="", required=False, help="Ceph Manager prometheus exporter port") + output_group.add_argument("--read-only", "-r", default=True, required=False, + help="Enable/Disable read-only mode for python script") upgrade_group = argP.add_argument_group('upgrade') upgrade_group.add_argument("--upgrade", action='store_true', default=False, @@ -446,6 +448,10 @@ def get_active_and_standby_mgrs(self): return all_mgr_ips_str, monitoring_endpoint_port def create_cephCSIKeyring_cephFSProvisioner(self): + if self._arg_parser.read_only: + raise ExecutionFailureException( + "Read-only mode is enabled. Pass '--read-only' or '-r' as False") + ''' command: ceph auth get-or-create client.csi-cephfs-provisioner mon 'allow r' mgr 'allow rw' osd 'allow rw tag cephfs metadata=*' ''' @@ -458,7 +464,7 @@ def create_cephCSIKeyring_cephFSProvisioner(self): if self._arg_parser.restricted_auth_permission: if metadata_pool == "": raise ExecutionFailureException( - "'cephfs_metadata_pool_name' not found, please set the '--cephfs-metadata-pool-name' flag") + "'cephfs_metadata_pool_name' not found, please set the '--cephfs-metadata-pool-name' flag") cmd_json = {"prefix": "auth get-or-create", "entity": entity, "caps": ["mon", "allow r", "mgr", "allow rw", @@ -479,6 +485,10 @@ def create_cephCSIKeyring_cephFSProvisioner(self): return str(json_out[0]['key']) def create_cephCSIKeyring_cephFSNode(self): + if self._arg_parser.read_only: + raise ExecutionFailureException( + "Read-only mode is enabled. Pass '--read-only' or '-r' as False") + data_pool = self._arg_parser.cephfs_data_pool_name cluster_name = self._arg_parser.cluster_name entity = "client.csi-cephfs-node" @@ -492,9 +502,10 @@ def create_cephCSIKeyring_cephFSNode(self): cmd_json = {"prefix": "auth get-or-create", "entity": entity, "caps": ["mon", "allow r", - "mgr", "allow rw", - "osd", "allow rw tag cephfs data={}".format(data_pool), - "mds", "allow rw"], + "mgr", "allow rw", + "osd", "allow rw tag cephfs data={}".format( + data_pool), + "mds", "allow rw"], "format": "json"} else: cmd_json = {"prefix": "auth get-or-create", @@ -513,12 +524,16 @@ def create_cephCSIKeyring_cephFSNode(self): return str(json_out[0]['key']) def create_cephCSIKeyring_RBDProvisioner(self): + if self._arg_parser.read_only: + raise ExecutionFailureException( + "Read-only mode is enabled. Pass '--read-only' or '-r' as False") + rbd_pool_name = self._arg_parser.rbd_data_pool_name cluster_name = self._arg_parser.cluster_name entity = "client.csi-rbd-provisioner" if cluster_name: entity = "client.csi-rbd-provisioner-{}".format(cluster_name) - cmd_json={} + cmd_json = {} if self._arg_parser.restricted_auth_permission: if rbd_pool_name == "": raise ExecutionFailureException( @@ -597,8 +612,10 @@ def get_cephfs_data_pool_details(self): return if matching_json_out: - self._arg_parser.cephfs_filesystem_name = str(matching_json_out['name']) - self._arg_parser.cephfs_metadata_pool_name = str(matching_json_out['metadata_pool']) + self._arg_parser.cephfs_filesystem_name = str( + matching_json_out['name']) + self._arg_parser.cephfs_metadata_pool_name = str( + matching_json_out['metadata_pool']) if type(matching_json_out['data_pools']) == list: # if the user has already provided data-pool-name, @@ -630,12 +647,16 @@ def get_cephfs_data_pool_details(self): self._arg_parser.cephfs_data_pool_name)) def create_cephCSIKeyring_RBDNode(self): + if self._arg_parser.read_only: + raise ExecutionFailureException( + "Read-only mode is enabled. Pass '--read-only' or '-r' as False") + rbd_pool_name = self._arg_parser.rbd_data_pool_name cluster_name = self._arg_parser.cluster_name entity = "client.csi-rbd-node" if cluster_name: entity = "client.csi-rbd-node-{}".format(cluster_name) - cmd_json={} + cmd_json = {} if self._arg_parser.restricted_auth_permission: if rbd_pool_name == "": raise ExecutionFailureException( @@ -660,6 +681,10 @@ def create_cephCSIKeyring_RBDNode(self): return str(json_out[0]['key']) def create_checkerKey(self): + if self._arg_parser.read_only: + raise ExecutionFailureException( + "Read-only mode is enabled. Pass '--read-only' or '-r' as False") + cmd_json = {"prefix": "auth get-or-create", "entity": self.run_as_user, "caps": ["mon", self.MIN_USER_CAP_PERMISSIONS['mon'], @@ -685,6 +710,10 @@ def get_ceph_dashboard_link(self): return json_out['dashboard'] def create_rgw_admin_ops_user(self): + if self._arg_parser.read_only: + raise ExecutionFailureException( + "Read-only mode is enabled. Pass '--read-only' or '-r' as False") + cmd = ['radosgw-admin', 'user', 'create', '--uid', self.EXTERNAL_RGW_ADMIN_OPS_USER_NAME, '--display-name', 'Rook RGW Admin Ops user', '--caps', 'buckets=*;users=*;usage=read;metadata=read;zone=read'] try: @@ -751,7 +780,8 @@ def _gen_output_map(self): self.out_map['CSI_CEPHFS_PROVISIONER_SECRET'] = '' # create CephFS node and provisioner keyring only when MDS exists if self.out_map['CEPHFS_FS_NAME'] and self.out_map['CEPHFS_POOL_NAME']: - self.out_map['CSI_CEPHFS_NODE_SECRET'] = self.create_cephCSIKeyring_cephFSNode() + self.out_map['CSI_CEPHFS_NODE_SECRET'] = self.create_cephCSIKeyring_cephFSNode( + ) self.out_map['CSI_CEPHFS_PROVISIONER_SECRET'] = self.create_cephCSIKeyring_cephFSProvisioner() self.out_map['RGW_ENDPOINT'] = self._arg_parser.rgw_endpoint self.out_map['RGW_TLS_CERT'] = '' @@ -1035,14 +1065,16 @@ def test_method_main_output(self): def test_method_create_cephCSIKeyring_cephFSProvisioner(self): csiKeyring = self.rjObj.create_cephCSIKeyring_cephFSProvisioner() - print("cephCSIKeyring without restricting it to a metadata pool. {}".format(csiKeyring)) + print("cephCSIKeyring without restricting it to a metadata pool. {}".format( + csiKeyring)) self.rjObj._arg_parser.restricted_auth_permission = True self.rjObj._arg_parser.cephfs_metadata_pool_name = "myfs-metadata" csiKeyring = self.rjObj.create_cephCSIKeyring_cephFSProvisioner() print("cephCSIKeyring for a specific metadata pool. {}".format(csiKeyring)) self.rjObj._arg_parser.cluster_name = "openshift-storage" csiKeyring = self.rjObj.create_cephCSIKeyring_cephFSProvisioner() - print("cephCSIKeyring for a specific metadata pool and cluster. {}".format(csiKeyring)) + print("cephCSIKeyring for a specific metadata pool and cluster. {}".format( + csiKeyring)) def test_non_zero_return_and_error(self): self.rjObj.cluster.return_val = 1