From 0a10c847229832b426ceb98be537e5319bac91d7 Mon Sep 17 00:00:00 2001 From: donggyu Date: Tue, 14 May 2024 11:51:34 +0900 Subject: [PATCH 1/3] add wf for creating/deleteing cluster role resource --- k8s-cli/k8s-cli.yaml | 185 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/k8s-cli/k8s-cli.yaml b/k8s-cli/k8s-cli.yaml index 8212ae31..035768f8 100644 --- a/k8s-cli/k8s-cli.yaml +++ b/k8s-cli/k8s-cli.yaml @@ -5,6 +5,191 @@ metadata: namespace: argo spec: templates: + - name: delete-cluster-role + inputs: + parameters: + - name: target_cluster_id + value: cj7e583yl + - name: is_self_target + value: 'true' + - name: cluster_role_name + value: test1 + - name: ignore_not_found + value: 'true' + script: + command: + - python3 + image: harbor.taco-cat.xyz/dev/python-keycloak-cli:v0.1.0 + source: |2 + + import sys + from kubernetes import client, config + import yaml + import base64 + import json + input_params = {'target_cluster_id': '{{inputs.parameters.target_cluster_id}}', 'is_self_target': '{{inputs.parameters.is_self_target}}', 'cluster_role_name': '{{inputs.parameters.cluster_role_name}}', 'ignore_not_found': '{{inputs.parameters.ignore_not_found}}'} + + def get_kubernetes_api(local=False): + if local: + import os + kubeconfig_path = os.path.expandvars('$HOME/.kube/config') + api_config = client.Configuration() + config.load_kube_config(config_file=kubeconfig_path, client_configuration=api_config) + else: + api_config = client.Configuration() + config.load_incluster_config(client_configuration=api_config) + return client.ApiClient(configuration=api_config) + + def get_kubernetes_api_from_kubeconfig(kubeconfig_str): + kubeconfig_dict = yaml.safe_load(kubeconfig_str) + api_config = client.Configuration() + config.load_kube_config_from_dict(kubeconfig_dict, client_configuration=api_config) + return client.ApiClient(configuration=api_config) + + def get_kubeconfig_secret(k8s_client, secret_name, secret_namespace): + api_instance = client.CoreV1Api(k8s_client) + secret_obj = api_instance.read_namespaced_secret(name=secret_name, namespace=secret_namespace) + encoded_data = secret_obj.data.get('value') + decoded_data = base64.b64decode(encoded_data).decode('utf-8') + return decoded_data + + def delete_cluster_role(api_client, name, ignore_exist): + api_instance = client.RbacAuthorizationV1Api(api_client) + if (ignore_exist == 'true'): + try: + api_instance.delete_cluster_role(name) + except Exception as e: + if ('Not Found' in str(e)): + print(f'cluster role "{name}" not found') + else: + raise e + else: + api_instance.delete_cluster_role(name) + + def input_validation(origin_input_params): + if ((not origin_input_params['target_cluster_id']) or (origin_input_params['target_cluster_id'] == '')): + raise Exception('target_cluster_id is required') + if ((not origin_input_params['is_self_target']) or (origin_input_params['is_self_target'] == '')): + raise Exception('is_self_target is required') + if ((not origin_input_params['cluster_role_name']) or (origin_input_params['cluster_role_name'] == '')): + raise Exception('cluster_role_name is required') + if ((not origin_input_params['ignore_not_found']) or (origin_input_params['ignore_not_found'] == '')): + raise Exception('ignore_not_found is required') + input_validation(input_params) + if (input_params['is_self_target'] == 'true'): + target_k8s_client = k8s_client = get_kubernetes_api(local=False) + else: + k8s_client = get_kubernetes_api(local=False) + target_k8s_kubeconfig = get_kubeconfig_secret(k8s_client, (input_params['target_cluster_id'] + '-tks-kubeconfig'), input_params['target_cluster_id']) + target_k8s_client = get_kubernetes_api_from_kubeconfig(target_k8s_kubeconfig) + try: + delete_cluster_role(target_k8s_client, input_params['cluster_role_name'], input_params['ignore_not_found']) + print(f"""delete cluster role "{input_params['cluster_role_name']}" success""") + except Exception as e: + print('Exception when calling delete_cluster_role') + print(e) + sys.exit(1) + sys.exit(0) + - name: create-cluster-role + inputs: + parameters: + - name: target_cluster_id + value: cj7e583yl + - name: is_self_target + value: 'true' + - name: cluster_role_name + value: test1 + - name: api_group + value: '*' + - name: resource_name + value: '*' + - name: verbs + value: '["get", "list"]' + - name: ignore_exist + value: 'true' + script: + command: + - python3 + image: harbor.taco-cat.xyz/dev/python-keycloak-cli:v0.1.0 + source: |2 + + import sys + from kubernetes import client, config + import yaml + import base64 + import json + input_params = {'target_cluster_id': '{{inputs.parameters.target_cluster_id}}', 'is_self_target': '{{inputs.parameters.is_self_target}}', 'cluster_role_name': '{{inputs.parameters.cluster_role_name}}', 'api_group': '{{inputs.parameters.api_group}}', 'resource_name': '{{inputs.parameters.resource_name}}', 'verbs': '{{inputs.parameters.verbs}}', 'ignore_exist': '{{inputs.parameters.ignore_exist}}'} + + def get_kubernetes_api(local=False): + if local: + import os + kubeconfig_path = os.path.expandvars('$HOME/.kube/config') + api_config = client.Configuration() + config.load_kube_config(config_file=kubeconfig_path, client_configuration=api_config) + else: + api_config = client.Configuration() + config.load_incluster_config(client_configuration=api_config) + return client.ApiClient(configuration=api_config) + + def get_kubernetes_api_from_kubeconfig(kubeconfig_str): + kubeconfig_dict = yaml.safe_load(kubeconfig_str) + api_config = client.Configuration() + config.load_kube_config_from_dict(kubeconfig_dict, client_configuration=api_config) + return client.ApiClient(configuration=api_config) + + def get_kubeconfig_secret(k8s_client, secret_name, secret_namespace): + api_instance = client.CoreV1Api(k8s_client) + secret_obj = api_instance.read_namespaced_secret(name=secret_name, namespace=secret_namespace) + encoded_data = secret_obj.data.get('value') + decoded_data = base64.b64decode(encoded_data).decode('utf-8') + return decoded_data + + def create_cluster_role(api_client, name, api_group, resource_name, verbs, ignore_exist): + api_instance = client.RbacAuthorizationV1Api(api_client) + body = {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'ClusterRole', 'metadata': {'name': name}, 'rules': [{'apiGroups': [api_group], 'resources': [resource_name], 'verbs': verbs}]} + if (ignore_exist == 'true'): + try: + return api_instance.create_cluster_role(body) + except client.ApiException as e: + if (e.status == 409): + print(f'cluster role "{name}" already exists') + return + else: + raise e + else: + return api_instance.create_cluster_role(body) + + def input_validation(origin_input_params): + if ((not origin_input_params['target_cluster_id']) or (origin_input_params['target_cluster_id'] == '')): + raise Exception('target_cluster_id is required') + if ((not origin_input_params['is_self_target']) or (origin_input_params['is_self_target'] == '')): + raise Exception('is_self_target is required') + if ((not origin_input_params['cluster_role_name']) or (origin_input_params['cluster_role_name'] == '')): + raise Exception('cluster_role_name is required') + if ((not origin_input_params['api_group']) or (origin_input_params['api_group'] == '')): + raise Exception('api_group is required') + if ((not origin_input_params['resource_name']) or (len(origin_input_params['resource_name']) == 0)): + raise Exception('resource_name is required') + if ((not origin_input_params['verbs']) or (len(origin_input_params['verbs']) == 0)): + raise Exception('verbs is required') + if ((not origin_input_params['ignore_exist']) or (len(origin_input_params['ignore_exist']) == 0)): + raise Exception('ignore_exist is required') + input_validation(input_params) + input_params['verbs'] = json.loads(input_params['verbs']) + if (input_params['is_self_target'] == 'true'): + target_k8s_client = k8s_client = get_kubernetes_api(local=False) + else: + k8s_client = get_kubernetes_api(local=False) + target_k8s_kubeconfig = get_kubeconfig_secret(k8s_client, (input_params['target_cluster_id'] + '-tks-kubeconfig'), input_params['target_cluster_id']) + target_k8s_client = get_kubernetes_api_from_kubeconfig(target_k8s_kubeconfig) + try: + create_cluster_role(target_k8s_client, input_params['cluster_role_name'], input_params['api_group'], input_params['resource_name'], input_params['verbs'], input_params['ignore_exist']) + print(f"""create cluster role "{input_params['cluster_role_name']}" success""") + except Exception as e: + print('Exception when calling create_cluster_role') + print(e) + sys.exit(1) + sys.exit(0) - name: delete-cluster-role-binding inputs: parameters: From 95c562b60e6d24ed9ed32041fbc09e5c94403cc3 Mon Sep 17 00:00:00 2001 From: donggyu Date: Tue, 14 May 2024 11:52:12 +0900 Subject: [PATCH 2/3] add rbac resource setting during create/import usercluster --- tks-cluster/create-usercluster-wftpl.yaml | 183 ++++++++++++++++++---- tks-cluster/import-usercluster-wftpl.yaml | 9 ++ 2 files changed, 159 insertions(+), 33 deletions(-) diff --git a/tks-cluster/create-usercluster-wftpl.yaml b/tks-cluster/create-usercluster-wftpl.yaml index 52e7a8d1..d0030dae 100644 --- a/tks-cluster/create-usercluster-wftpl.yaml +++ b/tks-cluster/create-usercluster-wftpl.yaml @@ -377,39 +377,8 @@ spec: - name: keycloak_credential_secret_namespace value: "keycloak" - - - name: set-cluster-role-binding-cluster-admin - templateRef: - name: k8s-client - template: create-cluster-role-binding - arguments: - parameters: - - name: target_cluster_id - value: "{{workflow.parameters.cluster_id}}" - - name: is_self_target - value: "false" - - name: rolebinding_name - value: "{{workflow.parameters.cluster_id}}-cluster-admin" - - name: role_name - value: "admin" - - name: group_list - value: '["{{workflow.parameters.cluster_id}}-cluster-admin", "cluster-admin"]' - - - - name: set-cluster-role-binding-cluster-view - templateRef: - name: k8s-client - template: create-cluster-role-binding - arguments: - parameters: - - name: target_cluster_id - value: "{{workflow.parameters.cluster_id}}" - - name: is_self_target - value: "false" - - name: rolebinding_name - value: "{{workflow.parameters.cluster_id}}-cluster-view" - - name: role_name - value: "view" - - name: group_list - value: '["{{workflow.parameters.cluster_id}}-cluster-view", "cluster-view"]' + - - name: create-default-rbac-resources + template: k8s-rbac-setting - - name: install-policy-management templateRef: @@ -739,3 +708,151 @@ spec: kubectl --kubeconfig kubeconfig_temp apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml -n kube-system kubectl --kubeconfig kubeconfig_temp apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml -n kube-system kubectl --kubeconfig kubeconfig_temp apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml -n kube-system + + + - name: k8s-rbac-setting + steps: + - - name: create-cluster-role-for-create + templateRef: + name: k8s-client + template: create-cluster-role + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: cluster_role_name + value: "cluster-admin-create" + - name: api_group + value: '*' + - name: resource_name + value: '*' + - name: verbs + value: '["create"]' + - name: ignore_exist + value: 'true' + - - name: create-cluster-role-for-read + templateRef: + name: k8s-client + template: create-cluster-role + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: cluster_role_name + value: "cluster-admin-read" + - name: api_group + value: '*' + - name: resource_name + value: '*' + - name: verbs + value: '["get", "list", "watch"]' + - name: ignore_exist + value: 'true' + - - name: create-cluster-role-for-update + templateRef: + name: k8s-client + template: create-cluster-role + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: cluster_role_name + value: "cluster-admin-update" + - name: api_group + value: '*' + - name: resource_name + value: '*' + - name: verbs + value: '["update", "patch"]' + - name: ignore_exist + value: 'true' + - - name: create-cluster-role-for-delete + templateRef: + name: k8s-client + template: create-cluster-role + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: cluster_role_name + value: "cluster-admin-delete" + - name: api_group + value: '*' + - name: resource_name + value: '*' + - name: verbs + value: '["delete", "deletecollection"]' + - name: ignore_exist + value: 'true' + - - name: set-cluster-role-binding-create + templateRef: + name: k8s-client + template: create-cluster-role-binding + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: rolebinding_name + value: "cluster-admin-create-rb" + - name: role_name + value: "cluster-admin-create" + - name: group_list + value: '["cluster-admin-create"]' + - - name: set-cluster-role-binding-read + templateRef: + name: k8s-client + template: create-cluster-role-binding + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: rolebinding_name + value: "cluster-admin-read-rb" + - name: role_name + value: "cluster-admin-read" + - name: group_list + value: '["cluster-admin-read"]' + - - name: set-cluster-role-binding-update + templateRef: + name: k8s-client + template: create-cluster-role-binding + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: rolebinding_name + value: "cluster-admin-update-rb" + - name: role_name + value: "cluster-admin-update" + - name: group_list + value: '["cluster-admin-update"]' + - - name: set-cluster-role-binding-delete + templateRef: + name: k8s-client + template: create-cluster-role-binding + arguments: + parameters: + - name: target_cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: is_self_target + value: "false" + - name: rolebinding_name + value: "cluster-admin-delete-rb" + - name: role_name + value: "cluster-admin-delete" + - name: group_list + value: '["cluster-admin-delete"]' diff --git a/tks-cluster/import-usercluster-wftpl.yaml b/tks-cluster/import-usercluster-wftpl.yaml index a0f21932..3698b62e 100644 --- a/tks-cluster/import-usercluster-wftpl.yaml +++ b/tks-cluster/import-usercluster-wftpl.yaml @@ -114,6 +114,15 @@ spec: - name: keycloak_credential_secret_namespace value: "keycloak" + - - name: create-default-rbac-resources + templateRef: + name: create-tks-usercluster + template: k8s-rbac-setting + arguments: + parameters: + - name: cluster_id + value: "{{ workflow.parameters.cluster_id }}" + ####################### # Template Definition # From e54ed4980e8c1cf5b73862d2b7e0c360bcaba3f9 Mon Sep 17 00:00:00 2001 From: donggyu Date: Fri, 17 May 2024 16:14:24 +0900 Subject: [PATCH 3/3] remove keycloak client wf so that tks-api will handle it --- tks-cluster/create-usercluster-wftpl.yaml | 19 ------------------- tks-cluster/import-usercluster-wftpl.yaml | 19 ------------------- tks-cluster/remove-usercluster-wftpl.yaml | 18 ------------------ 3 files changed, 56 deletions(-) diff --git a/tks-cluster/create-usercluster-wftpl.yaml b/tks-cluster/create-usercluster-wftpl.yaml index d0030dae..87c6ef0b 100644 --- a/tks-cluster/create-usercluster-wftpl.yaml +++ b/tks-cluster/create-usercluster-wftpl.yaml @@ -358,25 +358,6 @@ spec: ] when: "{{steps.tks-create-cluster-repo.outputs.parameters.infra_provider}} == byoh" - - - name: set-keycloak-config - templateRef: - name: set-user-cluster - template: main - arguments: - parameters: - - name: cluster_id - value: "{{ workflow.parameters.cluster_id }}" - - name: server_url - value: "{{ workflow.parameters.keycloak_url }}" - - name: target_realm_name - value: "{{ workflow.parameters.contract_id }}" - - name: target_client_id - value: "{{ workflow.parameters.cluster_id}}-k8s-api" - - name: keycloak_credential_secret_name - value: "keycloak" - - name: keycloak_credential_secret_namespace - value: "keycloak" - - - name: create-default-rbac-resources template: k8s-rbac-setting diff --git a/tks-cluster/import-usercluster-wftpl.yaml b/tks-cluster/import-usercluster-wftpl.yaml index 3698b62e..d9027e6f 100644 --- a/tks-cluster/import-usercluster-wftpl.yaml +++ b/tks-cluster/import-usercluster-wftpl.yaml @@ -95,25 +95,6 @@ spec: - name: contract_id value: "{{ workflow.parameters.contract_id }}" - - - name: set-keycloak-config - templateRef: - name: set-user-cluster - template: main - arguments: - parameters: - - name: cluster_id - value: "{{ workflow.parameters.cluster_id }}" - - name: server_url - value: "{{ workflow.parameters.keycloak_url }}" - - name: target_realm_name - value: "{{ workflow.parameters.contract_id }}" - - name: target_client_id - value: "{{ workflow.parameters.cluster_id}}-k8s-api" - - name: keycloak_credential_secret_name - value: "keycloak" - - name: keycloak_credential_secret_namespace - value: "keycloak" - - - name: create-default-rbac-resources templateRef: name: create-tks-usercluster diff --git a/tks-cluster/remove-usercluster-wftpl.yaml b/tks-cluster/remove-usercluster-wftpl.yaml index 09045b75..9944a036 100644 --- a/tks-cluster/remove-usercluster-wftpl.yaml +++ b/tks-cluster/remove-usercluster-wftpl.yaml @@ -225,24 +225,6 @@ spec: name: tks-delete-cluster-repo template: deleteClusterRepo - - - name: unset-keycloak-config - templateRef: - name: keycloak-client - template: delete-client - arguments: - parameters: - - name: server_url - value: "{{ workflow.parameters.keycloak_url }}" - - name: target_realm_name - value: "{{ workflow.parameters.contract_id }}" - - name: target_client_id - value: "{{ workflow.parameters.cluster_id}}-k8s-api" - - name: keycloak_credential_secret_name - value: "keycloak" - - name: keycloak_credential_secret_namespace - value: "keycloak" - - ####################### # Template Definition #