Files
homelab-manifests/headlamp-system/headlamp.yaml
T

390 lines
11 KiB
YAML

# =============================================================================
# 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.39.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