diff --git a/fleet/lib/netbox/README.md b/fleet/lib/netbox/README.md new file mode 100644 index 000000000..e7f56b0d7 --- /dev/null +++ b/fleet/lib/netbox/README.md @@ -0,0 +1,59 @@ +# NetBox Kubernetes Deployment + +## Overview + +NetBox is an Infrastructure Resource Modeling (IRM) application designed to empower network automation. This deployment provides a production-ready NetBox instance on Kubernetes using Helm charts and Fleet configuration management. + +## Architecture + +- **Chart**: netbox v6.1.5 from +- **Namespace**: netbox +- **Components**: Web application, worker processes, PostgreSQL database, Valkey cache +- **Ingress**: NGINX with Let's Encrypt TLS certificates + +## Configuration + +### Core Settings + +- **Timezone**: America/Santiago +- **Superuser**: +- **Change Log Retention**: 90 days +- **Job Retention**: 90 days +- **GraphQL**: Enabled +- **Login Required**: False + +### Security + +- Non-root container execution (UID/GID: 1000) +- Read-only root filesystem +- Dropped capabilities +- Runtime security profile enabled +- External secret management via Kubernetes secrets + +### Storage + +- **Persistence**: Disabled (ephemeral storage) +- **PostgreSQL**: 20Gi persistent storage (rook-ceph-block) +- **Media/Reports/Scripts**: Stored in ephemeral volumes + +### Resources + +| Component | CPU Request | Memory Request | CPU Limit | Memory Limit | +|-----------|-------------|----------------|-----------|--------------| +| NetBox | 500m | 1Gi | 1000m | 2Gi | +| Worker | 500m | 1Gi | 1000m | 2Gi | +| PostgreSQL| 250m | 512Mi | 500m | 1Gi | + +## Access + +NetBox is accessible via dynamically generated hostnames based on cluster configuration: + +```bash +https://netbox.{cluster-name}.{site}.lsst.org +``` + +## Maintenance + +- **Housekeeping**: Daily automated cleanup (00:00 UTC) +- **Job History**: 5 successful/failed jobs retained +- **Monitoring**: Available via cluster monitoring stack diff --git a/fleet/lib/netbox/base/externalsecret-netbox-keycloak.yaml b/fleet/lib/netbox/base/externalsecret-netbox-keycloak.yaml new file mode 100644 index 000000000..d33fc204e --- /dev/null +++ b/fleet/lib/netbox/base/externalsecret-netbox-keycloak.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: netbox-keycloak + namespace: netbox +spec: + secretStoreRef: + kind: ClusterSecretStore + name: onepassword + target: + name: netbox-keycloak + creationPolicy: Owner + data: + - secretKey: SOCIAL_AUTH_KEYCLOAK_KEY + remoteRef: + key: &item netbox-keycloak-sso + property: client-id + - secretKey: SOCIAL_AUTH_KEYCLOAK_SECRET + remoteRef: + key: *item + property: client-secret diff --git a/fleet/lib/netbox/base/externalsecret-netbox-postgresql.yaml b/fleet/lib/netbox/base/externalsecret-netbox-postgresql.yaml new file mode 100644 index 000000000..6a137bb18 --- /dev/null +++ b/fleet/lib/netbox/base/externalsecret-netbox-postgresql.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: netbox-postgresql + namespace: netbox +spec: + secretStoreRef: + kind: ClusterSecretStore + name: onepassword + target: + name: netbox-postgresql + creationPolicy: Owner + data: + - secretKey: password + remoteRef: + key: &item netbox-postgresql + property: password + - secretKey: postgres-password + remoteRef: + key: *item + property: postgres-password diff --git a/fleet/lib/netbox/base/externalsecret-netbox-secrets.yaml b/fleet/lib/netbox/base/externalsecret-netbox-secrets.yaml new file mode 100644 index 000000000..a6e25c74d --- /dev/null +++ b/fleet/lib/netbox/base/externalsecret-netbox-secrets.yaml @@ -0,0 +1,33 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: netbox-secrets + namespace: netbox +spec: + secretStoreRef: + kind: ClusterSecretStore + name: onepassword + target: + name: netbox-secrets + creationPolicy: Owner + data: + - secretKey: username + remoteRef: + key: &item netbox-secrets + property: username + - secretKey: password + remoteRef: + key: *item + property: password + - secretKey: email + remoteRef: + key: *item + property: email + - secretKey: api_token + remoteRef: + key: *item + property: apiToken + - secretKey: secret-key + remoteRef: + key: *item + property: secretKey diff --git a/fleet/lib/netbox/base/externalsecret-netbox-valkey.yaml b/fleet/lib/netbox/base/externalsecret-netbox-valkey.yaml new file mode 100644 index 000000000..e91338163 --- /dev/null +++ b/fleet/lib/netbox/base/externalsecret-netbox-valkey.yaml @@ -0,0 +1,17 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: netbox-valkey + namespace: netbox +spec: + secretStoreRef: + kind: ClusterSecretStore + name: onepassword + target: + name: netbox-valkey + creationPolicy: Owner + data: + - secretKey: valkey-password + remoteRef: + key: &item netbox-valkey + property: password diff --git a/fleet/lib/netbox/base/kustomization.yaml b/fleet/lib/netbox/base/kustomization.yaml new file mode 100644 index 000000000..3aaa5138a --- /dev/null +++ b/fleet/lib/netbox/base/kustomization.yaml @@ -0,0 +1,12 @@ +--- +resources: + - externalsecret-netbox-secrets.yaml + - externalsecret-netbox-valkey.yaml + - externalsecret-netbox-postgresql.yaml + - externalsecret-netbox-keycloak.yaml + +patches: + - path: netbox-plugin-init-patch.yaml + target: + kind: Deployment + name: netbox diff --git a/fleet/lib/netbox/base/netbox-plugin-init-patch.yaml b/fleet/lib/netbox/base/netbox-plugin-init-patch.yaml new file mode 100644 index 000000000..0d1aa42a2 --- /dev/null +++ b/fleet/lib/netbox/base/netbox-plugin-init-patch.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: netbox +spec: + template: + spec: + # Add shared volume for plugins + volumes: + - name: plugins-volume + emptyDir: {} + # Init container to install slurpit_netbox plugin + initContainers: + - name: install-plugins + image: python:3.11-slim + command: + - /bin/bash + - -c + - | + set -e + echo "Installing slurpit_netbox plugin..." + + # Install pip if not available + python -m ensurepip --upgrade + + # Install the slurpit_netbox plugin to shared volume + pip install --target /opt/plugins slurpit_netbox + + echo "Plugin installation completed" + ls -la /opt/plugins/ + volumeMounts: + - name: plugins-volume + mountPath: /opt/plugins + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + containers: + - name: netbox + # Mount the plugins volume + volumeMounts: + - name: plugins-volume + mountPath: /opt/netbox/plugins + # Update PYTHONPATH to include plugins directory + env: + - name: PYTHONPATH + value: "/opt/netbox/plugins:/opt/netbox" \ No newline at end of file diff --git a/fleet/lib/netbox/fleet.yaml b/fleet/lib/netbox/fleet.yaml new file mode 100644 index 000000000..fc970ed7d --- /dev/null +++ b/fleet/lib/netbox/fleet.yaml @@ -0,0 +1,17 @@ +--- +defaultNamespace: &name netbox +labels: + bundle: *name +namespaceLabels: + lsst.io/discover: "true" +kustomize: + dir: base +helm: + chart: &chart netbox + releaseName: *chart + repo: https://charts.netbox.oss.netboxlabs.com/ + version: 6.1.5 + timeoutSeconds: 600 + waitForJobs: true + valuesFiles: + - values.yaml diff --git a/fleet/lib/netbox/values.yaml b/fleet/lib/netbox/values.yaml new file mode 100644 index 000000000..edae054f6 --- /dev/null +++ b/fleet/lib/netbox/values.yaml @@ -0,0 +1,205 @@ +nameOverride: netbox +clusterDomain: cluster.local + +superuser: + name: admin + email: admin@lsst.org + existingSecret: netbox-secrets + + +allowedHosts: + - netbox.${ get .ClusterLabels "management.cattle.io/cluster-display-name" }.${ .ClusterLabels.site }.lsst.org + - netbox.kueyen.dev.lsst.org + +allowedHostsIncludesPodIP: false + +admins: + - [Admin User, admin@tudominio.com] + +internalIPs: [127.0.0.1] + +timeZone: America/Santiago + +# Disable persistent volumes to avoid multi-attach issues with ReadWriteOnce storage +# Media files will be stored in ephemeral storage +persistence: + enabled: false + # storageClass: rook-ceph-block + # accessMode: ReadWriteOnce + # size: 10Gi + # annotations: {} + +reportsPersistence: + enabled: false + # storageClass: rook-ceph-block + # accessMode: ReadWriteOnce + # size: 1Gi + # annotations: {} + +scriptsPersistence: + enabled: false + # storageClass: rook-ceph-block + # accessMode: ReadWriteOnce + # size: 1Gi + # annotations: {} + +resourcesPreset: medium +resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: 1000m + memory: 2Gi + +## @section Traffic Exposure Parameters + +ingress: + enabled: true + className: nginx + annotations: + cert-manager.io/cluster-issuer: letsencrypt + nginx.ingress.kubernetes.io/backend-protocol: HTTP + nginx.ingress.kubernetes.io/client-body-buffer-size: 10m + nginx.ingress.kubernetes.io/proxy-read-timeout: "60" + nginx.ingress.kubernetes.io/proxy-send-timeout: "60" + hosts: + - host: netbox.${ get .ClusterLabels "management.cattle.io/cluster-display-name" }.${ .ClusterLabels.site }.lsst.org + paths: + - / + tls: + - secretName: netbox-tls + hosts: + - netbox.${ get .ClusterLabels "management.cattle.io/cluster-display-name" }.${ .ClusterLabels.site }.lsst.org + +postgresql: + enabled: true + # Use default PostgreSQL version from chart (bitnami image tags are inconsistent) + auth: + username: netbox + database: netbox + # Dummy passwords - these are overridden by existingSecret + # Required by Bitnami chart to prevent upgrade errors + password: "unused" + postgresPassword: "unused" + existingSecret: netbox-postgresql + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + # Use external secret passwords for consistency + usePasswordFiles: false + # Ensure PostgreSQL is ready before Netbox starts + primary: + persistence: + enabled: true + storageClass: rook-ceph-block + size: 20Gi + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + # Prevent automatic restarts during upgrades + podDisruptionBudget: + create: true + minAvailable: 1 + # Use RollingUpdate strategy (Recreate is not valid for StatefulSets) + updateStrategy: + type: RollingUpdate + # Global PostgreSQL configuration to prevent credential mismatch + global: + postgresql: + auth: + # Dummy passwords - overridden by existingSecret + password: "unused" + postgresPassword: "unused" + existingSecret: netbox-postgresql + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + # Disable automatic version upgrades + upgradeRepmgrExtension: false + +valkey: + enabled: true + auth: + existingSecret: netbox-valkey + existingSecretPasswordKey: valkey-password + +## @section Worker for Netbox parameters + +worker: + enabled: true + replicaCount: 1 + # Fix kubectl image version - 1.33.3 doesn't exist + initContainer: + image: + registry: docker.io + repository: bitnami/kubectl + tag: 1.31-debian-12 + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: 1000m + memory: 2Gi + +## @section Cron housekeeping job parameters + +housekeeping: + enabled: true + schedule: 0 0 * * * + successfulJobsHistoryLimit: 5 + failedJobsHistoryLimit: 5 + resourcesPreset: medium + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: 1000m + memory: 2Gi + +# Database configuration using external secrets +extraEnvs: + - name: DB_WAIT_DEBUG + value: "1" + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: netbox-secrets + key: secret-key + - name: SOCIAL_AUTH_KEYCLOAK_KEY + valueFrom: + secretKeyRef: + name: netbox-keycloak + key: SOCIAL_AUTH_KEYCLOAK_KEY + - name: SOCIAL_AUTH_KEYCLOAK_SECRET + valueFrom: + secretKeyRef: + name: netbox-keycloak + key: SOCIAL_AUTH_KEYCLOAK_SECRET + - name: SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL + value: "https://keycloak.ls.lsst.org/realms/master/protocol/openid-connect/auth" + - name: SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL + value: "https://keycloak.ls.lsst.org/realms/master/protocol/openid-connect/token" + - name: SOCIAL_AUTH_KEYCLOAK_ID_KEY + value: "preferred_username" + + +# Plugin configuration +plugins: [] + +## @section Remote Authentication (SSO) Parameters + +remoteAuth: + enabled: true + backends: + - social_core.backends.keycloak.KeycloakOAuth2 + +# All Keycloak configuration is now done via environment variables in extraEnvs +# NetBox will automatically read SOCIAL_AUTH_* environment variables + diff --git a/fleet/s/dev/c/kueyen/netbox b/fleet/s/dev/c/kueyen/netbox new file mode 120000 index 000000000..ccfcf159f --- /dev/null +++ b/fleet/s/dev/c/kueyen/netbox @@ -0,0 +1 @@ +../../../../lib/netbox \ No newline at end of file