From c891ddb57d39178a30a81d9c5b5ed701494a0252 Mon Sep 17 00:00:00 2001 From: subhamkrai Date: Wed, 17 Nov 2021 10:09:47 +0530 Subject: [PATCH] security: add dry run mode for external cluster script Adding dry run mode for external cluster script. This will add cli argument `--dry-run`. By default `dry-run` option will be `False` which means it will only print something like below. ``` Execute: 'ceph fs ls' Execute: 'ceph fsid' Execute: 'ceph quorum_status' Execute: 'ceph auth get-or-create client.healthchecker mon allow r, allow command quorum_status, allow command version mgr allow command config osd allow rwx pool=default.rgw.meta, allow r pool= .rgw.root, allow rw pool=default.rgw.control, allow rx pool=default.rgw.log, allow x pool=default.rgw.buckets.index' Execute: 'ceph mgr services' Execute: 'ceph auth get-or-create client.csi-rbd-node mon profile rbd osd profile rbd' Execute: 'ceph auth get-or-create client.csi-rbd-provisioner mon profile rbd mgr allow rw osd profile rbd' Execute: 'ceph status' ``` Signed-off-by: subhamkrai --- .github/workflows/canary-integration-test.yml | 5 +++ .../create-external-cluster-resources.py | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index a72f31b84ffb..85d226a7b316 100644 --- a/.github/workflows/canary-integration-test.yml +++ b/.github/workflows/canary-integration-test.yml @@ -59,6 +59,11 @@ jobs: kubectl -n rook-ceph cp deploy/examples/create-external-cluster-resources.py $toolbox:/etc/ceph timeout 10 sh -c "until kubectl -n rook-ceph exec $toolbox -- python3 /etc/ceph/create-external-cluster-resources.py --rbd-data-pool-name replicapool; do echo 'waiting for script to succeed' && sleep 1; done" + - name: dry run external script create-external-cluster-resources.py + run: | + toolbox=$(kubectl get pod -l app=rook-ceph-tools -n rook-ceph -o jsonpath='{.items[*].metadata.name}') + kubectl -n rook-ceph exec $toolbox -- python3 /etc/ceph/create-external-cluster-resources.py --rbd-data-pool-name=replicapool --dry-run + - name: run external script create-external-cluster-resources.py unit tests run: | kubectl -n rook-ceph exec $(kubectl get pod -l app=rook-ceph-tools -n rook-ceph -o jsonpath='{.items[0].metadata.name}') -- python3 -m unittest /etc/ceph/create-external-cluster-resources.py diff --git a/deploy/examples/create-external-cluster-resources.py b/deploy/examples/create-external-cluster-resources.py index 5b8d93635c9e..685158ee0d61 100644 --- a/deploy/examples/create-external-cluster-resources.py +++ b/deploy/examples/create-external-cluster-resources.py @@ -195,6 +195,8 @@ def gen_arg_parser(cls, args_to_parse=None): help="Ceph Manager prometheus exporter port") output_group.add_argument("--rbd-metadata-ec-pool-name", default="", required=False, help="Provides the name of erasure coded RBD metadata pool") + output_group.add_argument("--dry-run", default=False, action='store_true', + help="Dry run prints the executed commands without running them") upgrade_group = argP.add_argument_group('upgrade') upgrade_group.add_argument("--upgrade", action='store_true', default=False, @@ -250,6 +252,10 @@ def validate_rgw_metadata_ec_pool_name(self): "Provided rbd_data_pool name, {}, does not exist".format(rbd_pool_name)) return rbd_metadata_ec_pool_name + def dry_run(self, msg): + if self._arg_parser.dry_run: + print("Execute: " + "'" + msg + "'") + def validate_rgw_endpoint_tls_cert(self): if self._arg_parser.rgw_tls_cert_path: with open(self._arg_parser.rgw_tls_cert_path, encoding='utf8') as f: @@ -352,6 +358,8 @@ def shutdown(self): self.cluster.shutdown() def get_fsid(self): + if self._arg_parser.dry_run: + return self.dry_run("ceph fsid") return str(self.cluster.get_fsid()) def _common_cmd_json_gen(self, cmd_json): @@ -370,6 +378,8 @@ def _common_cmd_json_gen(self, cmd_json): def get_ceph_external_mon_data(self): cmd_json = {"prefix": "quorum_status", "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix']) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -420,6 +430,8 @@ def _convert_hostname_to_ip(self, host_name): return ip def get_active_and_standby_mgrs(self): + if self._arg_parser.dry_run: + return "", self.dry_run("ceph status") monitoring_endpoint_port = self._arg_parser.monitoring_endpoint_port monitoring_endpoint_ip_list = self._arg_parser.monitoring_endpoint standby_mgrs = [] @@ -515,6 +527,8 @@ def create_cephCSIKeyring_cephFSProvisioner(self): "caps": ["mon", "allow r", "mgr", "allow rw", "osd", "allow rw tag cephfs metadata=*"], "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix'] + " " + cmd_json['entity'] + " " + " ".join(cmd_json['caps'])) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -550,6 +564,8 @@ def create_cephCSIKeyring_cephFSNode(self): "osd", "allow rw tag cephfs *=*", "mds", "allow rw"], "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix'] + " " + cmd_json['entity'] + " " + " ".join(cmd_json['caps'])) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -582,6 +598,8 @@ def create_cephCSIKeyring_RBDProvisioner(self): "mgr", "allow rw", "osd", "profile rbd"], "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix'] + " " + cmd_json['entity'] + " " + " ".join(cmd_json['caps'])) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -592,6 +610,8 @@ def create_cephCSIKeyring_RBDProvisioner(self): def get_cephfs_data_pool_details(self): cmd_json = {"prefix": "fs ls", "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix']) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, report an error if ret_val != 0: @@ -699,6 +719,8 @@ def create_cephCSIKeyring_RBDNode(self): "caps": ["mon", "profile rbd", "osd", "profile rbd"], "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix'] + " " + cmd_json['entity'] + " " + " ".join(cmd_json['caps'])) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -714,6 +736,8 @@ def create_checkerKey(self): "mgr", self.MIN_USER_CAP_PERMISSIONS['mgr'], "osd", self.MIN_USER_CAP_PERMISSIONS['osd'].format(self._arg_parser.rgw_pool_prefix)], "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix'] + " " + cmd_json['entity'] + " " + " ".join(cmd_json['caps'])) ret_val, json_out, err_msg = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -724,6 +748,8 @@ def create_checkerKey(self): def get_ceph_dashboard_link(self): cmd_json = {"prefix": "mgr services", "format": "json"} + if self._arg_parser.dry_run: + return self.dry_run("ceph " + cmd_json['prefix']) ret_val, json_out, _ = self._common_cmd_json_gen(cmd_json) # if there is an unsuccessful attempt, if ret_val != 0 or len(json_out) == 0: @@ -735,6 +761,8 @@ def get_ceph_dashboard_link(self): def create_rgw_admin_ops_user(self): 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'] + if self._arg_parser.dry_run: + return self.dry_run("ceph " + "".joing(cmd)) try: output = subprocess.check_output(cmd, stderr=subprocess.PIPE) @@ -967,6 +995,10 @@ def gen_json_out(self): "cert": self.out_map['RGW_TLS_CERT'], } }) + + if self._arg_parser.dry_run: + return "" + return json.dumps(json_out)+LINESEP def upgrade_user_permissions(self):