From 2ec1471d7fb1483bf1753e93b3971ce5a2df583c Mon Sep 17 00:00:00 2001
From: June <june@jsts.xyz>
Date: Sat, 15 Feb 2025 19:57:15 +0100
Subject: [PATCH] netbox: move NetBox from NixOS to Ansible

Also introduce netbox_hosts group for applying netbox role to multiple
hosts.
---
 inventories/chaosknoten/host_vars/netbox.yaml | 16 +++++
 inventories/chaosknoten/hosts.yaml            | 12 ++++
 playbooks/deploy.yaml                         |  5 ++
 .../netbox/netbox/configuration.py.j2         | 60 +++++++++++++++++++
 .../netbox/nginx/netbox.hamburg.ccc.de.conf   | 48 +++++++++++++++
 .../nginx/acme_challenge.conf                 |  2 +-
 .../public-reverse-proxy/nginx/nginx.conf     |  2 +-
 7 files changed, 143 insertions(+), 2 deletions(-)
 create mode 100644 inventories/chaosknoten/host_vars/netbox.yaml
 create mode 100644 resources/chaosknoten/netbox/netbox/configuration.py.j2
 create mode 100644 resources/chaosknoten/netbox/nginx/netbox.hamburg.ccc.de.conf

diff --git a/inventories/chaosknoten/host_vars/netbox.yaml b/inventories/chaosknoten/host_vars/netbox.yaml
new file mode 100644
index 0000000..2304112
--- /dev/null
+++ b/inventories/chaosknoten/host_vars/netbox.yaml
@@ -0,0 +1,16 @@
+netbox__version: "v4.1.7"
+netbox__db_password: "{{ lookup('community.general.passwordstore', 'noc/vm-secrets/chaosknoten/netbox/DATABASE_PASSWORD', create=false, missing='error') }}"
+netbox__config: "{{ lookup('ansible.builtin.template', 'resources/chaosknoten/netbox/netbox/configuration.py.j2') }}"
+netbox__custom_pipeline_oidc_group_and_role_mapping: true
+
+nginx__version_spec: ""
+nginx__configurations:
+  - name: netbox.hamburg.ccc.de
+    content: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/netbox/nginx/netbox.hamburg.ccc.de.conf') }}"
+
+certbot__version_spec: ""
+certbot__acme_account_email_address: j+letsencrypt-ccchh@jsts.xyz
+certbot__certificate_domains:
+  - "netbox.hamburg.ccc.de"
+certbot__new_cert_commands:
+  - "systemctl reload nginx.service"
diff --git a/inventories/chaosknoten/hosts.yaml b/inventories/chaosknoten/hosts.yaml
index 911a87d..0f10bea 100644
--- a/inventories/chaosknoten/hosts.yaml
+++ b/inventories/chaosknoten/hosts.yaml
@@ -32,6 +32,10 @@ all:
         mumble:
           ansible_host: mumble.hamburg.ccc.de
           ansible_user: chaos
+        netbox:
+          ansible_host: netbox-intern.hamburg.ccc.de
+          ansible_user: chaos
+          ansible_ssh_common_args: -J ssh://chaos@public-reverse-proxy.hamburg.ccc.de
         onlyoffice:
           ansible_host: onlyoffice-intern.hamburg.ccc.de
           ansible_user: chaos
@@ -64,6 +68,7 @@ all:
         keycloak:
         lists:
         mumble:
+        netbox:
         onlyoffice:
         pad:
         pretalx:
@@ -94,6 +99,7 @@ all:
         keycloak:
         lists:
         mumble:
+        netbox:
         onlyoffice:
         pad:
         pretalx:
@@ -112,6 +118,7 @@ all:
         keycloak:
         lists:
         mumble:
+        netbox:
         onlyoffice:
         pad:
         pretalx:
@@ -123,6 +130,7 @@ all:
         eh22-wiki:
         tickets:
         keycloak:
+        netbox:
         onlyoffice:
         pad:
         pretalx:
@@ -136,6 +144,7 @@ all:
         tickets:
         cloud:
         keycloak:
+        netbox:
         onlyoffice:
         pad:
         pretalx:
@@ -146,3 +155,6 @@ all:
       hosts:
         eh22-wiki:
         wiki:
+    netbox_hosts:
+      hosts:
+        netbox:
diff --git a/playbooks/deploy.yaml b/playbooks/deploy.yaml
index da2937f..66f03de 100644
--- a/playbooks/deploy.yaml
+++ b/playbooks/deploy.yaml
@@ -29,6 +29,11 @@
   roles:
     - dokuwiki
 
