mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 09:28:06 +00:00
feat: add gateway registration and org-proxy initialization
This commit is contained in:
Vendored
+2
@@ -16,6 +16,7 @@ import { TEventBusService } from "@app/ee/services/event/event-bus-service";
|
|||||||
import { TServerSentEventsService } from "@app/ee/services/event/event-sse-service";
|
import { TServerSentEventsService } from "@app/ee/services/event/event-sse-service";
|
||||||
import { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service";
|
import { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service";
|
||||||
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
|
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
|
||||||
|
import { TGatewayV2ServiceFactory } from "@app/ee/services/gateway-v2/gateway-v2-service";
|
||||||
import { TGithubOrgSyncServiceFactory } from "@app/ee/services/github-org-sync/github-org-sync-service";
|
import { TGithubOrgSyncServiceFactory } from "@app/ee/services/github-org-sync/github-org-sync-service";
|
||||||
import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
|
import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
|
||||||
import { TIdentityAuthTemplateServiceFactory } from "@app/ee/services/identity-auth-template";
|
import { TIdentityAuthTemplateServiceFactory } from "@app/ee/services/identity-auth-template";
|
||||||
@@ -305,6 +306,7 @@ declare module "fastify" {
|
|||||||
sse: TServerSentEventsService;
|
sse: TServerSentEventsService;
|
||||||
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
||||||
proxy: TProxyServiceFactory;
|
proxy: TProxyServiceFactory;
|
||||||
|
gatewayV2: TGatewayV2ServiceFactory;
|
||||||
};
|
};
|
||||||
// this is exclusive use for middlewares in which we need to inject data
|
// this is exclusive use for middlewares in which we need to inject data
|
||||||
// everywhere else access using service layer
|
// everywhere else access using service layer
|
||||||
|
|||||||
Vendored
+12
@@ -233,6 +233,9 @@ import {
|
|||||||
TOrgGatewayConfig,
|
TOrgGatewayConfig,
|
||||||
TOrgGatewayConfigInsert,
|
TOrgGatewayConfigInsert,
|
||||||
TOrgGatewayConfigUpdate,
|
TOrgGatewayConfigUpdate,
|
||||||
|
TOrgGatewayConfigV2,
|
||||||
|
TOrgGatewayConfigV2Insert,
|
||||||
|
TOrgGatewayConfigV2Update,
|
||||||
TOrgMemberships,
|
TOrgMemberships,
|
||||||
TOrgMembershipsInsert,
|
TOrgMembershipsInsert,
|
||||||
TOrgMembershipsUpdate,
|
TOrgMembershipsUpdate,
|
||||||
@@ -293,6 +296,9 @@ import {
|
|||||||
TProjectUserMembershipRoles,
|
TProjectUserMembershipRoles,
|
||||||
TProjectUserMembershipRolesInsert,
|
TProjectUserMembershipRolesInsert,
|
||||||
TProjectUserMembershipRolesUpdate,
|
TProjectUserMembershipRolesUpdate,
|
||||||
|
TProxies,
|
||||||
|
TProxiesInsert,
|
||||||
|
TProxiesUpdate,
|
||||||
TRateLimit,
|
TRateLimit,
|
||||||
TRateLimitInsert,
|
TRateLimitInsert,
|
||||||
TRateLimitUpdate,
|
TRateLimitUpdate,
|
||||||
@@ -1270,5 +1276,11 @@ declare module "knex/types/tables" {
|
|||||||
TOrgProxyConfigInsert,
|
TOrgProxyConfigInsert,
|
||||||
TOrgProxyConfigUpdate
|
TOrgProxyConfigUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.OrgGatewayConfigV2]: KnexOriginal.CompositeTableType<
|
||||||
|
TOrgGatewayConfigV2,
|
||||||
|
TOrgGatewayConfigV2Insert,
|
||||||
|
TOrgGatewayConfigV2Update
|
||||||
|
>;
|
||||||
|
[TableName.Proxy]: KnexOriginal.CompositeTableType<TProxies, TProxiesInsert, TProxiesUpdate>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,43 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
|
|
||||||
await createOnUpdateTrigger(knex, TableName.OrgProxyConfig);
|
await createOnUpdateTrigger(knex, TableName.OrgProxyConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.OrgGatewayConfigV2))) {
|
||||||
|
await knex.schema.createTable(TableName.OrgGatewayConfigV2, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.binary("encryptedRootGatewayCaPrivateKey").notNullable();
|
||||||
|
t.binary("encryptedRootGatewayCaCertificate").notNullable();
|
||||||
|
t.binary("encryptedGatewayServerCaPrivateKey").notNullable();
|
||||||
|
t.binary("encryptedGatewayServerCaCertificate").notNullable();
|
||||||
|
t.binary("encryptedGatewayServerCaCertificateChain").notNullable();
|
||||||
|
t.binary("encryptedGatewayClientCaPrivateKey").notNullable();
|
||||||
|
t.binary("encryptedGatewayClientCaCertificate").notNullable();
|
||||||
|
t.binary("encryptedGatewayClientCaCertificateChain").notNullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.OrgGatewayConfigV2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Proxy))) {
|
||||||
|
await knex.schema.createTable(TableName.Proxy, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
|
||||||
|
t.uuid("orgId");
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
|
||||||
|
t.uuid("identityId");
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
|
||||||
|
t.string("name").notNullable().unique();
|
||||||
|
t.string("ip").notNullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Proxy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
@@ -75,4 +112,10 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
|
|
||||||
await dropOnUpdateTrigger(knex, TableName.InstanceProxyConfig);
|
await dropOnUpdateTrigger(knex, TableName.InstanceProxyConfig);
|
||||||
await knex.schema.dropTableIfExists(TableName.InstanceProxyConfig);
|
await knex.schema.dropTableIfExists(TableName.InstanceProxyConfig);
|
||||||
|
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.OrgGatewayConfigV2);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.OrgGatewayConfigV2);
|
||||||
|
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Proxy);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Proxy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export * from "./models";
|
|||||||
export * from "./oidc-configs";
|
export * from "./oidc-configs";
|
||||||
export * from "./org-bots";
|
export * from "./org-bots";
|
||||||
export * from "./org-gateway-config";
|
export * from "./org-gateway-config";
|
||||||
|
export * from "./org-gateway-config-v2";
|
||||||
export * from "./org-memberships";
|
export * from "./org-memberships";
|
||||||
export * from "./org-proxy-config";
|
export * from "./org-proxy-config";
|
||||||
export * from "./org-roles";
|
export * from "./org-roles";
|
||||||
@@ -164,3 +165,4 @@ export * from "./user-group-membership";
|
|||||||
export * from "./users";
|
export * from "./users";
|
||||||
export * from "./webhooks";
|
export * from "./webhooks";
|
||||||
export * from "./workflow-integrations";
|
export * from "./workflow-integrations";
|
||||||
|
export * from "./proxies";
|
||||||
|
|||||||
@@ -182,7 +182,9 @@ export enum TableName {
|
|||||||
|
|
||||||
// gateway v2
|
// gateway v2
|
||||||
InstanceProxyConfig = "instance_proxy_config",
|
InstanceProxyConfig = "instance_proxy_config",
|
||||||
OrgProxyConfig = "org_proxy_config"
|
OrgProxyConfig = "org_proxy_config",
|
||||||
|
OrgGatewayConfigV2 = "org_gateway_config_v2",
|
||||||
|
Proxy = "proxies"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const OrgGatewayConfigV2Schema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
orgId: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
encryptedRootGatewayCaPrivateKey: zodBuffer,
|
||||||
|
encryptedRootGatewayCaCertificate: zodBuffer,
|
||||||
|
encryptedGatewayServerCaPrivateKey: zodBuffer,
|
||||||
|
encryptedGatewayServerCaCertificate: zodBuffer,
|
||||||
|
encryptedGatewayServerCaCertificateChain: zodBuffer,
|
||||||
|
encryptedGatewayClientCaPrivateKey: zodBuffer,
|
||||||
|
encryptedGatewayClientCaCertificate: zodBuffer,
|
||||||
|
encryptedGatewayClientCaCertificateChain: zodBuffer
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TOrgGatewayConfigV2 = z.infer<typeof OrgGatewayConfigV2Schema>;
|
||||||
|
export type TOrgGatewayConfigV2Insert = Omit<z.input<typeof OrgGatewayConfigV2Schema>, TImmutableDBKeys>;
|
||||||
|
export type TOrgGatewayConfigV2Update = Partial<Omit<z.input<typeof OrgGatewayConfigV2Schema>, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const ProxiesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
identityId: z.string().uuid().nullable().optional(),
|
||||||
|
name: z.string(),
|
||||||
|
ip: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TProxies = z.infer<typeof ProxiesSchema>;
|
||||||
|
export type TProxiesInsert = Omit<z.input<typeof ProxiesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TProxiesUpdate = Partial<Omit<z.input<typeof ProxiesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -1,24 +1,69 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
export const registerProxyRouter = async (server: FastifyZodProvider) => {
|
export const registerProxyRouter = async (server: FastifyZodProvider) => {
|
||||||
|
const appCfg = getConfig();
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/",
|
url: "/register-instance-proxy",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
ip: z.string()
|
ip: z.string(),
|
||||||
|
name: z.string()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.any()
|
200: z.any()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onRequest: (req, _, next) => {
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
|
||||||
|
if (appCfg.PROXY_AUTH_SECRET && authHeader === `Bearer ${appCfg.PROXY_AUTH_SECRET}`) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Invalid proxy auth secret"
|
||||||
|
});
|
||||||
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
return server.services.proxy.registerProxy(req.body);
|
return server.services.proxy.registerProxy({
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/register-org-proxy",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
ip: z.string(),
|
||||||
|
name: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.any()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
return server.services.proxy.registerProxy({
|
||||||
|
...req.body,
|
||||||
|
identityId: req.permission.id,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerGatewayV2Router = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
proxyName: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.any()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const gateway = await server.services.gatewayV2.registerGateway({
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
proxyName: req.body.proxyName,
|
||||||
|
actorId: req.permission.id
|
||||||
|
});
|
||||||
|
|
||||||
|
return gateway;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router";
|
import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router";
|
||||||
import { registerProjectRoleRouter } from "./project-role-router";
|
import { registerProjectRoleRouter } from "./project-role-router";
|
||||||
|
import { registerGatewayV2Router } from "./gateway-router";
|
||||||
|
|
||||||
export const registerV2EERoutes = async (server: FastifyZodProvider) => {
|
export const registerV2EERoutes = async (server: FastifyZodProvider) => {
|
||||||
// org role starts with organization
|
// org role starts with organization
|
||||||
@@ -23,6 +24,8 @@ export const registerV2EERoutes = async (server: FastifyZodProvider) => {
|
|||||||
prefix: "/identity-project-additional-privilege"
|
prefix: "/identity-project-additional-privilege"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.register(registerGatewayV2Router, { prefix: "/gateways" });
|
||||||
|
|
||||||
await server.register(
|
await server.register(
|
||||||
async (secretRotationV2Router) => {
|
async (secretRotationV2Router) => {
|
||||||
// register generic secret rotation endpoints
|
// register generic secret rotation endpoints
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
|
import { PgSqlLock } from "@app/keystore/keystore";
|
||||||
|
import { crypto } from "@app/lib/crypto";
|
||||||
|
import { constructPemChainFromCerts } from "@app/services/certificate/certificate-fns";
|
||||||
|
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
||||||
|
import {
|
||||||
|
createSerialNumber,
|
||||||
|
keyAlgorithmToAlgCfg
|
||||||
|
} from "@app/services/certificate-authority/certificate-authority-fns";
|
||||||
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
|
import { TProxyServiceFactory } from "../proxy/proxy-service";
|
||||||
|
import { TOrgGatewayConfigV2DALFactory } from "./org-gateway-config-v2-dal";
|
||||||
|
|
||||||
|
type TGatewayV2ServiceFactoryDep = {
|
||||||
|
orgGatewayConfigV2DAL: Pick<TOrgGatewayConfigV2DALFactory, "findOne" | "create" | "transaction" | "findById">;
|
||||||
|
kmsService: TKmsServiceFactory;
|
||||||
|
proxyService: TProxyServiceFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TGatewayV2ServiceFactory = ReturnType<typeof gatewayV2ServiceFactory>;
|
||||||
|
|
||||||
|
export const gatewayV2ServiceFactory = ({
|
||||||
|
orgGatewayConfigV2DAL,
|
||||||
|
kmsService,
|
||||||
|
proxyService
|
||||||
|
}: TGatewayV2ServiceFactoryDep) => {
|
||||||
|
const $getOrgCAs = async (orgId: string) => {
|
||||||
|
const { encryptor: orgKmsEncryptor, decryptor: orgKmsDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
const orgCAs = await orgGatewayConfigV2DAL.transaction(async (tx) => {
|
||||||
|
const orgGatewayConfigV2 = await orgGatewayConfigV2DAL.findOne({ orgId });
|
||||||
|
if (orgGatewayConfigV2) return orgGatewayConfigV2;
|
||||||
|
|
||||||
|
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.OrgGatewayV2Init(orgId)]);
|
||||||
|
|
||||||
|
// generate root CA
|
||||||
|
const rootCaKeyAlgorithm = CertKeyAlgorithm.RSA_2048;
|
||||||
|
const alg = keyAlgorithmToAlgCfg(rootCaKeyAlgorithm);
|
||||||
|
const rootCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
|
||||||
|
const rootCaSerialNumber = createSerialNumber();
|
||||||
|
const rootCaSkObj = crypto.nativeCrypto.KeyObject.from(rootCaKeys.privateKey);
|
||||||
|
const rootCaIssuedAt = new Date();
|
||||||
|
const rootCaExpiration = new Date(new Date().setFullYear(2045));
|
||||||
|
|
||||||
|
const rootCaCert = await x509.X509CertificateGenerator.createSelfSigned({
|
||||||
|
name: `O=${orgId},CN=Infisical Gateway Root CA`,
|
||||||
|
serialNumber: rootCaSerialNumber,
|
||||||
|
notBefore: rootCaIssuedAt,
|
||||||
|
notAfter: rootCaExpiration,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
keys: rootCaKeys,
|
||||||
|
extensions: [
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
new x509.KeyUsagesExtension(x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.cRLSign, true),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(rootCaKeys.publicKey)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// generate server CA
|
||||||
|
const serverCaSerialNumber = createSerialNumber();
|
||||||
|
const serverCaIssuedAt = new Date();
|
||||||
|
const serverCaExpiration = new Date(new Date().setFullYear(2045));
|
||||||
|
const serverCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
const serverCaSkObj = crypto.nativeCrypto.KeyObject.from(serverCaKeys.privateKey);
|
||||||
|
const serverCaCert = await x509.X509CertificateGenerator.create({
|
||||||
|
serialNumber: serverCaSerialNumber,
|
||||||
|
subject: `O=${orgId},CN=Infisical Gateway Server CA`,
|
||||||
|
issuer: rootCaCert.subject,
|
||||||
|
notBefore: serverCaIssuedAt,
|
||||||
|
notAfter: serverCaExpiration,
|
||||||
|
signingKey: rootCaKeys.privateKey,
|
||||||
|
publicKey: serverCaKeys.publicKey,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
extensions: [
|
||||||
|
new x509.KeyUsagesExtension(
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
x509.KeyUsageFlags.keyCertSign |
|
||||||
|
x509.KeyUsageFlags.cRLSign |
|
||||||
|
x509.KeyUsageFlags.digitalSignature |
|
||||||
|
x509.KeyUsageFlags.keyEncipherment,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new x509.BasicConstraintsExtension(true, 0, true),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(rootCaCert, false),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(serverCaKeys.publicKey)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// generate client CA
|
||||||
|
const clientCaSerialNumber = createSerialNumber();
|
||||||
|
const clientCaIssuedAt = new Date();
|
||||||
|
const clientCaExpiration = new Date(new Date().setFullYear(2045));
|
||||||
|
const clientCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
const clientCaSkObj = crypto.nativeCrypto.KeyObject.from(clientCaKeys.privateKey);
|
||||||
|
const clientCaCert = await x509.X509CertificateGenerator.create({
|
||||||
|
serialNumber: clientCaSerialNumber,
|
||||||
|
subject: `O=${orgId},CN=Infisical Gateway Client CA`,
|
||||||
|
issuer: rootCaCert.subject,
|
||||||
|
notBefore: clientCaIssuedAt,
|
||||||
|
notAfter: clientCaExpiration,
|
||||||
|
signingKey: rootCaKeys.privateKey,
|
||||||
|
publicKey: clientCaKeys.publicKey,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
extensions: [
|
||||||
|
new x509.KeyUsagesExtension(
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
x509.KeyUsageFlags.keyCertSign |
|
||||||
|
x509.KeyUsageFlags.cRLSign |
|
||||||
|
x509.KeyUsageFlags.digitalSignature |
|
||||||
|
x509.KeyUsageFlags.keyEncipherment,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new x509.BasicConstraintsExtension(true, 0, true),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(rootCaCert, false),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(clientCaKeys.publicKey)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const encryptedRootGatewayCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(
|
||||||
|
rootCaSkObj.export({
|
||||||
|
type: "pkcs8",
|
||||||
|
format: "der"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedRootGatewayCaCertificate = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(rootCaCert.rawData)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
const encryptedGatewayServerCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(serverCaSkObj.export({ type: "pkcs8", format: "der" }))
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedGatewayServerCaCertificate = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(serverCaCert.rawData)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedGatewayServerCaCertificateChain = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(constructPemChainFromCerts([rootCaCert]))
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
const encryptedGatewayClientCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(clientCaSkObj.export({ type: "pkcs8", format: "der" }))
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedGatewayClientCaCertificate = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(clientCaCert.rawData)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedGatewayClientCaCertificateChain = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(constructPemChainFromCerts([rootCaCert]))
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
return orgGatewayConfigV2DAL.create({
|
||||||
|
orgId,
|
||||||
|
encryptedRootGatewayCaPrivateKey,
|
||||||
|
encryptedRootGatewayCaCertificate,
|
||||||
|
encryptedGatewayServerCaPrivateKey,
|
||||||
|
encryptedGatewayServerCaCertificate,
|
||||||
|
encryptedGatewayServerCaCertificateChain,
|
||||||
|
encryptedGatewayClientCaPrivateKey,
|
||||||
|
encryptedGatewayClientCaCertificate,
|
||||||
|
encryptedGatewayClientCaCertificateChain
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootGatewayCaPrivateKey = orgKmsDecryptor({ cipherTextBlob: orgCAs.encryptedRootGatewayCaPrivateKey });
|
||||||
|
const rootGatewayCaCertificate = orgKmsDecryptor({ cipherTextBlob: orgCAs.encryptedRootGatewayCaCertificate });
|
||||||
|
|
||||||
|
const gatewayServerCaPrivateKey = orgKmsDecryptor({ cipherTextBlob: orgCAs.encryptedGatewayServerCaPrivateKey });
|
||||||
|
const gatewayServerCaCertificate = orgKmsDecryptor({ cipherTextBlob: orgCAs.encryptedGatewayServerCaCertificate });
|
||||||
|
const gatewayServerCaCertificateChain = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgCAs.encryptedGatewayServerCaCertificateChain
|
||||||
|
});
|
||||||
|
|
||||||
|
const gatewayClientCaPrivateKey = orgKmsDecryptor({ cipherTextBlob: orgCAs.encryptedGatewayClientCaPrivateKey });
|
||||||
|
const gatewayClientCaCertificate = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgCAs.encryptedGatewayClientCaCertificate
|
||||||
|
});
|
||||||
|
const gatewayClientCaCertificateChain = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgCAs.encryptedGatewayClientCaCertificateChain
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
rootGatewayCaPrivateKey,
|
||||||
|
rootGatewayCaCertificate,
|
||||||
|
gatewayServerCaPrivateKey,
|
||||||
|
gatewayServerCaCertificate,
|
||||||
|
gatewayServerCaCertificateChain,
|
||||||
|
gatewayClientCaPrivateKey,
|
||||||
|
gatewayClientCaCertificate,
|
||||||
|
gatewayClientCaCertificateChain
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerGateway = async ({ orgId, proxyName }: { orgId: string; actorId: string; proxyName: string }) => {
|
||||||
|
const orgCAs = await $getOrgCAs(orgId);
|
||||||
|
|
||||||
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
|
const gatewayServerCaCert = new x509.X509Certificate(orgCAs.gatewayServerCaCertificate);
|
||||||
|
const rootGatewayCaCert = new x509.X509Certificate(orgCAs.rootGatewayCaCertificate);
|
||||||
|
|
||||||
|
const gatewayServerCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
||||||
|
key: orgCAs.gatewayServerCaPrivateKey,
|
||||||
|
format: "der",
|
||||||
|
type: "pkcs8"
|
||||||
|
});
|
||||||
|
const gatewayServerCaPrivateKey = await crypto.nativeCrypto.subtle.importKey(
|
||||||
|
"pkcs8",
|
||||||
|
gatewayServerCaSkObj.export({ format: "der", type: "pkcs8" }),
|
||||||
|
alg,
|
||||||
|
true,
|
||||||
|
["sign"]
|
||||||
|
);
|
||||||
|
|
||||||
|
const gatewayServerKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
const gatewayServerCertIssuedAt = new Date();
|
||||||
|
const gatewayServerCertExpireAt = new Date(new Date().setMonth(new Date().getMonth() + 1));
|
||||||
|
const gatewayServerCertPrivateKey = crypto.nativeCrypto.KeyObject.from(gatewayServerKeys.privateKey);
|
||||||
|
|
||||||
|
const gatewayServerCertExtensions: x509.Extension[] = [
|
||||||
|
new x509.BasicConstraintsExtension(false),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(gatewayServerCaCert, false),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(gatewayServerKeys.publicKey),
|
||||||
|
new x509.CertificatePolicyExtension(["2.5.29.32.0"]), // anyPolicy
|
||||||
|
new x509.KeyUsagesExtension(
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
x509.KeyUsageFlags[CertKeyUsage.DIGITAL_SIGNATURE] | x509.KeyUsageFlags[CertKeyUsage.KEY_ENCIPHERMENT],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.SERVER_AUTH]], true)
|
||||||
|
];
|
||||||
|
|
||||||
|
const gatewayServerSerialNumber = createSerialNumber();
|
||||||
|
const gatewayServerCertificate = await x509.X509CertificateGenerator.create({
|
||||||
|
serialNumber: gatewayServerSerialNumber,
|
||||||
|
subject: `O=${orgId},CN=Gateway`,
|
||||||
|
issuer: gatewayServerCaCert.subject,
|
||||||
|
notBefore: gatewayServerCertIssuedAt,
|
||||||
|
notAfter: gatewayServerCertExpireAt,
|
||||||
|
signingKey: gatewayServerCaPrivateKey,
|
||||||
|
publicKey: gatewayServerKeys.publicKey,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
extensions: gatewayServerCertExtensions
|
||||||
|
});
|
||||||
|
|
||||||
|
const proxyCredentials = await proxyService.generateSshCredentialsForGateway({
|
||||||
|
proxyName,
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
pki: {
|
||||||
|
serverCertificate: gatewayServerCertificate.toString("pem"),
|
||||||
|
serverCertificateChain: constructPemChainFromCerts([gatewayServerCaCert, rootGatewayCaCert]),
|
||||||
|
serverPrivateKey: gatewayServerCertPrivateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
||||||
|
clientCA: rootGatewayCaCert.toString("pem")
|
||||||
|
},
|
||||||
|
ssh: {
|
||||||
|
clientCertificate: proxyCredentials.clientSshCert,
|
||||||
|
clientPrivateKey: proxyCredentials.clientSshPrivateKey,
|
||||||
|
serverCAPublicKey: proxyCredentials.serverCAPublicKey
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
registerGateway
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TOrgGatewayConfigV2DALFactory = ReturnType<typeof orgGatewayConfigV2DalFactory>;
|
||||||
|
|
||||||
|
export const orgGatewayConfigV2DalFactory = (db: TDbClient) => {
|
||||||
|
const orm = ormify(db, TableName.OrgGatewayConfigV2);
|
||||||
|
|
||||||
|
return orm;
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TProxyDALFactory = ReturnType<typeof proxyDalFactory>;
|
||||||
|
|
||||||
|
export const proxyDalFactory = (db: TDbClient) => {
|
||||||
|
const orm = ormify(db, TableName.Proxy);
|
||||||
|
|
||||||
|
return orm;
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export const isInstanceProxy = (proxyName: string) => {
|
||||||
|
return proxyName.startsWith("infisical-");
|
||||||
|
};
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
|
import { TProxies } from "@app/db/schemas";
|
||||||
import { PgSqlLock } from "@app/keystore/keystore";
|
import { PgSqlLock } from "@app/keystore/keystore";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { constructPemChainFromCerts, prependCertToPemChain } from "@app/services/certificate/certificate-fns";
|
import { constructPemChainFromCerts, prependCertToPemChain } from "@app/services/certificate/certificate-fns";
|
||||||
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
|
||||||
import {
|
import {
|
||||||
@@ -9,12 +11,15 @@ import {
|
|||||||
keyAlgorithmToAlgCfg
|
keyAlgorithmToAlgCfg
|
||||||
} from "@app/services/certificate-authority/certificate-authority-fns";
|
} from "@app/services/certificate-authority/certificate-authority-fns";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { createSshCert, createSshKeyPair } from "../ssh/ssh-certificate-authority-fns";
|
import { createSshCert, createSshKeyPair } from "../ssh/ssh-certificate-authority-fns";
|
||||||
import { SshCertType } from "../ssh/ssh-certificate-authority-types";
|
import { SshCertType } from "../ssh/ssh-certificate-authority-types";
|
||||||
import { SshCertKeyAlgorithm } from "../ssh-certificate/ssh-certificate-types";
|
import { SshCertKeyAlgorithm } from "../ssh-certificate/ssh-certificate-types";
|
||||||
import { TInstanceProxyConfigDALFactory } from "./instance-proxy-config-dal";
|
import { TInstanceProxyConfigDALFactory } from "./instance-proxy-config-dal";
|
||||||
import { TOrgProxyConfigDALFactory } from "./org-proxy-config-dal";
|
import { TOrgProxyConfigDALFactory } from "./org-proxy-config-dal";
|
||||||
|
import { TProxyDALFactory } from "./proxy-dal";
|
||||||
|
import { isInstanceProxy } from "./proxy-fns";
|
||||||
|
|
||||||
export type TProxyServiceFactory = ReturnType<typeof proxyServiceFactory>;
|
export type TProxyServiceFactory = ReturnType<typeof proxyServiceFactory>;
|
||||||
|
|
||||||
@@ -23,10 +28,12 @@ const INSTANCE_PROXY_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
|
|||||||
export const proxyServiceFactory = ({
|
export const proxyServiceFactory = ({
|
||||||
instanceProxyConfigDAL,
|
instanceProxyConfigDAL,
|
||||||
orgProxyConfigDAL,
|
orgProxyConfigDAL,
|
||||||
|
proxyDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}: {
|
}: {
|
||||||
instanceProxyConfigDAL: TInstanceProxyConfigDALFactory;
|
instanceProxyConfigDAL: TInstanceProxyConfigDALFactory;
|
||||||
orgProxyConfigDAL: TOrgProxyConfigDALFactory;
|
orgProxyConfigDAL: TOrgProxyConfigDALFactory;
|
||||||
|
proxyDAL: TProxyDALFactory;
|
||||||
kmsService: TKmsServiceFactory;
|
kmsService: TKmsServiceFactory;
|
||||||
}) => {
|
}) => {
|
||||||
const $getInstanceCAs = async () => {
|
const $getInstanceCAs = async () => {
|
||||||
@@ -36,8 +43,7 @@ export const proxyServiceFactory = ({
|
|||||||
|
|
||||||
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.InstanceProxyConfigInit()]);
|
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.InstanceProxyConfigInit()]);
|
||||||
|
|
||||||
const rootCaKeyAlgorithm = CertKeyAlgorithm.RSA_2048;
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
const alg = keyAlgorithmToAlgCfg(rootCaKeyAlgorithm);
|
|
||||||
const rootCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
const rootCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
|
||||||
// generate root CA
|
// generate root CA
|
||||||
@@ -370,21 +376,303 @@ export const proxyServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const registerProxy = async ({ ip }: { ip: string }) => {
|
const $getOrgCAs = async (orgId: string) => {
|
||||||
// initialize instance CAs if not yet initialized
|
|
||||||
const instanceCAs = await $getInstanceCAs();
|
const instanceCAs = await $getInstanceCAs();
|
||||||
|
const { encryptor: orgKmsEncryptor, decryptor: orgKmsDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: check if identity used already has an existing proxy. If the same IP, return the existing proxy. If not, create a new proxy and overwrite
|
const orgProxyConfig = await orgProxyConfigDAL.transaction(async (tx) => {
|
||||||
|
const existingOrgProxyConfig = await orgProxyConfigDAL.findOne(
|
||||||
|
{
|
||||||
|
orgId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
// generate proxy server PKI certificate
|
if (existingOrgProxyConfig) {
|
||||||
|
return existingOrgProxyConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.OrgProxyConfigInit(orgId)]);
|
||||||
|
|
||||||
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
|
const orgProxyCaCert = new x509.X509Certificate(instanceCAs.orgProxyPkiCaCertificate);
|
||||||
|
const rootProxyCaCert = new x509.X509Certificate(instanceCAs.rootProxyPkiCaCertificate);
|
||||||
|
const orgProxyCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
||||||
|
key: instanceCAs.orgProxyPkiCaPrivateKey,
|
||||||
|
format: "der",
|
||||||
|
type: "pkcs8"
|
||||||
|
});
|
||||||
|
const orgProxyClientCaPrivateKey = await crypto.nativeCrypto.subtle.importKey(
|
||||||
|
"pkcs8",
|
||||||
|
orgProxyCaSkObj.export({ format: "der", type: "pkcs8" }),
|
||||||
|
alg,
|
||||||
|
true,
|
||||||
|
["sign"]
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate org proxy client CA
|
||||||
|
const orgProxyClientCaSerialNumber = createSerialNumber();
|
||||||
|
const orgProxyClientCaIssuedAt = new Date();
|
||||||
|
const orgProxyClientCaExpiration = new Date(new Date().setFullYear(2045));
|
||||||
|
const orgProxyClientCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
const orgProxyClientCaSkObj = crypto.nativeCrypto.KeyObject.from(orgProxyClientCaKeys.privateKey);
|
||||||
|
const orgProxyClientCaCert = await x509.X509CertificateGenerator.create({
|
||||||
|
serialNumber: orgProxyClientCaSerialNumber,
|
||||||
|
subject: `O=${orgId},CN=Infisical Org Proxy Client CA`,
|
||||||
|
issuer: orgProxyCaCert.subject,
|
||||||
|
notBefore: orgProxyClientCaIssuedAt,
|
||||||
|
notAfter: orgProxyClientCaExpiration,
|
||||||
|
signingKey: orgProxyClientCaPrivateKey,
|
||||||
|
publicKey: orgProxyClientCaKeys.publicKey,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
extensions: [
|
||||||
|
new x509.KeyUsagesExtension(
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
x509.KeyUsageFlags.keyCertSign |
|
||||||
|
x509.KeyUsageFlags.cRLSign |
|
||||||
|
x509.KeyUsageFlags.digitalSignature |
|
||||||
|
x509.KeyUsageFlags.keyEncipherment,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new x509.BasicConstraintsExtension(true, 0, true),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(orgProxyCaCert, false),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(orgProxyClientCaKeys.publicKey)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const orgProxyClientCaChain = constructPemChainFromCerts([orgProxyCaCert, rootProxyCaCert]);
|
||||||
|
|
||||||
|
// generate org SSH CA
|
||||||
|
const orgSshServerCaKeyPair = await createSshKeyPair(SshCertKeyAlgorithm.RSA_2048);
|
||||||
|
const orgSshClientCaKeyPair = await createSshKeyPair(SshCertKeyAlgorithm.RSA_2048);
|
||||||
|
|
||||||
|
// generate org proxy server CA
|
||||||
|
const orgProxyServerCaSerialNumber = createSerialNumber();
|
||||||
|
const orgProxyServerCaIssuedAt = new Date();
|
||||||
|
const orgProxyServerCaExpiration = new Date(new Date().setFullYear(2045));
|
||||||
|
const orgProxyServerCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
const orgProxyServerCaSkObj = crypto.nativeCrypto.KeyObject.from(orgProxyServerCaKeys.privateKey);
|
||||||
|
const orgProxyServerCaCert = await x509.X509CertificateGenerator.create({
|
||||||
|
serialNumber: orgProxyServerCaSerialNumber,
|
||||||
|
subject: `O=${orgId},CN=Infisical Org Proxy Server CA`,
|
||||||
|
issuer: orgProxyCaCert.subject,
|
||||||
|
notBefore: orgProxyServerCaIssuedAt,
|
||||||
|
notAfter: orgProxyServerCaExpiration,
|
||||||
|
signingKey: orgProxyClientCaPrivateKey,
|
||||||
|
publicKey: orgProxyServerCaKeys.publicKey,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
extensions: [
|
||||||
|
new x509.KeyUsagesExtension(
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
x509.KeyUsageFlags.keyCertSign |
|
||||||
|
x509.KeyUsageFlags.cRLSign |
|
||||||
|
x509.KeyUsageFlags.digitalSignature |
|
||||||
|
x509.KeyUsageFlags.keyEncipherment,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new x509.BasicConstraintsExtension(true, 0, true),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(orgProxyCaCert, false),
|
||||||
|
await x509.SubjectKeyIdentifierExtension.create(orgProxyServerCaKeys.publicKey)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const orgProxyServerCaChain = constructPemChainFromCerts([orgProxyCaCert, rootProxyCaCert]);
|
||||||
|
|
||||||
|
const encryptedProxyPkiClientCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(
|
||||||
|
orgProxyClientCaSkObj.export({
|
||||||
|
type: "pkcs8",
|
||||||
|
format: "der"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedProxyPkiClientCaCertificate = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgProxyClientCaCert.rawData)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
const encryptedProxyPkiClientCaCertificateChain = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgProxyClientCaChain)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
const encryptedProxyPkiServerCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(
|
||||||
|
orgProxyServerCaSkObj.export({
|
||||||
|
type: "pkcs8",
|
||||||
|
format: "der"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedProxyPkiServerCaCertificate = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgProxyServerCaCert.rawData)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedProxyPkiServerCaCertificateChain = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgProxyServerCaChain)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
const encryptedProxySshClientCaPublicKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgSshClientCaKeyPair.publicKey)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedProxySshClientCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgSshClientCaKeyPair.privateKey)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
const encryptedProxySshServerCaPublicKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgSshServerCaKeyPair.publicKey)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
const encryptedProxySshServerCaPrivateKey = orgKmsEncryptor({
|
||||||
|
plainText: Buffer.from(orgSshServerCaKeyPair.privateKey)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
return orgProxyConfigDAL.create({
|
||||||
|
orgId,
|
||||||
|
encryptedProxyPkiClientCaPrivateKey,
|
||||||
|
encryptedProxyPkiClientCaCertificate,
|
||||||
|
encryptedProxyPkiClientCaCertificateChain,
|
||||||
|
encryptedProxyPkiServerCaPrivateKey,
|
||||||
|
encryptedProxyPkiServerCaCertificate,
|
||||||
|
encryptedProxyPkiServerCaCertificateChain,
|
||||||
|
encryptedProxySshClientCaPublicKey,
|
||||||
|
encryptedProxySshClientCaPrivateKey,
|
||||||
|
encryptedProxySshServerCaPublicKey,
|
||||||
|
encryptedProxySshServerCaPrivateKey
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const proxyPkiClientCaPrivateKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxyPkiClientCaPrivateKey
|
||||||
|
});
|
||||||
|
const proxyPkiClientCaCertificate = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxyPkiClientCaCertificate
|
||||||
|
});
|
||||||
|
const proxyPkiClientCaCertificateChain = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxyPkiClientCaCertificateChain
|
||||||
|
});
|
||||||
|
|
||||||
|
const proxyPkiServerCaPrivateKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxyPkiServerCaPrivateKey
|
||||||
|
});
|
||||||
|
const proxyPkiServerCaCertificate = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxyPkiServerCaCertificate
|
||||||
|
});
|
||||||
|
const proxyPkiServerCaCertificateChain = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxyPkiServerCaCertificateChain
|
||||||
|
});
|
||||||
|
|
||||||
|
const proxySshClientCaPublicKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxySshClientCaPublicKey
|
||||||
|
});
|
||||||
|
const proxySshClientCaPrivateKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxySshClientCaPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const proxySshServerCaPublicKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxySshServerCaPublicKey
|
||||||
|
});
|
||||||
|
const proxySshServerCaPrivateKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgProxyConfig.encryptedProxySshServerCaPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
proxyPkiClientCaPrivateKey,
|
||||||
|
proxyPkiClientCaCertificate,
|
||||||
|
proxyPkiClientCaCertificateChain,
|
||||||
|
proxyPkiServerCaPrivateKey,
|
||||||
|
proxyPkiServerCaCertificate,
|
||||||
|
proxyPkiServerCaCertificateChain,
|
||||||
|
proxySshClientCaPublicKey,
|
||||||
|
proxySshClientCaPrivateKey,
|
||||||
|
proxySshServerCaPublicKey,
|
||||||
|
proxySshServerCaPrivateKey
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateSshCredentialsForGateway = async ({ proxyName, orgId }: { proxyName: string; orgId: string }) => {
|
||||||
|
let proxy: TProxies | null;
|
||||||
|
if (isInstanceProxy(proxyName)) {
|
||||||
|
proxy = await proxyDAL.findOne({
|
||||||
|
name: proxyName
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
proxy = await proxyDAL.findOne({
|
||||||
|
orgId,
|
||||||
|
name: proxyName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!proxy) {
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: "Proxy not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyAlgorithm = SshCertKeyAlgorithm.RSA_2048;
|
||||||
|
const { publicKey: proxyClientSshPublicKey, privateKey: proxyClientSshPrivateKey } =
|
||||||
|
await createSshKeyPair(keyAlgorithm);
|
||||||
|
|
||||||
|
if (isInstanceProxy(proxyName)) {
|
||||||
|
const instanceCAs = await $getInstanceCAs();
|
||||||
|
const proxyClientSshCert = await createSshCert({
|
||||||
|
caPrivateKey: instanceCAs.instanceProxySshServerCaPrivateKey.toString("utf8"),
|
||||||
|
clientPublicKey: proxyClientSshPublicKey,
|
||||||
|
keyId: `proxy-client-${proxy.id}`,
|
||||||
|
principals: [orgId],
|
||||||
|
certType: SshCertType.USER,
|
||||||
|
requestedTtl: "30d"
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
clientSshCert: proxyClientSshCert.signedPublicKey,
|
||||||
|
clientSshPrivateKey: proxyClientSshPrivateKey,
|
||||||
|
serverCAPublicKey: instanceCAs.instanceProxySshServerCaPublicKey.toString("utf8")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const orgCAs = await $getOrgCAs(orgId);
|
||||||
|
const proxyClientSshCert = await createSshCert({
|
||||||
|
caPrivateKey: orgCAs.proxySshServerCaPrivateKey.toString("utf8"),
|
||||||
|
clientPublicKey: proxyClientSshPublicKey,
|
||||||
|
keyId: `proxy-client-${proxy.id}`,
|
||||||
|
principals: [orgId],
|
||||||
|
certType: SshCertType.USER,
|
||||||
|
requestedTtl: "30d"
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
clientSshCert: proxyClientSshCert.signedPublicKey,
|
||||||
|
clientSshPrivateKey: proxyClientSshPrivateKey,
|
||||||
|
serverCAPublicKey: orgCAs.proxySshServerCaPublicKey.toString("utf8")
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const $generateProxyCredentials = async ({
|
||||||
|
ip,
|
||||||
|
orgId,
|
||||||
|
rootProxyPkiCaCertificate,
|
||||||
|
proxyPkiServerCaCertificate,
|
||||||
|
proxyPkiServerCaPrivateKey,
|
||||||
|
proxySshServerCaPrivateKey,
|
||||||
|
proxyPkiServerCaCertificateChain,
|
||||||
|
proxySshClientCaPublicKey
|
||||||
|
}: {
|
||||||
|
ip: string;
|
||||||
|
rootProxyPkiCaCertificate: Buffer;
|
||||||
|
proxyPkiServerCaCertificate: Buffer;
|
||||||
|
proxyPkiServerCaPrivateKey: Buffer;
|
||||||
|
proxySshServerCaPrivateKey: Buffer;
|
||||||
|
proxyPkiServerCaCertificateChain: Buffer;
|
||||||
|
proxySshClientCaPublicKey: Buffer;
|
||||||
|
orgId?: string;
|
||||||
|
}) => {
|
||||||
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
const proxyServerCaCert = new x509.X509Certificate(instanceCAs.instanceProxyPkiServerCaCertificate);
|
const proxyServerCaCert = new x509.X509Certificate(proxyPkiServerCaCertificate);
|
||||||
const rootProxyCaCert = new x509.X509Certificate(instanceCAs.rootProxyPkiCaCertificate);
|
const rootProxyCaCert = new x509.X509Certificate(rootProxyPkiCaCertificate);
|
||||||
const proxyServerCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
const proxyServerCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
||||||
key: instanceCAs.instanceProxyPkiServerCaPrivateKey,
|
key: proxyPkiServerCaPrivateKey,
|
||||||
format: "der",
|
format: "der",
|
||||||
type: "pkcs8"
|
type: "pkcs8"
|
||||||
});
|
});
|
||||||
|
|
||||||
const proxyServerCaPrivateKey = await crypto.nativeCrypto.subtle.importKey(
|
const proxyServerCaPrivateKey = await crypto.nativeCrypto.subtle.importKey(
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
proxyServerCaSkObj.export({ format: "der", type: "pkcs8" }),
|
proxyServerCaSkObj.export({ format: "der", type: "pkcs8" }),
|
||||||
@@ -416,7 +704,7 @@ export const proxyServiceFactory = ({
|
|||||||
const proxyServerSerialNumber = createSerialNumber();
|
const proxyServerSerialNumber = createSerialNumber();
|
||||||
const proxyServerCertificate = await x509.X509CertificateGenerator.create({
|
const proxyServerCertificate = await x509.X509CertificateGenerator.create({
|
||||||
serialNumber: proxyServerSerialNumber,
|
serialNumber: proxyServerSerialNumber,
|
||||||
subject: `CN=${ip},O=Infisical,OU=Proxy`,
|
subject: `CN=${ip},O=${orgId ?? "Infisical"},OU=Proxy`,
|
||||||
issuer: proxyServerCaCert.subject,
|
issuer: proxyServerCaCert.subject,
|
||||||
notBefore: proxyServerCertIssuedAt,
|
notBefore: proxyServerCertIssuedAt,
|
||||||
notAfter: proxyServerCertExpireAt,
|
notAfter: proxyServerCertExpireAt,
|
||||||
@@ -432,7 +720,7 @@ export const proxyServiceFactory = ({
|
|||||||
await createSshKeyPair(keyAlgorithm);
|
await createSshKeyPair(keyAlgorithm);
|
||||||
|
|
||||||
const proxyServerSshCert = await createSshCert({
|
const proxyServerSshCert = await createSshCert({
|
||||||
caPrivateKey: instanceCAs.instanceProxySshServerCaPrivateKey.toString("utf8"),
|
caPrivateKey: proxySshServerCaPrivateKey.toString("utf8"),
|
||||||
clientPublicKey: proxyServerSshPublicKey,
|
clientPublicKey: proxyServerSshPublicKey,
|
||||||
keyId: "proxy-server",
|
keyId: "proxy-server",
|
||||||
principals: [ip],
|
principals: [ip],
|
||||||
@@ -445,7 +733,7 @@ export const proxyServiceFactory = ({
|
|||||||
serverCertificate: proxyServerCertificate.toString("pem"),
|
serverCertificate: proxyServerCertificate.toString("pem"),
|
||||||
serverCertificateChain: prependCertToPemChain(
|
serverCertificateChain: prependCertToPemChain(
|
||||||
proxyServerCaCert,
|
proxyServerCaCert,
|
||||||
instanceCAs.instanceProxyPkiServerCaCertificateChain.toString("utf8")
|
proxyPkiServerCaCertificateChain.toString("utf8")
|
||||||
),
|
),
|
||||||
serverPrivateKey: proxyServerCertPrivateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
serverPrivateKey: proxyServerCertPrivateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
||||||
clientCA: rootProxyCaCert.toString("pem")
|
clientCA: rootProxyCaCert.toString("pem")
|
||||||
@@ -453,12 +741,138 @@ export const proxyServiceFactory = ({
|
|||||||
ssh: {
|
ssh: {
|
||||||
serverCertificate: proxyServerSshCert.signedPublicKey,
|
serverCertificate: proxyServerSshCert.signedPublicKey,
|
||||||
serverPrivateKey: proxyServerSshPrivateKey,
|
serverPrivateKey: proxyServerSshPrivateKey,
|
||||||
clientCAPublicKey: instanceCAs.instanceProxySshClientCaPublicKey.toString("utf8")
|
clientCAPublicKey: proxySshClientCaPublicKey.toString("utf8")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const registerProxy = async ({
|
||||||
|
ip,
|
||||||
|
name,
|
||||||
|
identityId,
|
||||||
|
orgId
|
||||||
|
}: {
|
||||||
|
ip: string;
|
||||||
|
name: string;
|
||||||
|
identityId?: string;
|
||||||
|
orgId?: string;
|
||||||
|
}) => {
|
||||||
|
let proxy: TProxies;
|
||||||
|
const isOrgProxy = identityId && orgId;
|
||||||
|
|
||||||
|
if (isOrgProxy) {
|
||||||
|
// organization proxy
|
||||||
|
if (isInstanceProxy(name)) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Org proxy name cannot start with 'infisical-'. This is reserved for internal use."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy = await proxyDAL.transaction(async (tx) => {
|
||||||
|
const existingProxy = await proxyDAL.findOne(
|
||||||
|
{
|
||||||
|
identityId,
|
||||||
|
orgId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingProxy && (existingProxy.ip !== ip || existingProxy.name !== name)) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Org proxy with this machine identity already exists."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existingProxy) {
|
||||||
|
return proxyDAL.create(
|
||||||
|
{
|
||||||
|
ip,
|
||||||
|
name,
|
||||||
|
identityId,
|
||||||
|
orgId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingProxy;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// instance proxy
|
||||||
|
if (!name.startsWith("infisical-")) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Instance proxy name must start with 'infisical-'."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy = await proxyDAL.transaction(async (tx) => {
|
||||||
|
const existingProxy = await proxyDAL.findOne(
|
||||||
|
{
|
||||||
|
name
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingProxy && existingProxy.ip !== ip) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Instance proxy with this name already exists"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existingProxy) {
|
||||||
|
return proxyDAL.create(
|
||||||
|
{
|
||||||
|
ip,
|
||||||
|
name
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingProxy;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInstanceProxy(name)) {
|
||||||
|
const instanceCAs = await $getInstanceCAs();
|
||||||
|
return $generateProxyCredentials({
|
||||||
|
ip,
|
||||||
|
rootProxyPkiCaCertificate: instanceCAs.rootProxyPkiCaCertificate,
|
||||||
|
|
||||||
|
proxyPkiServerCaCertificate: instanceCAs.instanceProxyPkiServerCaCertificate,
|
||||||
|
proxyPkiServerCaPrivateKey: instanceCAs.instanceProxyPkiServerCaPrivateKey,
|
||||||
|
proxyPkiServerCaCertificateChain: instanceCAs.instanceProxyPkiServerCaCertificateChain,
|
||||||
|
|
||||||
|
proxySshServerCaPrivateKey: instanceCAs.instanceProxySshServerCaPrivateKey,
|
||||||
|
proxySshClientCaPublicKey: instanceCAs.instanceProxySshClientCaPublicKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy.orgId) {
|
||||||
|
const orgCAs = await $getOrgCAs(proxy.orgId);
|
||||||
|
const instanceCAs = await $getInstanceCAs();
|
||||||
|
|
||||||
|
return $generateProxyCredentials({
|
||||||
|
ip,
|
||||||
|
orgId: proxy.orgId,
|
||||||
|
rootProxyPkiCaCertificate: instanceCAs.rootProxyPkiCaCertificate,
|
||||||
|
|
||||||
|
proxyPkiServerCaCertificate: orgCAs.proxyPkiServerCaCertificate,
|
||||||
|
proxyPkiServerCaPrivateKey: orgCAs.proxyPkiServerCaPrivateKey,
|
||||||
|
proxyPkiServerCaCertificateChain: orgCAs.proxyPkiServerCaCertificateChain,
|
||||||
|
|
||||||
|
proxySshServerCaPrivateKey: orgCAs.proxySshServerCaPrivateKey,
|
||||||
|
proxySshClientCaPublicKey: orgCAs.proxySshClientCaPublicKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Unhandled proxy type"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registerProxy
|
registerProxy,
|
||||||
|
generateSshCredentialsForGateway
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export const PgSqlLock = {
|
|||||||
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`),
|
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`),
|
||||||
CreateFolder: (envId: string, projectId: string) => pgAdvisoryLockHashText(`create-folder:${envId}-${projectId}`),
|
CreateFolder: (envId: string, projectId: string) => pgAdvisoryLockHashText(`create-folder:${envId}-${projectId}`),
|
||||||
SshInit: (projectId: string) => pgAdvisoryLockHashText(`ssh-bootstrap:${projectId}`),
|
SshInit: (projectId: string) => pgAdvisoryLockHashText(`ssh-bootstrap:${projectId}`),
|
||||||
InstanceProxyConfigInit: () => pgAdvisoryLockHashText("instance-proxy-config-init")
|
InstanceProxyConfigInit: () => pgAdvisoryLockHashText("instance-proxy-config-init"),
|
||||||
|
OrgGatewayV2Init: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-v2-init:${orgId}`),
|
||||||
|
OrgProxyConfigInit: (orgId: string) => pgAdvisoryLockHashText(`org-proxy-config-init:${orgId}`)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// all the key prefixes used must be set here to avoid conflict
|
// all the key prefixes used must be set here to avoid conflict
|
||||||
|
|||||||
@@ -233,6 +233,8 @@ const envSchema = z
|
|||||||
GATEWAY_RELAY_REALM: zpStr(z.string().optional()),
|
GATEWAY_RELAY_REALM: zpStr(z.string().optional()),
|
||||||
GATEWAY_RELAY_AUTH_SECRET: zpStr(z.string().optional()),
|
GATEWAY_RELAY_AUTH_SECRET: zpStr(z.string().optional()),
|
||||||
|
|
||||||
|
PROXY_AUTH_SECRET: zpStr(z.string().optional()),
|
||||||
|
|
||||||
DYNAMIC_SECRET_ALLOW_INTERNAL_IP: zodStrBool.default("false"),
|
DYNAMIC_SECRET_ALLOW_INTERNAL_IP: zodStrBool.default("false"),
|
||||||
DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()).default(
|
DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()).default(
|
||||||
process.env.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID
|
process.env.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.url.includes("/api/v1/proxies/register-instance-proxy")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { authMode, token, actor } = await extractAuth(req, appCfg.AUTH_SECRET);
|
const { authMode, token, actor } = await extractAuth(req, appCfg.AUTH_SECRET);
|
||||||
|
|
||||||
if (!authMode) return;
|
if (!authMode) return;
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ import { tokenServiceFactory } from "@app/services/auth-token/auth-token-service
|
|||||||
import { certificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
import { certificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
||||||
import { certificateDALFactory } from "@app/services/certificate/certificate-dal";
|
import { certificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||||
import { certificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal";
|
import { certificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal";
|
||||||
|
import { gatewayV2ServiceFactory } from "@app/ee/services/gateway-v2/gateway-v2-service";
|
||||||
|
import { orgGatewayConfigV2DalFactory } from "@app/ee/services/gateway-v2/org-gateway-config-v2-dal";
|
||||||
import { certificateServiceFactory } from "@app/services/certificate/certificate-service";
|
import { certificateServiceFactory } from "@app/services/certificate/certificate-service";
|
||||||
import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
|
import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
|
||||||
import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
||||||
@@ -317,6 +319,7 @@ import { registerV1Routes } from "./v1";
|
|||||||
import { initializeOauthConfigSync } from "./v1/sso-router";
|
import { initializeOauthConfigSync } from "./v1/sso-router";
|
||||||
import { registerV2Routes } from "./v2";
|
import { registerV2Routes } from "./v2";
|
||||||
import { registerV3Routes } from "./v3";
|
import { registerV3Routes } from "./v3";
|
||||||
|
import { proxyDalFactory } from "@app/ee/services/proxy/proxy-dal";
|
||||||
|
|
||||||
const histogram = monitorEventLoopDelay({ resolution: 20 });
|
const histogram = monitorEventLoopDelay({ resolution: 20 });
|
||||||
histogram.enable();
|
histogram.enable();
|
||||||
@@ -944,6 +947,9 @@ export const registerRoutes = async (
|
|||||||
|
|
||||||
const instanceProxyConfigDAL = instanceProxyConfigDalFactory(db);
|
const instanceProxyConfigDAL = instanceProxyConfigDalFactory(db);
|
||||||
const orgProxyConfigDAL = orgProxyConfigDalFactory(db);
|
const orgProxyConfigDAL = orgProxyConfigDalFactory(db);
|
||||||
|
const proxyDAL = proxyDalFactory(db);
|
||||||
|
|
||||||
|
const orgGatewayConfigV2DAL = orgGatewayConfigV2DalFactory(db);
|
||||||
|
|
||||||
const certificateService = certificateServiceFactory({
|
const certificateService = certificateServiceFactory({
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
@@ -1969,9 +1975,16 @@ export const registerRoutes = async (
|
|||||||
const proxyService = proxyServiceFactory({
|
const proxyService = proxyServiceFactory({
|
||||||
instanceProxyConfigDAL,
|
instanceProxyConfigDAL,
|
||||||
orgProxyConfigDAL,
|
orgProxyConfigDAL,
|
||||||
|
proxyDAL,
|
||||||
kmsService
|
kmsService
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const gatewayV2Service = gatewayV2ServiceFactory({
|
||||||
|
kmsService,
|
||||||
|
proxyService,
|
||||||
|
orgGatewayConfigV2DAL
|
||||||
|
});
|
||||||
|
|
||||||
// setup the communication with license key server
|
// setup the communication with license key server
|
||||||
await licenseService.init();
|
await licenseService.init();
|
||||||
|
|
||||||
@@ -2104,7 +2117,8 @@ export const registerRoutes = async (
|
|||||||
reminder: reminderService,
|
reminder: reminderService,
|
||||||
bus: eventBusService,
|
bus: eventBusService,
|
||||||
sse: sseService,
|
sse: sseService,
|
||||||
proxy: proxyService
|
proxy: proxyService,
|
||||||
|
gatewayV2: gatewayV2Service
|
||||||
});
|
});
|
||||||
|
|
||||||
const cronJobs: CronJob[] = [];
|
const cronJobs: CronJob[] = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user