← Back to DevBytes

Kubernetes Dashboard: Complete Implementation Guide

Introduction to Kubernetes Dashboard

The Kubernetes Dashboard is a general-purpose, web-based user interface for Kubernetes clusters. It allows administrators and developers to manage and troubleshoot applications running inside a cluster, as well as manage the cluster itself, without resorting to the command line. Originally developed by the Kubernetes community and now maintained as a sub-project under the kubernetes organization, the Dashboard provides a visual overview of nodes, namespaces, workloads, services, configurations, and storage resources.

What Is the Kubernetes Dashboard?

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

At its core, the Kubernetes Dashboard is a stateless web application that communicates with the Kubernetes API server to fetch, display, and modify cluster resources. It runs as a Deployment inside your cluster and exposes a service that you can access through various methods. The UI is built with modern JavaScript frameworks and renders responsive pages that work on desktops, tablets, and mobile devices.

Key capabilities of the Dashboard include:

Why the Kubernetes Dashboard Matters

While kubectl is powerful, it presents a steep learning curve for newcomers and can slow down routine tasks that benefit from visual context. The Dashboard bridges this gap. For platform engineering teams, it serves as a lightweight observability console that doesn't require spinning up Grafana or a full monitoring stack just to check pod status. For developers, it provides self-service access to logs, shell sessions, and deployment status without granting SSH access to nodes or requiring deep Kubernetes expertise.

In production environments, the Dashboard helps on-call engineers quickly triage issues by scanning pod health, restart counts, and resource utilization across namespaces. It also serves as an auditing and validation tool—you can visually confirm that ConfigMaps, Secrets, and Ingress rules are configured correctly before promoting changes.

Prerequisites

Step 1 — Deploy the Kubernetes Dashboard

The official distribution ships as a single YAML manifest containing all required resources: a Namespace, a ServiceAccount, a Secret for the ServiceAccount token, a ClusterRole and ClusterRoleBinding for default access, a Deployment, and a Service. Deploy it with a single kubectl command:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

This creates the kubernetes-dashboard namespace and installs all components. Verify the deployment:

kubectl get pods -n kubernetes-dashboard
kubectl get svc -n kubernetes-dashboard

Expected output shows the dashboard pod running and a service named kubernetes-dashboard of type ClusterIP exposed on port 443 (the dashboard serves HTTPS internally using auto-generated certificates).

Step 2 — Choose an Access Method

Because the Dashboard Service is ClusterIP by default, it is only reachable inside the cluster. You need to expose it externally or use a proxied connection. There are several approaches, each with different security implications.

Option A: kubectl proxy (development only)

The simplest method for local development is kubectl proxy, which creates an HTTP proxy on your local machine that authenticates to the API server using your kubeconfig credentials:

kubectl proxy

This listens on http://localhost:8001. Access the dashboard at:

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

Note: This method skips authentication entirely because the proxy passes your kubeconfig credentials. It is suitable for quick exploration but should not be used in production.

Option B: NodePort (testing environments)

Patch the service to NodePort type to expose it on a static port across all nodes:

kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard \
  -p '{"spec":{"type":"NodePort"}}'

Then retrieve the assigned port:

kubectl get svc kubernetes-dashboard -n kubernetes-dashboard \
  -o jsonpath='{.spec.ports[0].nodePort}'

Access via https://<node-ip>:<nodePort>. You'll need to accept the self-signed certificate warning in your browser.

Option C: Ingress with TLS termination (production)

For production, route traffic through an Ingress controller that terminates TLS with a trusted certificate. First create a TLS Secret (or use cert-manager to automate it), then deploy an Ingress resource:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dashboard-ingress
  namespace: kubernetes-dashboard
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    # Alternative if you terminate TLS at the ingress:
    # nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - dashboard.example.com
    secretName: dashboard-tls-secret
  rules:
  - host: dashboard.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kubernetes-dashboard
            port:
              number: 443

Apply this manifest:

kubectl apply -f dashboard-ingress.yaml

Then configure DNS to point dashboard.example.com at your Ingress controller's external IP.

Step 3 — Configure Authentication and RBAC