+- name: Ensure NetBox deployment on netbox_hosts
+  hosts: netbox_hosts
+  roles:
+    - netbox
+
 - name: Ensure NGINX deployment on nginx_hosts, which are also public_reverse_proxy_hosts, before certbot role runs
   hosts: nginx_hosts:&public_reverse_proxy_hosts
   roles:
diff --git a/resources/chaosknoten/netbox/netbox/configuration.py.j2 b/resources/chaosknoten/netbox/netbox/configuration.py.j2
new file mode 100644
index 0000000..789a539
--- /dev/null
+++ b/resources/chaosknoten/netbox/netbox/configuration.py.j2
@@ -0,0 +1,60 @@
+ALLOWED_HOSTS = [ "netbox.hamburg.ccc.de" ]
+DATABASE = {
+  "HOST": "localhost",
+  "NAME": "netbox",
+  "USER": "netbox",
+  "PASSWORD": "{{ lookup('community.general.passwordstore', 'noc/vm-secrets/chaosknoten/netbox/DATABASE_PASSWORD', create=false, missing='error') }}",
+}
+REDIS = {
+    "tasks": {
+      "HOST": "localhost",
+      "PORT": 6379,
+      "USERNAME": "",
+      "PASSWORD": "",
+      "DATABASE": 0,
+      "SSL": False,
+    },
+    "caching": {
+      "HOST": "localhost",
+      "PORT": 6379,
+      "USERNAME": "",
+      "PASSWORD": "",
+      "DATABASE": 1,
+      "SSL": False,
+    },
+}
+SECRET_KEY = "{{ lookup('community.general.passwordstore', 'noc/vm-secrets/chaosknoten/netbox/SECRET_KEY', create=false, missing='error') }}"
+SESSION_COOKIE_SECURE = True
+
+# CCCHH ID (Keycloak) integration.
+# https://github.com/python-social-auth/social-core/blob/0925304a9e437f8b729862687d3a808c7fb88a95/social_core/backends/keycloak.py#L7
+# https://python-social-auth.readthedocs.io/en/latest/backends/keycloak.html
+REMOTE_AUTH_BACKEND = "social_core.backends.keycloak.KeycloakOAuth2"
+SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL = (
+    "https://id.hamburg.ccc.de/realms/ccchh/protocol/openid-connect/token"
+)
+SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL = (
+    "https://id.hamburg.ccc.de/realms/ccchh/protocol/openid-connect/auth"
+)
+SOCIAL_AUTH_KEYCLOAK_KEY = "netbox"
+SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi/Shi+b2OyYNGVFPsa6qf9SesEpRl5U5rpwgmt8H7NawMvwpPUYVW9o46QW0ulYcDmysT3BzpP3tagO/SFNoOjZdYe0D9nJ7vEp8KHbzR09KCfkyQIi0wLssKnDotVHL5JeUY+iKk+gjiwF9FSFSHPBqsST7hXVAut9LkOvs2aDod9AzbTH/uYbt4wfUm5l/1Ii8D+K7YcsFGUIqxv4XS/ylKqObqN4M2dac69iIwapoh6reaBQEm66vrOzJ+3yi4DZuPrkShJqi2hddtoyZihyCkF+eJJKEI5LrBf1KZB3Ec2YUrqk93ZGUGs/XY6R87QSfR3hJ82B1wnF+c2pw+QIDAQAB"
+SOCIAL_AUTH_KEYCLOAK_SECRET = "{{ lookup('community.general.passwordstore', 'noc/vm-secrets/chaosknoten/netbox/SOCIAL_AUTH_KEYCLOAK_SECRET', create=false, missing='error') }}"
+# Use custom OIDC group and role mapping pipeline functions added in via
+# netbox__custom_pipeline_oidc_group_and_role_mapping.
+# The default pipeline this is based on can be found here:
+# https://github.com/netbox-community/netbox/blob/main/netbox/netbox/settings.py
+SOCIAL_AUTH_PIPELINE = [
+    "social_core.pipeline.social_auth.social_details",
+    "social_core.pipeline.social_auth.social_uid",
+    "social_core.pipeline.social_auth.social_user",
+    "social_core.pipeline.user.get_username",
+    "social_core.pipeline.user.create_user",
+    "social_core.pipeline.social_auth.associate_user",
+    "netbox.authentication.user_default_groups_handler",
+    "social_core.pipeline.social_auth.load_extra_data",
+    "social_core.pipeline.user.user_details",
+    # Custom OIDC group and role mapping functions.
+    "netbox.custom_pipeline_oidc_mapping.add_groups",
+    "netbox.custom_pipeline_oidc_mapping.remove_groups",
+    "netbox.custom_pipeline_oidc_mapping.set_roles",
+]
diff --git a/resources/chaosknoten/netbox/nginx/netbox.hamburg.ccc.de.conf b/resources/chaosknoten/netbox/nginx/netbox.hamburg.ccc.de.conf
new file mode 100644
index 0000000..5550686
--- /dev/null
+++ b/resources/chaosknoten/netbox/nginx/netbox.hamburg.ccc.de.conf
@@ -0,0 +1,48 @@
+# partly generated 2022-01-08, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration
+# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6
+server {
+    # Listen on a custom port for the proxy protocol.
+    listen 8443 ssl http2 proxy_protocol;
+    # Make use of the ngx_http_realip_module to set the $remote_addr and
+    # $remote_port to the client address and client port, when using proxy
+    # protocol.
+    # First set our proxy protocol proxy as trusted.
+    set_real_ip_from 172.31.17.140;
+    # Then tell the realip_module to get the addreses from the proxy protocol
+    # header.
+    real_ip_header proxy_protocol;
+
+    server_name netbox.hamburg.ccc.de;
+
+    ssl_certificate /etc/letsencrypt/live/netbox.hamburg.ccc.de/fullchain.pem;
+    ssl_certificate_key /etc/letsencrypt/live/netbox.hamburg.ccc.de/privkey.pem;
+    # verify chain of trust of OCSP response using Root CA and Intermediate certs
+    ssl_trusted_certificate /etc/letsencrypt/live/netbox.hamburg.ccc.de/chain.pem;
+
+    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
+    add_header Strict-Transport-Security "max-age=63072000" always;
+
+    proxy_set_header Host $host;
+    proxy_set_header X-Forwarded-Host $host;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header X-Forwarded-Port 443;
+    # This is https in any case.
+    proxy_set_header X-Forwarded-Proto https;
+    # Hide the X-Forwarded header.
+    proxy_hide_header X-Forwarded;
+    # Assume we are the only Reverse Proxy (well using Proxy Protocol, but that
+    # is transparent).
+    # Also provide "_hidden" for by, since it's not relevant.
+    proxy_set_header Forwarded "for=$remote_addr;proto=https;host=$host;by=_hidden";
+
+    client_max_body_size 25m;
+
+    location /static/ {
+        alias /opt/netbox/netbox/static/;
+    }
+
+    location / {
+        proxy_pass http://127.0.0.1:8001;
+    }
+}
diff --git a/resources/chaosknoten/public-reverse-proxy/nginx/acme_challenge.conf b/resources/chaosknoten/public-reverse-proxy/nginx/acme_challenge.conf
index d5ae146..c3f9fed 100644
--- a/resources/chaosknoten/public-reverse-proxy/nginx/acme_challenge.conf
+++ b/resources/chaosknoten/public-reverse-proxy/nginx/acme_challenge.conf
@@ -17,7 +17,7 @@ map $host $upstream_acme_challenge_host {
     invite.hamburg.ccc.de 172.31.17.144:31820;
     keycloak-admin.hamburg.ccc.de 172.31.17.144:31820;
     matrix.hamburg.ccc.de 172.31.17.150:31820;
-    netbox.hamburg.ccc.de 172.31.17.149:31820;
+    netbox.hamburg.ccc.de 172.31.17.167:31820;
     onlyoffice.hamburg.ccc.de 172.31.17.147:31820;
     pad.hamburg.ccc.de 172.31.17.141:31820;
     pretalx.hamburg.ccc.de 172.31.17.157:31820;
diff --git a/resources/chaosknoten/public-reverse-proxy/nginx/nginx.conf b/resources/chaosknoten/public-reverse-proxy/nginx/nginx.conf
index 0529f4c..dfcf8d2 100644
--- a/resources/chaosknoten/public-reverse-proxy/nginx/nginx.conf
+++ b/resources/chaosknoten/public-reverse-proxy/nginx/nginx.conf
@@ -32,7 +32,7 @@ stream {
         onlyoffice.hamburg.ccc.de 172.31.17.147:8443;
         hackertours.hamburg.ccc.de 172.31.17.151:8443;
         staging.hackertours.hamburg.ccc.de 172.31.17.151:8443;
-        netbox.hamburg.ccc.de 172.31.17.149:8443;
+        netbox.hamburg.ccc.de 172.31.17.167:8443;
         matrix.hamburg.ccc.de 172.31.17.150:8443;
         element.hamburg.ccc.de 172.31.17.151:8443;
         branding-resources.hamburg.ccc.de 172.31.17.151:8443;