The Kubernetes Dashboard is a web-based UI that gives cluster operators a visual overview of workloads, services, namespaces, and resource utilization without dropping into kubectl for every task. On RHEL 8 with a running Kubernetes cluster, deploying the dashboard takes only a few kubectl commands. This tutorial covers installation, creating a service account with the necessary RBAC permissions, generating a bearer token for authentication, accessing the dashboard securely via kubectl proxy, and optionally exposing it externally through a NodePort or Ingress.

Prerequisites

  • RHEL 8 with Kubernetes installed (kubeadm cluster or equivalent) and kubectl configured
  • Cluster nodes in Ready state: kubectl get nodes
  • A default StorageClass or no persistent volume claims required (dashboard is stateless)
  • kubectl able to reach the API server: kubectl cluster-info
  • For external access: a working Ingress controller (e.g., ingress-nginx) or direct NodePort access

Step 1 — Deploy the Kubernetes Dashboard

Apply the official recommended manifest from the Kubernetes GitHub repository. This creates the kubernetes-dashboard namespace and deploys all required resources including the dashboard deployment, service, and RBAC objects.

# Deploy the latest stable Kubernetes Dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

# Watch the deployment roll out
kubectl -n kubernetes-dashboard rollout status deployment/kubernetes-dashboard

# Verify all pods are running
kubectl -n kubernetes-dashboard get pods

# List all resources created in the namespace
kubectl -n kubernetes-dashboard get all

Step 2 — Create an Admin Service Account

The dashboard ships with minimal RBAC permissions. Create a dedicated admin-user ServiceAccount and bind it to the built-in cluster-admin ClusterRole. Restrict this account to read-only access in production environments.

# Create the ServiceAccount
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
EOF

# Create the ClusterRoleBinding
cat <<'EOF' | kubectl apply -f -
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
EOF

# Verify the binding
kubectl get clusterrolebinding admin-user -o yaml

Step 3 — Generate a Bearer Token

Kubernetes 1.24+ removed automatic long-lived token secrets for ServiceAccounts. Use kubectl create token to generate a short-lived token. For a persistent token, create a Secret of type kubernetes.io/service-account-token.

# Generate a short-lived bearer token (valid 1 hour by default)
kubectl -n kubernetes-dashboard create token admin-user

# Generate a token with a custom expiry (e.g., 24 hours)
kubectl -n kubernetes-dashboard create token admin-user --duration=86400s

# For a non-expiring token (Kubernetes 1.24+), create a secret manually
cat <<'EOF' | kubectl apply -f -
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
EOF

# Retrieve the token from the secret
kubectl -n kubernetes-dashboard get secret admin-user-token 
  -o jsonpath="{.data.token}" | base64 --decode && echo

Step 4 — Access the Dashboard via kubectl proxy

kubectl proxy creates an authenticated tunnel from your local machine to the Kubernetes API server, making the dashboard available at a localhost URL without exposing it on the network. This is the safest access method for local administration.

# Start the proxy in the background
kubectl proxy &

# The dashboard is now accessible at:
# http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

# Test with curl (you will see an HTML redirect — open in browser)
curl -I http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

# On a headless RHEL 8 server, forward the port to your workstation via SSH
# Run this on your LOCAL workstation:
# ssh -L 8001:localhost:8001 user@rhel8-server
# Then open http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

# Stop the proxy
kill %1

Step 5 — Expose via NodePort for External Access

For environments where kubectl proxy is impractical, patch the dashboard service to type NodePort. The dashboard always enforces HTTPS; browsers will show a self-signed certificate warning that you must accept.

# Patch the service to NodePort
kubectl -n kubernetes-dashboard patch service kubernetes-dashboard 
  -p '{"spec":{"type":"NodePort"}}'

# Find the assigned NodePort
kubectl -n kubernetes-dashboard get service kubernetes-dashboard
# Look for a port mapping like 443:3XXXX/TCP

# Get a node IP
kubectl get nodes -o wide | awk 'NR>1 {print $6}'

# Open in browser (replace NODE_IP and NODE_PORT)
# https://NODE_IP:NODE_PORT

# Ensure the port is open in the RHEL 8 firewall
NODE_PORT=$(kubectl -n kubernetes-dashboard get service kubernetes-dashboard 
  -o jsonpath='{.spec.ports[0].nodePort}')
firewall-cmd --add-port=${NODE_PORT}/tcp --permanent
firewall-cmd --reload

Step 6 — Expose via Ingress with TLS

For production access, front the dashboard with an Ingress resource and a valid TLS certificate managed by cert-manager. This provides a proper hostname, avoids NodePort limitations, and enables access control at the Ingress layer.

# Create a TLS secret for the dashboard hostname
kubectl -n kubernetes-dashboard create secret tls dashboard-tls 
  --cert=/etc/ssl/dashboard.example.com/tls.crt 
  --key=/etc/ssl/dashboard.example.com/tls.key

# Create the Ingress resource
cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - dashboard.example.com
    secretName: dashboard-tls
  rules:
  - host: dashboard.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kubernetes-dashboard
            port:
              number: 443
EOF

# Verify the Ingress
kubectl -n kubernetes-dashboard get ingress
# Access at: https://dashboard.example.com

Conclusion

The Kubernetes Dashboard provides a convenient visual interface for monitoring workloads and resources, but it must be protected carefully. Always use kubectl proxy or an Ingress with TLS for access — never expose the dashboard over plain HTTP or with a wildcard ClusterRoleBinding in production. Short-lived tokens generated with kubectl create token are preferable to long-lived secret tokens, and you should audit RBAC bindings regularly to ensure the dashboard service account has only the permissions it genuinely needs. With these precautions in place, the dashboard is a powerful addition to any RHEL 8 Kubernetes environment.

Next steps: How to Install and Use Skopeo for Container Image Management on RHEL 8, How to Configure Docker Daemon TLS Encryption on RHEL 8, and How to Build Docker Images with Multi-Stage Builds on RHEL 8.