The Dashboard supports two authentication mechanisms: a Bearer Token (most common and recommended) and kubeconfig file upload. The default installation creates a kubernetes-dashboard ServiceAccount with cluster-admin privileges, which is dangerously broad. In production you should create scoped RBAC roles.

Creating a dedicated viewer ServiceAccount

First, create a ServiceAccount and a ClusterRole that grants read-only access to most resources but prevents modifications:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-viewer
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: dashboard-viewer-role
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps", "persistentvolumeclaims", "events", "namespaces"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
  resources: ["jobs", "cronjobs"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
  resources: ["pods", "nodes"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-viewer-binding
subjects:
- kind: ServiceAccount
  name: dashboard-viewer
  namespace: kubernetes-dashboard
roleRef:
  kind: ClusterRole
  name: dashboard-viewer-role
  apiGroup: rbac.authorization.k8s.io

Apply it:

kubectl apply -f dashboard-viewer-rbac.yaml

Retrieving the Bearer Token

For Kubernetes 1.24+, the recommended way to obtain a long-lived token is to create a Secret manually bound to the ServiceAccount:

apiVersion: v1
kind: Secret
metadata:
  name: dashboard-viewer-token
  namespace: kubernetes-dashboard
  annotations:
    kubernetes.io/service-account.name: dashboard-viewer
type: kubernetes.io/service-account-token

Apply and extract the token:

kubectl apply -f dashboard-viewer-token-secret.yaml
kubectl get secret dashboard-viewer-token -n kubernetes-dashboard \
  -o jsonpath='{.data.token}' | base64 --decode

On older clusters (pre-1.24), the token is automatically created and can be retrieved directly:

kubectl -n kubernetes-dashboard create token dashboard-viewer

Copy the token value. When you open the Dashboard in your browser, select the "Token" authentication method and paste it. The UI will then show only resources permitted by the dashboard-viewer-role ClusterRole.

Step 4 — Navigating the Dashboard Interface

Once authenticated, the Dashboard presents several sections accessible from the left sidebar:

Creating resources from the UI

Click the + icon in the top-right corner. You can paste YAML or JSON directly into the editor, upload a file, or use guided forms for Deployments, Services, and Ingresses. The editor validates syntax before submission:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-example
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi

Paste this into the editor, select "Create", and the deployment appears in the Workloads list within seconds.

Viewing logs and executing commands

Navigate to a pod's detail page. You'll see a "Logs" tab that streams stdout/stderr from any container in the pod. Use the container dropdown to switch between init containers, sidecars, and main application containers. The logs view supports searching, filtering by date, and downloading as a text file.

The "Exec" tab opens an interactive terminal inside the container. This is equivalent to kubectl exec -it and is invaluable for debugging environment variables, network connectivity, or file system state without leaving the browser.

Step 5 — Integrating with the Metrics Server

If CPU and memory graphs appear empty or show "metrics not available", deploy the Metrics Server:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Verify it is running and producing metrics:

kubectl get pods -n kube-system -l k8s-app=metrics-server
kubectl top nodes
kubectl top pods -A

Refresh the Dashboard; node and pod resource graphs should now populate. The Dashboard queries the metrics.k8s.io API group, which the Metrics Server registers.

Complete Secure Deployment Example

Below is a consolidated, production-oriented setup script that deploys the Dashboard, creates a scoped ServiceAccount, exposes it via an Ingress, and applies network policies to restrict access:

#!/bin/bash
# Deploy the Kubernetes Dashboard with secure defaults

set -e

DASHBOARD_VERSION="v2.7.0"
NAMESPACE="kubernetes-dashboard"
DOMAIN="dashboard.internal.example.com"

echo "[1/5] Deploying Dashboard ${DASHBOARD_VERSION}..."
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/${DASHBOARD_VERSION}/aio/deploy/recommended.yaml

echo "[2/5] Creating read-only ServiceAccount..."
cat <

Best Practices

  • Never use the default cluster-admin ServiceAccount in production. The out-of-the-box kubernetes-dashboard ServiceAccount has full privileges. Replace it with scoped RBAC roles that grant only the permissions your team actually needs.
  • Place the Dashboard behind an authenticating reverse proxy. Use NGINX Ingress with OAuth2-Proxy, basic auth, or an identity-aware proxy. This adds a second layer of authentication before the user even reaches the Dashboard's token prompt.
  • Rotate tokens regularly. If using manually created ServiceAccount token Secrets, implement a rotation policy (e.g., recreate the Secret every 30 days and distribute new tokens). Consider using the kubernetes.io/service-account-token type with an expiration field set.
  • Restrict network access with NetworkPolicy. Allow only your Ingress controller namespace to communicate with the Dashboard pod on port 8443. Block all other inbound traffic to the kubernetes-dashboard namespace.
  • Audit Dashboard access. Enable Kubernetes audit logging for the kubernetes-dashboard namespace and specifically for the dashboard ServiceAccount actions. Ship these logs to your SIEM.
  • Pin the Dashboard version. Avoid using latest tags. Pin to a specific version like v2.7.0 and test upgrades in a staging cluster before rolling out.
  • Disable the "Skip" authentication button. In older Dashboard versions, a "Skip" button appears on the login page. You can disable it by passing --enable-skip-login=false to the deployment args.
  • Run the Dashboard on a dedicated internal domain. Use something like dashboard.internal.example.com that is not publicly routable, and configure split-horizon DNS or VPN access for your team.
  • Monitor the Dashboard itself. The Dashboard is a workload like any other. Set up alerts for pod crashes, high error rates in its logs, and unusual latency when proxying API calls.
  • Use the Dashboard as a complement, not a replacement for kubectl. The UI excels at visualization and quick inspection; for scripting, CI/CD pipelines, and complex bulk operations, kubectl and the API remain the authoritative tools.

Common Issues and Troubleshooting

Dashboard returns "Unauthorized" after token paste

Verify the token is still valid and corresponds to a ServiceAccount with a ClusterRoleBinding. Check:

kubectl auth can-i --list --as=system:serviceaccount:kubernetes-dashboard:your-sa -n default

If the token has expired, regenerate it as described in Step 3.

Blank resource graphs or "metrics not available"

Confirm the Metrics Server is deployed and healthy:

kubectl get deployment metrics-server -n kube-system
kubectl top nodes

If kubectl top also fails, check the Metrics Server logs for certificate or network issues.

Dashboard pod keeps restarting

Check the Dashboard logs:

kubectl logs -n kubernetes-dashboard deployment/kubernetes-dashboard

Common causes include OOMKilled due to large clusters (increase memory limits) or certificate file permission errors (the dashboard runs as user nobody with a restricted filesystem).

TLS certificate errors in browser

The Dashboard's internal certificate is self-signed and not trusted by browsers. When using kubectl proxy, the connection is tunneled and this is not an issue. For Ingress, configure TLS termination at the Ingress level using a trusted certificate, and set the backend protocol annotation to HTTPS as shown in the Ingress example above.

CSRF errors on form submissions

The Dashboard implements CSRF protection. If you see "CSRF token missing" errors, ensure you are accessing the Dashboard through its proper URL and not via a raw IP:port that strips headers. Ingress configurations should preserve the X-CSRF-TOKEN header.

Upgrading the Dashboard

To upgrade to a newer version, first check the version compatibility matrix in the official release notes. Then delete the old deployment (your RBAC objects and Secrets are safe in the namespace) and apply the new manifest:

kubectl delete deployment kubernetes-dashboard -n kubernetes-dashboard
kubectl delete service kubernetes-dashboard -n kubernetes-dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

Your existing ServiceAccount tokens and Ingress configurations remain intact. Verify the new pod is running and re-test authentication.

Conclusion

The Kubernetes Dashboard transforms cluster administration from a purely terminal-driven experience into an interactive, visual workflow that accelerates troubleshooting, simplifies resource management, and empowers developers with self-service capabilities. By following the deployment steps outlined in this guide—installing the Dashboard, securing it with scoped RBAC and Ingress-based TLS, and integrating the Metrics Server—you gain a powerful observability console that respects your cluster's security boundaries. Remember that the Dashboard is most effective when treated as a managed service within your cluster: version-pinned, network-restricted, token-rotated, and continuously audited. With these practices in place, it becomes an indispensable part of your Kubernetes toolchain, bridging the gap between raw API access and full-stack observability platforms.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles