Establish clean homelab infrastructure baseline
Reorganize the brownfield repository, remove retired and generated artifacts, harden ignore rules, and record the GitOps/IaC redesign.
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
# NetBox — IPAM + DCIM, candidate "source of truth for network facts".
|
||||
# THIS IS AN EVALUATION DEPLOYMENT (see CONTEXT.md §1: adoption is not decided).
|
||||
# Nothing else in the repo reads from NetBox yet; it is safe to delete outright.
|
||||
#
|
||||
# Chart: netbox/netbox 8.3.38 (app v4.6.5)
|
||||
# helm repo add netbox https://netbox-community.github.io/netbox-chart/
|
||||
#
|
||||
# Shape mirrors the other k3s services here: external shared Postgres, private
|
||||
# exposure over the Tailscale ingress, authentication delegated to Authelia OIDC.
|
||||
|
||||
# Pin the app image; the chart default matches but drifts on every chart bump.
|
||||
image:
|
||||
tag: v4.6.5
|
||||
|
||||
# --- Local break-glass superuser -------------------------------------------
|
||||
# Deliberately kept, exactly like Grafana's local admin: NetBox's SSO group->
|
||||
# superuser mapping does not exist (that feature is LDAP-only, see README), so
|
||||
# the first SSO login lands as an ordinary user and needs promoting BY someone.
|
||||
# Password is generated by the chart and preserved in the netbox-superuser Secret.
|
||||
superuser:
|
||||
name: admin
|
||||
email: [email protected]
|
||||
|
||||
# NetBox refuses writes via any hostname not listed here. The pod IP is appended
|
||||
# automatically (allowedHostsIncludesPodIP) for the k8s probes.
|
||||
allowedHosts:
|
||||
- netbox.ad.ddupan.top
|
||||
- netbox.netbox.svc.cluster.local
|
||||
- localhost
|
||||
|
||||
# Envoy terminates TLS and forwards plain HTTP, so Django sees an http:// request
|
||||
# carrying an https:// Origin header. Without this, every POST (including the login
|
||||
# form) fails CSRF verification — it presents as "login is broken", not "config is
|
||||
# missing". Same requirement behind any TLS-terminating proxy.
|
||||
csrf:
|
||||
trustedOrigins:
|
||||
- https://netbox.ad.ddupan.top
|
||||
|
||||
# It is an infrastructure source of truth on a private tailnet, but "on the
|
||||
# tailnet" is not authentication — require a login for read access too.
|
||||
#
|
||||
# This logs a benign FutureWarning at startup ("LOGIN_REQUIRED is deprecated ...
|
||||
# can be removed from your configuration file"): NetBox v5.0 drops the setting and
|
||||
# makes login mandatory, i.e. true is the direction of travel. The warning is
|
||||
# unavoidable via this chart — the ConfigMap always emits the key, and NetBox warns
|
||||
# on false as well ("unauthenticated access will no longer be supported").
|
||||
loginRequired: true
|
||||
|
||||
# Everything else in this homelab is UTC (the node is Etc/UTC); stay consistent
|
||||
# so timestamps line up with VictoriaLogs.
|
||||
timeZone: UTC
|
||||
|
||||
# Version check phones home to api.github.com. The WAN flaps (CONTEXT.md §6) and
|
||||
# a blocking outbound call on page render is exactly what we don't want.
|
||||
releaseCheck:
|
||||
url: ""
|
||||
|
||||
# --- Authentication: Authelia forward-auth (trusted headers) --------------
|
||||
# Authelia authenticates + enforces 2FA at the GATEWAY (securitypolicy.yaml); by the
|
||||
# time a request arrives here it is already authenticated, and Envoy has attached
|
||||
# Remote-* headers describing who the user is.
|
||||
#
|
||||
# WHY NOT OIDC (which this used to be): NetBox has NO SSO group -> role mapping.
|
||||
# REMOTE_AUTH_SUPERUSER_GROUPS and AUTH_LDAP_USER_FLAGS_BY_GROUP are LDAP-only; the
|
||||
# social-auth pipeline only runs user_default_groups_handler, so an OIDC user landed
|
||||
# as an ordinary member of one static group and had to be promoted BY HAND, and AD
|
||||
# group changes never propagated. With header auth, REMOTE_AUTH_GROUP_SYNC_ENABLED
|
||||
# re-evaluates group membership on EVERY request — the same declarative AD-group
|
||||
# pattern already used by Grafana and Proxmox.
|
||||
#
|
||||
# ⚠⚠ THIS SETTING IS ONLY SAFE BEHIND THE GATEWAY. RemoteUserBackend trusts the
|
||||
# header unconditionally — NetBox has no trusted-proxy allowlist. Two things keep
|
||||
# that honest, and BOTH must stay true:
|
||||
# 1. Envoy sets these headers from Authelia's response, and Envoy Gateway's
|
||||
# headersToBackend OVERRIDES any client-supplied value ("coexisting headers
|
||||
# will be overridden"), so a spoofed Remote-User cannot survive the hop.
|
||||
# 2. networkpolicy.yaml restricts pod ingress to the gateway namespace, so nothing
|
||||
# in-cluster can bypass Envoy and talk to :8080 directly.
|
||||
# Removing either one turns `Remote-User: admin` into an instant superuser.
|
||||
remoteAuth:
|
||||
enabled: true
|
||||
backends:
|
||||
- netbox.authentication.RemoteUserBackend
|
||||
# Authelia's header names. NetBox's defaults assume HTTP_REMOTE_USER_GROUP, but
|
||||
# Authelia emits Remote-Groups -> HTTP_REMOTE_GROUPS, and joins values with a
|
||||
# COMMA where NetBox defaults to "|". Both must be overridden or group sync
|
||||
# silently yields one group literally named "a,b,c".
|
||||
header: HTTP_REMOTE_USER
|
||||
groupHeader: HTTP_REMOTE_GROUPS
|
||||
groupSeparator: ","
|
||||
# Authelia sends Remote-Email and Remote-Name (a single display name); it has no
|
||||
# split given/family name, so the first/last-name headers are left unmapped.
|
||||
userEmail: HTTP_REMOTE_EMAIL
|
||||
autoCreateUser: true
|
||||
autoCreateGroups: true # mirror AD groups into NetBox groups as they appear
|
||||
groupSyncEnabled: true # re-evaluate membership on every request
|
||||
# AD group -> NetBox role. Managed in ../../infrastructure/samba-ad (samba_ad_groups).
|
||||
superuserGroups:
|
||||
- netbox-admins
|
||||
staffGroups:
|
||||
- netbox-admins # is_staff => access to the Django admin site
|
||||
|
||||
# The OIDC client config that used to live here (SOCIAL_AUTH_OIDC_*) is gone; the
|
||||
# netbox-secrets Secret now only carries the database password.
|
||||
extraConfig: []
|
||||
|
||||
# --- Postgres: the shared CNPG cluster ------------------------------------
|
||||
# Dedicated role + database, no shared superuser — same as Authelia and Gitea.
|
||||
postgresql:
|
||||
enabled: false
|
||||
externalDatabase:
|
||||
host: shared-postgresql-rw.shared-db.svc.cluster.local
|
||||
port: 5432
|
||||
database: netbox
|
||||
username: netbox
|
||||
existingSecretName: netbox-secrets
|
||||
existingSecretKey: postgresql-password
|
||||
|
||||
# --- Valkey (Redis) for the RQ task queue + caching -----------------------
|
||||
# Bundled subchart rather than a shared instance: nothing else in the cluster
|
||||
# runs Redis, and NetBox wants two logical databases of its own.
|
||||
#
|
||||
# ⚠ Bitnami's public catalog no longer serves versioned tags (only `latest`,
|
||||
# versioned images moved to the `bitnamilegacy` repo), which is why the chart
|
||||
# ships `tag: latest`. `latest` is not reproducible, so pin the DIGEST instead —
|
||||
# resolved 2026-07-25 for bitnami/valkey:latest.
|
||||
valkey:
|
||||
image:
|
||||
digest: sha256:5d43ca8bb57aa263ef78d1684dbf1e4b4f63844727eafdd5ea2b0e102a25b141
|
||||
# Single node: the chart default is primary+replica, which buys nothing here
|
||||
# (one k8s node, no HA anywhere in this cluster — CONTEXT.md §6).
|
||||
architecture: standalone
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: localpv-zfs-ceph
|
||||
size: 1Gi
|
||||
resourcesPreset: micro
|
||||
|
||||
# --- Storage --------------------------------------------------------------
|
||||
# Media = uploaded images/attachments only; the real data is in Postgres.
|
||||
#
|
||||
# ⚠ NOT localpv-zfs-ceph, unlike every other PVC here. The chart mounts this ONE
|
||||
# RWO claim into BOTH Deployments (web and worker — the worker writes files the web
|
||||
# serves), and the OpenEBS ZFS class provisions a **zvol**: a block device with xfs
|
||||
# on it, which cannot be mounted twice. Whichever pod won the race mounted it and
|
||||
# the other stuck in Init forever with
|
||||
# verifyMount: device already mounted at [...]
|
||||
# from the CSI node plugin. local-path is hostPath-based, so kubelet can bind-mount
|
||||
# the same directory into both pods. (localpv-zfs-ceph stays correct for the valkey
|
||||
# PVC below — single StatefulSet pod, no sharing.)
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: local-path
|
||||
size: 2Gi
|
||||
|
||||
# --- LAN exposure via the Contour gateway ---------------------------------
|
||||
# https://netbox.ad.ddupan.top — reachable from any LAN host, no Tailscale client
|
||||
# needed, and it does not traverse the WAN. Deliberately NOT on the cloudflared
|
||||
# tunnel: a full inventory of the network is not something to publish.
|
||||
#
|
||||
# Gateway API, not Ingress. The shared gateway lives in ../../platform/envoy-gateway and already
|
||||
# terminates TLS with the *.ad.ddupan.top wildcard from ../../platform/cert-manager — so this
|
||||
# service needs no cert of its own, just this route plus a DNS A record on the DC
|
||||
# (../../infrastructure/samba-ad). Authentication is enforced at the gateway by the SecurityPolicy in
|
||||
# securitypolicy.yaml, before a request ever reaches this pod.
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
httpRoute:
|
||||
enabled: true
|
||||
parentRefs:
|
||||
- name: eg
|
||||
namespace: envoy-gateway-system
|
||||
sectionName: https # the :443 listener; :80 is for ACME/redirects only
|
||||
hostnames:
|
||||
- netbox.ad.ddupan.top
|
||||
|
||||
# --- Resource budget ------------------------------------------------------
|
||||
# The laptop is the single k3s node and already runs everything (CONTEXT.md §6);
|
||||
# at survey time it had ~4 GiB RAM headroom. Keep this deployment modest.
|
||||
resourcesPreset: medium # 500m/1Gi requests, 750m/1.5Gi limits
|
||||
|
||||
worker:
|
||||
resourcesPreset: small # 500m/512Mi requests — one worker, no bulk jobs yet
|
||||
|
||||
# Nightly changelog/job pruning. Retentions are the chart defaults (90 days).
|
||||
housekeeping:
|
||||
enabled: true
|
||||
schedule: "17 4 * * *"
|
||||
Reference in New Issue
Block a user