Get the headers into the traefik config

This commit is contained in:
Owen
2025-09-11 12:20:50 -07:00
parent 612446c3c9
commit 1eacb8ff36
7 changed files with 84 additions and 46 deletions

View File

@@ -31,6 +31,8 @@ def convert_and_send(file_path, url, headers):
# convert the parsed YAML to a JSON string
json_payload = json.dumps(parsed_yaml)
print("Converted JSON payload:")
print(json_payload)
# Encode the JSON string to Base64
encoded_json = base64.b64encode(json_payload.encode('utf-8')).decode('utf-8')

View File

@@ -5,16 +5,19 @@ resources:
full-domain: level1.test3.example.com
host-header: example.com
tls-server-name: example.com
auth:
pincode: 123456
password: sadfasdfadsf
sso-enabled: true
sso-roles:
- Member
sso-users:
- owen@fossorial.io
whitelist-users:
- owen@fossorial.io
# auth:
# pincode: 123456
# password: sadfasdfadsf
# sso-enabled: true
# sso-roles:
# - Member
# sso-users:
# - owen@fossorial.io
# whitelist-users:
# - owen@fossorial.io
headers:
- X-Example-Header: example-value
- X-Another-Header: another-value
targets:
- site: lively-yosemite-toad
hostname: localhost
@@ -24,15 +27,11 @@ resources:
hostname: localhost
method: http
port: 8001
- site: glossy-plains-viscacha-rat
hostname: localhost
method: http
port: 8001
resource-nice-id2:
name: this is other resource
protocol: tcp
proxy-port: 3000
targets:
- site: glossy-plains-viscacha-rat
- site: lively-yosemite-toad
hostname: localhost
port: 3000

View File

