fix: allow host-networked egress proxy

This commit is contained in:
Codex
2026-06-26 17:28:34 +00:00
parent 678dc427d6
commit 1a11d3654a
6 changed files with 35 additions and 2 deletions
+2
View File
@@ -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
+2
View File
@@ -66,6 +66,7 @@ export function egressProxySummary(proxy: Sub2ApiEgressProxyConfig): Record<stri
image: proxy.image,
imagePullPolicy: proxy.imagePullPolicy,
listenPort: proxy.listenPort,
hostNetwork: proxy.hostNetwork,
sourceConfigRef: proxy.sourceConfigRef,
sourceFingerprint: proxy.sourceFingerprint,
sourceRef: proxy.sourceRef,
@@ -164,6 +165,7 @@ export function plan(options: TargetOptions): Record<string, unknown> {
? {
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,
+1
View File
@@ -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`),
+1
View File
@@ -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;
+13
View File
@@ -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,
+16 -2
View File
@@ -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);
}