fix: allow host-networked egress proxy
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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`),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user