dashboard icon indicating copy to clipboard operation
dashboard copied to clipboard

Minimal permission for karmada dashboard

Open warjiang opened this issue 3 months ago • 2 comments

What would you like to be added: Don't use kubeconfig directly, prefered to use jwt token as the first choice, if not fallback to kubeconfig.

Why is this needed: Security is an important topic for karmada dashboard development, since some security problems have been submited, we should pay more attention to security. Currently, karmada dashboard relies on kubeconfig file including karmada-api context and karmada-host context to take control of apisever including karmada apiserver and kubernetes apiserver, but we found that it's not necessary to use kubeconfig directly from early bi-weekly meetiing discussion. So we decided to minibase the permission requirements, but make sure karmada dasbboard still works.

warjiang avatar Sep 17 '25 06:09 warjiang

for the kubernetes-dashboard-api module, follow the instructions:

  1. on member cluster, create a serviceaccount and authorize the serviceaccount

    kubectl apply --kubeconfig ~/.kube/members.config --context member1 -f - <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: testsa
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: testsa
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
      - kind: ServiceAccount
        name: testsa
        namespace: default
    EOF
    
  2. on karmada control-plane , create a serviceaccount and authorize the serviceaccount with clusters/proxy permission

    kubectl apply --kubeconfig ~/.kube/karmada.config --context karmada-apiserver -f - <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: testsa
      namespace: default
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: cluster-proxy-clusterrole
    rules:
      - apiGroups:
          - 'cluster.karmada.io'
        resources:
          - clusters/proxy
        resourceNames:
          - member1
        verbs:
          - '*'
      - apiGroups:
          - cluster.karmada.io
        resources:
          - clusters
        verbs:
          - list
          - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: cluster-proxy-clusterrolebinding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-proxy-clusterrole
    subjects:
      - kind: ServiceAccount
        name: testsa
        namespace: default
      # The token generated by the serviceaccount can parse the group information. Therefore, you need to specify the group information below.
      - kind: Group
        name: "system:serviceaccounts"
      - kind: Group
        name: "system:serviceaccounts:default"
    EOF
    
  3. validate the service acount with jwt token

    • create a secret for sa and generate a jwt token
      kubectl apply --kubeconfig ~/.kube/karmada.config --context karmada-apiserver -f - <<EOF
      apiVersion: v1
      kind: Secret
      metadata:
        name: testsa
        annotations:
          kubernetes.io/service-account.name: testsa
      type: kubernetes.io/service-account-token
      EOF
      
      command to fetch jwt token
      kubectl --kubeconfig ~/.kube/karmada.config --context karmada-apiserver get secret testsa -oyaml | grep token: | awk '{print $2}' | base64 -d
      
    • generate a kubeconfig based on jwt token
      TOKEN=$(kubectl --kubeconfig ~/.kube/karmada.config --context karmada-apiserver  get secret testsa -oyaml | grep token: | awk '{print $2}' | base64 -d)
      cat > testsa.config <<EOF
      apiVersion: v1
      clusters:
      - cluster:
          insecure-skip-tls-verify: true
          server: {karmada-apiserver-address} # Replace {karmada-apiserver-address} with karmada-apiserver-address. You can find it in /root/.kube/karmada.config file.
        name: testsa
      contexts:
      - context:
          cluster: testsa
          user: testsa
        name: testsa
      current-context: testsa
      kind: Config
      users:
      - name: testsa
        user:
          token: {token} # Replace {token} with the token obtain above.
      EOF
      
    • test the kubeconfig file:
      • get resource from member1 cluster ✅ Image

      • get resource from member2/member3 cluster ❌ Image

  4. test the jwt token with rest api(throw the api module lifted from the kubernetes dashboard)

    • get resource from member1 cluster ✅

      curl -s GET 'http://127.0.0.1:8000/api/v1/namespace?filterBy&sortBy&itemsPerPage&page&metricNames&aggregations' \
      --header 'X-Member-ClusterName: member1' \
      --header 'Authorization: Bearer {token}'
      
      Image
    • get resource from member2 cluster ❌

      curl -s GET 'http://127.0.0.1:8000/api/v1/namespace?filterBy&sortBy&itemsPerPage&page&metricNames&aggregations' \
      --header 'X-Member-ClusterName: member2' \
      --header 'Authorization: Bearer {token}'
      
      Image

references:

  • https://karmada.io/docs/userguide/globalview/aggregated-api-endpoint/#step2-grant-permission-to-user-systemadmin
  • https://karmada.io/docs/userguide/bestpractices/unified-auth/#step2-create-serviceaccount-in-karmada-control-plane

warjiang avatar Sep 18 '25 06:09 warjiang

TBD

for the karmada-dashboard-api module, currently used permissions:

  • read configmap from karmada-host
  • permission for communication with karmada-api-server

references:

  • https://karmada.io/docs/next/administrator/security/component-permission/

warjiang avatar Oct 15 '25 05:10 warjiang