mirror of
https://github.com/Infisical/infisical.git
synced 2025-08-28 18:55:53 +00:00
Compare commits
3 Commits
fix-infere
...
feat/gatew
Author | SHA1 | Date | |
---|---|---|---|
|
2fb13463bc | ||
|
ae62c59382 | ||
|
cc34b92d56 |
4
backend/src/@types/fastify.d.ts
vendored
4
backend/src/@types/fastify.d.ts
vendored
@@ -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 { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-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 { TGroupServiceFactory } from "@app/ee/services/group/group-service";
|
||||
import { TIdentityAuthTemplateServiceFactory } from "@app/ee/services/identity-auth-template";
|
||||
@@ -31,6 +32,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
||||
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
||||
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-types";
|
||||
import { TProjectUserAdditionalPrivilegeServiceFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types";
|
||||
import { TProxyServiceFactory } from "@app/ee/services/proxy/proxy-service";
|
||||
import { RateLimitConfiguration, TRateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-types";
|
||||
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-types";
|
||||
import { TScimServiceFactory } from "@app/ee/services/scim/scim-types";
|
||||
@@ -303,6 +305,8 @@ declare module "fastify" {
|
||||
bus: TEventBusService;
|
||||
sse: TServerSentEventsService;
|
||||
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
||||
proxy: TProxyServiceFactory;
|
||||
gatewayV2: TGatewayV2ServiceFactory;
|
||||
};
|
||||
// this is exclusive use for middlewares in which we need to inject data
|
||||
// everywhere else access using service layer
|
||||
|
28
backend/src/@types/knex.d.ts
vendored
28
backend/src/@types/knex.d.ts
vendored
@@ -179,6 +179,9 @@ import {
|
||||
TIncidentContacts,
|
||||
TIncidentContactsInsert,
|
||||
TIncidentContactsUpdate,
|
||||
TInstanceProxyConfig,
|
||||
TInstanceProxyConfigInsert,
|
||||
TInstanceProxyConfigUpdate,
|
||||
TIntegrationAuths,
|
||||
TIntegrationAuthsInsert,
|
||||
TIntegrationAuthsUpdate,
|
||||
@@ -230,9 +233,15 @@ import {
|
||||
TOrgGatewayConfig,
|
||||
TOrgGatewayConfigInsert,
|
||||
TOrgGatewayConfigUpdate,
|
||||
TOrgGatewayConfigV2,
|
||||
TOrgGatewayConfigV2Insert,
|
||||
TOrgGatewayConfigV2Update,
|
||||
TOrgMemberships,
|
||||
TOrgMembershipsInsert,
|
||||
TOrgMembershipsUpdate,
|
||||
TOrgProxyConfig,
|
||||
TOrgProxyConfigInsert,
|
||||
TOrgProxyConfigUpdate,
|
||||
TOrgRoles,
|
||||
TOrgRolesInsert,
|
||||
TOrgRolesUpdate,
|
||||
@@ -287,6 +296,9 @@ import {
|
||||
TProjectUserMembershipRoles,
|
||||
TProjectUserMembershipRolesInsert,
|
||||
TProjectUserMembershipRolesUpdate,
|
||||
TProxies,
|
||||
TProxiesInsert,
|
||||
TProxiesUpdate,
|
||||
TRateLimit,
|
||||
TRateLimitInsert,
|
||||
TRateLimitUpdate,
|
||||
@@ -1254,5 +1266,21 @@ declare module "knex/types/tables" {
|
||||
TRemindersRecipientsInsert,
|
||||
TRemindersRecipientsUpdate
|
||||
>;
|
||||
[TableName.InstanceProxyConfig]: KnexOriginal.CompositeTableType<
|
||||
TInstanceProxyConfig,
|
||||
TInstanceProxyConfigInsert,
|
||||
TInstanceProxyConfigUpdate
|
||||
>;
|
||||
[TableName.OrgProxyConfig]: KnexOriginal.CompositeTableType<
|
||||
TOrgProxyConfig,
|
||||
TOrgProxyConfigInsert,
|
||||
TOrgProxyConfigUpdate
|
||||
>;
|
||||
[TableName.OrgGatewayConfigV2]: KnexOriginal.CompositeTableType<
|
||||
TOrgGatewayConfigV2,
|
||||
TOrgGatewayConfigV2Insert,
|
||||
TOrgGatewayConfigV2Update
|
||||
>;
|
||||
[TableName.Proxy]: KnexOriginal.CompositeTableType<TProxies, TProxiesInsert, TProxiesUpdate>;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,144 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.InstanceProxyConfig))) {
|
||||
await knex.schema.createTable(TableName.InstanceProxyConfig, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.timestamps(true, true, true);
|
||||
|
||||
// Root CA for proxy PKI
|
||||
t.binary("encryptedRootProxyPkiCaPrivateKey").notNullable();
|
||||
t.binary("encryptedRootProxyPkiCaCertificate").notNullable();
|
||||
|
||||
// Instance CA for proxy PKI
|
||||
t.binary("encryptedInstanceProxyPkiCaPrivateKey").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiCaCertificate").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiCaCertificateChain").notNullable();
|
||||
|
||||
// Instance client/server intermediates for proxy PKI
|
||||
t.binary("encryptedInstanceProxyPkiClientCaPrivateKey").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiClientCaCertificate").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiClientCaCertificateChain").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiServerCaPrivateKey").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiServerCaCertificate").notNullable();
|
||||
t.binary("encryptedInstanceProxyPkiServerCaCertificateChain").notNullable();
|
||||
|
||||
// Org Parent CAs for proxy
|
||||
t.binary("encryptedOrgProxyPkiCaPrivateKey").notNullable();
|
||||
t.binary("encryptedOrgProxyPkiCaCertificate").notNullable();
|
||||
t.binary("encryptedOrgProxyPkiCaCertificateChain").notNullable();
|
||||
|
||||
// Instance SSH CAs for proxy
|
||||
t.binary("encryptedInstanceProxySshClientCaPrivateKey").notNullable();
|
||||
t.binary("encryptedInstanceProxySshClientCaPublicKey").notNullable();
|
||||
t.binary("encryptedInstanceProxySshServerCaPrivateKey").notNullable();
|
||||
t.binary("encryptedInstanceProxySshServerCaPublicKey").notNullable();
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.InstanceProxyConfig);
|
||||
}
|
||||
|
||||
// Org-level proxy configuration (one-to-one with organization)
|
||||
if (!(await knex.schema.hasTable(TableName.OrgProxyConfig))) {
|
||||
await knex.schema.createTable(TableName.OrgProxyConfig, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.timestamps(true, true, true);
|
||||
|
||||
t.uuid("orgId").notNullable().unique();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
|
||||
// Org-scoped proxy PKI (client + server)
|
||||
t.binary("encryptedProxyPkiClientCaPrivateKey").notNullable();
|
||||
t.binary("encryptedProxyPkiClientCaCertificate").notNullable();
|
||||
t.binary("encryptedProxyPkiClientCaCertificateChain").notNullable();
|
||||
t.binary("encryptedProxyPkiServerCaPrivateKey").notNullable();
|
||||
t.binary("encryptedProxyPkiServerCaCertificate").notNullable();
|
||||
t.binary("encryptedProxyPkiServerCaCertificateChain").notNullable();
|
||||
|
||||
// Org-scoped proxy SSH (client + server)
|
||||
t.binary("encryptedProxySshClientCaPrivateKey").notNullable();
|
||||
t.binary("encryptedProxySshClientCaPublicKey").notNullable();
|
||||
t.binary("encryptedProxySshServerCaPrivateKey").notNullable();
|
||||
t.binary("encryptedProxySshServerCaPublicKey").notNullable();
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.GatewayV2))) {
|
||||
await knex.schema.createTable(TableName.GatewayV2, (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").unique();
|
||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||
|
||||
t.uuid("proxyId");
|
||||
t.foreign("proxyId").references("id").inTable(TableName.Proxy).onDelete("CASCADE");
|
||||
|
||||
t.string("name").notNullable().unique();
|
||||
});
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.GatewayV2);
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await dropOnUpdateTrigger(knex, TableName.OrgProxyConfig);
|
||||
await knex.schema.dropTableIfExists(TableName.OrgProxyConfig);
|
||||
|
||||
await dropOnUpdateTrigger(knex, 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);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.GatewayV2);
|
||||
await knex.schema.dropTableIfExists(TableName.GatewayV2);
|
||||
}
|
@@ -57,6 +57,7 @@ export * from "./identity-token-auths";
|
||||
export * from "./identity-ua-client-secrets";
|
||||
export * from "./identity-universal-auths";
|
||||
export * from "./incident-contacts";
|
||||
export * from "./instance-proxy-config";
|
||||
export * from "./integration-auths";
|
||||
export * from "./integrations";
|
||||
export * from "./internal-certificate-authorities";
|
||||
@@ -75,7 +76,9 @@ export * from "./models";
|
||||
export * from "./oidc-configs";
|
||||
export * from "./org-bots";
|
||||
export * from "./org-gateway-config";
|
||||
export * from "./org-gateway-config-v2";
|
||||
export * from "./org-memberships";
|
||||
export * from "./org-proxy-config";
|
||||
export * from "./org-roles";
|
||||
export * from "./organizations";
|
||||
export * from "./pki-alerts";
|
||||
@@ -162,3 +165,4 @@ export * from "./user-group-membership";
|
||||
export * from "./users";
|
||||
export * from "./webhooks";
|
||||
export * from "./workflow-integrations";
|
||||
export * from "./proxies";
|
||||
|
38
backend/src/db/schemas/instance-proxy-config.ts
Normal file
38
backend/src/db/schemas/instance-proxy-config.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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 InstanceProxyConfigSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
encryptedRootProxyPkiCaPrivateKey: zodBuffer,
|
||||
encryptedRootProxyPkiCaCertificate: zodBuffer,
|
||||
encryptedInstanceProxyPkiCaPrivateKey: zodBuffer,
|
||||
encryptedInstanceProxyPkiCaCertificate: zodBuffer,
|
||||
encryptedInstanceProxyPkiCaCertificateChain: zodBuffer,
|
||||
encryptedInstanceProxyPkiClientCaPrivateKey: zodBuffer,
|
||||
encryptedInstanceProxyPkiClientCaCertificate: zodBuffer,
|
||||
encryptedInstanceProxyPkiClientCaCertificateChain: zodBuffer,
|
||||
encryptedInstanceProxyPkiServerCaPrivateKey: zodBuffer,
|
||||
encryptedInstanceProxyPkiServerCaCertificate: zodBuffer,
|
||||
encryptedInstanceProxyPkiServerCaCertificateChain: zodBuffer,
|
||||
encryptedOrgProxyPkiCaPrivateKey: zodBuffer,
|
||||
encryptedOrgProxyPkiCaCertificate: zodBuffer,
|
||||
encryptedOrgProxyPkiCaCertificateChain: zodBuffer,
|
||||
encryptedInstanceProxySshClientCaPrivateKey: zodBuffer,
|
||||
encryptedInstanceProxySshClientCaPublicKey: zodBuffer,
|
||||
encryptedInstanceProxySshServerCaPrivateKey: zodBuffer,
|
||||
encryptedInstanceProxySshServerCaPublicKey: zodBuffer
|
||||
});
|
||||
|
||||
export type TInstanceProxyConfig = z.infer<typeof InstanceProxyConfigSchema>;
|
||||
export type TInstanceProxyConfigInsert = Omit<z.input<typeof InstanceProxyConfigSchema>, TImmutableDBKeys>;
|
||||
export type TInstanceProxyConfigUpdate = Partial<Omit<z.input<typeof InstanceProxyConfigSchema>, TImmutableDBKeys>>;
|
@@ -178,7 +178,14 @@ export enum TableName {
|
||||
SecretScanningConfig = "secret_scanning_configs",
|
||||
// reminders
|
||||
Reminder = "reminders",
|
||||
ReminderRecipient = "reminders_recipients"
|
||||
ReminderRecipient = "reminders_recipients",
|
||||
|
||||
// gateway v2
|
||||
InstanceProxyConfig = "instance_proxy_config",
|
||||
OrgProxyConfig = "org_proxy_config",
|
||||
OrgGatewayConfigV2 = "org_gateway_config_v2",
|
||||
Proxy = "proxies",
|
||||
GatewayV2 = "gateways_v2"
|
||||
}
|
||||
|
||||
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
||||
|
29
backend/src/db/schemas/org-gateway-config-v2.ts
Normal file
29
backend/src/db/schemas/org-gateway-config-v2.ts
Normal file
@@ -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>>;
|
31
backend/src/db/schemas/org-proxy-config.ts
Normal file
31
backend/src/db/schemas/org-proxy-config.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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 OrgProxyConfigSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
orgId: z.string().uuid(),
|
||||
encryptedProxyPkiClientCaPrivateKey: zodBuffer,
|
||||
encryptedProxyPkiClientCaCertificate: zodBuffer,
|
||||
encryptedProxyPkiClientCaCertificateChain: zodBuffer,
|
||||
encryptedProxyPkiServerCaPrivateKey: zodBuffer,
|
||||
encryptedProxyPkiServerCaCertificate: zodBuffer,
|
||||
encryptedProxyPkiServerCaCertificateChain: zodBuffer,
|
||||
encryptedProxySshClientCaPrivateKey: zodBuffer,
|
||||
encryptedProxySshClientCaPublicKey: zodBuffer,
|
||||
encryptedProxySshServerCaPrivateKey: zodBuffer,
|
||||
encryptedProxySshServerCaPublicKey: zodBuffer
|
||||
});
|
||||
|
||||
export type TOrgProxyConfig = z.infer<typeof OrgProxyConfigSchema>;
|
||||
export type TOrgProxyConfigInsert = Omit<z.input<typeof OrgProxyConfigSchema>, TImmutableDBKeys>;
|
||||
export type TOrgProxyConfigUpdate = Partial<Omit<z.input<typeof OrgProxyConfigSchema>, TImmutableDBKeys>>;
|
22
backend/src/db/schemas/proxies.ts
Normal file
22
backend/src/db/schemas/proxies.ts
Normal file
@@ -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>>;
|
@@ -23,6 +23,7 @@ import { registerOrgRoleRouter } from "./org-role-router";
|
||||
import { registerPITRouter } from "./pit-router";
|
||||
import { registerProjectRoleRouter } from "./project-role-router";
|
||||
import { registerProjectRouter } from "./project-router";
|
||||
import { registerProxyRouter } from "./proxy-router";
|
||||
import { registerRateLimitRouter } from "./rate-limit-router";
|
||||
import { registerSamlRouter } from "./saml-router";
|
||||
import { registerScimRouter } from "./scim-router";
|
||||
@@ -79,6 +80,7 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
||||
);
|
||||
|
||||
await server.register(registerGatewayRouter, { prefix: "/gateways" });
|
||||
await server.register(registerProxyRouter, { prefix: "/proxies" });
|
||||
await server.register(registerGithubOrgSyncRouter, { prefix: "/github-org-sync-config" });
|
||||
|
||||
await server.register(
|
||||
|
69
backend/src/ee/routes/v1/proxy-router.ts
Normal file
69
backend/src/ee/routes/v1/proxy-router.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
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 { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const registerProxyRouter = async (server: FastifyZodProvider) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/register-instance-proxy",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
schema: {
|
||||
body: z.object({
|
||||
ip: z.string(),
|
||||
name: z.string()
|
||||
}),
|
||||
response: {
|
||||
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) => {
|
||||
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
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
29
backend/src/ee/routes/v2/gateway-router.ts
Normal file
29
backend/src/ee/routes/v2/gateway-router.ts
Normal file
@@ -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 { registerProjectRoleRouter } from "./project-role-router";
|
||||
import { registerGatewayV2Router } from "./gateway-router";
|
||||
|
||||
export const registerV2EERoutes = async (server: FastifyZodProvider) => {
|
||||
// org role starts with organization
|
||||
@@ -23,6 +24,8 @@ export const registerV2EERoutes = async (server: FastifyZodProvider) => {
|
||||
prefix: "/identity-project-additional-privilege"
|
||||
});
|
||||
|
||||
await server.register(registerGatewayV2Router, { prefix: "/gateways" });
|
||||
|
||||
await server.register(
|
||||
async (secretRotationV2Router) => {
|
||||
// register generic secret rotation endpoints
|
||||
|
279
backend/src/ee/services/gateway-v2/gateway-v2-service.ts
Normal file
279
backend/src/ee/services/gateway-v2/gateway-v2-service.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
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);
|
||||
|
||||
// TODO: Save gateway to DB and set Gateway ID as principal in SSH certificate
|
||||
// only throw error if proxy is different from existing DB record
|
||||
|
||||
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.getCredentialsForGateway({
|
||||
proxyName,
|
||||
orgId
|
||||
});
|
||||
|
||||
return {
|
||||
// TODO: return gateway ID
|
||||
proxyIp: proxyCredentials.proxyIp,
|
||||
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;
|
||||
};
|
11
backend/src/ee/services/proxy/instance-proxy-config-dal.ts
Normal file
11
backend/src/ee/services/proxy/instance-proxy-config-dal.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TInstanceProxyConfigDALFactory = ReturnType<typeof instanceProxyConfigDalFactory>;
|
||||
|
||||
export const instanceProxyConfigDalFactory = (db: TDbClient) => {
|
||||
const orm = ormify(db, TableName.InstanceProxyConfig);
|
||||
|
||||
return orm;
|
||||
};
|
11
backend/src/ee/services/proxy/org-proxy-config-dal.ts
Normal file
11
backend/src/ee/services/proxy/org-proxy-config-dal.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TOrgProxyConfigDALFactory = ReturnType<typeof orgProxyConfigDalFactory>;
|
||||
|
||||
export const orgProxyConfigDalFactory = (db: TDbClient) => {
|
||||
const orm = ormify(db, TableName.OrgProxyConfig);
|
||||
|
||||
return orm;
|
||||
};
|
11
backend/src/ee/services/proxy/proxy-dal.ts
Normal file
11
backend/src/ee/services/proxy/proxy-dal.ts
Normal file
@@ -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;
|
||||
};
|
3
backend/src/ee/services/proxy/proxy-fns.ts
Normal file
3
backend/src/ee/services/proxy/proxy-fns.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const isInstanceProxy = (proxyName: string) => {
|
||||
return proxyName.startsWith("infisical-");
|
||||
};
|
880
backend/src/ee/services/proxy/proxy-service.ts
Normal file
880
backend/src/ee/services/proxy/proxy-service.ts
Normal file
@@ -0,0 +1,880 @@
|
||||
import * as x509 from "@peculiar/x509";
|
||||
|
||||
import { TProxies } from "@app/db/schemas";
|
||||
import { PgSqlLock } from "@app/keystore/keystore";
|
||||
import { crypto } from "@app/lib/crypto";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { constructPemChainFromCerts, prependCertToPemChain } 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 { createSshCert, createSshKeyPair } from "../ssh/ssh-certificate-authority-fns";
|
||||
import { SshCertType } from "../ssh/ssh-certificate-authority-types";
|
||||
import { SshCertKeyAlgorithm } from "../ssh-certificate/ssh-certificate-types";
|
||||
import { TInstanceProxyConfigDALFactory } from "./instance-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>;
|
||||
|
||||
const INSTANCE_PROXY_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
export const proxyServiceFactory = ({
|
||||
instanceProxyConfigDAL,
|
||||
orgProxyConfigDAL,
|
||||
proxyDAL,
|
||||
kmsService
|
||||
}: {
|
||||
instanceProxyConfigDAL: TInstanceProxyConfigDALFactory;
|
||||
orgProxyConfigDAL: TOrgProxyConfigDALFactory;
|
||||
proxyDAL: TProxyDALFactory;
|
||||
kmsService: TKmsServiceFactory;
|
||||
}) => {
|
||||
const $getInstanceCAs = async () => {
|
||||
const instanceConfig = await instanceProxyConfigDAL.transaction(async (tx) => {
|
||||
const existingInstanceProxyConfig = await instanceProxyConfigDAL.findById(INSTANCE_PROXY_CONFIG_UUID);
|
||||
if (existingInstanceProxyConfig) return existingInstanceProxyConfig;
|
||||
|
||||
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.InstanceProxyConfigInit()]);
|
||||
|
||||
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||
const rootCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||
|
||||
// generate root CA
|
||||
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=Infisical,CN=Infisical Instance Root Proxy 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 org proxy CA
|
||||
const orgProxyCaSerialNumber = createSerialNumber();
|
||||
const orgProxyCaIssuedAt = new Date();
|
||||
const orgProxyCaExpiration = new Date(new Date().setFullYear(2045));
|
||||
const orgProxyCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||
const orgProxyCaSkObj = crypto.nativeCrypto.KeyObject.from(orgProxyCaKeys.privateKey);
|
||||
const orgProxyCaCert = await x509.X509CertificateGenerator.create({
|
||||
serialNumber: orgProxyCaSerialNumber,
|
||||
subject: `O=Infisical,CN=Infisical Organization Proxy CA`,
|
||||
issuer: rootCaCert.subject,
|
||||
notBefore: orgProxyCaIssuedAt,
|
||||
notAfter: orgProxyCaExpiration,
|
||||
signingKey: rootCaKeys.privateKey,
|
||||
publicKey: orgProxyCaKeys.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(orgProxyCaKeys.publicKey)
|
||||
]
|
||||
});
|
||||
const orgProxyCaChain = constructPemChainFromCerts([rootCaCert]);
|
||||
|
||||
// generate instance proxy CA
|
||||
const instanceProxyCaSerialNumber = createSerialNumber();
|
||||
const instanceProxyCaIssuedAt = new Date();
|
||||
const instanceProxyCaExpiration = new Date(new Date().setFullYear(2045));
|
||||
const instanceProxyCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||
const instanceProxyCaSkObj = crypto.nativeCrypto.KeyObject.from(instanceProxyCaKeys.privateKey);
|
||||
const instanceProxyCaCert = await x509.X509CertificateGenerator.create({
|
||||
serialNumber: instanceProxyCaSerialNumber,
|
||||
subject: `O=Infisical,CN=Infisical Instance Proxy CA`,
|
||||
issuer: rootCaCert.subject,
|
||||
notBefore: instanceProxyCaIssuedAt,
|
||||
notAfter: instanceProxyCaExpiration,
|
||||
signingKey: rootCaKeys.privateKey,
|
||||
publicKey: instanceProxyCaKeys.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(instanceProxyCaKeys.publicKey)
|
||||
]
|
||||
});
|
||||
const instanceProxyCaChain = constructPemChainFromCerts([rootCaCert]);
|
||||
|
||||
// generate instance proxy client CA
|
||||
const instanceProxyClientCaSerialNumber = createSerialNumber();
|
||||
const instanceProxyClientCaIssuedAt = new Date();
|
||||
const instanceProxyClientCaExpiration = new Date(new Date().setFullYear(2045));
|
||||
const instanceProxyClientCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||
const instanceProxyClientCaSkObj = crypto.nativeCrypto.KeyObject.from(instanceProxyClientCaKeys.privateKey);
|
||||
const instanceProxyClientCaCert = await x509.X509CertificateGenerator.create({
|
||||
serialNumber: instanceProxyClientCaSerialNumber,
|
||||
subject: `O=Infisical,CN=Infisical Instance Proxy Client CA`,
|
||||
issuer: instanceProxyCaCert.subject,
|
||||
notBefore: instanceProxyClientCaIssuedAt,
|
||||
notAfter: instanceProxyClientCaExpiration,
|
||||
signingKey: instanceProxyCaKeys.privateKey,
|
||||
publicKey: instanceProxyClientCaKeys.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(instanceProxyCaCert, false),
|
||||
await x509.SubjectKeyIdentifierExtension.create(instanceProxyClientCaKeys.publicKey)
|
||||
]
|
||||
});
|
||||
const instanceProxyClientCaChain = constructPemChainFromCerts([instanceProxyCaCert, rootCaCert]);
|
||||
|
||||
// generate instance proxy server CA
|
||||
const instanceProxyServerCaSerialNumber = createSerialNumber();
|
||||
const instanceProxyServerCaIssuedAt = new Date();
|
||||
const instanceProxyServerCaExpiration = new Date(new Date().setFullYear(2045));
|
||||
const instanceProxyServerCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||
const instanceProxyServerCaSkObj = crypto.nativeCrypto.KeyObject.from(instanceProxyServerCaKeys.privateKey);
|
||||
const instanceProxyServerCaCert = await x509.X509CertificateGenerator.create({
|
||||
serialNumber: instanceProxyServerCaSerialNumber,
|
||||
subject: `O=Infisical,CN=Infisical Instance Proxy Server CA`,
|
||||
issuer: instanceProxyCaCert.subject,
|
||||
notBefore: instanceProxyServerCaIssuedAt,
|
||||
notAfter: instanceProxyServerCaExpiration,
|
||||
signingKey: instanceProxyCaKeys.privateKey,
|
||||
publicKey: instanceProxyServerCaKeys.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(instanceProxyCaCert, false),
|
||||
await x509.SubjectKeyIdentifierExtension.create(instanceProxyServerCaKeys.publicKey)
|
||||
]
|
||||
});
|
||||
const instanceProxyServerCaChain = constructPemChainFromCerts([instanceProxyCaCert, rootCaCert]);
|
||||
|
||||
const instanceSshServerCaKeyPair = await createSshKeyPair(SshCertKeyAlgorithm.RSA_2048);
|
||||
const instanceSshClientCaKeyPair = await createSshKeyPair(SshCertKeyAlgorithm.RSA_2048);
|
||||
|
||||
const encryptWithRoot = kmsService.encryptWithRootKey();
|
||||
|
||||
// root proxy CA
|
||||
const encryptedRootProxyPkiCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(
|
||||
rootCaSkObj.export({
|
||||
type: "pkcs8",
|
||||
format: "der"
|
||||
})
|
||||
)
|
||||
);
|
||||
const encryptedRootProxyPkiCaCertificate = encryptWithRoot(Buffer.from(rootCaCert.rawData));
|
||||
|
||||
// org proxy CA
|
||||
const encryptedOrgProxyPkiCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(
|
||||
orgProxyCaSkObj.export({
|
||||
type: "pkcs8",
|
||||
format: "der"
|
||||
})
|
||||
)
|
||||
);
|
||||
const encryptedOrgProxyPkiCaCertificate = encryptWithRoot(Buffer.from(orgProxyCaCert.rawData));
|
||||
const encryptedOrgProxyPkiCaCertificateChain = encryptWithRoot(Buffer.from(orgProxyCaChain));
|
||||
|
||||
// instance proxy CA
|
||||
const encryptedInstanceProxyPkiCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(
|
||||
instanceProxyCaSkObj.export({
|
||||
type: "pkcs8",
|
||||
format: "der"
|
||||
})
|
||||
)
|
||||
);
|
||||
const encryptedInstanceProxyPkiCaCertificate = encryptWithRoot(Buffer.from(instanceProxyCaCert.rawData));
|
||||
const encryptedInstanceProxyPkiCaCertificateChain = encryptWithRoot(Buffer.from(instanceProxyCaChain));
|
||||
|
||||
// instance proxy client CA
|
||||
const encryptedInstanceProxyPkiClientCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(
|
||||
instanceProxyClientCaSkObj.export({
|
||||
type: "pkcs8",
|
||||
format: "der"
|
||||
})
|
||||
)
|
||||
);
|
||||
const encryptedInstanceProxyPkiClientCaCertificate = encryptWithRoot(
|
||||
Buffer.from(instanceProxyClientCaCert.rawData)
|
||||
);
|
||||
const encryptedInstanceProxyPkiClientCaCertificateChain = encryptWithRoot(
|
||||
Buffer.from(instanceProxyClientCaChain)
|
||||
);
|
||||
|
||||
// instance proxy server CA
|
||||
const encryptedInstanceProxyPkiServerCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(
|
||||
instanceProxyServerCaSkObj.export({
|
||||
type: "pkcs8",
|
||||
format: "der"
|
||||
})
|
||||
)
|
||||
);
|
||||
const encryptedInstanceProxyPkiServerCaCertificate = encryptWithRoot(
|
||||
Buffer.from(instanceProxyServerCaCert.rawData)
|
||||
);
|
||||
const encryptedInstanceProxyPkiServerCaCertificateChain = encryptWithRoot(
|
||||
Buffer.from(instanceProxyServerCaChain)
|
||||
);
|
||||
|
||||
const encryptedInstanceProxySshClientCaPublicKey = encryptWithRoot(
|
||||
Buffer.from(instanceSshClientCaKeyPair.publicKey)
|
||||
);
|
||||
const encryptedInstanceProxySshClientCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(instanceSshClientCaKeyPair.privateKey)
|
||||
);
|
||||
|
||||
const encryptedInstanceProxySshServerCaPublicKey = encryptWithRoot(
|
||||
Buffer.from(instanceSshServerCaKeyPair.publicKey)
|
||||
);
|
||||
const encryptedInstanceProxySshServerCaPrivateKey = encryptWithRoot(
|
||||
Buffer.from(instanceSshServerCaKeyPair.privateKey)
|
||||
);
|
||||
|
||||
return instanceProxyConfigDAL.create({
|
||||
// @ts-expect-error id is kept as fixed for idempotence and to avoid race condition
|
||||
id: INSTANCE_PROXY_CONFIG_UUID,
|
||||
encryptedRootProxyPkiCaPrivateKey,
|
||||
encryptedRootProxyPkiCaCertificate,
|
||||
encryptedInstanceProxyPkiCaPrivateKey,
|
||||
encryptedInstanceProxyPkiCaCertificate,
|
||||
encryptedInstanceProxyPkiCaCertificateChain,
|
||||
encryptedInstanceProxyPkiClientCaPrivateKey,
|
||||
encryptedInstanceProxyPkiClientCaCertificate,
|
||||
encryptedInstanceProxyPkiClientCaCertificateChain,
|
||||
encryptedInstanceProxyPkiServerCaPrivateKey,
|
||||
encryptedInstanceProxyPkiServerCaCertificate,
|
||||
encryptedInstanceProxyPkiServerCaCertificateChain,
|
||||
encryptedOrgProxyPkiCaPrivateKey,
|
||||
encryptedOrgProxyPkiCaCertificate,
|
||||
encryptedOrgProxyPkiCaCertificateChain,
|
||||
encryptedInstanceProxySshClientCaPublicKey,
|
||||
encryptedInstanceProxySshClientCaPrivateKey,
|
||||
encryptedInstanceProxySshServerCaPublicKey,
|
||||
encryptedInstanceProxySshServerCaPrivateKey
|
||||
});
|
||||
});
|
||||
|
||||
// decrypt the instance config
|
||||
const decryptWithRoot = kmsService.decryptWithRootKey();
|
||||
|
||||
// decrypt root proxy CA
|
||||
const rootProxyPkiCaPrivateKey = decryptWithRoot(instanceConfig.encryptedRootProxyPkiCaPrivateKey);
|
||||
const rootProxyPkiCaCertificate = decryptWithRoot(instanceConfig.encryptedRootProxyPkiCaCertificate);
|
||||
|
||||
// decrypt org proxy CA
|
||||
const orgProxyPkiCaPrivateKey = decryptWithRoot(instanceConfig.encryptedOrgProxyPkiCaPrivateKey);
|
||||
const orgProxyPkiCaCertificate = decryptWithRoot(instanceConfig.encryptedOrgProxyPkiCaCertificate);
|
||||
const orgProxyPkiCaCertificateChain = decryptWithRoot(instanceConfig.encryptedOrgProxyPkiCaCertificateChain);
|
||||
|
||||
// decrypt instance proxy CA
|
||||
const instanceProxyPkiCaPrivateKey = decryptWithRoot(instanceConfig.encryptedInstanceProxyPkiCaPrivateKey);
|
||||
const instanceProxyPkiCaCertificate = decryptWithRoot(instanceConfig.encryptedInstanceProxyPkiCaCertificate);
|
||||
const instanceProxyPkiCaCertificateChain = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiCaCertificateChain
|
||||
);
|
||||
|
||||
// decrypt instance proxy client CA
|
||||
const instanceProxyPkiClientCaPrivateKey = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiClientCaPrivateKey
|
||||
);
|
||||
const instanceProxyPkiClientCaCertificate = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiClientCaCertificate
|
||||
);
|
||||
const instanceProxyPkiClientCaCertificateChain = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiClientCaCertificateChain
|
||||
);
|
||||
|
||||
// decrypt instance proxy server CA
|
||||
const instanceProxyPkiServerCaPrivateKey = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiServerCaPrivateKey
|
||||
);
|
||||
const instanceProxyPkiServerCaCertificate = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiServerCaCertificate
|
||||
);
|
||||
const instanceProxyPkiServerCaCertificateChain = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxyPkiServerCaCertificateChain
|
||||
);
|
||||
|
||||
// decrypt SSH keys
|
||||
const instanceProxySshClientCaPublicKey = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxySshClientCaPublicKey
|
||||
);
|
||||
const instanceProxySshClientCaPrivateKey = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxySshClientCaPrivateKey
|
||||
);
|
||||
const instanceProxySshServerCaPublicKey = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxySshServerCaPublicKey
|
||||
);
|
||||
const instanceProxySshServerCaPrivateKey = decryptWithRoot(
|
||||
instanceConfig.encryptedInstanceProxySshServerCaPrivateKey
|
||||
);
|
||||
|
||||
return {
|
||||
rootProxyPkiCaPrivateKey,
|
||||
rootProxyPkiCaCertificate,
|
||||
orgProxyPkiCaPrivateKey,
|
||||
orgProxyPkiCaCertificate,
|
||||
orgProxyPkiCaCertificateChain,
|
||||
instanceProxyPkiCaPrivateKey,
|
||||
instanceProxyPkiCaCertificate,
|
||||
instanceProxyPkiCaCertificateChain,
|
||||
instanceProxyPkiClientCaPrivateKey,
|
||||
instanceProxyPkiClientCaCertificate,
|
||||
instanceProxyPkiClientCaCertificateChain,
|
||||
instanceProxyPkiServerCaPrivateKey,
|
||||
instanceProxyPkiServerCaCertificate,
|
||||
instanceProxyPkiServerCaCertificateChain,
|
||||
instanceProxySshClientCaPublicKey,
|
||||
instanceProxySshClientCaPrivateKey,
|
||||
instanceProxySshServerCaPublicKey,
|
||||
instanceProxySshServerCaPrivateKey
|
||||
};
|
||||
};
|
||||
|
||||
const $getOrgCAs = async (orgId: string) => {
|
||||
const instanceCAs = await $getInstanceCAs();
|
||||
const { encryptor: orgKmsEncryptor, decryptor: orgKmsDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.Organization,
|
||||
orgId
|
||||
});
|
||||
|
||||
const orgProxyConfig = await orgProxyConfigDAL.transaction(async (tx) => {
|
||||
const existingOrgProxyConfig = await orgProxyConfigDAL.findOne(
|
||||
{
|
||||
orgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
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 getCredentialsForGateway = 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: ["gateway ID"], // TODO: set gateway ID as principal in SSH certificate
|
||||
certType: SshCertType.USER,
|
||||
requestedTtl: "30d"
|
||||
});
|
||||
|
||||
return {
|
||||
proxyIp: proxy.ip,
|
||||
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 {
|
||||
proxyIp: proxy.ip,
|
||||
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 proxyServerCaCert = new x509.X509Certificate(proxyPkiServerCaCertificate);
|
||||
const rootProxyCaCert = new x509.X509Certificate(rootProxyPkiCaCertificate);
|
||||
const proxyServerCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
||||
key: proxyPkiServerCaPrivateKey,
|
||||
format: "der",
|
||||
type: "pkcs8"
|
||||
});
|
||||
|
||||
const proxyServerCaPrivateKey = await crypto.nativeCrypto.subtle.importKey(
|
||||
"pkcs8",
|
||||
proxyServerCaSkObj.export({ format: "der", type: "pkcs8" }),
|
||||
alg,
|
||||
true,
|
||||
["sign"]
|
||||
);
|
||||
|
||||
const proxyServerKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||
const proxyServerCertIssuedAt = new Date();
|
||||
const proxyServerCertExpireAt = new Date(new Date().setMonth(new Date().getMonth() + 1));
|
||||
const proxyServerCertPrivateKey = crypto.nativeCrypto.KeyObject.from(proxyServerKeys.privateKey);
|
||||
|
||||
const proxyServerCertExtensions: x509.Extension[] = [
|
||||
new x509.BasicConstraintsExtension(false),
|
||||
await x509.AuthorityKeyIdentifierExtension.create(proxyServerCaCert, false),
|
||||
await x509.SubjectKeyIdentifierExtension.create(proxyServerKeys.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),
|
||||
// san
|
||||
new x509.SubjectAlternativeNameExtension([{ type: "ip", value: ip }], false)
|
||||
];
|
||||
|
||||
const proxyServerSerialNumber = createSerialNumber();
|
||||
const proxyServerCertificate = await x509.X509CertificateGenerator.create({
|
||||
serialNumber: proxyServerSerialNumber,
|
||||
subject: `CN=${ip},O=${orgId ?? "Infisical"},OU=Proxy`,
|
||||
issuer: proxyServerCaCert.subject,
|
||||
notBefore: proxyServerCertIssuedAt,
|
||||
notAfter: proxyServerCertExpireAt,
|
||||
signingKey: proxyServerCaPrivateKey,
|
||||
publicKey: proxyServerKeys.publicKey,
|
||||
signingAlgorithm: alg,
|
||||
extensions: proxyServerCertExtensions
|
||||
});
|
||||
|
||||
// generate proxy server SSH certificate
|
||||
const keyAlgorithm = SshCertKeyAlgorithm.RSA_2048;
|
||||
const { publicKey: proxyServerSshPublicKey, privateKey: proxyServerSshPrivateKey } =
|
||||
await createSshKeyPair(keyAlgorithm);
|
||||
|
||||
const proxyServerSshCert = await createSshCert({
|
||||
caPrivateKey: proxySshServerCaPrivateKey.toString("utf8"),
|
||||
clientPublicKey: proxyServerSshPublicKey,
|
||||
keyId: "proxy-server",
|
||||
principals: [`${ip}:2222`],
|
||||
certType: SshCertType.HOST,
|
||||
requestedTtl: "30d"
|
||||
});
|
||||
|
||||
return {
|
||||
pki: {
|
||||
serverCertificate: proxyServerCertificate.toString("pem"),
|
||||
serverCertificateChain: prependCertToPemChain(
|
||||
proxyServerCaCert,
|
||||
proxyPkiServerCaCertificateChain.toString("utf8")
|
||||
),
|
||||
serverPrivateKey: proxyServerCertPrivateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
||||
clientCA: rootProxyCaCert.toString("pem")
|
||||
},
|
||||
ssh: {
|
||||
serverCertificate: proxyServerSshCert.signedPublicKey,
|
||||
serverPrivateKey: proxyServerSshPrivateKey,
|
||||
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 {
|
||||
registerProxy,
|
||||
getCredentialsForGateway
|
||||
};
|
||||
};
|
@@ -13,7 +13,10 @@ export const PgSqlLock = {
|
||||
SecretRotationV2Creation: (folderId: string) => pgAdvisoryLockHashText(`secret-rotation-v2-creation:${folderId}`),
|
||||
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`),
|
||||
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"),
|
||||
OrgGatewayV2Init: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-v2-init:${orgId}`),
|
||||
OrgProxyConfigInit: (orgId: string) => pgAdvisoryLockHashText(`org-proxy-config-init:${orgId}`)
|
||||
} as const;
|
||||
|
||||
// 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_AUTH_SECRET: zpStr(z.string().optional()),
|
||||
|
||||
PROXY_AUTH_SECRET: zpStr(z.string().optional()),
|
||||
|
||||
DYNAMIC_SECRET_ALLOW_INTERNAL_IP: zodStrBool.default("false"),
|
||||
DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()).default(
|
||||
process.env.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID
|
||||
|
@@ -121,6 +121,10 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.url.includes("/api/v1/proxies/register-instance-proxy")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { authMode, token, actor } = await extractAuth(req, appCfg.AUTH_SECRET);
|
||||
|
||||
if (!authMode) return;
|
||||
|
@@ -70,6 +70,9 @@ import { projectTemplateDALFactory } from "@app/ee/services/project-template/pro
|
||||
import { projectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
|
||||
import { projectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
|
||||
import { projectUserAdditionalPrivilegeServiceFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-service";
|
||||
import { instanceProxyConfigDalFactory } from "@app/ee/services/proxy/instance-proxy-config-dal";
|
||||
import { orgProxyConfigDalFactory } from "@app/ee/services/proxy/org-proxy-config-dal";
|
||||
import { proxyServiceFactory } from "@app/ee/services/proxy/proxy-service";
|
||||
import { rateLimitDALFactory } from "@app/ee/services/rate-limit/rate-limit-dal";
|
||||
import { rateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-service";
|
||||
import { samlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
|
||||
@@ -144,6 +147,8 @@ import { tokenServiceFactory } from "@app/services/auth-token/auth-token-service
|
||||
import { certificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
||||
import { certificateDALFactory } from "@app/services/certificate/certificate-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 { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
|
||||
import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
||||
@@ -314,6 +319,7 @@ import { registerV1Routes } from "./v1";
|
||||
import { initializeOauthConfigSync } from "./v1/sso-router";
|
||||
import { registerV2Routes } from "./v2";
|
||||
import { registerV3Routes } from "./v3";
|
||||
import { proxyDalFactory } from "@app/ee/services/proxy/proxy-dal";
|
||||
|
||||
const histogram = monitorEventLoopDelay({ resolution: 20 });
|
||||
histogram.enable();
|
||||
@@ -939,6 +945,12 @@ export const registerRoutes = async (
|
||||
const pkiSubscriberDAL = pkiSubscriberDALFactory(db);
|
||||
const pkiTemplatesDAL = pkiTemplatesDALFactory(db);
|
||||
|
||||
const instanceProxyConfigDAL = instanceProxyConfigDalFactory(db);
|
||||
const orgProxyConfigDAL = orgProxyConfigDalFactory(db);
|
||||
const proxyDAL = proxyDalFactory(db);
|
||||
|
||||
const orgGatewayConfigV2DAL = orgGatewayConfigV2DalFactory(db);
|
||||
|
||||
const certificateService = certificateServiceFactory({
|
||||
certificateDAL,
|
||||
certificateBodyDAL,
|
||||
@@ -1960,6 +1972,19 @@ export const registerRoutes = async (
|
||||
appConnectionDAL
|
||||
});
|
||||
|
||||
const proxyService = proxyServiceFactory({
|
||||
instanceProxyConfigDAL,
|
||||
orgProxyConfigDAL,
|
||||
proxyDAL,
|
||||
kmsService
|
||||
});
|
||||
|
||||
const gatewayV2Service = gatewayV2ServiceFactory({
|
||||
kmsService,
|
||||
proxyService,
|
||||
orgGatewayConfigV2DAL
|
||||
});
|
||||
|
||||
// setup the communication with license key server
|
||||
await licenseService.init();
|
||||
|
||||
@@ -2091,7 +2116,9 @@ export const registerRoutes = async (
|
||||
secretScanningV2: secretScanningV2Service,
|
||||
reminder: reminderService,
|
||||
bus: eventBusService,
|
||||
sse: sseService
|
||||
sse: sseService,
|
||||
proxy: proxyService,
|
||||
gatewayV2: gatewayV2Service
|
||||
});
|
||||
|
||||
const cronJobs: CronJob[] = [];
|
||||
|
@@ -52,6 +52,9 @@ export const constructPemChainFromCerts = (certificates: x509.X509Certificate[])
|
||||
.join("\n")
|
||||
.trim();
|
||||
|
||||
export const prependCertToPemChain = (cert: x509.X509Certificate, pemChain: string) =>
|
||||
`${cert.toString("pem")}\n${pemChain}`;
|
||||
|
||||
export const splitPemChain = (pemText: string) => {
|
||||
const re2Pattern = new RE2("-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----", "g");
|
||||
|
||||
|
Reference in New Issue
Block a user