134 lines
3.3 KiB
TypeScript
134 lines
3.3 KiB
TypeScript
import { Construct } from "constructs";
|
|
import { Manifest } from "@cdktf/provider-kubernetes/lib/manifest";
|
|
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
|
|
|
|
import { PrivateCertificate } from "../../cert-manager";
|
|
|
|
export type IngressRouteOptions = {
|
|
provider: KubernetesProvider;
|
|
namespace: string;
|
|
name: string;
|
|
|
|
/** Hostname for this route (e.g. npm.dogar.dev) */
|
|
host: string;
|
|
|
|
/** Path prefix (default: "/") */
|
|
path?: string;
|
|
|
|
/** Backend K8s Service */
|
|
serviceName: string;
|
|
servicePort: number;
|
|
serviceProtocol?: "http" | "https";
|
|
|
|
/** EntryPoints (default: ["websecure"]) */
|
|
entryPoints?: string[];
|
|
|
|
/** TLS secret name for HTTPS termination */
|
|
tlsSecretName?: string;
|
|
|
|
/** Extra middlewares (traefik format: namespace/name) */
|
|
middlewares?: string[];
|
|
};
|
|
|
|
export class IngressRoute extends Construct {
|
|
public readonly manifest: Manifest;
|
|
|
|
constructor(scope: Construct, id: string, opts: IngressRouteOptions) {
|
|
super(scope, id);
|
|
|
|
const name = opts.name;
|
|
const path = opts.path ?? "/";
|
|
const entryPoints = opts.entryPoints ?? ["websecure"];
|
|
|
|
const { provider, namespace } = opts;
|
|
|
|
if (opts.serviceProtocol === "https") {
|
|
new PrivateCertificate(this, "internal-cert", {
|
|
provider,
|
|
namespace,
|
|
name: `${opts.serviceName}-tls-internal`,
|
|
secretName: `${opts.serviceName}-tls-internal`,
|
|
dnsNames: [
|
|
opts.serviceName,
|
|
`${opts.serviceName}.${opts.namespace}.svc`,
|
|
`${opts.serviceName}.${opts.namespace}.svc.cluster.local`,
|
|
],
|
|
usages: ["digital signature", "key encipherment", "server auth"],
|
|
});
|
|
|
|
new Manifest(this, `${name}-https-transport`, {
|
|
provider,
|
|
manifest: {
|
|
apiVersion: "traefik.io/v1alpha1",
|
|
kind: "ServersTransport",
|
|
metadata: {
|
|
name: `${name}-https-transport`,
|
|
namespace,
|
|
},
|
|
spec: {
|
|
serverName: `${opts.serviceName}.${opts.namespace}.svc.cluster.local`,
|
|
rootCAs: [
|
|
{
|
|
secret: "root-secret",
|
|
},
|
|
],
|
|
insecureSkipVerify: false,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
const route: any = {
|
|
match: `Host(\`${opts.host}\`) && PathPrefix(\`${path}\`)`,
|
|
kind: "Rule",
|
|
services: [
|
|
{
|
|
namespace,
|
|
name: opts.serviceName,
|
|
port: opts.servicePort,
|
|
scheme: opts.serviceProtocol ?? "http",
|
|
serversTransport:
|
|
opts.serviceProtocol === "https"
|
|
? `${name}-https-transport`
|
|
: undefined,
|
|
},
|
|
],
|
|
};
|
|
|
|
if (opts.middlewares?.length) {
|
|
route.middlewares = opts.middlewares.map((mw) => {
|
|
const [namespace, name] = mw.split("/");
|
|
return { name, namespace };
|
|
});
|
|
}
|
|
|
|
const spec: any = {
|
|
entryPoints,
|
|
routes: [route],
|
|
};
|
|
|
|
if (opts.tlsSecretName) {
|
|
spec.tls = {
|
|
secretName: opts.tlsSecretName,
|
|
options: {
|
|
name: "tls-options",
|
|
namespace: "homelab",
|
|
},
|
|
};
|
|
}
|
|
|
|
this.manifest = new Manifest(this, name, {
|
|
provider,
|
|
manifest: {
|
|
apiVersion: "traefik.io/v1alpha1",
|
|
kind: "IngressRoute",
|
|
metadata: {
|
|
name,
|
|
namespace,
|
|
},
|
|
spec,
|
|
},
|
|
});
|
|
}
|
|
}
|