fix(oci): give Authentik worker outbound access

This commit is contained in:
Jonatan
2026-10-31 09:00:46 +01:00
parent f5ce0438f9
commit 6968409ae5
4 changed files with 39 additions and 9 deletions
+4 -3
View File
@@ -34,7 +34,8 @@
"repository": "https://github.com/goauthentik/authentik", "repository": "https://github.com/goauthentik/authentik",
"tips": [ "tips": [
"The server and worker share /data and /templates through host directories; those directories are not included in Proxmox CT backups.", "The server and worker share /data and /templates through host directories; those directories are not included in Proxmox CT backups.",
"The worker Docker-socket mount is omitted. Use the embedded outpost or deploy and manage a separate outpost manually." "The worker Docker-socket mount is omitted. Use the embedded outpost or deploy and manage a separate outpost manually.",
"The worker gets an interface on the selected Proxmox bridge for outbound access; PostgreSQL stays on the private stack network."
], ],
"mini_changelog": [], "mini_changelog": [],
"display_version": "2026.8.5", "display_version": "2026.8.5",
@@ -213,7 +214,7 @@
"depends_on": [ "depends_on": [
"postgresql" "postgresql"
], ],
"frontend_network": false, "frontend_network": true,
"private_network": true, "private_network": true,
"compose": { "compose": {
"command": "worker", "command": "worker",
@@ -311,7 +312,7 @@
"private_creation": "automatic-create-if-missing", "private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service", "private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases", "service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports", "dependency_external_access": "worker-through-selected-proxmox-bridge; postgresql-private-only",
"prompt_user_for_private_network": false "prompt_user_for_private_network": false
}, },
"storage": [ "storage": [
+4 -3
View File
@@ -34,7 +34,8 @@
"repository": "https://github.com/goauthentik/authentik", "repository": "https://github.com/goauthentik/authentik",
"tips": [ "tips": [
"The server and worker share /data and /templates through host directories; those directories are not included in Proxmox CT backups.", "The server and worker share /data and /templates through host directories; those directories are not included in Proxmox CT backups.",
"The worker Docker-socket mount is omitted. Use the embedded outpost or deploy and manage a separate outpost manually." "The worker Docker-socket mount is omitted. Use the embedded outpost or deploy and manage a separate outpost manually.",
"The worker gets an interface on the selected Proxmox bridge for outbound access; PostgreSQL stays on the private stack network."
], ],
"mini_changelog": [], "mini_changelog": [],
"display_version": "2026.8.5", "display_version": "2026.8.5",
@@ -213,7 +214,7 @@
"depends_on": [ "depends_on": [
"postgresql" "postgresql"
], ],
"frontend_network": false, "frontend_network": true,
"private_network": true, "private_network": true,
"compose": { "compose": {
"command": "worker", "command": "worker",
@@ -311,7 +312,7 @@
"private_creation": "automatic-create-if-missing", "private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service", "private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases", "service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports", "dependency_external_access": "worker-through-selected-proxmox-bridge; postgresql-private-only",
"prompt_user_for_private_network": false "prompt_user_for_private_network": false
}, },
"storage": [ "storage": [
+9 -3
View File
@@ -655,8 +655,14 @@ def build_stack(template, ui, mode='advanced'):
from .custom_mounts import ask_stack_custom_mounts from .custom_mounts import ask_stack_custom_mounts
ask_stack_custom_mounts(ui, drafts, volumes) ask_stack_custom_mounts(ui, drafts, volumes)
bridge = ask_bridge(ui, translate('Access bridge'), defaults['bridge'], mode) bridge = ask_bridge(ui, translate('Access bridge'), defaults['bridge'], mode)
frontend_names = [s['name'] for s in services if s['name'] == template['compose_stack']['main_service'] or (custom and service_endpoint(s))] frontend_names = [
address_labels = frontend_names if custom else [''] s['name'] for s in services
if (s['name'] == template['compose_stack']['main_service']
or s.get('frontend_network') is True
or (custom and service_endpoint(s)))
]
labelled_frontends = custom or len(frontend_names) > 1
address_labels = frontend_names if labelled_frontends else ['']
addresses, gateway = access.ask_addresses(ui, bridge, address_labels) addresses, gateway = access.ask_addresses(ui, bridge, address_labels)
timezone = quiet.ask(translate('Timezone'), host.timezone()) timezone = quiet.ask(translate('Timezone'), host.timezone())
envs = resolve_environments(services, timezone, generators, literal=literal) envs = resolve_environments(services, timezone, generators, literal=literal)
@@ -749,7 +755,7 @@ def build_stack(template, ui, mode='advanced'):
plans[-1]['public_environment_bindings'] = public_bindings[s['name']] plans[-1]['public_environment_bindings'] = public_bindings[s['name']]
if s['name'] in frontend_names and s['name'] not in jobs: if s['name'] in frontend_names and s['name'] not in jobs:
plans[-1]['frontend'] = True plans[-1]['frontend'] = True
plans[-1]['frontend_ipv4'] = addresses[s['name']] if custom else addresses[''] plans[-1]['frontend_ipv4'] = addresses[s['name']] if labelled_frontends else addresses['']
if mode != DEFAULT_MODE: if mode != DEFAULT_MODE:
from .extra_devices import ask_stack_extra_devices from .extra_devices import ask_stack_extra_devices
ask_stack_extra_devices(ui, plans) ask_stack_extra_devices(ui, plans)
+22
View File
@@ -2,10 +2,16 @@
import json import json
from pathlib import Path from pathlib import Path
import sys
import unittest import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1] ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from proxmenux_oci.installer import DEFAULT_MODE
from proxmenux_oci.stack import DefaultsUI, build_stack
class AuthentikRecipeTests(unittest.TestCase): class AuthentikRecipeTests(unittest.TestCase):
@@ -130,6 +136,22 @@ class AuthentikRecipeTests(unittest.TestCase):
["9000:9000", "9443:9443"], ["9000:9000", "9443:9443"],
) )
def test_worker_gets_lan_interface_while_postgresql_stays_private(self):
selected = {"worker": "192.0.2.21/24", "server": "192.0.2.22/24"}
with patch("proxmenux_oci.installer.ask_storage", return_value="local-zfs"), \
patch("proxmenux_oci.installer.ask_bridge", return_value="vmbr0"), \
patch("proxmenux_oci.host.timezone", return_value="UTC"), \
patch("proxmenux_oci.network.ask_addresses", return_value=(selected, "192.0.2.1")) as ask_addresses:
plan = build_stack(self.curated, DefaultsUI(), DEFAULT_MODE)
services = {service["name"]: service for service in plan["services"]}
self.assertEqual(ask_addresses.call_args.args[2], ["worker", "server"])
self.assertTrue(services["worker"]["frontend"])
self.assertEqual(services["worker"]["frontend_ipv4"], selected["worker"])
self.assertTrue(services["server"]["frontend"])
self.assertEqual(services["server"]["frontend_ipv4"], selected["server"])
self.assertNotIn("frontend", services["postgresql"])
def test_first_run_discloses_the_initial_admin_setup_without_faking_a_password(self): def test_first_run_discloses_the_initial_admin_setup_without_faking_a_password(self):
first_run = self.curated["first_run"] first_run = self.curated["first_run"]
self.assertEqual(first_run["endpoints"][0]["port"], 9000) self.assertEqual(first_run["endpoints"][0]["port"], 9000)