# ============================================================================= # Headlamp - Kubernetes Dashboard # Version: 0.39.0 # Namespace: headlamp-system # Domain: headlamp.dooplex.hu # Authentication: Authentik OIDC # ============================================================================= # # PREREQUISITES - Create in Authentik: # 1. Create OAuth2/OIDC Provider: # - Name: headlamp # - Authorization flow: default-provider-authorization-explicit-consent # - Client type: Confidential # - Client ID: headlamp (or auto-generated) # - Redirect URIs: https://headlamp.dooplex.hu/oidc-callback # - Scopes: email, openid, profile # - Signing Key: Select your certificate # # 2. Create Application: # - Name: Headlamp # - Slug: headlamp # - Provider: (select the provider created above) # - Launch URL: https://headlamp.dooplex.hu # # 3. Create the secret with OIDC credentials: # kubectl create secret generic headlamp-oidc -n headlamp-system \ # --from-literal=client-id='your-client-id' \ # --from-literal=client-secret='your-client-secret' # # NOTE: For full OIDC authentication to K8s API (user identity passed to k8s), # you need to configure k3s with OIDC flags. Add to /etc/rancher/k3s/config.yaml: # kube-apiserver-arg: # - "oidc-issuer-url=https://authentik.dooplex.hu/application/o/headlamp/" # - "oidc-client-id=headlamp" # - "oidc-username-claim=email" # - "oidc-groups-claim=groups" # Then restart k3s: sudo systemctl restart k3s # # After enabling API server OIDC, create ClusterRoleBinding for your user/group: # kubectl create clusterrolebinding oidc-cluster-admin \ # --clusterrole=cluster-admin \ # --user=your-email@example.com # # ============================================================================= --- apiVersion: v1 kind: Namespace metadata: name: headlamp-system labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp --- apiVersion: v1 kind: ServiceAccount metadata: name: headlamp namespace: headlamp-system labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp --- # ClusterRole for Headlamp to access cluster resources # This is a read-heavy role suitable for dashboard viewing apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: headlamp labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp rules: # Core resources - full access for management - apiGroups: [""] resources: - configmaps - endpoints - persistentvolumeclaims - pods - pods/log - pods/exec - replicationcontrollers - replicationcontrollers/scale - serviceaccounts - services - nodes - namespaces - events - secrets - resourcequotas - limitranges - persistentvolumes verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Apps resources - apiGroups: ["apps"] resources: - daemonsets - deployments - deployments/scale - replicasets - replicasets/scale - statefulsets - statefulsets/scale verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Batch resources - apiGroups: ["batch"] resources: - cronjobs - jobs verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Autoscaling - apiGroups: ["autoscaling"] resources: - horizontalpodautoscalers verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Networking - apiGroups: ["networking.k8s.io"] resources: - ingresses - networkpolicies - ingressclasses verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Storage - apiGroups: ["storage.k8s.io"] resources: - storageclasses - volumeattachments - csidrivers - csinodes verbs: ["get", "list", "watch"] # RBAC - apiGroups: ["rbac.authorization.k8s.io"] resources: - clusterroles - clusterrolebindings - roles - rolebindings verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Policy - apiGroups: ["policy"] resources: - poddisruptionbudgets - podsecuritypolicies verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # Certificates - apiGroups: ["certificates.k8s.io"] resources: - certificatesigningrequests verbs: ["get", "list", "watch"] # API extensions - apiGroups: ["apiextensions.k8s.io"] resources: - customresourcedefinitions verbs: ["get", "list", "watch"] # Metrics - apiGroups: ["metrics.k8s.io"] resources: - nodes - pods verbs: ["get", "list", "watch"] # Discovery - apiGroups: ["discovery.k8s.io"] resources: - endpointslices verbs: ["get", "list", "watch"] # Events - apiGroups: ["events.k8s.io"] resources: - events verbs: ["get", "list", "watch"] # Coordination - apiGroups: ["coordination.k8s.io"] resources: - leases verbs: ["get", "list", "watch"] # Node - apiGroups: ["node.k8s.io"] resources: - runtimeclasses verbs: ["get", "list", "watch"] # Scheduling - apiGroups: ["scheduling.k8s.io"] resources: - priorityclasses verbs: ["get", "list", "watch"] # Longhorn CRDs - apiGroups: ["longhorn.io"] resources: ["*"] verbs: ["get", "list", "watch"] # Cert-manager CRDs - apiGroups: ["cert-manager.io"] resources: ["*"] verbs: ["get", "list", "watch"] # ArgoCD CRDs - apiGroups: ["argoproj.io"] resources: ["*"] verbs: ["get", "list", "watch"] # CloudNativePG CRDs - apiGroups: ["postgresql.cnpg.io"] resources: ["*"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: headlamp labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: headlamp subjects: - kind: ServiceAccount name: headlamp namespace: headlamp-system --- apiVersion: v1 kind: ConfigMap metadata: name: headlamp-config namespace: headlamp-system labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp data: # Headlamp configuration # Note: OIDC settings are passed via environment variables config.yaml: | # Additional headlamp configuration can be placed here if needed --- apiVersion: apps/v1 kind: Deployment metadata: name: headlamp namespace: headlamp-system labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp app.kubernetes.io/version: "0.39.0" spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp template: metadata: labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp app.kubernetes.io/version: "0.39.0" spec: serviceAccountName: headlamp automountServiceAccountToken: true containers: - name: headlamp image: ghcr.io/headlamp-k8s/headlamp:v0.40.0 imagePullPolicy: IfNotPresent args: - "-in-cluster" - "-plugins-dir=/headlamp/plugins" env: # OIDC Configuration for Authentik - name: HEADLAMP_CONFIG_OIDC_CLIENT_ID valueFrom: secretKeyRef: name: headlamp-oidc key: client-id - name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET valueFrom: secretKeyRef: name: headlamp-oidc key: client-secret - name: HEADLAMP_CONFIG_OIDC_IDP_ISSUER_URL value: "https://authentik.dooplex.hu/application/o/headlamp/" - name: HEADLAMP_CONFIG_OIDC_SCOPES value: "openid,profile,email" ports: - name: http containerPort: 4466 protocol: TCP livenessProbe: httpGet: path: / port: http initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi volumeMounts: - name: plugins mountPath: /headlamp/plugins volumes: - name: plugins emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: headlamp namespace: headlamp-system labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp spec: type: ClusterIP ports: - name: http port: 80 targetPort: http protocol: TCP selector: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: headlamp namespace: headlamp-system labels: app.kubernetes.io/name: headlamp app.kubernetes.io/instance: headlamp annotations: cert-manager.io/cluster-issuer: letsencrypt-prod external-dns.alpha.kubernetes.io/hostname: headlamp.dooplex.hu,headlamp.home nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-buffer-size: "16k" nginx.ingress.kubernetes.io/proxy-buffers-number: "4" nginx.ingress.kubernetes.io/configuration-snippet: | set $geo_allowed 0; if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; } if ($remote_addr ~ "^10\.") { set $geo_allowed 1; } if ($geoip2_country_code = "HU") { set $geo_allowed 1; } if ($geo_allowed = 0) { return 403 "Access restricted to Hungary"; } # Homepage integration annotations gethomepage.dev/enabled: "true" gethomepage.dev/name: "Headlamp" gethomepage.dev/description: "Kubernetes Dashboard" gethomepage.dev/group: "Infrastructure" gethomepage.dev/icon: "headlamp.png" spec: ingressClassName: nginx-internal rules: - host: headlamp.dooplex.hu http: paths: - path: / pathType: Prefix backend: service: name: headlamp port: number: 80 - host: headlamp.home http: paths: - path: / pathType: Prefix backend: service: name: headlamp port: number: 80 tls: - hosts: - headlamp.dooplex.hu secretName: headlamp-tls