@@ -96,6 +96,7 @@ export const resources = pgTable("resources", {
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
onDelete: "cascade"
}),
headers: text("headers"), // comma-separated list of headers to add to the request
});
export const targets = pgTable("targets", {

View File

@@ -107,7 +107,8 @@ export const resources = sqliteTable("resources", {
enableProxy: integer("enableProxy", { mode: "boolean" }).default(true),
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
onDelete: "cascade"
})
}),
headers: text("headers"), // comma-separated list of headers to add to the request
});
export const targets = sqliteTable("targets", {

View File

@@ -120,6 +120,17 @@ export async function updateResources(
const http = resourceData.protocol == "http";
const protocol =
resourceData.protocol == "http" ? "tcp" : resourceData.protocol;
const resourceEnabled = resourceData.enabled == undefined || resourceData.enabled == null ? true : resourceData.enabled;
let headers = "";
for (const headerObj of resourceData.headers || []) {
for (const [key, value] of Object.entries(headerObj)) {
headers += `${key}: ${value},`;
}
}
// if there are headers, remove the trailing comma
if (headers.endsWith(",")) {
headers = headers.slice(0, -1);
}
if (existingResource) {
let domain;
@@ -152,7 +163,7 @@ export async function updateResources(
fullDomain: http ? resourceData["full-domain"] : null,
subdomain: domain ? domain.subdomain : null,
domainId: domain ? domain.domainId : null,
enabled: resourceData.enabled ? true : false,
enabled: resourceEnabled,
sso: resourceData.auth?.["sso-enabled"] || false,
ssl: resourceData.ssl ? true : false,
setHostHeader: resourceData["host-header"] || null,
@@ -161,7 +172,8 @@ export async function updateResources(
"whitelist-users"
]
? resourceData.auth["whitelist-users"].length > 0
: false
: false,
headers: headers || null,
})
.where(
eq(resources.resourceId, existingResource.resourceId)
@@ -379,11 +391,12 @@ export async function updateResources(
fullDomain: http ? resourceData["full-domain"] : null,
subdomain: domain ? domain.subdomain : null,
domainId: domain ? domain.domainId : null,
enabled: resourceData.enabled ? true : false,
enabled: resourceEnabled,
sso: resourceData.auth?.["sso-enabled"] || false,
setHostHeader: resourceData["host-header"] || null,
tlsServerName: resourceData["tls-server-name"] || null,
ssl: resourceData.ssl ? true : false
ssl: resourceData.ssl ? true : false,
headers: headers || null
})
.returning();

View File

@@ -44,7 +44,8 @@ export const ResourceSchema = z
targets: z.array(TargetSchema.nullable()).optional().default([]),
auth: AuthSchema.optional(),
"host-header": z.string().optional(),
"tls-server-name": z.string().optional()
"tls-server-name": z.string().optional(),
headers: z.array(z.record(z.string(), z.string())).optional().default([]),
})
.refine(
(resource) => {

View File

@@ -54,7 +54,8 @@ export async function traefikConfigProvider(
config.getRawConfig().traefik.site_types
);
if (traefikConfig?.http?.middlewares) { // BECAUSE SOMETIMES THE CONFIG CAN BE EMPTY IF THERE IS NOTHING
if (traefikConfig?.http?.middlewares) {
// BECAUSE SOMETIMES THE CONFIG CAN BE EMPTY IF THERE IS NOTHING
traefikConfig.http.middlewares[badgerMiddlewareName] = {
plugin: {
[badgerMiddlewareName]: {
@@ -124,6 +125,7 @@ export async function getTraefikConfig(
tlsServerName: resources.tlsServerName,
setHostHeader: resources.setHostHeader,
enableProxy: resources.enableProxy,
headers: resources.headers,
// Target fields
targetId: targets.targetId,
targetEnabled: targets.enabled,
@@ -152,7 +154,7 @@ export async function getTraefikConfig(
inArray(sites.type, siteTypes),
config.getRawConfig().traefik.allow_raw_resources
? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true
: eq(resources.http, true),
: eq(resources.http, true)
)
);
@@ -177,7 +179,8 @@ export async function getTraefikConfig(
tlsServerName: row.tlsServerName,
setHostHeader: row.setHostHeader,
enableProxy: row.enableProxy,
targets: []
targets: [],
headers: row.headers
});
}
@@ -296,13 +299,52 @@ export async function getTraefikConfig(
const additionalMiddlewares =
config.getRawConfig().traefik.additional_middlewares || [];
let routerMiddlewares = [
badgerMiddlewareName,
...additionalMiddlewares
];
if (resource.headers && resource.headers.length > 0) {
const headersMiddlewareName = `${resource.resourceId}-headers-middleware`;
// if there are headers, parse them into an object
let headersObj: { [key: string]: string } = {};
const headersArr = resource.headers.split(",");
for (const header of headersArr) {
const [key, value] = header
.split(":")
.map((s: string) => s.trim());
if (key && value) {
headersObj[key] = value;
}
}
if (resource.setHostHeader) {
headersObj["Host"] = resource.setHostHeader;
}
// check if the object is not empty
if (Object.keys(headersObj).length > 0) {
// Add the headers middleware
if (!config_output.http.middlewares) {
config_output.http.middlewares = {};
}
config_output.http.middlewares[headersMiddlewareName] = {
headers: {
customRequestHeaders: headersObj
}
};
routerMiddlewares.push(headersMiddlewareName);
}
}
config_output.http.routers![routerName] = {
entryPoints: [
resource.ssl
? config.getRawConfig().traefik.https_entrypoint
: config.getRawConfig().traefik.http_entrypoint
],
middlewares: [badgerMiddlewareName, ...additionalMiddlewares],
middlewares: routerMiddlewares,
service: serviceName,
rule: `Host(\`${fullDomain}\`)`,
priority: 100,
@@ -413,27 +455,6 @@ export async function getTraefikConfig(
serviceName
].loadBalancer.serversTransport = transportName;
}
// Add the host header middleware
if (resource.setHostHeader) {
if (!config_output.http.middlewares) {
config_output.http.middlewares = {};
}
config_output.http.middlewares[hostHeaderMiddlewareName] = {
headers: {
customRequestHeaders: {
Host: resource.setHostHeader
}
}
};
if (!config_output.http.routers![routerName].middlewares) {
config_output.http.routers![routerName].middlewares = [];
}
config_output.http.routers![routerName].middlewares = [
...config_output.http.routers![routerName].middlewares,
hostHeaderMiddlewareName
];
}
} else {
// Non-HTTP (TCP/UDP) configuration
if (!resource.enableProxy) {