How to Install Kubernetes Dashboard on Ubuntu 26.04 with Secure Access

how to install kubernetes dashboard on ubuntu with secure access

Table of Contents

  1. What is Kubernetes Dashboard
  2. The Tesla Lesson: Why Security Comes First
  3. Prerequisites
  4. Method 1: Install via Helm (Recommended)
  5. Method 2: Install via kubectl apply (Quick)
  6. Create an Admin User and Service Account
  7. Generate a Long-Lived Access Token
  8. Access Method 1: kubectl proxy (Local Development)
  9. Access Method 2: kubectl port-forward (Recommended for Teams)
  10. Access Method 3: NodePort (Internal Network)
  11. Access Method 4: Ingress with TLS (Production)
  12. Create Role-Based Users (Least Privilege)
  13. Security Hardening Checklist
  14. Dashboard Overview: Key Features
  15. Common Issues and Quick Fixes
  16. Kubernetes Dashboard vs KubeSphere: Which to Use
  17. Next Steps

Managing a Kubernetes cluster through kubectl commands alone is efficient once you know what you’re doing — but when you need to quickly visualize what’s running, browse logs across multiple pods, or give a team member cluster visibility without a kubectl tutorial, a web UI makes an enormous practical difference. The Kubernetes Dashboard is the official web-based UI maintained by the Kubernetes project itself, and this guide covers the complete installation and — crucially — the security configuration that most tutorials skip.

What is Kubernetes Dashboard

Kubernetes Dashboard is the official web-based UI for managing Kubernetes clusters. It provides a visual interface to deploy applications, troubleshoot workloads, and manage cluster resources without memorizing kubectl commands.

What you can do from the Dashboard:

  • View and manage Pods, Deployments, StatefulSets, DaemonSets, Services, Ingresses
  • Browse logs from any running container in real time
  • Monitor resource usage (CPU and memory) when Metrics Server is installed
  • Deploy applications from YAML or via forms
  • Inspect events — see why pods are crashing or failing to schedule
  • Manage storage — PersistentVolumes, PersistentVolumeClaims, StorageClasses
  • View RBAC — roles, role bindings, service accounts

The Dashboard is not installed by default because it requires careful security configuration. An improperly secured Dashboard can expose your entire cluster to attackers.

The Tesla Lesson: Why Security Comes First

In 2018, Tesla’s cloud infrastructure was compromised through an unsecured Kubernetes Dashboard. The attackers gained access to an administrative console that was not password-protected, then used the cluster to mine cryptocurrency — running cryptomining workloads on Tesla’s cloud budget. Do not let that be you.

Most “how to install” guides stop at deployment, leaving the Dashboard in a dangerously exposed state. The Dashboard has full visibility into your cluster and, with the right permissions, can create, modify, and delete any resource.

The three non-negotiables before any team member accesses the Dashboard:

  1. Strong authentication — token-based or OIDC, never anonymous
  2. Granular RBAC — least privilege; not everyone needs cluster-admin
  3. Encrypted transport — HTTPS always, even on internal networks

Prerequisites

Before installing the Dashboard, ensure you have:

  • A running Kubernetes cluster — see our Install Kubernetes Cluster on Ubuntu 26.04 guide
  • kubectl configured and connected: kubectl cluster-info should succeed
  • helm v3+ installed (for Method 1)
  • Metrics Server installed (for resource usage visualization)

Verify cluster access:

kubectl get nodes
# All nodes should show Ready

kubectl cluster-info
# Kubernetes control plane is running at https://...

Method 1: Install via Helm (Recommended)

Helm offers more customization options than the raw manifest and is the recommended approach for production installations.

# Add the Kubernetes Dashboard Helm repository
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
helm repo update

# Install the Dashboard
helm upgrade --install kubernetes-dashboard \
  kubernetes-dashboard/kubernetes-dashboard \
  --create-namespace \
  --namespace kubernetes-dashboard \
  --set nginx.enabled=false \
  --set cert-manager.enabled=false \
  --set app.ingress.enabled=false

We disable the bundled nginx and cert-manager since most clusters already have these. Enable them if your cluster doesn’t:

# Alternative: enable bundled nginx ingress and cert-manager
helm upgrade --install kubernetes-dashboard \
  kubernetes-dashboard/kubernetes-dashboard \
  --create-namespace \
  --namespace kubernetes-dashboard

Verify installation:

kubectl get pods -n kubernetes-dashboard
# NAME                                         READY   STATUS    RESTARTS
# kubernetes-dashboard-api-xxx                 1/1     Running   0
# kubernetes-dashboard-auth-xxx                1/1     Running   0
# kubernetes-dashboard-kong-xxx                1/1     Running   0
# kubernetes-dashboard-metrics-scraper-xxx     1/1     Running   0
# kubernetes-dashboard-web-xxx                 1/1     Running   0

kubectl get svc -n kubernetes-dashboard

Method 2: Install via kubectl apply (Quick)

For a faster setup without Helm:

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

Verify:

kubectl get pods -n kubernetes-dashboard
kubectl get svc -n kubernetes-dashboard
# NAME                        TYPE        CLUSTER-IP     PORT(S)
# kubernetes-dashboard        ClusterIP   10.96.x.x      443/TCP
# dashboard-metrics-scraper   ClusterIP   10.96.x.x      8000/TCP

The Dashboard service is ClusterIP by default — only reachable from inside the cluster. Access methods are covered from Step 8 onward.

Create an Admin User and Service Account

The Dashboard needs a token to authenticate. Create service accounts with appropriate permissions.

Create the admin service account and bind it to cluster-admin:

# admin-user.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: admin-user
    namespace: kubernetes-dashboard

Apply it:

kubectl apply -f admin-user.yaml

Security note: cluster-admin grants full control over the entire cluster. Use this only for your personal admin account — for team members, create scoped roles (see Step 12). Never share the admin token.

Generate a Long-Lived Access Token

In Kubernetes 1.24+, service accounts no longer auto-generate permanent tokens. Create one explicitly:

# admin-user-token.yaml
apiVersion: v1
kind: Secret
metadata:
  name: admin-user-token
  namespace: kubernetes-dashboard
  annotations:
    kubernetes.io/service-account.name: "admin-user"
type: kubernetes.io/service-account-token
kubectl apply -f admin-user-token.yaml

Retrieve the token:

kubectl get secret admin-user-token \
  -n kubernetes-dashboard \
  -o jsonpath="{.data.token}" | base64 -d

Copy this token — you’ll use it to log into the Dashboard. Store it securely (password manager, not a text file on the desktop).

Alternative: Generate a short-lived token (for temporary access):

# Creates a token valid for 1 hour
kubectl create token admin-user \
  -n kubernetes-dashboard \
  --duration=3600s

Short-lived tokens are preferable when you don’t need persistent Dashboard access — they expire automatically, reducing exposure time if the token is accidentally shared.

Access Method 1: kubectl proxy (Local Development)

The simplest method for local development. Creates a secure tunnel from your machine to the cluster.

kubectl proxy
# Starting to serve on 127.0.0.1:8001

Open in your browser:

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

Pros: No additional setup, uses your kubeconfig authentication
Cons: Only accessible from the machine running the proxy — not suitable for team access or remote servers

Access Method 2: kubectl port-forward (Recommended for Teams)

Port forwarding creates a secure tunnel from your local machine directly to the Dashboard pod.

kubectl port-forward \
  -n kubernetes-dashboard \
  service/kubernetes-dashboard-kong-proxy \
  8443:443

Access at: https://localhost:8443

Your browser will warn about a self-signed certificate — this is expected. Accept the certificate and proceed. You’ll see the Dashboard login screen — paste the token from Step 7.

For Helm installation, find the correct service name:

kubectl get svc -n kubernetes-dashboard
# Find the service that exposes port 443
# Typically: kubernetes-dashboard-kong-proxy

kubectl port-forward \
  -n kubernetes-dashboard \
  service/kubernetes-dashboard-kong-proxy 8443:443

Make port-forward persistent (keep it running in background):

# Run in background with nohup
nohup kubectl port-forward \
  -n kubernetes-dashboard \
  service/kubernetes-dashboard-kong-proxy 8443:443 \
  > /tmp/dashboard-forward.log 2>&1 &

echo "Dashboard available at https://localhost:8443"

Pros: Secure (no ports exposed), works over SSH tunneling, uses cluster authentication
Cons: Requires kubectl access; must be re-run after interruption

Access Method 3: NodePort (Internal Network)

Expose the Dashboard on a fixed port on every cluster node — suitable for access within a trusted internal network:

# Patch the service to NodePort
kubectl patch svc kubernetes-dashboard \
  -n kubernetes-dashboard \
  -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30443}]}}'

Access at: https://<any-node-ip>:30443

For Helm installation, patch the kong-proxy service:

kubectl patch svc kubernetes-dashboard-kong-proxy \
  -n kubernetes-dashboard \
  -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30443}]}}'

Pros: Persistent access, no port-forward session needed
Cons: Exposed on all nodes; requires firewall to restrict access to trusted IPs only

