mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-15 08:49:59 +02:00
Dont load private resource inference without a exit node loaded
This commit is contained in:
@@ -767,15 +767,14 @@ export async function getTraefikConfig(
|
|||||||
if (!config_output.http.middlewares) {
|
if (!config_output.http.middlewares) {
|
||||||
config_output.http.middlewares = {};
|
config_output.http.middlewares = {};
|
||||||
}
|
}
|
||||||
config_output.http.middlewares[aiGatewayTrustMiddlewareNameResource] =
|
config_output.http.middlewares[aiGatewayTrustMiddlewareNameResource] = {
|
||||||
{
|
headers: {
|
||||||
headers: {
|
customRequestHeaders: {
|
||||||
customRequestHeaders: {
|
[AI_GATEWAY_TRUST_HEADER]: getAiGatewayTrustToken(),
|
||||||
[AI_GATEWAY_TRUST_HEADER]: getAiGatewayTrustToken(),
|
[AI_GATEWAY_RESOURCE_TYPE_HEADER]: "resource"
|
||||||
[AI_GATEWAY_RESOURCE_TYPE_HEADER]: "resource"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
config_output.http.middlewares[
|
config_output.http.middlewares[
|
||||||
aiGatewayTrustMiddlewareNameSiteResource
|
aiGatewayTrustMiddlewareNameSiteResource
|
||||||
] = {
|
] = {
|
||||||
@@ -798,15 +797,14 @@ export async function getTraefikConfig(
|
|||||||
const enableAiGatewayClientIpHeader =
|
const enableAiGatewayClientIpHeader =
|
||||||
config.getRawConfig().server.enable_ai_gateway_client_ip_header;
|
config.getRawConfig().server.enable_ai_gateway_client_ip_header;
|
||||||
if (enableAiGatewayClientIpHeader) {
|
if (enableAiGatewayClientIpHeader) {
|
||||||
config_output.http.middlewares[aiGatewayClientIpMiddlewareName] =
|
config_output.http.middlewares[aiGatewayClientIpMiddlewareName] = {
|
||||||
{
|
plugin: {
|
||||||
plugin: {
|
badger: {
|
||||||
badger: {
|
disableForwardAuth: true,
|
||||||
disableForwardAuth: true,
|
realIpHeader: AI_GATEWAY_CLIENT_IP_HEADER
|
||||||
realIpHeader: AI_GATEWAY_CLIENT_IP_HEADER
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public inference resources: same TLS/cert-resolver handling as
|
// Public inference resources: same TLS/cert-resolver handling as
|
||||||
@@ -935,90 +933,94 @@ export async function getTraefikConfig(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const sr of siteResourcesInference) {
|
if (exitNode) {
|
||||||
if (!sr.enabled || !sr.fullDomain) continue;
|
for (const sr of siteResourcesInference) {
|
||||||
|
if (!sr.enabled || !sr.fullDomain) continue;
|
||||||
|
|
||||||
if (!config_output.http.routers) config_output.http.routers = {};
|
if (!config_output.http.routers)
|
||||||
if (!config_output.http.services) config_output.http.services = {};
|
config_output.http.routers = {};
|
||||||
|
if (!config_output.http.services)
|
||||||
|
config_output.http.services = {};
|
||||||
|
|
||||||
const fullDomain = sr.fullDomain;
|
const fullDomain = sr.fullDomain;
|
||||||
const srKey = `inference-sr${sr.siteResourceId}`;
|
const srKey = `inference-sr${sr.siteResourceId}`;
|
||||||
const routerName = `${srKey}-router`;
|
const routerName = `${srKey}-router`;
|
||||||
const serviceName = `${srKey}-service`;
|
const serviceName = `${srKey}-service`;
|
||||||
const rule = `Host(\`${fullDomain}\`) && ClientIP(${exitNode.address})`; // restrict to coming from the exit node ip range that the client is connected to
|
const rule = `Host(\`${fullDomain}\`) && ClientIP(${exitNode.address})`; // restrict to coming from the exit node ip range that the client is connected to
|
||||||
|
|
||||||
const domainParts = fullDomain.split(".");
|
const domainParts = fullDomain.split(".");
|
||||||
const wildCard =
|
const wildCard =
|
||||||
domainParts.length <= 2
|
domainParts.length <= 2
|
||||||
? `*.${domainParts.join(".")}`
|
? `*.${domainParts.join(".")}`
|
||||||
: `*.${domainParts.slice(1).join(".")}`;
|
: `*.${domainParts.slice(1).join(".")}`;
|
||||||
|
|
||||||
const globalDefaultResolver =
|
const globalDefaultResolver =
|
||||||
config.getRawConfig().traefik.cert_resolver;
|
config.getRawConfig().traefik.cert_resolver;
|
||||||
const globalDefaultPreferWildcard =
|
const globalDefaultPreferWildcard =
|
||||||
config.getRawConfig().traefik.prefer_wildcard_cert;
|
config.getRawConfig().traefik.prefer_wildcard_cert;
|
||||||
|
|
||||||
const tls = {
|
const tls = {
|
||||||
certResolver: globalDefaultResolver,
|
certResolver: globalDefaultResolver,
|
||||||
...(globalDefaultPreferWildcard
|
...(globalDefaultPreferWildcard
|
||||||
? { domains: [{ main: wildCard }] }
|
? { domains: [{ main: wildCard }] }
|
||||||
: {})
|
: {})
|
||||||
};
|
};
|
||||||
|
|
||||||
const srHeadersMiddlewareName = `${srKey}-headers-middleware`;
|
const srHeadersMiddlewareName = `${srKey}-headers-middleware`;
|
||||||
if (!config_output.http.middlewares) {
|
if (!config_output.http.middlewares) {
|
||||||
config_output.http.middlewares = {};
|
config_output.http.middlewares = {};
|
||||||
}
|
|
||||||
config_output.http.middlewares[srHeadersMiddlewareName] = {
|
|
||||||
headers: {
|
|
||||||
customRequestHeaders: {
|
|
||||||
...(aiGatewayHost ? { Host: aiGatewayHost } : {}),
|
|
||||||
"p-host": fullDomain
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
config_output.http.middlewares[srHeadersMiddlewareName] = {
|
||||||
|
headers: {
|
||||||
|
customRequestHeaders: {
|
||||||
|
...(aiGatewayHost ? { Host: aiGatewayHost } : {}),
|
||||||
|
"p-host": fullDomain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const additionalMiddlewares =
|
const additionalMiddlewares =
|
||||||
config.getRawConfig().traefik.additional_middlewares || [];
|
config.getRawConfig().traefik.additional_middlewares || [];
|
||||||
const routerMiddlewares = [
|
const routerMiddlewares = [
|
||||||
...(enableAiGatewayClientIpHeader
|
...(enableAiGatewayClientIpHeader
|
||||||
? [aiGatewayClientIpMiddlewareName]
|
? [aiGatewayClientIpMiddlewareName]
|
||||||
: []),
|
: []),
|
||||||
aiGatewayTrustMiddlewareNameSiteResource,
|
aiGatewayTrustMiddlewareNameSiteResource,
|
||||||
srHeadersMiddlewareName,
|
srHeadersMiddlewareName,
|
||||||
...additionalMiddlewares
|
...additionalMiddlewares
|
||||||
];
|
];
|
||||||
|
|
||||||
if (sr.ssl) {
|
if (sr.ssl) {
|
||||||
config_output.http.routers[routerName + "-redirect"] = {
|
config_output.http.routers[routerName + "-redirect"] = {
|
||||||
|
entryPoints: [
|
||||||
|
config.getRawConfig().traefik.http_entrypoint
|
||||||
|
],
|
||||||
|
middlewares: [redirectHttpsMiddlewareName],
|
||||||
|
service: serviceName,
|
||||||
|
rule,
|
||||||
|
priority: 200 // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
config_output.http.routers[routerName] = {
|
||||||
entryPoints: [
|
entryPoints: [
|
||||||
config.getRawConfig().traefik.http_entrypoint
|
sr.ssl
|
||||||
|
? config.getRawConfig().traefik.https_entrypoint
|
||||||
|
: config.getRawConfig().traefik.http_entrypoint
|
||||||
],
|
],
|
||||||
middlewares: [redirectHttpsMiddlewareName],
|
middlewares: routerMiddlewares,
|
||||||
service: serviceName,
|
service: serviceName,
|
||||||
rule,
|
rule,
|
||||||
priority: 200 // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
priority: 200, // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
||||||
|
...(sr.ssl ? { tls } : {})
|
||||||
|
};
|
||||||
|
|
||||||
|
config_output.http.services[serviceName] = {
|
||||||
|
loadBalancer: {
|
||||||
|
servers: [{ url: aiGatewayUrl }]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
config_output.http.routers[routerName] = {
|
|
||||||
entryPoints: [
|
|
||||||
sr.ssl
|
|
||||||
? config.getRawConfig().traefik.https_entrypoint
|
|
||||||
: config.getRawConfig().traefik.http_entrypoint
|
|
||||||
],
|
|
||||||
middlewares: routerMiddlewares,
|
|
||||||
service: serviceName,
|
|
||||||
rule,
|
|
||||||
priority: 200, // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
|
||||||
...(sr.ssl ? { tls } : {})
|
|
||||||
};
|
|
||||||
|
|
||||||
config_output.http.services[serviceName] = {
|
|
||||||
loadBalancer: {
|
|
||||||
servers: [{ url: aiGatewayUrl }]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1581,15 +1581,14 @@ export async function getTraefikConfig(
|
|||||||
"ai-gateway-trust-headers-resource";
|
"ai-gateway-trust-headers-resource";
|
||||||
const aiGatewayTrustMiddlewareNameSiteResource =
|
const aiGatewayTrustMiddlewareNameSiteResource =
|
||||||
"ai-gateway-trust-headers-site-resource";
|
"ai-gateway-trust-headers-site-resource";
|
||||||
config_output.http.middlewares[aiGatewayTrustMiddlewareNameResource] =
|
config_output.http.middlewares[aiGatewayTrustMiddlewareNameResource] = {
|
||||||
{
|
headers: {
|
||||||
headers: {
|
customRequestHeaders: {
|
||||||
customRequestHeaders: {
|
[AI_GATEWAY_TRUST_HEADER]: getAiGatewayTrustToken(),
|
||||||
[AI_GATEWAY_TRUST_HEADER]: getAiGatewayTrustToken(),
|
[AI_GATEWAY_RESOURCE_TYPE_HEADER]: "resource"
|
||||||
[AI_GATEWAY_RESOURCE_TYPE_HEADER]: "resource"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
config_output.http.middlewares[
|
config_output.http.middlewares[
|
||||||
aiGatewayTrustMiddlewareNameSiteResource
|
aiGatewayTrustMiddlewareNameSiteResource
|
||||||
] = {
|
] = {
|
||||||
@@ -1612,15 +1611,14 @@ export async function getTraefikConfig(
|
|||||||
const enableAiGatewayClientIpHeader =
|
const enableAiGatewayClientIpHeader =
|
||||||
config.getRawConfig().server.enable_ai_gateway_client_ip_header;
|
config.getRawConfig().server.enable_ai_gateway_client_ip_header;
|
||||||
if (enableAiGatewayClientIpHeader) {
|
if (enableAiGatewayClientIpHeader) {
|
||||||
config_output.http.middlewares[aiGatewayClientIpMiddlewareName] =
|
config_output.http.middlewares[aiGatewayClientIpMiddlewareName] = {
|
||||||
{
|
plugin: {
|
||||||
plugin: {
|
badger: {
|
||||||
badger: {
|
disableForwardAuth: true,
|
||||||
disableForwardAuth: true,
|
realIpHeader: AI_GATEWAY_CLIENT_IP_HEADER
|
||||||
realIpHeader: AI_GATEWAY_CLIENT_IP_HEADER
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public inference resources: same TLS/cert-resolver handling as
|
// Public inference resources: same TLS/cert-resolver handling as
|
||||||
@@ -1742,108 +1740,116 @@ export async function getTraefikConfig(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private (siteResource) inference resources: routed by their alias
|
if (exitNode) {
|
||||||
// instead of a public fullDomain, and deliberately WITHOUT the
|
// Private (siteResource) inference resources: routed by their alias
|
||||||
// badger middleware - no per-user auth/policy stack exists for
|
// instead of a public fullDomain, and deliberately WITHOUT the
|
||||||
// siteResources today (see plan doc), so gating here is
|
// badger middleware - no per-user auth/policy stack exists for
|
||||||
// reachability-only for now.
|
// siteResources today (see plan doc), so gating here is
|
||||||
for (const sr of siteResourcesInference) {
|
// reachability-only for now.
|
||||||
if (!sr.enabled || !sr.fullDomain) continue;
|
for (const sr of siteResourcesInference) {
|
||||||
|
if (!sr.enabled || !sr.fullDomain) continue;
|
||||||
|
|
||||||
if (!config_output.http.routers) config_output.http.routers = {};
|
if (!config_output.http.routers)
|
||||||
if (!config_output.http.services) config_output.http.services = {};
|
config_output.http.routers = {};
|
||||||
|
if (!config_output.http.services)
|
||||||
|
config_output.http.services = {};
|
||||||
|
|
||||||
const fullDomain = sr.fullDomain;
|
const fullDomain = sr.fullDomain;
|
||||||
const srKey = `inference-sr${sr.siteResourceId}`;
|
const srKey = `inference-sr${sr.siteResourceId}`;
|
||||||
const routerName = `${srKey}-router`;
|
const routerName = `${srKey}-router`;
|
||||||
const serviceName = `${srKey}-service`;
|
const serviceName = `${srKey}-service`;
|
||||||
const rule = `Host(\`${fullDomain}\`) && ClientIP(\`${exitNode.address}\`)`; // restrict to coming from the exit node ip range that the client is connected to
|
const rule = `Host(\`${fullDomain}\`) && ClientIP(\`${exitNode.address}\`)`; // restrict to coming from the exit node ip range that the client is connected to
|
||||||
|
|
||||||
let tls: any = {};
|
let tls: any = {};
|
||||||
if (!privateConfig.getRawPrivateConfig().flags.use_pangolin_dns) {
|
if (
|
||||||
const domainParts = fullDomain.split(".");
|
!privateConfig.getRawPrivateConfig().flags.use_pangolin_dns
|
||||||
const wildCard =
|
) {
|
||||||
domainParts.length <= 2
|
const domainParts = fullDomain.split(".");
|
||||||
? `*.${domainParts.join(".")}`
|
const wildCard =
|
||||||
: `*.${domainParts.slice(1).join(".")}`;
|
domainParts.length <= 2
|
||||||
|
? `*.${domainParts.join(".")}`
|
||||||
|
: `*.${domainParts.slice(1).join(".")}`;
|
||||||
|
|
||||||
const globalDefaultResolver =
|
const globalDefaultResolver =
|
||||||
config.getRawConfig().traefik.cert_resolver;
|
config.getRawConfig().traefik.cert_resolver;
|
||||||
const globalDefaultPreferWildcard =
|
const globalDefaultPreferWildcard =
|
||||||
config.getRawConfig().traefik.prefer_wildcard_cert;
|
config.getRawConfig().traefik.prefer_wildcard_cert;
|
||||||
|
|
||||||
tls = {
|
tls = {
|
||||||
certResolver: globalDefaultResolver,
|
certResolver: globalDefaultResolver,
|
||||||
...(globalDefaultPreferWildcard
|
...(globalDefaultPreferWildcard
|
||||||
? { domains: [{ main: wildCard }] }
|
? { domains: [{ main: wildCard }] }
|
||||||
: {})
|
: {})
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const matchingCert = validCerts.find(
|
const matchingCert = validCerts.find(
|
||||||
(cert) => cert.queriedDomain === fullDomain
|
(cert) => cert.queriedDomain === fullDomain
|
||||||
);
|
|
||||||
if (!matchingCert) {
|
|
||||||
logger.debug(
|
|
||||||
`No matching certificate found for inference siteResource fullDomain: ${fullDomain}`
|
|
||||||
);
|
);
|
||||||
continue;
|
if (!matchingCert) {
|
||||||
}
|
logger.debug(
|
||||||
}
|
`No matching certificate found for inference siteResource fullDomain: ${fullDomain}`
|
||||||
|
);
|
||||||
const additionalMiddlewares =
|
continue;
|
||||||
config.getRawConfig().traefik.additional_middlewares || [];
|
|
||||||
const routerMiddlewares: string[] = [
|
|
||||||
...(enableAiGatewayClientIpHeader
|
|
||||||
? [aiGatewayClientIpMiddlewareName]
|
|
||||||
: []),
|
|
||||||
aiGatewayTrustMiddlewareNameSiteResource
|
|
||||||
];
|
|
||||||
|
|
||||||
if (aiGatewayOverride) {
|
|
||||||
const srHeadersMiddlewareName = `${srKey}-headers-middleware`;
|
|
||||||
config_output.http.middlewares[srHeadersMiddlewareName] = {
|
|
||||||
headers: {
|
|
||||||
customRequestHeaders: {
|
|
||||||
...(aiGatewayHost ? { Host: aiGatewayHost } : {}),
|
|
||||||
"p-host": fullDomain
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
routerMiddlewares.push(srHeadersMiddlewareName);
|
|
||||||
}
|
|
||||||
|
|
||||||
routerMiddlewares.push(...additionalMiddlewares);
|
const additionalMiddlewares =
|
||||||
|
config.getRawConfig().traefik.additional_middlewares || [];
|
||||||
|
const routerMiddlewares: string[] = [
|
||||||
|
...(enableAiGatewayClientIpHeader
|
||||||
|
? [aiGatewayClientIpMiddlewareName]
|
||||||
|
: []),
|
||||||
|
aiGatewayTrustMiddlewareNameSiteResource
|
||||||
|
];
|
||||||
|
|
||||||
if (sr.ssl) {
|
if (aiGatewayOverride) {
|
||||||
config_output.http.routers[routerName + "-redirect"] = {
|
const srHeadersMiddlewareName = `${srKey}-headers-middleware`;
|
||||||
|
config_output.http.middlewares[srHeadersMiddlewareName] = {
|
||||||
|
headers: {
|
||||||
|
customRequestHeaders: {
|
||||||
|
...(aiGatewayHost
|
||||||
|
? { Host: aiGatewayHost }
|
||||||
|
: {}),
|
||||||
|
"p-host": fullDomain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
routerMiddlewares.push(srHeadersMiddlewareName);
|
||||||
|
}
|
||||||
|
|
||||||
|
routerMiddlewares.push(...additionalMiddlewares);
|
||||||
|
|
||||||
|
if (sr.ssl) {
|
||||||
|
config_output.http.routers[routerName + "-redirect"] = {
|
||||||
|
entryPoints: [
|
||||||
|
config.getRawConfig().traefik.http_entrypoint
|
||||||
|
],
|
||||||
|
middlewares: [redirectHttpsMiddlewareName],
|
||||||
|
service: serviceName,
|
||||||
|
rule,
|
||||||
|
priority: 200 // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
config_output.http.routers[routerName] = {
|
||||||
entryPoints: [
|
entryPoints: [
|
||||||
config.getRawConfig().traefik.http_entrypoint
|
sr.ssl
|
||||||
|
? config.getRawConfig().traefik.https_entrypoint
|
||||||
|
: config.getRawConfig().traefik.http_entrypoint
|
||||||
],
|
],
|
||||||
middlewares: [redirectHttpsMiddlewareName],
|
middlewares: routerMiddlewares,
|
||||||
service: serviceName,
|
service: serviceName,
|
||||||
rule,
|
rule,
|
||||||
priority: 200 // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
priority: 200, // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
||||||
|
...(sr.ssl ? { tls } : {})
|
||||||
|
};
|
||||||
|
|
||||||
|
config_output.http.services[serviceName] = {
|
||||||
|
loadBalancer: {
|
||||||
|
servers: [{ url: aiGatewayUrl }]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
config_output.http.routers[routerName] = {
|
|
||||||
entryPoints: [
|
|
||||||
sr.ssl
|
|
||||||
? config.getRawConfig().traefik.https_entrypoint
|
|
||||||
: config.getRawConfig().traefik.http_entrypoint
|
|
||||||
],
|
|
||||||
middlewares: routerMiddlewares,
|
|
||||||
service: serviceName,
|
|
||||||
rule,
|
|
||||||
priority: 200, // we want to match on the site resource first because the clientIP rule is more specific than the public inference resource rule, which is just the exit node IP range. so we give it a higher priority to ensure it matches first.
|
|
||||||
...(sr.ssl ? { tls } : {})
|
|
||||||
};
|
|
||||||
|
|
||||||
config_output.http.services[serviceName] = {
|
|
||||||
loadBalancer: {
|
|
||||||
servers: [{ url: aiGatewayUrl }]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user