diff --git a/app_serving/delete-java-app.yaml b/app_serving/delete-java-app.yaml index fdccfc24..0612aaad 100644 --- a/app_serving/delete-java-app.yaml +++ b/app_serving/delete-java-app.yaml @@ -134,7 +134,8 @@ spec: # Delete preview svc and namespace kubectl delete service --all -n {{workflow.parameters.namespace}} 2> >(tee -a $DELETE_LOG >&2) || true - kubectl delete ns {{workflow.parameters.namespace}} || true + ## Do not delete ns for now + # kubectl delete ns {{workflow.parameters.namespace}} || true echo "App {{workflow.parameters.app_name}} was deleted successfully." | tee -a $DELETE_LOG diff --git a/deploy_apps/tks-remove-servicemesh-wftpl.yaml b/deploy_apps/tks-remove-servicemesh-wftpl.yaml index 26d2354c..52186ad9 100644 --- a/deploy_apps/tks-remove-servicemesh-wftpl.yaml +++ b/deploy_apps/tks-remove-servicemesh-wftpl.yaml @@ -11,6 +11,8 @@ spec: value: "service-mesh" - name: keycloak_url value: "" + - name: organization_id + value: "" #=============================== # For tks-info task #=============================== @@ -26,7 +28,7 @@ spec: value: "app={{workflow.parameters.cluster_id}}-{{workflow.parameters.app_group}}" - name: base_repo_branch value: "main" - + # volumes: # - name: tks-proto-vol # configMap: @@ -42,6 +44,39 @@ spec: templateRef: name: remove-servicemesh-all template: remove-start + - - name: kiali-delete-keycloak-client + templateRef: + name: keycloak-client + template: delete-client + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-kiali" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + + - - name: jaeger-delete-keycloak-client + templateRef: + name: keycloak-client + template: delete-client + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-gatekeeper-jaeger" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" #- - name: updateTksInfo # templateRef: diff --git a/deploy_apps/tks-service-mesh-wftpl.yaml b/deploy_apps/tks-service-mesh-wftpl.yaml index 082845c6..2bf15fbf 100644 --- a/deploy_apps/tks-service-mesh-wftpl.yaml +++ b/deploy_apps/tks-service-mesh-wftpl.yaml @@ -18,6 +18,8 @@ spec: value: "{{workflow.parameters.site_name}}" - name: keycloak_url value: "" + - name: organization_id + value: "o086tb3zc" #=============================== # For tks-info task #=============================== @@ -29,7 +31,7 @@ spec: value: "Aabbead61" - name: base_repo_branch value: "main" - + # volumes: # - name: tks-proto-vol # configMap: @@ -41,10 +43,476 @@ spec: #========================================================= - name: deploy-tks-service-mesh steps: + - - name: kiali-create-keycloak-client + templateRef: + name: keycloak-client + template: create-client + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-kiali" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - - name: kiali-update-keycloak-client-secret + templateRef: + name: keycloak-client + template: update-client-secret + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-kiali" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: client_secret_value + value: "" + - - name: kiali-get-keycloak-client-secret + templateRef: + name: keycloak-client + template: get-client-secret + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-kiali" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: client_secret_enabled + value: 'true' + - name: client_secret_value + value: "" + - - name: jaeger-create-keycloak-client + templateRef: + name: keycloak-client + template: create-client + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-gatekeeper-jaeger" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - - name: jaeger-update-keycloak-client-secret + templateRef: + name: keycloak-client + template: update-client-secret + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-gatekeeper-jaeger" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: client_secret_enabled + value: 'true' + - name: client_secret_value + value: "" + - - name: jaeger-get-keycloak-client-secret + templateRef: + name: keycloak-client + template: get-client-secret + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-gatekeeper-jaeger" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - - name: update-oidc-git + template: update-oidc-git + arguments: + parameters: + - name: client_secret + value: "{{steps.jaeger-get-keycloak-client-secret.outputs.parameters.client-secret}}" + - name: cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: keycloak_url + value: "{{workflow.parameters.keycloak_url}}/auth" + - name: organization_id + value: "{{workflow.parameters.organization_id}}" + - - name: kiali-create-keycloak-secret-to-k8s-cluster + template: create-keycloak-secret-to-k8s-cluster + arguments: + parameters: + - name: client_secret + value: "{{steps.kiali-get-keycloak-client-secret.outputs.parameters.client-secret}}" + - name: cluster_id + value: "{{workflow.parameters.cluster_id}}" + - name: namespace + value: "tks-msa" - - name: install-service-mesh-app templateRef: name: service-mesh template: deploy-start + - - name: kiali-get-ep + template: kiali-get-ep + arguments: + parameters: + - name: cluster_id + value: "{{workflow.parameters.cluster_id}}" + - - name: kiali-append-client-redirect-uri-http + templateRef: + name: keycloak-client + template: append-client-redirect-uri + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-kiali" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: redirect_uri + value: "http://{{ steps.kiali-get-ep.outputs.parameters.kiali_ep }}/*" + - - name: kiali-append-client-redirect-uri-https + templateRef: + name: keycloak-client + template: append-client-redirect-uri + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-kiali" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: redirect_uri + value: "https://{{ steps.kiali-get-ep.outputs.parameters.kiali_ep }}/*" + - - name: jaeger-get-ep + template: jaeger-get-ep + arguments: + parameters: + - name: cluster_id + value: "{{workflow.parameters.cluster_id}}" + - - name: jaeger-append-client-redirect-uri-http + templateRef: + name: keycloak-client + template: append-client-redirect-uri + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-gatekeeper-jaeger" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: redirect_uri + value: "http://{{ steps.jaeger-get-ep.outputs.parameters.jaeger_ep }}/*" + - - name: jaeger-append-client-redirect-uri-https + templateRef: + name: keycloak-client + template: append-client-redirect-uri + arguments: + parameters: + - name: server_url + value: "{{ workflow.parameters.keycloak_url }}/auth" + - name: target_realm_name + value: "{{ workflow.parameters.organization_id }}" + - name: target_client_id + value: "{{ workflow.parameters.cluster_id }}-gatekeeper-jaeger" + - name: keycloak_credential_secret_name + value: "keycloak" + - name: keycloak_credential_secret_namespace + value: "keycloak" + - name: redirect_uri + value: "https://{{ steps.jaeger-get-ep.outputs.parameters.jaeger_ep }}/*" + + - name: kiali-get-ep + inputs: + parameters: + - name: cluster_id + outputs: + parameters: + - name: kiali_ep + valueFrom: + path: /mnt/out/kiali_ep.txt + volumes: + - name: out + emptyDir: {} + container: + name: kiali-get-ep + image: 'harbor.taco-cat.xyz/tks/shyaml_jq_yq_kubectl_python:3.11' + command: + - /bin/bash + - '-c' + - | + function log() { + level=$1 + msg=$2 + date=$(date '+%F %H:%M:%S') + echo "[$date] $level $msg" + } + + cluster_id={{inputs.parameters.cluster_id}} + + ################# + # Get endpoints + ################# + kube_secret=$(kubectl get secret -n ${cluster_id} ${cluster_id}-tks-kubeconfig -o jsonpath="{.data.value}" | base64 -d) + cat <<< "$kube_secret" > kubeconfig + + while ! kubectl --kubeconfig=kubeconfig get svc -n tks-msa kiali --ignore-not-found; do + echo "Waiting for the grafana service to appear in cluster ${cluster_id} (5s)" + sleep 5 + done + + kiali_ep_secret=$(kubectl get secret -n ${cluster_id} tks-endpoint-secret -o jsonpath='{.data.kiali}'| base64 -d ) + + if [ "$kiali_ep_secret" == "" ]; then + while [ -z $(kubectl --kubeconfig=kubeconfig get svc -n tks-msa kiali -o jsonpath="{.status.loadBalancer.ingress[*].hostname}") ]; do + if [ "$(kubectl --kubeconfig=kubeconfig get svc -n tks-msa kiali -o jsonpath='{.spec.type}')" != "LoadBalancer" ]; then + log "FAIL" "A service for the kiali in ${cluster_id} is not configured properly.(No LoadBalancer)" + exit -1 + fi + + echo "Waiting for generating the loadbalancer of kiali(3s)" + sleep 3 + done + + endpoint=$(kubectl --kubeconfig=kubeconfig get svc -n tks-msa kiali -o jsonpath="{.status.loadBalancer.ingress[0].hostname}") + endpoint="${endpoint}:20001" + else + endpoint=${kiali_ep_secret} + fi + + echo ${endpoint} > /mnt/out/kiali_ep.txt + + envFrom: + - secretRef: + name: tks-api-secret + volumeMounts: + - name: out + mountPath: /mnt/out + + - name: update-oidc-git + inputs: + parameters: + - name: client_secret + - name: cluster_id + - name: keycloak_url + - name: organization_id + container: + name: update-kiali-resource-git + image: 'harbor.taco-cat.xyz/tks/shyaml_jq_yq_kubectl_python:3.11' + command: + - /bin/bash + - '-c' + - | + function log() { + level=$1 + msg=$2 + date=$(date '+%F %H:%M:%S') + echo "[$date] $level $msg" + } + + cluster_id={{inputs.parameters.cluster_id}} + keycloak_url={{inputs.parameters.keycloak_url}} + organization_id={{workflow.parameters.organization_id}} + client_secret={{inputs.parameters.client_secret}} + + ################# + # updates + ################# + GIT_ACCOUNT={{workflow.parameters.github_account}} + if [[ $GIT_SVC_URL == https://* ]]; then + repository_base=https://${TOKEN//[$'\t\r\n ']}@${GIT_SVC_URL/http:\/\//}/${GIT_ACCOUNT}/ + else + repository_base=http://${TOKEN//[$'\t\r\n ']}@${GIT_SVC_URL/http:\/\//}/${GIT_ACCOUNT}/ + fi + + GIT_SVC_HTTP=${GIT_SVC_URL%://*} + GIT_SVC_BASE_URL=${GIT_SVC_URL#*//} + git clone $GIT_SVC_HTTP://$(echo -n $TOKEN)@${GIT_SVC_BASE_URL}/${USERNAME}/${cluster_id}.git + cd ${cluster_id} + + # Update global variable + yq -i e ".global.keycloakClientPrefix=\"${cluster_id}\"" ${cluster_id}/service-mesh/site-values.yaml + yq -i e ".global.keycloakIssuerUri=\"${keycloak_url}/realms/${organization_id}\"" ${cluster_id}/service-mesh/site-values.yaml + yq -i e ".global.gatekeeperSecret=\"${client_secret}\"" ${cluster_id}/service-mesh/site-values.yaml + + git config --global user.name "tks" + git config --global user.email "tks@sktelecom.com" + + log "INFO" "##### commit changes oidc global variable" + cmessage="changes oidc global variable for keycloak" + git add ${cluster_id}/service-mesh/site-values.yaml + git commit -m "change oidc global variable." -m "$cmessage" + git push + + sleep 30 + git clone $GIT_SVC_HTTP://$(echo -n $TOKEN)@${GIT_SVC_BASE_URL}/${USERNAME}/${cluster_id}-manifests.git + cd ${cluster_id}-manifests + + DESIRED_PATTERN="client-id: ${cluster_id}-gatekeeper-jaeger" + + while true; do + git pull + # Check if the file contains the desired pattern + if grep -q "$DESIRED_PATTERN" "${cluster_id}/service-mesh/gatekeeper/Secret_gatekeeper.yaml"; then + exit 0 + else + echo "$(date): Not desired rendered state." + fi + # Wait for 10 seconds + sleep 10 + done + + envFrom: + - secretRef: + name: "git-svc-token" + + - name: jaeger-get-ep + inputs: + parameters: + - name: cluster_id + outputs: + parameters: + - name: jaeger_ep + valueFrom: + path: /mnt/out/jaeger_ep.txt + volumes: + - name: out + emptyDir: { } + container: + name: jaeger-get-ep + image: 'harbor.taco-cat.xyz/tks/shyaml_jq_yq_kubectl_python:3.11' + command: + - /bin/bash + - '-c' + - | + function log() { + level=$1 + msg=$2 + date=$(date '+%F %H:%M:%S') + echo "[$date] $level $msg" + } + + cluster_id={{inputs.parameters.cluster_id}} + + ################# + # Get endpoints + ################# + kube_secret=$(kubectl get secret -n ${cluster_id} ${cluster_id}-tks-kubeconfig -o jsonpath="{.data.value}" | base64 -d) + cat <<< "$kube_secret" > kubeconfig + + while ! kubectl --kubeconfig=kubeconfig get svc -n tks-msa gatekeeper --ignore-not-found; do + echo "Waiting for the jaeger service to appear in cluster ${cluster_id} (5s)" + sleep 5 + done + + jaeger_ep_secret=$(kubectl get secret -n ${cluster_id} tks-endpoint-secret -o jsonpath='{.data.jaeger}'| base64 -d ) + if [ "$jaeger_ep_secret" == "" ]; then + echo "jager_ep_empty" + while [ -z $(kubectl --kubeconfig=kubeconfig get svc -n tks-msa gatekeeper -o jsonpath="{.status.loadBalancer.ingress[*].hostname}") ]; do + if [ "$(kubectl --kubeconfig=kubeconfig get svc -n tks-msa gatekeeper -o jsonpath='{.spec.type}')" != "LoadBalancer" ]; then + log "FAIL" "A service for the gatekeeper in ${cluster_id} is not configured properly.(No LoadBalancer)" + exit -1 + fi + + echo "Waiting for generating the loadbalancer of jaeger(3s)" + sleep 3 + done + endpoint=$(kubectl --kubeconfig=kubeconfig get svc -n tks-msa gatekeeper -o jsonpath="{.status.loadBalancer.ingress[0].hostname}") + endpoint="${endpoint}:3000" + else + endpoint=${jaeger_ep_secret} + fi + + echo ${endpoint} > /mnt/out/jaeger_ep.txt + + envFrom: + - secretRef: + name: tks-api-secret + volumeMounts: + - name: out + mountPath: /mnt/out + + - name: create-keycloak-secret-to-k8s-cluster + inputs: + parameters: + - name: client_secret + - name: cluster_id + - name: namespace + container: + name: create-secret + image: 'harbor.taco-cat.xyz/tks/shyaml_jq_yq_kubectl_python:3.11' + command: + - /bin/bash + - '-c' + - | + function log() { + level=$1 + msg=$2 + date=$(date '+%F %H:%M:%S') + echo "[$date] $level $msg" + } + + client_secret={{inputs.parameters.client_secret}} + cluster_id={{inputs.parameters.cluster_id}} + namespace={{inputs.parameters.namespace}} + + ################# + # Get endpoints + ################# + kube_secret=$(kubectl get secret -n ${cluster_id} ${cluster_id}-tks-kubeconfig -o jsonpath="{.data.value}" | base64 -d) + cat <<< "$kube_secret" > kubeconfig + + kubectl --kubeconfig=kubeconfig create ns ${namespace} || true + + kubectl --kubeconfig=kubeconfig apply -f - << EOF + apiVersion: v1 + kind: Secret + metadata: + name: kiali + namespace: tks-msa + type: Opaque + data: + oidc-secret: $(echo -n "$client_secret" | base64) + EOF + #========================================================= # Template Definition diff --git a/git-repo/create-cluster-repo.yaml b/git-repo/create-cluster-repo.yaml index fdfed90a..ea5e1f20 100644 --- a/git-repo/create-cluster-repo.yaml +++ b/git-repo/create-cluster-repo.yaml @@ -130,9 +130,12 @@ spec: byoh) cluster_endpoint_host=$(echo $CLUSTER_INFO | jq -r '.byoClusterEndpointHost') cluster_endpoint_port=$(echo $CLUSTER_INFO | jq -r '.byoClusterEndpointPort') + client_id=${CLUSTER_ID}-k8s-api yq -i e ".global.clusterEndpointHost=\"$cluster_endpoint_host\"" $CLUSTER_ID/$CLUSTER_ID/tks-cluster/site-values.yaml yq -i e ".global.clusterEndpointPort=$cluster_endpoint_port" $CLUSTER_ID/$CLUSTER_ID/tks-cluster/site-values.yaml + yq -i e ".global.keycloakIssuerUri=$KEYCLOAK_URL" $CLUSTER_ID/$CLUSTER_ID/tks-cluster/site-values.yaml + yq -i e ".global.keycloakClientId=$client_id" $CLUSTER_ID/$CLUSTER_ID/tks-cluster/site-values.yaml ;; *) @@ -180,6 +183,8 @@ spec: value: "{{workflow.parameters.template_name}}" - name: CLOUD_ACCOUNT_ID value: "{{workflow.parameters.cloud_account_id}}" + - name: KEYCLOAK_URL + value: "{{workflow.parameters.keycloak_url}}" - name: CLUSTER_INFO value: "{{inputs.parameters.cluster_info}}" - name: ARGO_TOKEN diff --git a/keycloak-client/lib/keycloak-clients.yaml b/keycloak-client/lib/keycloak-clients.yaml index e2bcc0de..77f21f58 100644 --- a/keycloak-client/lib/keycloak-clients.yaml +++ b/keycloak-client/lib/keycloak-clients.yaml @@ -481,7 +481,7 @@ spec: - name: target_realm_name value: test3 - name: target_client_id - value: k8s-oidc6 + value: test-client2 - name: keycloak_credential_secret_name value: keycloak - name: keycloak_credential_secret_namespace @@ -669,12 +669,10 @@ spec: value: keycloak - name: keycloak_credential_secret_namespace value: keycloak - - name: client_role_name - value: admin - name: client_secret_enabled - value: 'false' + value: 'true' - name: client_secret_value - value: test + value: '' script: command: - python3 @@ -682,12 +680,12 @@ spec: source: |2 from keycloak import KeycloakOpenID, KeycloakAdmin, KeycloakOpenIDConnection - import requests from kubernetes import client, config import sys import base64 - import json - input_params = {'server_url': '{{inputs.parameters.server_url}}', 'target_realm_name': '{{inputs.parameters.target_realm_name}}', 'target_client_id': '{{inputs.parameters.target_client_id}}', 'keycloak_credential_secret_name': '{{inputs.parameters.keycloak_credential_secret_name}}', 'keycloak_credential_secret_namespace': '{{inputs.parameters.keycloak_credential_secret_namespace}}', 'client_role_name': '{{inputs.parameters.client_role_name}}', 'client_secret_enabled': '{{inputs.parameters.client_secret_enabled}}', 'client_secret_value': '{{inputs.parameters.client_secret_value}}'} + import secrets + import string + input_params = {'server_url': '{{inputs.parameters.server_url}}', 'target_realm_name': '{{inputs.parameters.target_realm_name}}', 'target_client_id': '{{inputs.parameters.target_client_id}}', 'keycloak_credential_secret_name': '{{inputs.parameters.keycloak_credential_secret_name}}', 'keycloak_credential_secret_namespace': '{{inputs.parameters.keycloak_credential_secret_namespace}}', 'client_secret_enabled': '{{inputs.parameters.client_secret_enabled}}', 'client_secret_value': '{{inputs.parameters.client_secret_value}}'} def get_kubernetes_api(local=False): if local: @@ -704,20 +702,6 @@ spec: decoded_data = base64.b64decode(encoded_data).decode('utf-8') return decoded_data - def create_client(url, realm_name, client_id, token): - if (url[(- 1)] == '/'): - url = url[:(- 1)] - path = f'/admin/realms/{realm_name}/clients' - headers = {'Content-Type': 'application/json', 'Authorization': ('Bearer ' + token['access_token'])} - data = {'clientId': client_id, 'enabled': True, 'publicClient': True, 'protocol': 'openid-connect', 'standardFlowEnabled': True, 'implicitFlowEnabled': False, 'directAccessGrantsEnabled': True, 'serviceAccountsEnabled': False, 'authorizationServicesEnabled': False, 'fullScopeAllowed': True} - response = requests.post((url + path), headers=headers, json=data) - if (response.status_code == 201): - print(f'create client {client_id} success') - elif (response.status_code == 409): - raise Exception(response.text) - else: - raise Exception(response.text) - def input_validation(origin_input_params): if (not (origin_input_params['server_url'][(- 1)] == '/')): origin_input_params['server_url'] += '/' @@ -744,25 +728,20 @@ spec: try: try: hashed_client_id = keycloak_admin.get_client_id(input_params['target_client_id']) - print(f"""hashed_client_id of client id "{input_params['target_client_id']}" is "{hashed_client_id}"""") + print(f"""hashed_client_id of client id "{input_params['target_client_id']}" is "{hashed_client_id}".""") client = keycloak_admin.get_client(client_id=hashed_client_id) except Exception as inner_e: print(inner_e) raise Exception(f"""get client id "{input_params['target_client_id']} failed""") try: if (input_params['client_secret_enabled'] == 'true'): - if (input_params['client_secret_value'] == 'null'): - print('null') - client['publicClient'] = False - keycloak_admin.update_client(client_id=hashed_client_id, payload=client) - print(json.dumps(keycloak_admin.get_client(client_id=hashed_client_id), indent=4, sort_keys=True)) + if (input_params['client_secret_value'] == ''): + characters = (string.ascii_letters + string.digits) + client['secret'] = ''.join((secrets.choice(characters) for i in range(32))) else: - client['publicClient'] = False - keycloak_admin.update_client(client_id=hashed_client_id, payload=client) - client_secret = input_params['client_secret_value'] - client['secret'] = client_secret - keycloak_admin.update_client(client_id=hashed_client_id, payload=client) - print(client_secret) + client['secret'] = input_params['client_secret_value'] + client['publicClient'] = False + keycloak_admin.update_client(client_id=hashed_client_id, payload=client) else: client['publicClient'] = True keycloak_admin.update_client(client_id=hashed_client_id, payload=client) @@ -777,3 +756,120 @@ spec: print('create client failed') keycloak_openid.logout(keycloak_admin.connection.token['refresh_token']) sys.exit(1) + - name: get-client-secret + inputs: + parameters: + - name: server_url + value: http://tks-console-dev.taco-cat.xyz/auth/ + - name: target_realm_name + value: test3 + - name: target_client_id + value: test-client2 + - name: keycloak_credential_secret_name + value: keycloak + - name: keycloak_credential_secret_namespace + value: keycloak + outputs: + parameters: + - name: client-secret + valueFrom: + path: /out/client_secret.txt + volumes: + - name: out + emptyDir: {} + script: + volumeMounts: + - name: out + mountPath: "/out" + command: + - python3 + image: harbor-cicd.taco-cat.xyz/dev/python-keycloak-cli:v0.1.0 + source: |2 + + from keycloak import KeycloakOpenID, KeycloakAdmin, KeycloakOpenIDConnection + import requests + from kubernetes import client, config + import sys + import base64 + import json + output_params = {} + input_params = {'server_url': '{{inputs.parameters.server_url}}', 'target_realm_name': '{{inputs.parameters.target_realm_name}}', 'target_client_id': '{{inputs.parameters.target_client_id}}', 'keycloak_credential_secret_name': '{{inputs.parameters.keycloak_credential_secret_name}}', 'keycloak_credential_secret_namespace': '{{inputs.parameters.keycloak_credential_secret_namespace}}'} + + def get_kubernetes_api(local=False): + if local: + import os + kubeconfig_path = os.path.expandvars('$HOME/.kube/config') + config.load_kube_config(config_file=kubeconfig_path) + else: + config.load_incluster_config() + return client.CoreV1Api() + + def get_secret(k8s_client, secret_name, secret_namespace): + secret_obj = k8s_client.read_namespaced_secret(name=secret_name, namespace=secret_namespace) + encoded_data = secret_obj.data.get('admin-password') + decoded_data = base64.b64decode(encoded_data).decode('utf-8') + return decoded_data + + def get_client_secret(url, realm_name, client_id, token): + if (url[(- 1)] == '/'): + url = url[:(- 1)] + path = f'/admin/realms/{realm_name}/clients' + headers = {'Content-Type': 'application/json', 'Authorization': ('Bearer ' + token['access_token'])} + params = {'clientId': client_id} + response = requests.get((url + path), headers=headers, params=params) + if (response.status_code == 200): + client_data = response.json() + if client_data: + client_secret = client_data[0]['secret'] + return client_secret + else: + print(f'No client found with clientId: {client_id}') + + def input_validation(origin_input_params): + if (not (origin_input_params['server_url'][(- 1)] == '/')): + origin_input_params['server_url'] += '/' + input_validation(input_params) + k8s_client = get_kubernetes_api(local=False) + try: + secret_name = input_params['keycloak_credential_secret_name'] + secret_namespace = input_params['keycloak_credential_secret_namespace'] + secret = get_secret(k8s_client, secret_name, secret_namespace) + print(f'get secret "{secret_name}" in "{secret_namespace}" namespace') + except Exception as e: + print(e) + print(f'failed to get secret "{secret_name}" in "{secret_namespace}" namespace') + sys.exit(1) + keycloak_connection = KeycloakOpenIDConnection(server_url=input_params['server_url'], client_id='admin-cli', realm_name=input_params['target_realm_name'], user_realm_name='master', username='admin', password=secret, verify=False) + keycloak_openid = KeycloakOpenID(server_url=input_params['server_url'], client_id='admin-cli', realm_name='master') + try: + keycloak_admin = KeycloakAdmin(connection=keycloak_connection) + print(f"login to {input_params['server_url']} success") + except Exception as e: + print(e) + print(f"login to {input_params['server_url']} failed") + sys.exit(1) + try: + try: + hashed_client_id = keycloak_admin.get_client_id(input_params['target_client_id']) + print(f"""hashed_client_id of client id "{input_params['target_client_id']}" is "{hashed_client_id}".""") + client = keycloak_admin.get_client(client_id=hashed_client_id) + except Exception as inner_e: + print(inner_e) + raise Exception(f"""get client id "{input_params['target_client_id']}" failed""") + try: + client_secret = get_client_secret(input_params['server_url'], input_params['target_realm_name'], input_params['target_client_id'], keycloak_admin.connection.token) + print(f"""client secret of client id "{input_params['target_client_id']}" is "{client_secret}".""") + output_params['client_secret'] = client_secret + print('write client secret to /out/client_secret.txt') + with open('/out/client_secret.txt', 'w') as file: + file.write(client_secret) + except Exception as inner_e: + print(inner_e) + raise Exception(f"""get client secret of client id "{input_params['target_client_id']}" failed""") + print(f'get client secret success') + keycloak_openid.logout(keycloak_admin.connection.token['refresh_token']) + except Exception as e: + print(e) + print('Get client secret failed') + keycloak_openid.logout(keycloak_admin.connection.token['refresh_token']) + sys.exit(1)