Restrict port 30443 with UFW:

# Allow only from your office/home network
sudo ufw allow from 192.168.1.0/24 to any port 30443 comment "K8s Dashboard internal"
sudo ufw deny 30443
sudo ufw reload

Access Method 4: Ingress with TLS (Production)

For production access, deploy the Dashboard behind an Ingress controller with TLS certificates from cert-manager.

Prerequisites: An Ingress controller (nginx-ingress) and cert-manager installed in the cluster.

# dashboard-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kubernetes-dashboard-ingress
  namespace: kubernetes-dashboard
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
    # Rate limit to prevent brute force
    nginx.ingress.kubernetes.io/limit-rps: "10"
    # IP allowlist — restrict to your office/VPN IP range
    nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.1.0/24,10.0.0.0/8"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - dashboard.yourdomain.com
      secretName: dashboard-tls-cert
  rules:
    - host: dashboard.yourdomain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kubernetes-dashboard-kong-proxy
                port:
                  number: 443

Create a TLS certificate with cert-manager:

# dashboard-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: dashboard-tls
  namespace: kubernetes-dashboard
spec:
  secretName: dashboard-tls-cert
  dnsNames:
    - dashboard.yourdomain.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Apply both:

kubectl apply -f dashboard-certificate.yaml
kubectl apply -f dashboard-ingress.yaml

Access at: https://dashboard.yourdomain.com

The nginx.ingress.kubernetes.io/whitelist-source-range annotation is critical — it restricts Dashboard access to specific IP ranges at the ingress level, before a request even reaches the Dashboard pod. Even if someone knows the URL, they can’t reach the login page from an unauthorized IP.

Pros: Real domain, valid SSL certificate, accessible from anywhere on allowlisted IPs
Cons: Most complex setup; requires Ingress controller and cert-manager

Create Role-Based Users (Least Privilege)

Not everyone who needs Dashboard access needs cluster-admin. Create scoped service accounts for team members:

Read-only user for developers:

# readonly-user.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: readonly-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: dashboard-readonly
rules:
  - apiGroups: [""]
    resources:
      - pods
      - pods/log
      - services
      - endpoints
      - persistentvolumeclaims
      - configmaps
      - namespaces
      - nodes
      - events
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources:
      - deployments
      - replicasets
      - statefulsets
      - daemonsets
    verbs: ["get", "list", "watch"]
  - apiGroups: ["batch"]
    resources:
      - jobs
      - cronjobs
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: readonly-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: dashboard-readonly
subjects:
  - kind: ServiceAccount
    name: readonly-user
    namespace: kubernetes-dashboard
---
apiVersion: v1
kind: Secret
metadata:
  name: readonly-user-token
  namespace: kubernetes-dashboard
  annotations:
    kubernetes.io/service-account.name: "readonly-user"
type: kubernetes.io/service-account-token

Namespace-scoped user (can manage their own namespace only):

# namespace-user.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dev-team-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-team-binding
  namespace: development    # Scoped to 'development' namespace only
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: edit              # Built-in role: create/edit/delete most resources
subjects:
  - kind: ServiceAccount
    name: dev-team-user
    namespace: kubernetes-dashboard

Generate tokens for each user:

# Read-only user token
kubectl get secret readonly-user-token \
  -n kubernetes-dashboard \
  -o jsonpath="{.data.token}" | base64 -d

# Short-lived token for dev-team-user (expires in 8 hours)
kubectl create token dev-team-user \
  -n kubernetes-dashboard \
  --duration=28800s

Distribute separate tokens to separate team members — this way you can revoke one person’s access without affecting others.

Security Hardening Checklist

The default Dashboard installation is not secure. Configure these controls before granting any team member access.

Authentication:

  • [ ] Never use --enable-skip-login flag in production — this allows login without a token
  • [ ] Never use --insecure-port — Dashboard should always serve over HTTPS
  • [ ] Use short-lived tokens for temporary access; long-lived tokens only for service accounts
  • [ ] Rotate long-lived tokens regularly — delete and recreate the Secret

Authorization:

  • [ ] Only one or two people have cluster-admin binding
  • [ ] All other users have scoped roles (read-only or namespace-limited)
  • [ ] Review all ClusterRoleBindings: kubectl get clusterrolebindings -o wide | grep dashboard

Network access:

  • [ ] Dashboard never exposed directly to the public internet without IP allowlisting
  • [ ] Use port-forward or a VPN for personal access
  • [ ] If using NodePort or Ingress, restrict with ufw or nginx whitelist-source-range
  • [ ] Consider access via SSH tunnel only for maximum security: ssh -L 8443:localhost:8443 user@k8s-server

