From ec6ffc9a762363f1a46af4f813e6dac9de00b0fb Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 1 Jan 2026 11:27:51 +0100 Subject: [PATCH] added headlamp --- argocd-apps/homelab.yaml | 22 ++ headlamp-system/headlamp.yaml | 381 ++++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 headlamp-system/headlamp.yaml diff --git a/argocd-apps/homelab.yaml b/argocd-apps/homelab.yaml index 693cb48..108a89c 100644 --- a/argocd-apps/homelab.yaml +++ b/argocd-apps/homelab.yaml @@ -636,3 +636,25 @@ spec: - CreateNamespace=true - PruneLast=true --- +# Headlamp +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: headlamp + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: homelab + source: + repoURL: https://gitea.dooplex.hu/admin/homelab-manifests.git + targetRevision: main + path: headlamp-system + destination: + server: https://kubernetes.default.svc + namespace: headlamp-system + syncPolicy: + syncOptions: + - CreateNamespace=true + - PruneLast=true +--- diff --git a/headlamp-system/headlamp.yaml b/headlamp-system/headlamp.yaml new file mode 100644 index 0000000..9b6fb59 --- /dev/null +++ b/headlamp-system/headlamp.yaml @@ -0,0 +1,381 @@ +# ============================================================================= +# 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" + # 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