mirror of
https://github.com/fosrl/pangolin.git
synced 2026-10-21 12:09:04 +02:00
Make sure the MTLS is enforced for redirects
This commit is contained in:
@@ -407,6 +407,7 @@ export async function getTraefikConfig(
|
||||
wildcard: row.resourceWildcard,
|
||||
ssl: attachedToResource ? !!row.resourceSsl : row.ssl,
|
||||
attachedTo: attachedToResource ? "resource" : "domain",
|
||||
resourceId: row.resourceId,
|
||||
matchPath: row.matchPath,
|
||||
pathMatchType: row.pathMatchType,
|
||||
priority: row.priority,
|
||||
@@ -416,7 +417,8 @@ export async function getTraefikConfig(
|
||||
}
|
||||
|
||||
// Trusted client-CA certificates for resources that require mTLS: HTTP,
|
||||
// browser-gateway (SSH/RDP/VNC) and inference resources served over SSL.
|
||||
// browser-gateway (SSH/RDP/VNC) and inference resources served over SSL,
|
||||
// and the redirects attached to them.
|
||||
const mtlsCaCertsByResource = await getMtlsCaCertificatesByResource([
|
||||
...[...resourcesMap.values()]
|
||||
.filter((r) => r.mode === "http" && r.ssl)
|
||||
@@ -424,7 +426,12 @@ export async function getTraefikConfig(
|
||||
...[...browserGatewayResourcesMap.values()]
|
||||
.filter((r) => r.ssl)
|
||||
.map((r) => r.resourceId),
|
||||
...inferenceResources.filter((r) => r.ssl).map((r) => r.resourceId)
|
||||
...inferenceResources.filter((r) => r.ssl).map((r) => r.resourceId),
|
||||
// redirects attached to a resource share its host, and are emitted
|
||||
// even on exit nodes that don't serve the resource itself
|
||||
...redirectRoutes
|
||||
.filter((r) => r.attachedTo === "resource" && r.ssl)
|
||||
.map((r) => r.resourceId!)
|
||||
]);
|
||||
|
||||
// make sure we have at least one resource
|
||||
@@ -639,6 +646,7 @@ export async function getTraefikConfig(
|
||||
buildRedirectConfig({
|
||||
config_output,
|
||||
redirects: redirectRoutes,
|
||||
mtlsCaCertsByResource,
|
||||
badgerMiddlewareName,
|
||||
redirectHttpsMiddlewareName,
|
||||
resolveTls: (redirect) =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import logger from "@server/logger";
|
||||
import config from "@server/lib/config";
|
||||
import { applyMtlsConfig } from "@server/lib/traefik/mtls";
|
||||
import {
|
||||
buildHostRule,
|
||||
appendPathMatch,
|
||||
@@ -12,6 +13,8 @@ export type RedirectRouteRow = {
|
||||
fullDomain: string;
|
||||
hasSubdomain: boolean;
|
||||
attachedTo: "resource" | "domain";
|
||||
/** Set when attachedTo is "resource". */
|
||||
resourceId: number | null;
|
||||
enabled: boolean;
|
||||
name: string;
|
||||
wildcard: boolean | null;
|
||||
@@ -35,13 +38,16 @@ export function buildRedirectConfig(params: {
|
||||
badgerMiddlewareName: string;
|
||||
redirectHttpsMiddlewareName: string;
|
||||
resolveTls: (row: RedirectRouteRow) => any | null;
|
||||
// trusted client-CA PEMs for resources that require mTLS
|
||||
mtlsCaCertsByResource: Map<number, string[]>;
|
||||
}): void {
|
||||
const {
|
||||
config_output,
|
||||
redirects,
|
||||
badgerMiddlewareName,
|
||||
redirectHttpsMiddlewareName,
|
||||
resolveTls
|
||||
resolveTls,
|
||||
mtlsCaCertsByResource
|
||||
} = params;
|
||||
|
||||
if (redirects.length === 0) {
|
||||
@@ -72,6 +78,27 @@ export function buildRedirectConfig(params: {
|
||||
}
|
||||
}
|
||||
|
||||
// A redirect attached to a resource listens on the resource's host,
|
||||
// and Traefik resolves TLS options per host: unless it references the
|
||||
// resource's mTLS options too, Traefik falls back to the defaults and
|
||||
// the resource's mTLS is no longer enforced.
|
||||
const redirectMiddlewares = [...routerMiddlewares];
|
||||
if (
|
||||
redirect.ssl &&
|
||||
redirect.attachedTo === "resource" &&
|
||||
redirect.resourceId !== null
|
||||
) {
|
||||
const mtlsOptionsName = applyMtlsConfig(
|
||||
config_output,
|
||||
redirect.resourceId,
|
||||
mtlsCaCertsByResource.get(redirect.resourceId),
|
||||
redirectMiddlewares
|
||||
);
|
||||
if (mtlsOptionsName) {
|
||||
tls = { ...tls, options: mtlsOptionsName };
|
||||
}
|
||||
}
|
||||
|
||||
if (!config_output.http.routers) {
|
||||
config_output.http.routers = {};
|
||||
}
|
||||
@@ -113,7 +140,7 @@ export function buildRedirectConfig(params: {
|
||||
|
||||
config_output.http.routers[routerName] = {
|
||||
entryPoints: [redirect.ssl ? httpsEntrypoint : httpEntrypoint],
|
||||
middlewares: routerMiddlewares,
|
||||
middlewares: redirectMiddlewares,
|
||||
service: NOOP_SERVICE,
|
||||
rule,
|
||||
priority,
|
||||
|
||||
@@ -488,6 +488,7 @@ export async function getTraefikConfig(
|
||||
wildcard: row.resourceWildcard,
|
||||
ssl: attachedToResource ? !!row.resourceSsl : row.ssl,
|
||||
attachedTo: attachedToResource ? "resource" : "domain",
|
||||
resourceId: row.resourceId,
|
||||
matchPath: row.matchPath,
|
||||
pathMatchType: row.pathMatchType,
|
||||
priority: row.priority,
|
||||
@@ -547,7 +548,8 @@ export async function getTraefikConfig(
|
||||
}
|
||||
|
||||
// Trusted client-CA certificates for resources that require mTLS: HTTP,
|
||||
// browser-gateway (SSH/RDP/VNC) and inference resources served over SSL.
|
||||
// browser-gateway (SSH/RDP/VNC) and inference resources served over SSL,
|
||||
// and the redirects attached to them.
|
||||
const mtlsCaCertsByResource = await getMtlsCaCertificatesByResource([
|
||||
...[...resourcesMap.values()]
|
||||
.filter((r) => r.mode === "http" && r.ssl)
|
||||
@@ -555,7 +557,12 @@ export async function getTraefikConfig(
|
||||
...[...browserGatewayResourcesMap.values()]
|
||||
.filter((r) => r.ssl)
|
||||
.map((r) => r.resourceId),
|
||||
...inferenceResources.filter((r) => r.ssl).map((r) => r.resourceId)
|
||||
...inferenceResources.filter((r) => r.ssl).map((r) => r.resourceId),
|
||||
// redirects attached to a resource share its host, and are emitted
|
||||
// even on exit nodes that don't serve the resource itself
|
||||
...redirectRoutes
|
||||
.filter((r) => r.attachedTo === "resource" && r.ssl)
|
||||
.map((r) => r.resourceId!)
|
||||
]);
|
||||
|
||||
const traefikRateLimit = config.getRawConfig().traefik.rate_limit;
|
||||
@@ -920,6 +927,7 @@ export async function getTraefikConfig(
|
||||
buildRedirectConfig({
|
||||
config_output,
|
||||
redirects: redirectRoutes,
|
||||
mtlsCaCertsByResource,
|
||||
badgerMiddlewareName,
|
||||
redirectHttpsMiddlewareName,
|
||||
resolveTls: (redirect) => {
|
||||
|
||||
Reference in New Issue
Block a user