Transport:

  • [ ] Always HTTPS — never HTTP except through kubectl proxy (which uses the API server’s own TLS)
  • [ ] Self-signed certs are acceptable for internal access; use proper certs (cert-manager + Let’s Encrypt) for any browser access without certificate warnings

Monitoring:

  • [ ] Enable Kubernetes audit logging to track Dashboard actions
  • [ ] Alert on any ClusterRoleBinding creation involving the Dashboard namespace

Dashboard Overview: Key Features

Once logged in with the admin token, the Dashboard shows:

Workloads section:

  • Deployments — rollout status, pod counts, restart history
  • Pods — live status, node placement, resource usage, log streaming
  • StatefulSets, DaemonSets, Jobs, CronJobs — all visible and manageable

Cluster section:

  • Nodes — CPU/memory capacity and allocation, conditions
  • Namespaces — overview of all namespaces
  • Persistent Volumes — storage classes and claim status

Config section:

  • ConfigMaps and Secrets — view (not decode) secret names and metadata
  • Resource Quotas and Limit Ranges — per-namespace resource constraints

Quick actions directly from the UI:

  • Scale a Deployment (change replica count)
  • Roll back a Deployment to a previous revision
  • Delete a stuck Pod (to trigger rescheduling)
  • Exec into a running container (terminal in browser)
  • View real-time logs across multiple containers

The resource usage graphs — showing CPU and memory per pod and node — only populate when the Metrics Server is installed. See our Kubernetes cluster guide for Metrics Server installation steps.

Common Issues and Quick Fixes

SymptomLikely CauseFix
Dashboard login page shows but token rejectedToken from wrong service account, or expiredRegenerate token: kubectl create token admin-user -n kubernetes-dashboard
Dashboard pods not startingInsufficient resources on nodesCheck kubectl describe pod -n kubernetes-dashboard; verify node has capacity
kubectl proxy works but browser shows “not found”Wrong URL pathUse exact URL: .../services/https:kubernetes-dashboard:/proxy/ (note https:)
Port-forward disconnects frequentlyNetwork timeout or idle connectionUse --pod-running-timeout=5m flag; restart port-forward
Self-signed cert warning in browserDashboard uses self-signed cert by defaultAccept the warning for internal use; use cert-manager + Let’s Encrypt for production
Metrics not showing (CPU/memory)Metrics Server not installedInstall Metrics Server (see kubeadm install guide)
NodePort not accessibleFirewall blocking port 30443Check UFW: sudo ufw status; add allow rule for your IP
Dashboard shows “Unauthorized” after loginToken lacks required RBAC permissionsVerify ClusterRoleBinding is created correctly

Kubernetes Dashboard vs KubeSphere: Which to Use

Kubernetes DashboardKubeSphere
InstallationSimple (single kubectl apply or Helm)Complex (runs on top of K8s)
Resource usageMinimal (~100MB RAM)Heavy (~4GB RAM minimum)
Multi-tenancy❌ No✅ Yes (workspace isolation)
CI/CD built-in❌ No✅ Yes (Jenkins-based)
Monitoring built-inBasic (needs Metrics Server)✅ Full (Prometheus-based)
Log viewing✅ Per-pod log streaming✅ Centralized logs
App marketplace❌ No✅ Yes
Learning curveLowMedium
Best forQuick cluster visibility, individualsEnterprise multi-team environments

Use Kubernetes Dashboard when: you want quick visibility into a cluster without adding heavyweight dependencies, or for personal/single-team use.

Use KubeSphere when: you have multiple teams sharing a cluster and need workspace isolation, built-in CI/CD, and enterprise-grade observability. See our KubeSphere and Kubernetes Security guide for the full setup.

Next Steps

With the Kubernetes Dashboard running securely:

  • Harden your cluster — the Dashboard gives you visibility, but the underlying Kubernetes security still needs attention. Our KubeSphere and Kubernetes Security Hardening guide covers RBAC, Pod Security Standards, network policies, and secret encryption.
  • Add monitoring — install the Prometheus + Grafana monitoring stack alongside the Dashboard for metric-based alerting that the Dashboard alone doesn’t provide.
  • Centralize logs — the Dashboard streams individual pod logs, but for searching across all pods or setting log-based alerts, add Grafana Loki to your cluster.
  • Consider KubeSphere — if your team has grown to the point where per-user RBAC management in the Dashboard feels like overhead, KubeSphere’s workspace model handles multi-team access natively with a richer UI.
(Visited 3 times, 1 visits today)

You may also like