feat: primary forwarding mode completed

This commit is contained in:
=
2025-09-04 21:58:21 +05:30
parent c116eb9ed2
commit 035156bcc3
8 changed files with 77 additions and 5 deletions

View File

@@ -25,6 +25,7 @@
"@fastify/multipart": "8.3.1", "@fastify/multipart": "8.3.1",
"@fastify/passport": "^2.4.0", "@fastify/passport": "^2.4.0",
"@fastify/rate-limit": "^9.0.0", "@fastify/rate-limit": "^9.0.0",
"@fastify/reply-from": "^9.8.0",
"@fastify/request-context": "^5.1.0", "@fastify/request-context": "^5.1.0",
"@fastify/session": "^10.7.0", "@fastify/session": "^10.7.0",
"@fastify/static": "^7.0.4", "@fastify/static": "^7.0.4",
@@ -8044,6 +8045,42 @@
"toad-cache": "^3.3.0" "toad-cache": "^3.3.0"
} }
}, },
"node_modules/@fastify/reply-from": {
"version": "9.8.0",
"resolved": "https://registry.npmjs.org/@fastify/reply-from/-/reply-from-9.8.0.tgz",
"integrity": "sha512-bPNVaFhEeNI0Lyl6404YZaPFokudCplidE3QoOcr78yOy6H9sYw97p5KPYvY/NJNUHfFtvxOaSAHnK+YSiv/Mg==",
"license": "MIT",
"dependencies": {
"@fastify/error": "^3.0.0",
"end-of-stream": "^1.4.4",
"fast-content-type-parse": "^1.1.0",
"fast-querystring": "^1.0.0",
"fastify-plugin": "^4.0.0",
"toad-cache": "^3.7.0",
"undici": "^5.19.1"
}
},
"node_modules/@fastify/reply-from/node_modules/@fastify/busboy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@fastify/reply-from/node_modules/undici": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/@fastify/request-context": { "node_modules/@fastify/request-context": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@fastify/request-context/-/request-context-5.1.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/request-context/-/request-context-5.1.0.tgz",
@@ -29330,9 +29367,10 @@
} }
}, },
"node_modules/toad-cache": { "node_modules/toad-cache": {
"version": "3.3.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.3.0.tgz", "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz",
"integrity": "sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==", "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==",
"license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }

View File

@@ -145,6 +145,7 @@
"@fastify/multipart": "8.3.1", "@fastify/multipart": "8.3.1",
"@fastify/passport": "^2.4.0", "@fastify/passport": "^2.4.0",
"@fastify/rate-limit": "^9.0.0", "@fastify/rate-limit": "^9.0.0",
"@fastify/reply-from": "^9.8.0",
"@fastify/request-context": "^5.1.0", "@fastify/request-context": "^5.1.0",
"@fastify/session": "^10.7.0", "@fastify/session": "^10.7.0",
"@fastify/static": "^7.0.4", "@fastify/static": "^7.0.4",

View File

@@ -162,6 +162,7 @@ declare module "fastify" {
}; };
// identity injection. depending on which kinda of token the information is filled in auth // identity injection. depending on which kinda of token the information is filled in auth
auth: TAuthMode; auth: TAuthMode;
isPrimaryForwardingMode: boolean;
permission: { permission: {
authMethod: ActorAuthMethod; authMethod: ActorAuthMethod;
type: ActorType; type: ActorType;

View File

@@ -218,6 +218,8 @@ const envSchema = z
), ),
PARAMS_FOLDER_SECRET_DETECTION_ENTROPY: z.coerce.number().optional().default(3.7), PARAMS_FOLDER_SECRET_DETECTION_ENTROPY: z.coerce.number().optional().default(3.7),
INFISICAL_PRIMARY_URL: zpStr(z.string().optional()),
// HSM // HSM
HSM_LIB_PATH: zpStr(z.string().optional()), HSM_LIB_PATH: zpStr(z.string().optional()),
HSM_PIN: zpStr(z.string().optional()), HSM_PIN: zpStr(z.string().optional()),

View File

@@ -107,11 +107,16 @@ export const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
}; };
// ! Important: You can only 100% count on the `req.permission.orgId` field being present when the auth method is Identity Access Token (Machine Identity). // ! Important: You can only 100% count on the `req.permission.orgId` field being present when the auth method is Identity Access Token (Machine Identity).
export const injectIdentity = fp(async (server: FastifyZodProvider) => { export const injectIdentity = fp(async (server: FastifyZodProvider, opt: { isPrimaryForwardingMode?: boolean }) => {
server.decorateRequest("auth", null); server.decorateRequest("auth", null);
server.decorateRequest("isPrimaryForwardingMode", Boolean(opt.isPrimaryForwardingMode));
server.addHook("onRequest", async (req) => { server.addHook("onRequest", async (req) => {
const appCfg = getConfig(); const appCfg = getConfig();
if (opt.isPrimaryForwardingMode && req.method !== "GET") {
return;
}
if (req.url.includes(".well-known/est") || req.url.includes("/api/v3/auth/")) { if (req.url.includes(".well-known/est") || req.url.includes("/api/v3/auth/")) {
return; return;
} }

View File

@@ -10,6 +10,10 @@ interface TAuthOptions {
export const verifyAuth = export const verifyAuth =
<T extends FastifyRequest>(authStrategies: AuthMode[], options: TAuthOptions = { requireOrg: true }) => <T extends FastifyRequest>(authStrategies: AuthMode[], options: TAuthOptions = { requireOrg: true }) =>
(req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => { (req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => {
if (req.isPrimaryForwardingMode && req.method !== "GET") {
return done();
}
if (!Array.isArray(authStrategies)) throw new Error("Auth strategy must be array"); if (!Array.isArray(authStrategies)) throw new Error("Auth strategy must be array");
if (!req.auth) throw new UnauthorizedError({ message: "Token missing" }); if (!req.auth) throw new UnauthorizedError({ message: "Token missing" });

View File

@@ -0,0 +1,14 @@
import replyFrom from "@fastify/reply-from";
import fp from "fastify-plugin";
export const primaryForwardingMode = fp(async (server, opt: { primaryUrl: string }) => {
await server.register(replyFrom, {
base: opt.primaryUrl
});
server.addHook("preValidation", async (request, reply) => {
if (request.url.startsWith("/api") && ["POST", "PUT", "DELETE", "PATCH"].includes(request.method)) {
return reply.from(request.url);
}
});
});

View File

@@ -312,6 +312,7 @@ import { injectAssumePrivilege } from "../plugins/auth/inject-assume-privilege";
import { injectIdentity } from "../plugins/auth/inject-identity"; import { injectIdentity } from "../plugins/auth/inject-identity";
import { injectPermission } from "../plugins/auth/inject-permission"; import { injectPermission } from "../plugins/auth/inject-permission";
import { injectRateLimits } from "../plugins/inject-rate-limits"; import { injectRateLimits } from "../plugins/inject-rate-limits";
import { primaryForwardingMode } from "../plugins/primary-forwarding-mode";
import { registerV1Routes } from "./v1"; import { registerV1Routes } from "./v1";
import { initializeOauthConfigSync } from "./v1/sso-router"; import { initializeOauthConfigSync } from "./v1/sso-router";
import { registerV2Routes } from "./v2"; import { registerV2Routes } from "./v2";
@@ -2146,8 +2147,14 @@ export const registerRoutes = async (
user: userDAL, user: userDAL,
kmipClient: kmipClientDAL kmipClient: kmipClientDAL
}); });
const isPrimaryForwardingMode = Boolean(envConfig.INFISICAL_PRIMARY_URL);
if (isPrimaryForwardingMode) {
logger.info(`Infisical primary instance is configured: ${envConfig.INFISICAL_PRIMARY_URL}`);
await server.register(injectIdentity, { userDAL, serviceTokenDAL }); await server.register(primaryForwardingMode, { primaryUrl: envConfig.INFISICAL_PRIMARY_URL as string });
}
await server.register(injectIdentity, { isPrimaryForwardingMode });
await server.register(injectAssumePrivilege); await server.register(injectAssumePrivilege);
await server.register(injectPermission); await server.register(injectPermission);
await server.register(injectRateLimits); await server.register(injectRateLimits);