From 1a11d3654a41f39e9286a6bbeaf42aaad0b7ccd3 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 26 Jun 2026 17:28:34 +0000 Subject: [PATCH] fix: allow host-networked egress proxy --- config/platform-infra/sub2api.yaml | 2 ++ scripts/src/platform-infra/actions.ts | 2 ++ scripts/src/platform-infra/config.ts | 1 + scripts/src/platform-infra/entry.ts | 1 + scripts/src/platform-infra/manifest.ts | 13 +++++++++++++ scripts/src/platform-infra/policy.ts | 18 ++++++++++++++++-- 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/config/platform-infra/sub2api.yaml b/config/platform-infra/sub2api.yaml index 565be4f6..cee19342 100644 --- a/config/platform-infra/sub2api.yaml +++ b/config/platform-infra/sub2api.yaml @@ -150,6 +150,7 @@ targets: image: 127.0.0.1:5000/platform-infra/sing-box:latest imagePullPolicy: IfNotPresent listenPort: 10808 + hostNetwork: true sourceConfigRef: config/platform-infra/egress-proxy-sources.yaml#sources.master-shadowsocks applyToSub2Api: true applyToSentinel: true @@ -245,6 +246,7 @@ targets: image: ghcr.io/sagernet/sing-box:latest imagePullPolicy: IfNotPresent listenPort: 10808 + hostNetwork: false sourceConfigRef: config/platform-infra/egress-proxy-sources.yaml#sources.master-shadowsocks applyToSub2Api: true applyToSentinel: true diff --git a/scripts/src/platform-infra/actions.ts b/scripts/src/platform-infra/actions.ts index 712f9ab3..8da28648 100644 --- a/scripts/src/platform-infra/actions.ts +++ b/scripts/src/platform-infra/actions.ts @@ -66,6 +66,7 @@ export function egressProxySummary(proxy: Sub2ApiEgressProxyConfig): Record { ? { mode: `${target.id} in-cluster HTTP proxy client to ${target.egressProxy.sourceType}`, service: `${target.egressProxy.serviceName}.${target.namespace}.svc.cluster.local:${target.egressProxy.listenPort}`, + hostNetwork: target.egressProxy.hostNetwork, sourceRef: target.egressProxy.sourceRef, sourceType: target.egressProxy.sourceType, applyToSub2Api: target.egressProxy.applyToSub2Api, diff --git a/scripts/src/platform-infra/config.ts b/scripts/src/platform-infra/config.ts index 2bfd2e91..c7e9f088 100644 --- a/scripts/src/platform-infra/config.ts +++ b/scripts/src/platform-infra/config.ts @@ -305,6 +305,7 @@ export function parseEgressProxyConfig(value: unknown, path: string): Sub2ApiEgr image: stringField(record, "image", `${path}.egressProxy`), imagePullPolicy, listenPort: integerField(record, "listenPort", `${path}.egressProxy`), + hostNetwork: booleanField(record, "hostNetwork", `${path}.egressProxy`), sourceConfigRef, sourceFingerprint: source?.fingerprint ?? null, sourceRef: source?.sourceRef ?? stringField(record, "sourceRef", `${path}.egressProxy`), diff --git a/scripts/src/platform-infra/entry.ts b/scripts/src/platform-infra/entry.ts index 1b13a682..d375e748 100644 --- a/scripts/src/platform-infra/entry.ts +++ b/scripts/src/platform-infra/entry.ts @@ -169,6 +169,7 @@ export interface Sub2ApiEgressProxyConfig { image: string; imagePullPolicy: "Always" | "IfNotPresent" | "Never"; listenPort: number; + hostNetwork: boolean; sourceConfigRef: string | null; sourceFingerprint: string | null; sourceRef: string; diff --git a/scripts/src/platform-infra/manifest.ts b/scripts/src/platform-infra/manifest.ts index 9bf296d1..bf068d65 100644 --- a/scripts/src/platform-infra/manifest.ts +++ b/scripts/src/platform-infra/manifest.ts @@ -575,6 +575,11 @@ export function renderEgressProxyManifest(target: Sub2ApiTargetConfig): string { const proxy = target.egressProxy; if (proxy === null || !proxy.enabled) return ""; const proxyConfigHash = egressProxyConfigHash(proxy); + const hostNetworkSpec = proxy.hostNetwork + ? ` hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet +` + : ""; return `--- apiVersion: v1 kind: Service @@ -611,6 +616,11 @@ metadata: unidesk.ai/proxy-source: ${proxy.sourceType} spec: replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: ${proxy.deploymentName} @@ -627,9 +637,11 @@ spec: unidesk.ai/proxy-source-config-ref: "${proxy.sourceConfigRef ?? ""}" unidesk.ai/proxy-source-fingerprint: "${proxy.sourceFingerprint ?? ""}" unidesk.ai/proxy-selected-outbound: "${proxy.sourceType === "subscription-url" ? proxy.preferredOutbound : "shadowsocks"}" + unidesk.ai/proxy-host-network: "${proxy.hostNetwork}" unidesk.ai/proxy-config-template: "${egressProxyConfigTemplateVersion}" unidesk.ai/proxy-config-hash: "${proxyConfigHash}" spec: +${hostNetworkSpec} terminationGracePeriodSeconds: 10 containers: - name: proxy image: ${proxy.image} @@ -674,6 +686,7 @@ export function egressProxyConfigHash(proxy: Sub2ApiEgressProxyConfig): string { .update(JSON.stringify({ templateVersion: egressProxyConfigTemplateVersion, listenPort: proxy.listenPort, + hostNetwork: proxy.hostNetwork, sourceType: proxy.sourceType, sourceConfigRef: proxy.sourceConfigRef, sourceRef: proxy.sourceRef, diff --git a/scripts/src/platform-infra/policy.ts b/scripts/src/platform-infra/policy.ts index 66c497d9..fba4a7ba 100644 --- a/scripts/src/platform-infra/policy.ts +++ b/scripts/src/platform-infra/policy.ts @@ -75,8 +75,10 @@ export function policyChecks(sub2api: Sub2ApiConfig, yaml: string, target: Sub2A }, { name: "no-host-network", - ok: !/^\s*hostNetwork:\s*true\s*$/mu.test(yaml), - detail: "Pods must not join the host network.", + ok: hostNetworkPolicyOk(yaml, target), + detail: target.egressProxy?.hostNetwork === true + ? "Only the YAML-declared egress proxy Deployment may join the host network." + : "Pods must not join the host network unless explicitly allowed by YAML for the egress proxy.", }, { name: "no-host-port", @@ -154,3 +156,15 @@ export function policyChecks(sub2api: Sub2ApiConfig, yaml: string, target: Sub2A return checks; } + +function hostNetworkPolicyOk(yaml: string, target: Sub2ApiTargetConfig): boolean { + const matches = [...yaml.matchAll(/^\s*hostNetwork:\s*true\s*$/gmu)]; + if (matches.length === 0) return true; + const proxy = target.egressProxy; + if (proxy === null || !proxy.enabled || !proxy.hostNetwork || matches.length !== 1) return false; + const egressProxyDeployment = new RegExp( + `kind:\\s*Deployment[\\s\\S]*?name:\\s*${escapeRegExp(proxy.deploymentName)}[\\s\\S]*?hostNetwork:\\s*true`, + "u", + ); + return egressProxyDeployment.test(yaml); +}