diff --git a/flake.lock b/flake.lock index 3b4fcc5..7ac78d8 100644 --- a/flake.lock +++ b/flake.lock @@ -248,16 +248,16 @@ ] }, "locked": { - "lastModified": 1785348116, - "narHash": "sha256-AVycTcomtfvQJ/AHvMg5xu7lVoOzDXxjN+pV7mqUIQ4=", + "lastModified": 1785979955, + "narHash": "sha256-OP96Ak4OBydR98keoNYKdGY8j+wrIys0LafSZgwS20g=", "owner": "basecamp", "repo": "basecamp-cli", - "rev": "e1059fb123a03295ce6176272e4bbaf43d7971c6", + "rev": "61a5591de1da9bc99c56b8072a4d6bad2c9b9e47", "type": "github" }, "original": { "owner": "basecamp", - "ref": "v0.8.0-rc.1", + "ref": "v0.9.0", "repo": "basecamp-cli", "type": "github" } @@ -295,6 +295,29 @@ "type": "github" } }, + "buzz": { + "inputs": { + "nixpkgs": [ + "m3ta-nixpkgs", + "nixpkgs" + ], + "rust-overlay": "rust-overlay", + "treefmt-nix": "treefmt-nix_2" + }, + "locked": { + "lastModified": 1785934673, + "narHash": "sha256-U/hMY9kkcdxt497yfGuT7+ytrRmE+E15KF6Sc6VrbZo=", + "owner": "mulatta", + "repo": "buzz.nix", + "rev": "f4bb77a87f1ec10e5ad51cfe6d0c4fca481c0534", + "type": "github" + }, + "original": { + "owner": "mulatta", + "repo": "buzz.nix", + "type": "github" + } + }, "darwin": { "inputs": { "nixpkgs": [ @@ -740,17 +763,18 @@ "inputs": { "agents": "agents_4", "basecamp": "basecamp_2", + "buzz": "buzz", "nixpkgs": "nixpkgs_7", "nixpkgs-master": "nixpkgs-master_2", "opencode": "opencode_2", "openspec": "openspec_2" }, "locked": { - "lastModified": 1785997099, - "narHash": "sha256-HReUmHC6RCRnrTuuFq0mYeH+7hnmhJCwZtrBUN97Xho=", + "lastModified": 1786563125, + "narHash": "sha256-a6Rom/Tn66AqPipVRkYu8aaQqFkJjbKh9GaaHVo660g=", "ref": "refs/heads/master", - "rev": "e69ce45b76e39e2b8a6f63f94b1d7fafbafc3ba8", - "revCount": 375, + "rev": "af9422c7b5b0c028a7379a329075bef450a9dfb3", + "revCount": 379, "type": "git", "url": "https://code.m3ta.dev/m3tam3re/nixpkgs" }, @@ -847,7 +871,7 @@ "nixpkgs": [ "nixpkgs" ], - "treefmt-nix": "treefmt-nix_2" + "treefmt-nix": "treefmt-nix_3" }, "locked": { "lastModified": 1785356851, @@ -1472,6 +1496,28 @@ "zugferd-service": "zugferd-service" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "m3ta-nixpkgs", + "buzz", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785820796, + "narHash": "sha256-sZXy8mzUMi2cOGulhoW4HWAZB6JhXOAx1x8J4auZFWk=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "b6916ba032e02122d6ed3064f40cabe937363d43", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "systems": { "locked": { "lastModified": 1681028828, @@ -1554,6 +1600,28 @@ } }, "treefmt-nix_2": { + "inputs": { + "nixpkgs": [ + "m3ta-nixpkgs", + "buzz", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785360170, + "narHash": "sha256-XE1lKgQ3eIO3E7zWryqcRsax+mYXod/5RHBn4YaR9YE=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "d1187f8bc71fb8aab02395869ec3f5c1920f75c0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_3": { "inputs": { "nixpkgs": [ "nixos-anywhere", diff --git a/hosts/AZ-CLD-1/secrets.nix b/hosts/AZ-CLD-1/secrets.nix index bb60efe..f8c650b 100644 --- a/hosts/AZ-CLD-1/secrets.nix +++ b/hosts/AZ-CLD-1/secrets.nix @@ -88,6 +88,18 @@ file = ../../secrets/pgbouncer-userlist.age; owner = "pgbouncer"; }; + pgbouncer-tls-cert = { + file = ../../secrets/server.crt.age; + owner = "pgbouncer"; + group = "pgbouncer"; + mode = "0444"; + }; + pgbouncer-tls-key = { + file = ../../secrets/server.key.age; + owner = "pgbouncer"; + group = "pgbouncer"; + mode = "0400"; + }; vaultwarden-env = { file = ../../secrets/vaultwarden-env.age; }; diff --git a/hosts/AZ-CLD-1/services/containers/default.nix b/hosts/AZ-CLD-1/services/containers/default.nix index 7e4e927..fd01bb9 100644 --- a/hosts/AZ-CLD-1/services/containers/default.nix +++ b/hosts/AZ-CLD-1/services/containers/default.nix @@ -7,7 +7,7 @@ ./litellm.nix ./librechat-dev.nix ./netbird.nix - ./portainer.nix + # ./portainer.nix ./zammad-hr.nix ]; system.activationScripts.createPodmanNetworkWeb = lib.mkAfter '' diff --git a/hosts/AZ-CLD-1/services/containers/homarr.nix b/hosts/AZ-CLD-1/services/containers/homarr.nix index 13679e6..b537243 100644 --- a/hosts/AZ-CLD-1/services/containers/homarr.nix +++ b/hosts/AZ-CLD-1/services/containers/homarr.nix @@ -13,6 +13,7 @@ in { AUTH_OIDC_CLIENT_NAME = "Azure"; AUTH_OIDC_SCOPE_OVERWRITE = "openid email profile"; AUTH_OIDC_GROUPS_ATTRIBUTE = "roles"; + AUTH_OIDC_GROUPS_LOCAL_MANAGEMENT = "true"; }; environmentFiles = [config.age.secrets.homarr-env.path]; ports = ["127.0.0.1:${toString servicePort}:7575"]; diff --git a/hosts/AZ-CLD-1/services/containers/zammad-hr.nix b/hosts/AZ-CLD-1/services/containers/zammad-hr.nix index fab3170..9fadb4b 100644 --- a/hosts/AZ-CLD-1/services/containers/zammad-hr.nix +++ b/hosts/AZ-CLD-1/services/containers/zammad-hr.nix @@ -21,7 +21,9 @@ ipOffset = 40; # Domain-Konfiguration - zammadDomain = "hr-ticket.az-gruppe.com"; + zammadDomain = "tickets.az-gruppe.com"; + # Alte Domain wird per 301 auf zammadDomain weitergeleitet (siehe Traefik-Config unten) + zammadDomainOld = "hr-ticket.az-gruppe.com"; sharedEnvironment = { MEMCACHE_SERVERS = "zammad-memcached:11211"; @@ -29,7 +31,12 @@ POSTGRESQL_HOST = "10.89.0.1"; POSTGRESQL_USER = "zammad_${instanceName}"; POSTGRESQL_PORT = "6433"; - POSTGRESQL_OPTIONS = "?pool=5"; + # pool=50 entspricht dem Zammad-Default (config/database/database.yml). + # Der Scheduler startet mehrere BackgroundServices-Threads gleichzeitig + # (ProcessSessions/Scheduled/Delayed/DelayedAI + Cleanup/fetch); pool=5 + # war zu klein -> ActiveRecord::ConnectionTimeoutError beim Start. + # Wird durch PgBouncer-Session (default_pool_size=30) server-seitig gedeckelt. + POSTGRESQL_OPTIONS = "?pool=50"; REDIS_URL = "redis://zammad-redis:6379"; TZ = "Europe/Berlin"; BACKUP_DIR = "/var/tmp/zammad"; @@ -232,7 +239,7 @@ in { --env POSTGRESQL_HOST=10.89.0.1 \ --env POSTGRESQL_USER=zammad_${instanceName} \ --env POSTGRESQL_PORT=6433 \ - --env POSTGRESQL_OPTIONS='?pool=5' \ + --env POSTGRESQL_OPTIONS='?pool=50' \ --env REDIS_URL=redis://zammad-redis:6379 \ --env TZ=Europe/Berlin \ --env ELASTICSEARCH_ENABLED=true \ @@ -305,6 +312,13 @@ in { }; }; + # Permanenter Redirect von der alten Domain auf die neue + middlewares."${serviceName}-redirect-old-domain".redirectRegex = { + permanent = true; + regex = "^https?://${lib.replaceStrings ["."] ["\\."] zammadDomainOld}/(.*)"; + replacement = "https://${zammadDomain}/\${1}"; + }; + routers.${serviceName} = { rule = "Host(`${zammadDomain}`)"; tls = { @@ -314,5 +328,15 @@ in { entrypoints = "websecure"; middlewares = ["${serviceName}-headers"]; }; + + routers."${serviceName}-old-domain-redirect" = { + rule = "Host(`${zammadDomainOld}`)"; + tls = { + certResolver = "ionos"; + }; + service = serviceName; + entrypoints = "websecure"; + middlewares = ["${serviceName}-redirect-old-domain"]; + }; }; } diff --git a/hosts/AZ-CLD-1/services/pgbouncer.nix b/hosts/AZ-CLD-1/services/pgbouncer.nix index ff9b7db..b568e4f 100644 --- a/hosts/AZ-CLD-1/services/pgbouncer.nix +++ b/hosts/AZ-CLD-1/services/pgbouncer.nix @@ -22,11 +22,17 @@ log_connections = 1; log_disconnections = 1; + client_tls_sslmode = "require"; + client_tls_cert_file = config.age.secrets.pgbouncer-tls-cert.path; + client_tls_key_file = config.age.secrets.pgbouncer-tls-key.path; + client_tls_protocols = "secure"; + server_reset_query = "DISCARD ALL"; server_check_query = "SELECT 1"; server_check_delay = 30; - server_tls_sslmode = "prefer"; + server_tls_sslmode = "require"; + server_tls_protocols = "secure"; }; mkDatabases = dbs: @@ -92,11 +98,13 @@ in { admin_users = ${commonSettings.admin_users} stats_users = ${commonSettings.stats_users} + client_tls_sslmode = ${commonSettings.client_tls_sslmode} + client_tls_cert_file = ${commonSettings.client_tls_cert_file} + client_tls_key_file = ${commonSettings.client_tls_key_file} + client_tls_protocols = ${commonSettings.client_tls_protocols} + max_client_conn = 300 - # session-Mode: 1 Client-Conn = 1 Server-Conn. zammad_hr haelt via mehrere - # Prozesse (rails+scheduler+websocket) real ~15 Conns -> pro (user,db) 15. - # outline/vaultwarden schoepfen das nie aus (eigene Slots je user,db). - default_pool_size = 15 + default_pool_size = 30 min_pool_size = 1 query_wait_timeout = 30 @@ -105,7 +113,8 @@ in { server_reset_query = DISCARD ALL server_check_query = SELECT 1 server_check_delay = 30 - server_tls_sslmode = prefer + server_tls_sslmode = ${commonSettings.server_tls_sslmode} + server_tls_protocols = ${commonSettings.server_tls_protocols} # PID/Socket getrennt von der Haupt-Instanz halten. pidfile = /run/pgbouncer-session/pgbouncer.pid diff --git a/hosts/AZ-PRM-1/secrets.nix b/hosts/AZ-PRM-1/secrets.nix index ef3b6fb..e53441a 100644 --- a/hosts/AZ-PRM-1/secrets.nix +++ b/hosts/AZ-PRM-1/secrets.nix @@ -25,6 +25,16 @@ in { owner = "traefik"; mode = "0400"; }; + netbox-secret-key = { + file = ../../secrets/netbox-secret-key.age; + owner = "netbox"; + mode = "0400"; + }; + netbox-api-token-pepper = { + file = ../../secrets/netbox-api-token-pepper.age; + owner = "netbox"; + mode = "0400"; + }; traefik-env = { file = ../../secrets/traefik-env.age; }; diff --git a/hosts/AZ-PRM-1/services/default.nix b/hosts/AZ-PRM-1/services/default.nix index 3b623c8..043e0b9 100644 --- a/hosts/AZ-PRM-1/services/default.nix +++ b/hosts/AZ-PRM-1/services/default.nix @@ -8,6 +8,7 @@ ./monitoring ./n8n.nix ./netbird.nix + ./netbox.nix ./pgadmin.nix ./phishboard.nix ./postgres.nix diff --git a/hosts/AZ-PRM-1/services/netbox.nix b/hosts/AZ-PRM-1/services/netbox.nix new file mode 100644 index 0000000..72027de --- /dev/null +++ b/hosts/AZ-PRM-1/services/netbox.nix @@ -0,0 +1,79 @@ +{ + config, + pkgs, + ... +}: let + serviceName = "netbox"; + servicePort = config.m3ta.ports.get serviceName; + staticPort = config.m3ta.ports.get "netbox-static"; + hostName = "nb.l.az-gruppe.com"; + staticRoot = "${config.services.netbox.dataDir}/static"; +in { + services.netbox = { + enable = true; + package = pkgs.unstable.netbox; + listenAddress = "127.0.0.1"; + port = servicePort; + secretKeyFile = config.age.secrets.netbox-secret-key.path; + apiTokenPeppersFile = config.age.secrets.netbox-api-token-pepper.path; + + settings = { + ALLOWED_HOSTS = [hostName "localhost" "127.0.0.1"]; + SECURE_SSL_REDIRECT = true; + SESSION_COOKIE_SECURE = true; + CSRF_COOKIE_SECURE = true; + }; + + extraConfig = '' + SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + ''; + }; + + services.nginx = { + enable = true; + virtualHosts.netbox-static = { + listen = [ + { + addr = "127.0.0.1"; + port = staticPort; + } + ]; + locations."/static/" = { + alias = "${staticRoot}/"; + extraConfig = '' + expires 1h; + access_log off; + ''; + }; + }; + }; + + users.users.nginx.extraGroups = ["netbox"]; + + # Traefik-Routing: zwei Backends (App + Static), ein Host + services.traefik.dynamicConfigOptions.http = { + services = { + ${serviceName}.loadBalancer.servers = [ + {url = "http://127.0.0.1:${toString servicePort}/";} + ]; + "${serviceName}-static".loadBalancer.servers = [ + {url = "http://127.0.0.1:${toString staticPort}/";} + ]; + }; + + routers = { + ${serviceName} = { + rule = "Host(`${hostName}`) && !PathPrefix(`/static`)"; + tls.certResolver = "ionos"; + service = serviceName; + entrypoints = "websecure"; + }; + "${serviceName}-static" = { + rule = "Host(`${hostName}`) && PathPrefix(`/static`)"; + tls.certResolver = "ionos"; + service = "${serviceName}-static"; + entrypoints = "websecure"; + }; + }; + }; +} diff --git a/hosts/AZ-PRM-1/services/postgres.nix b/hosts/AZ-PRM-1/services/postgres.nix index 1caa6d5..d99175e 100644 --- a/hosts/AZ-PRM-1/services/postgres.nix +++ b/hosts/AZ-PRM-1/services/postgres.nix @@ -39,6 +39,7 @@ authentication = pkgs.lib.mkOverride 10 '' # Local connections (Unix socket) local all postgres peer + local netbox netbox peer local n8n n8n scram-sha-256 # Localhost connections (IPv4 and IPv6) @@ -64,7 +65,7 @@ services.postgresqlBackup = { enable = true; startAt = "03:10:00"; - databases = ["baserow" "kestra" "n8n"]; + databases = ["baserow" "kestra" "n8n" "netbox"]; }; networking.firewall = { extraCommands = '' diff --git a/hosts/common/ports.nix b/hosts/common/ports.nix index 4819ea4..be0b688 100644 --- a/hosts/common/ports.nix +++ b/hosts/common/ports.nix @@ -35,6 +35,8 @@ litellm = 4000; n8n = 5678; + netbox = 8001; + netbox-static = 8002; kestra = 5080; kestra-metrics = 5081; zugferd-service = 5060; diff --git a/secrets.nix b/secrets.nix index ea7e5e0..e324003 100644 --- a/secrets.nix +++ b/secrets.nix @@ -33,6 +33,8 @@ in { "secrets/n8n-db.age".publicKeys = systems ++ users; "secrets/n8n-runner-auth-token-cld.age".publicKeys = systems ++ users; "secrets/n8n-runner-auth-token-prm.age".publicKeys = systems ++ users; + "secrets/netbox-secret-key.age".publicKeys = systems ++ users; + "secrets/netbox-api-token-pepper.age".publicKeys = systems ++ users; "secrets/cld-var-backup-sync-ssh-key.age".publicKeys = [AZ-CLD-1] ++ users; "secrets/netbird-auth-secret.age".publicKeys = systems ++ users; "secrets/netbird-db-password.age".publicKeys = systems ++ users; diff --git a/secrets/netbox-api-token-pepper.age b/secrets/netbox-api-token-pepper.age new file mode 100644 index 0000000..1263d06 --- /dev/null +++ b/secrets/netbox-api-token-pepper.age @@ -0,0 +1,18 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyA5c3BQ +MEJKRHFldmszVy9XMDB6eDhUemhHOEI2K2JaekVOZGtuRHcrRkZVCjYzaEladkRD +cGJtZnl3aVN6YnZ4d0l2d3JHRittb2hQNW0yeURCTStod3MKLT4gc3NoLWVkMjU1 +MTkgU3JIYXFBIFRqd05Tckc1NGtSek1ia2NKejIwWkl5OExWY09wY3VTRE1TeE9K +dTlXaTgKbFBkbklKLzVJZ0dQOU1semNjNU45bk0zekRReFIvcmhVV2NjTnJNSXZ0 +UQotPiBzc2gtZWQyNTUxOSBsR3FWWmcgcitFcHJvTm1Uc2Q5UWFad1I0cGlCZWQv +MmlqdGZDbzhPQmtreVo2L3pSdwowS2xTcWhhWUs1WDExK1NteXRPNzVLM2RwZ3dh +bDBZeml4MGlkSktITzF3Ci0+IHNzaC1lZDI1NTE5IENTTXloZyByTytWN3A5Z3Jt +aXE1cmEwQlYzaDM3QjJzZ0tYSjFralc4dzE1MjByb1VjCnpra3pqNEZXS3JuOHBq +NWhKWXFadDRPNSsyVWxKVWxURXVCbzlVSlVmNkEKLT4gfD8laiIpLWdyZWFzZSBT +SVRJIFp9JF9xClY2MVFTenQ5TXBsczQwVHZhUU5BSnR1R1RCWmU4T1pWTEU1Vnhx +TmxyL2Zmb1p5VXNscVBFcm12NHo2N0IyRkQKdk9QWW01OXg1UEN4UnJpWXF4ckha +TVI3WU9nd1dnMkpFODN1SEcwejE4Z1hXSGpFdGJxb1R1N3J3UQotLS0ga2ZReEJV +cVN5dW5wK09tdzJVQjVsZ25GYU0xcndlMHloNFNuZFI2T1BXRQoKJ6ftKtkdC473 +uLbkeR2haQ2HnNtrJIRo1hBrhToR4YkGnc3uCFdNX/xuCxAMznR88Np2rja9LSjk +/y0Kzqpm+5oUcgoW5rHyy3ur3h06HkZ+jPkZAWSMFCPuemTmeYy+HLT0 +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/netbox-secret-key.age b/secrets/netbox-secret-key.age new file mode 100644 index 0000000..c31ec44 --- /dev/null +++ b/secrets/netbox-secret-key.age @@ -0,0 +1,18 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpoVnNlZyA4NGp1 +a0pOS2xOMngwSkw3VmJKSkc4UnMvRXp1SElxLzFpaVo1M1hYSkJBCnBPTFk0Yk5y +dlp4Z3Q5aGkwYTFXRms5RWJsZFhiMmhPRnVET2Q3K2xBZVUKLT4gc3NoLWVkMjU1 +MTkgU3JIYXFBIHNJRkF3OVF0U0thQjRScGNvdGRmSFc2WWIvMkdpY1BmT1d5YldS +S3VPbDQKN0VLY3U4Z3dPbmt0OFRlb0VpR3RzZEFvTVdVWmduVkladEgyUDNtVmZk +awotPiBzc2gtZWQyNTUxOSBsR3FWWmcgM0swTjBuUzFYOXZCd29wc0ZIZHVySS9i +d3lmWllaL1prNWZzNXBBbi9tVQpoUit0K0lDRkErQzVpa21RSXRBRGo1aFJBbU1Q +bmJTMS9uYjUxMmljMmVBCi0+IHNzaC1lZDI1NTE5IENTTXloZyA2WXhxWVgyYWRl +VytNMzVPdFZSY252V0Y2TnA2NzA2QzVtNEJpN3BGcXdvCmN3RWFCN1FibStuWjFy +QjhQQWpwcGFkOFVaWWJwQzJoZ3NXbHNYT2NHQ2cKLT4gI2JmNHUtZ3JlYXNlIDMK +RFpVaHh2dEhBRjZBam4wV2xOd3d3Zk4vc1lYRGhoaU85b1Y2alZkTDlZWWIzTjNI +aExFUzl5OHJoLy9CK3FQbAp0ME9mS21iRThlZjNTV0hTOU1UUnppam50Vk5YRlp2 +WCtya1MxSFBWCi0tLSBLSnhkUVYwQmNmRzBjdXd4WFFueG53eWkwNVdRWmpuMk9i +cFcwM0tvcWRFCgVyq4v+1nfCjI7R7rsKRI7jsTluy376hFPgjZULUYAsAiWBV400 +R+YoFO+zsem78tNo2xzfepwyhtjAscMWOyACM0tPlhW4k2LVxp2SGJzy1xJ5H+Fz +GGC4Jb5UW+8LQ/0= +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/pgbouncer-userlist.age b/secrets/pgbouncer-userlist.age index 4bcb2f6..8f6a6ed 100644 Binary files a/secrets/pgbouncer-userlist.age and b/secrets/pgbouncer-userlist.age differ