diff --git a/backend/src/@types/knex.d.ts b/backend/src/@types/knex.d.ts index b09b02046..416a0013b 100644 --- a/backend/src/@types/knex.d.ts +++ b/backend/src/@types/knex.d.ts @@ -68,9 +68,6 @@ import { TExternalKms, TExternalKmsInsert, TExternalKmsUpdate, - TGatewayInstanceConfig, - TGatewayInstanceConfigInsert, - TGatewayInstanceConfigUpdate, TGateways, TGatewaysInsert, TGatewaysUpdate, @@ -185,9 +182,9 @@ import { TOrgBots, TOrgBotsInsert, TOrgBotsUpdate, - TOrgGatewayRootCa, - TOrgGatewayRootCaInsert, - TOrgGatewayRootCaUpdate, + TOrgGatewayConfig, + TOrgGatewayConfigInsert, + TOrgGatewayConfigUpdate, TOrgMemberships, TOrgMembershipsInsert, TOrgMembershipsUpdate, @@ -940,15 +937,10 @@ declare module "knex/types/tables" { TKmipClientCertificatesUpdate >; [TableName.Gateway]: KnexOriginal.CompositeTableType; - [TableName.GatewayInstanceConfig]: KnexOriginal.CompositeTableType< - TGatewayInstanceConfig, - TGatewayInstanceConfigInsert, - TGatewayInstanceConfigUpdate - >; - [TableName.OrgGatewayRootCa]: KnexOriginal.CompositeTableType< - TOrgGatewayRootCa, - TOrgGatewayRootCaInsert, - TOrgGatewayRootCaUpdate + [TableName.OrgGatewayConfig]: KnexOriginal.CompositeTableType< + TOrgGatewayConfig, + TOrgGatewayConfigInsert, + TOrgGatewayConfigUpdate >; } } diff --git a/backend/src/db/migrations/20250212191958_create-gateway.ts b/backend/src/db/migrations/20250212191958_create-gateway.ts index 635cd7427..ee9ef0ef7 100644 --- a/backend/src/db/migrations/20250212191958_create-gateway.ts +++ b/backend/src/db/migrations/20250212191958_create-gateway.ts @@ -4,47 +4,43 @@ import { TableName } from "../schemas"; import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; export async function up(knex: Knex): Promise { - if (!(await knex.schema.hasTable(TableName.GatewayInstanceConfig))) { - await knex.schema.createTable(TableName.GatewayInstanceConfig, (t) => { + if (!(await knex.schema.hasTable(TableName.OrgGatewayConfig))) { + await knex.schema.createTable(TableName.OrgGatewayConfig, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); - t.string("caKeyAlgorithm").notNullable(); - t.boolean("isDisabled").defaultTo(false); + t.string("rootCaKeyAlgorithm").notNullable(); - t.string("infisicalClientCaSerialNumber").notNullable(); - t.datetime("infisicalClientCaIssuedAt").notNullable(); - t.datetime("infisicalClientCaExpiration").notNullable(); - t.binary("encryptedInfisicalClientCaCertificate").notNullable(); - t.binary("encryptedInfisicalClientCaPrivateKey").notNullable(); + t.datetime("rootCaIssuedAt").notNullable(); + t.datetime("rootCaExpiration").notNullable(); + t.string("rootCaSerialNumber").notNullable(); + t.binary("encryptedRootCaCertificate").notNullable(); + t.binary("encryptedRootCaPrivateKey").notNullable(); - t.string("infisicalClientCertSerialNumber").notNullable(); - t.string("infisicalClientCertKeyAlgorithm").notNullable(); - t.datetime("infisicalClientCertIssuedAt").notNullable(); - t.datetime("infisicalClientCertExpiration").notNullable(); - t.binary("encryptedInfisicalClientCertificate").notNullable(); - t.binary("encryptedInfisicalClientPrivateKey").notNullable(); - t.timestamps(true, true, true); - }); + t.datetime("clientCaIssuedAt").notNullable(); + t.datetime("clientCaExpiration").notNullable(); + t.string("clientCaSerialNumber"); + t.binary("encryptedClientCaCertificate").notNullable(); + t.binary("encryptedClientCaPrivateKey").notNullable(); - await createOnUpdateTrigger(knex, TableName.GatewayInstanceConfig); - } + t.string("clientCertSerialNumber").notNullable(); + t.string("clientCertKeyAlgorithm").notNullable(); + t.datetime("clientCertIssuedAt").notNullable(); + t.datetime("clientCertExpiration").notNullable(); + t.binary("encryptedClientCertificate").notNullable(); + t.binary("encryptedClientPrivateKey").notNullable(); - if (!(await knex.schema.hasTable(TableName.OrgGatewayRootCa))) { - await knex.schema.createTable(TableName.OrgGatewayRootCa, (t) => { - t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); - t.string("caKeyAlgorithm").notNullable(); - t.string("caSerialNumber").notNullable(); - t.datetime("caIssuedAt").notNullable(); - t.datetime("caExpiration").notNullable(); - t.binary("encryptedCaCertificate").notNullable(); - t.binary("encryptedCaPrivateKey").notNullable(); + t.datetime("gatewayCaIssuedAt").notNullable(); + t.datetime("gatewayCaExpiration").notNullable(); + t.string("gatewayCaSerialNumber").notNullable(); + t.binary("encryptedGatewayCaCertificate").notNullable(); + t.binary("encryptedGatewayCaPrivateKey").notNullable(); t.uuid("orgId").notNullable(); t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE"); - + t.unique("orgId"); t.timestamps(true, true, true); }); - await createOnUpdateTrigger(knex, TableName.OrgGatewayRootCa); + await createOnUpdateTrigger(knex, TableName.OrgGatewayConfig); } if (!(await knex.schema.hasTable(TableName.Gateway))) { @@ -60,7 +56,7 @@ export async function up(knex: Knex): Promise { t.binary("relayAddress").notNullable(); t.uuid("orgGatewayRootCaId").notNullable(); - t.foreign("orgGatewayRootCaId").references("id").inTable(TableName.OrgGatewayRootCa).onDelete("CASCADE"); + t.foreign("orgGatewayRootCaId").references("id").inTable(TableName.OrgGatewayConfig).onDelete("CASCADE"); t.uuid("identityId").notNullable(); t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE"); @@ -73,12 +69,9 @@ export async function up(knex: Knex): Promise { } export async function down(knex: Knex): Promise { - await knex.schema.dropTableIfExists(TableName.GatewayInstanceConfig); - await dropOnUpdateTrigger(knex, TableName.GatewayInstanceConfig); - await knex.schema.dropTableIfExists(TableName.Gateway); await dropOnUpdateTrigger(knex, TableName.Gateway); - await knex.schema.dropTableIfExists(TableName.OrgGatewayRootCa); - await dropOnUpdateTrigger(knex, TableName.OrgGatewayRootCa); + await knex.schema.dropTableIfExists(TableName.OrgGatewayConfig); + await dropOnUpdateTrigger(knex, TableName.OrgGatewayConfig); } diff --git a/backend/src/db/schemas/gateway-instance-config.ts b/backend/src/db/schemas/gateway-instance-config.ts deleted file mode 100644 index f59b4b781..000000000 --- a/backend/src/db/schemas/gateway-instance-config.ts +++ /dev/null @@ -1,33 +0,0 @@ -// 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 GatewayInstanceConfigSchema = z.object({ - id: z.string().uuid(), - caKeyAlgorithm: z.string(), - isDisabled: z.boolean().default(false).nullable().optional(), - infisicalClientCaSerialNumber: z.string(), - infisicalClientCaIssuedAt: z.date(), - infisicalClientCaExpiration: z.date(), - encryptedInfisicalClientCaCertificate: zodBuffer, - encryptedInfisicalClientCaPrivateKey: zodBuffer, - infisicalClientCertSerialNumber: z.string(), - infisicalClientCertKeyAlgorithm: z.string(), - infisicalClientCertIssuedAt: z.date(), - infisicalClientCertExpiration: z.date(), - encryptedInfisicalClientCertificate: zodBuffer, - encryptedInfisicalClientPrivateKey: zodBuffer, - createdAt: z.date(), - updatedAt: z.date() -}); - -export type TGatewayInstanceConfig = z.infer; -export type TGatewayInstanceConfigInsert = Omit, TImmutableDBKeys>; -export type TGatewayInstanceConfigUpdate = Partial, TImmutableDBKeys>>; diff --git a/backend/src/db/schemas/index.ts b/backend/src/db/schemas/index.ts index 9e03cb246..b4d4138f8 100644 --- a/backend/src/db/schemas/index.ts +++ b/backend/src/db/schemas/index.ts @@ -20,7 +20,6 @@ export * from "./certificates"; export * from "./dynamic-secret-leases"; export * from "./dynamic-secrets"; export * from "./external-kms"; -export * from "./gateway-instance-config"; export * from "./gateways"; export * from "./git-app-install-sessions"; export * from "./git-app-org"; @@ -59,7 +58,7 @@ export * from "./ldap-group-maps"; export * from "./models"; export * from "./oidc-configs"; export * from "./org-bots"; -export * from "./org-gateway-root-ca"; +export * from "./org-gateway-config"; export * from "./org-memberships"; export * from "./org-roles"; export * from "./organizations"; diff --git a/backend/src/db/schemas/models.ts b/backend/src/db/schemas/models.ts index 069a9ea51..7d7f2fe4e 100644 --- a/backend/src/db/schemas/models.ts +++ b/backend/src/db/schemas/models.ts @@ -114,8 +114,7 @@ export enum TableName { SnapshotSecretV2 = "secret_snapshot_secrets_v2", ProjectSplitBackfillIds = "project_split_backfill_ids", // Gateway - GatewayInstanceConfig = "gateway_instance_config", - OrgGatewayRootCa = "org_gateway_root_ca", + OrgGatewayConfig = "org_gateway_config", Gateway = "gateways", // junction tables with tags SecretV2JnTag = "secret_v2_tag_junction", diff --git a/backend/src/db/schemas/org-gateway-config.ts b/backend/src/db/schemas/org-gateway-config.ts new file mode 100644 index 000000000..ddf18c3fc --- /dev/null +++ b/backend/src/db/schemas/org-gateway-config.ts @@ -0,0 +1,43 @@ +// 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 OrgGatewayConfigSchema = z.object({ + id: z.string().uuid(), + rootCaKeyAlgorithm: z.string(), + rootCaIssuedAt: z.date(), + rootCaExpiration: z.date(), + rootCaSerialNumber: z.string(), + encryptedRootCaCertificate: zodBuffer, + encryptedRootCaPrivateKey: zodBuffer, + clientCaIssuedAt: z.date(), + clientCaExpiration: z.date(), + clientCaSerialNumber: z.string().nullable().optional(), + encryptedClientCaCertificate: zodBuffer, + encryptedClientCaPrivateKey: zodBuffer, + clientCertSerialNumber: z.string(), + clientCertKeyAlgorithm: z.string(), + clientCertIssuedAt: z.date(), + clientCertExpiration: z.date(), + encryptedClientCertificate: zodBuffer, + encryptedClientPrivateKey: zodBuffer, + gatewayCaIssuedAt: z.date(), + gatewayCaExpiration: z.date(), + gatewayCaSerialNumber: z.string(), + encryptedGatewayCaCertificate: zodBuffer, + encryptedGatewayCaPrivateKey: zodBuffer, + orgId: z.string().uuid(), + createdAt: z.date(), + updatedAt: z.date() +}); + +export type TOrgGatewayConfig = z.infer; +export type TOrgGatewayConfigInsert = Omit, TImmutableDBKeys>; +export type TOrgGatewayConfigUpdate = Partial, TImmutableDBKeys>>; diff --git a/backend/src/db/schemas/org-gateway-root-ca.ts b/backend/src/db/schemas/org-gateway-root-ca.ts deleted file mode 100644 index 96c36fb37..000000000 --- a/backend/src/db/schemas/org-gateway-root-ca.ts +++ /dev/null @@ -1,27 +0,0 @@ -// 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 OrgGatewayRootCaSchema = z.object({ - id: z.string().uuid(), - caKeyAlgorithm: z.string(), - caSerialNumber: z.string(), - caIssuedAt: z.date(), - caExpiration: z.date(), - encryptedCaCertificate: zodBuffer, - encryptedCaPrivateKey: zodBuffer, - orgId: z.string().uuid(), - createdAt: z.date(), - updatedAt: z.date() -}); - -export type TOrgGatewayRootCa = z.infer; -export type TOrgGatewayRootCaInsert = Omit, TImmutableDBKeys>; -export type TOrgGatewayRootCaUpdate = Partial, TImmutableDBKeys>>; diff --git a/backend/src/ee/routes/v1/gateway-router.ts b/backend/src/ee/routes/v1/gateway-router.ts index 27dbd850b..4282d41e0 100644 --- a/backend/src/ee/routes/v1/gateway-router.ts +++ b/backend/src/ee/routes/v1/gateway-router.ts @@ -27,6 +27,7 @@ export const registerGatewayRouter = async (server: FastifyZodProvider) => { 200: z.object({ turnServerUsername: z.string(), turnServerPassword: z.string(), + turnServerRealm: z.string(), turnServerAddress: z.string(), infisicalStaticIp: z.string() }) diff --git a/backend/src/ee/services/gateway/gateway-instance-config-dal.ts b/backend/src/ee/services/gateway/gateway-instance-config-dal.ts deleted file mode 100644 index 14dcb7b9f..000000000 --- a/backend/src/ee/services/gateway/gateway-instance-config-dal.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; -import { ormify } from "@app/lib/knex"; - -export type TGatewayInstanceConfigDALFactory = ReturnType; - -export const gatewayInstanceConfigDALFactory = (db: TDbClient) => { - const orm = ormify(db, TableName.GatewayInstanceConfig); - - return orm; -}; diff --git a/backend/src/ee/services/gateway/gateway-service.ts b/backend/src/ee/services/gateway/gateway-service.ts index 1d3b87e15..330d48d0e 100644 --- a/backend/src/ee/services/gateway/gateway-service.ts +++ b/backend/src/ee/services/gateway/gateway-service.ts @@ -2,6 +2,8 @@ import crypto from "node:crypto"; import { ForbiddenError } from "@casl/ability"; import * as x509 from "@peculiar/x509"; +import fs from "fs/promises"; +import path from "path/posix"; import { PgSqlLock } from "@app/keystore/keystore"; import { getConfig } from "@app/lib/config/env"; @@ -21,13 +23,13 @@ import { OrgGatewayPermissionActions, OrgPermissionSubjects } from "../permissio import { TPermissionServiceFactory } from "../permission/permission-service"; import { TGatewayDALFactory } from "./gateway-dal"; import { TExchangeAllocatedRelayAddressDTO, TGetGatewayByIdDTO, TListGatewaysDTO } from "./gateway-types"; -import { TOrgGatewayRootCaDALFactory } from "./org-gateway-root-ca-dal"; +import { TOrgGatewayConfigDALFactory } from "./org-gateway-config-dal"; type TGatewayServiceFactoryDep = { gatewayDAL: TGatewayDALFactory; - orgGatewayRootCaDAL: Pick; + orgGatewayConfigDAL: Pick; licenseService: Pick; - kmsService: Pick; + kmsService: Pick; permissionService: Pick; }; @@ -37,9 +39,9 @@ export type TGatewayServiceFactory = ReturnType; export const gatewayServiceFactory = ({ gatewayDAL, licenseService, - orgGatewayRootCaDAL, kmsService, - permissionService + permissionService, + orgGatewayConfigDAL }: TGatewayServiceFactoryDep) => { const $validateOrgAccessToGateway = async (orgId: string) => { if (!licenseService.onPremFeatures.gateway) { @@ -64,7 +66,8 @@ export const gatewayServiceFactory = ({ if ( !envCfg.GATEWAY_RELAY_AUTH_SECRET || !envCfg.GATEWAY_RELAY_ADDRESS || - !envCfg.GATEWAY_INFISICAL_STATIC_IP_ADDRESS + !envCfg.GATEWAY_INFISICAL_STATIC_IP_ADDRESS || + !envCfg.GATEWAY_RELAY_REALM ) { throw new BadRequestError({ message: "Gateway handshake failed due to missing instance config." @@ -79,6 +82,7 @@ export const gatewayServiceFactory = ({ return { turnServerUsername, turnServerPassword, + turnServerRealm: envCfg.GATEWAY_RELAY_REALM, turnServerAddress: envCfg.GATEWAY_RELAY_ADDRESS, infisicalStaticIp: envCfg.GATEWAY_INFISICAL_STATIC_IP_ADDRESS }; @@ -94,63 +98,208 @@ export const gatewayServiceFactory = ({ orgId: identityOrg }); - const orgGatewayRootCa = await orgGatewayRootCaDAL.transaction(async (tx) => { + const orgGatewayConfig = await orgGatewayConfigDAL.transaction(async (tx) => { await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.OrgGatewayRootCaInit(identityOrg)]); - const existingGateway = await orgGatewayRootCaDAL.findOne({ orgId: identityOrg }); - if (existingGateway) return existingGateway; + const existingGatewayConfig = await orgGatewayConfigDAL.findOne({ orgId: identityOrg }); + if (existingGatewayConfig) return existingGatewayConfig; + const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048); // generate root CA - const orgGatewayRootCaSerialNumber = createSerialNumber(); - const orgGatewayRootCaKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); - const orgGatewayCaSkObj = crypto.KeyObject.from(orgGatewayRootCaKeys.privateKey); - const orgGatewayCaIssuedAt = new Date(); - const orgGatewayCaExpiration = new Date(new Date().setFullYear(new Date().getFullYear() + 25)); - - const orgGatewayCaCert = await x509.X509CertificateGenerator.createSelfSigned({ - name: `CN=Org Gateway Root CA,O=${identityOrg}`, - serialNumber: orgGatewayRootCaSerialNumber, - notBefore: orgGatewayCaIssuedAt, - notAfter: orgGatewayCaExpiration, + const rootCaKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); + const rootCaSerialNumber = createSerialNumber(); + const rootCaSkObj = crypto.KeyObject.from(rootCaKeys.privateKey); + const rootCaIssuedAt = new Date(); + const rootCaKeyAlgorithm = CertKeyAlgorithm.RSA_2048; + const rootCaExpiration = new Date(new Date().setFullYear(2045)); + const rootCaCert = await x509.X509CertificateGenerator.createSelfSigned({ + name: "CN=Infisical Gateway Root CA", + serialNumber: rootCaSerialNumber, + notBefore: rootCaIssuedAt, + notAfter: rootCaExpiration, signingAlgorithm: alg, - keys: orgGatewayRootCaKeys, + keys: rootCaKeys, extensions: [ // eslint-disable-next-line no-bitwise new x509.KeyUsagesExtension(x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.cRLSign, true), - await x509.SubjectKeyIdentifierExtension.create(orgGatewayRootCaKeys.publicKey) + await x509.SubjectKeyIdentifierExtension.create(rootCaKeys.publicKey) ] }); - return orgGatewayRootCaDAL.create({ + // generate client ca + const clientCaSerialNumber = createSerialNumber(); + const clientCaIssuedAt = new Date(); + const clientCaExpiration = new Date(new Date().setFullYear(2045)); + const clientCaKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); + const clientCaSkObj = crypto.KeyObject.from(clientCaKeys.privateKey); + + const clientCaCert = await x509.X509CertificateGenerator.create({ + serialNumber: clientCaSerialNumber, + subject: "CN=Client Intermediate 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 clientKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); + const clientCertSerialNumber = createSerialNumber(); + const clientCert = await x509.X509CertificateGenerator.create({ + serialNumber: clientCertSerialNumber, + subject: "O=infisical,OU=gateway,CN=cloud-client", + issuer: clientCaCert.subject, + notAfter: clientCaExpiration, + notBefore: clientCaIssuedAt, + signingKey: clientCaKeys.privateKey, + publicKey: clientKeys.publicKey, + signingAlgorithm: alg, + extensions: [ + new x509.BasicConstraintsExtension(false), + await x509.AuthorityKeyIdentifierExtension.create(clientCaCert, false), + await x509.SubjectKeyIdentifierExtension.create(clientKeys.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] | + x509.KeyUsageFlags[CertKeyUsage.KEY_AGREEMENT], + true + ), + new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.CLIENT_AUTH]], true) + ] + }); + const clientSkObj = crypto.KeyObject.from(clientKeys.privateKey); + + // generate gateway ca + const gatewayCaSerialNumber = createSerialNumber(); + const gatewayCaIssuedAt = new Date(); + const gatewayCaExpiration = new Date(new Date().setFullYear(new Date().getFullYear() + 10)); + const gatewayCaKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); + const gatewayCaSkObj = crypto.KeyObject.from(gatewayCaKeys.privateKey); + const gatewayCaCert = await x509.X509CertificateGenerator.create({ + serialNumber: gatewayCaSerialNumber, + subject: "CN=KMIP Server Intermediate CA", + issuer: rootCaCert.subject, + notBefore: gatewayCaIssuedAt, + notAfter: gatewayCaExpiration, + signingKey: rootCaKeys.privateKey, + publicKey: gatewayCaKeys.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(gatewayCaKeys.publicKey) + ] + }); + + await fs.writeFile(path.join(__dirname, "./root-ca-cert"), rootCaCert.toString("pem")); + await fs.writeFile(path.join(__dirname, "./client-ca-cert"), clientCaCert.toString("pem")); + await fs.writeFile(path.join(__dirname, "./gateway-ca-cert"), gatewayCaCert.toString("pem")); + await fs.writeFile(path.join(__dirname, "./client-cert"), clientCert.toString("pem")); + await fs.writeFile( + path.join(__dirname, "./client-key"), + clientSkObj.export({ type: "pkcs8", format: "pem" }) as string + ); + + return orgGatewayConfigDAL.create({ orgId: identityOrg, - caIssuedAt: orgGatewayCaIssuedAt, - caExpiration: orgGatewayCaExpiration, - caSerialNumber: orgGatewayRootCaSerialNumber, - encryptedCaCertificate: orgKmsEncryptor({ plainText: Buffer.from(orgGatewayCaCert.rawData) }).cipherTextBlob, - encryptedCaPrivateKey: orgKmsEncryptor({ - plainText: orgGatewayCaSkObj.export({ + rootCaIssuedAt, + rootCaExpiration, + rootCaSerialNumber, + rootCaKeyAlgorithm, + encryptedRootCaPrivateKey: orgKmsEncryptor({ + plainText: rootCaSkObj.export({ type: "pkcs8", format: "der" }) }).cipherTextBlob, - caKeyAlgorithm: CertKeyAlgorithm.RSA_2048 + encryptedRootCaCertificate: orgKmsEncryptor({ plainText: Buffer.from(rootCaCert.rawData) }).cipherTextBlob, + + clientCaIssuedAt, + clientCaExpiration, + clientCaSerialNumber, + encryptedClientCaPrivateKey: orgKmsEncryptor({ + plainText: clientCaSkObj.export({ + type: "pkcs8", + format: "der" + }) + }).cipherTextBlob, + encryptedClientCaCertificate: orgKmsEncryptor({ + plainText: Buffer.from(clientCaCert.rawData) + }).cipherTextBlob, + + clientCertIssuedAt: clientCaIssuedAt, + clientCertExpiration: clientCaExpiration, + clientCertKeyAlgorithm: CertKeyAlgorithm.RSA_2048, + clientCertSerialNumber, + encryptedClientPrivateKey: orgKmsEncryptor({ + plainText: clientSkObj.export({ + type: "pkcs8", + format: "der" + }) + }).cipherTextBlob, + encryptedClientCertificate: orgKmsEncryptor({ + plainText: Buffer.from(clientCert.rawData) + }).cipherTextBlob, + + gatewayCaIssuedAt, + gatewayCaExpiration, + gatewayCaSerialNumber, + encryptedGatewayCaPrivateKey: orgKmsEncryptor({ + plainText: gatewayCaSkObj.export({ + type: "pkcs8", + format: "der" + }) + }).cipherTextBlob, + encryptedGatewayCaCertificate: orgKmsEncryptor({ + plainText: Buffer.from(gatewayCaCert.rawData) + }).cipherTextBlob }); }); - const caCertObj = new x509.X509Certificate( + const rootCaCert = new x509.X509Certificate( orgKmsDecryptor({ - cipherTextBlob: orgGatewayRootCa.encryptedCaCertificate + cipherTextBlob: orgGatewayConfig.encryptedRootCaCertificate }) ); - const caAlg = keyAlgorithmToAlgCfg(orgGatewayRootCa.caKeyAlgorithm as CertKeyAlgorithm); - const caSkObj = crypto.createPrivateKey({ - key: orgKmsDecryptor({ cipherTextBlob: orgGatewayRootCa.encryptedCaPrivateKey }), + const clientCaCert = new x509.X509Certificate( + orgKmsDecryptor({ + cipherTextBlob: orgGatewayConfig.encryptedClientCaCertificate + }) + ); + + const gatewayCaAlg = keyAlgorithmToAlgCfg(orgGatewayConfig.rootCaKeyAlgorithm as CertKeyAlgorithm); + const gatewayCaSkObj = crypto.createPrivateKey({ + key: orgKmsDecryptor({ cipherTextBlob: orgGatewayConfig.encryptedGatewayCaPrivateKey }), format: "der", type: "pkcs8" }); - const caPrivateKey = await crypto.subtle.importKey( + const gatewayCaPrivateKey = await crypto.subtle.importKey( "pkcs8", - caSkObj.export({ format: "der", type: "pkcs8" }), - caAlg, + gatewayCaSkObj.export({ format: "der", type: "pkcs8" }), + gatewayCaAlg, true, ["sign"] ); @@ -160,9 +309,10 @@ export const gatewayServiceFactory = ({ const certIssuedAt = new Date(); // then need to periodically init const certExpireAt = new Date(new Date().setMonth(new Date().getMonth() + 1)); + const extensions: x509.Extension[] = [ new x509.BasicConstraintsExtension(false), - await x509.AuthorityKeyIdentifierExtension.create(caCertObj, false), + await x509.AuthorityKeyIdentifierExtension.create(rootCaCert, false), await x509.SubjectKeyIdentifierExtension.create(gatewayKeys.publicKey), new x509.CertificatePolicyExtension(["2.5.29.32.0"]), // anyPolicy new x509.KeyUsagesExtension( @@ -172,7 +322,8 @@ export const gatewayServiceFactory = ({ ), new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.SERVER_AUTH]], true), // san - new x509.SubjectAlternativeNameExtension([{ type: "ip", value: relayAddress }], false) + // TODO(gateway): change this later + new x509.SubjectAlternativeNameExtension([{ type: "ip", value: "127.0.0.1" }], false) ]; const serialNumber = createSerialNumber(); @@ -180,10 +331,10 @@ export const gatewayServiceFactory = ({ const gatewayCertificate = await x509.X509CertificateGenerator.create({ serialNumber, subject: `CN=${identityId},O=${identityOrg}`, - issuer: caCertObj.subject, + issuer: rootCaCert.subject, notBefore: certIssuedAt, notAfter: certExpireAt, - signingKey: caPrivateKey, + signingKey: gatewayCaPrivateKey, publicKey: gatewayKeys.publicKey, signingAlgorithm: alg, extensions @@ -191,7 +342,7 @@ export const gatewayServiceFactory = ({ await gatewayDAL.transaction(async (tx) => { await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.OrgGatewayCertExchange(identityOrg)]); - const existingGateway = await gatewayDAL.findOne({ identityId, orgGatewayRootCaId: orgGatewayRootCa.id }); + const existingGateway = await gatewayDAL.findOne({ identityId, orgGatewayRootCaId: orgGatewayConfig.id }); if (existingGateway) { return gatewayDAL.updateById(existingGateway.id, { keyAlgorithm: CertKeyAlgorithm.RSA_2048, @@ -209,16 +360,18 @@ export const gatewayServiceFactory = ({ serialNumber, relayAddress: orgKmsEncryptor({ plainText: Buffer.from(relayAddress) }).cipherTextBlob, identityId, - orgGatewayRootCaId: orgGatewayRootCa.id, + orgGatewayRootCaId: orgGatewayConfig.id, name: alphaNumericNanoId(8) }); }); + const gatewayCertificateChain = `${clientCaCert.toString("pem")}\n${rootCaCert.toString("pem")}`.trim(); + return { serialNumber, privateKey: privateKey.export({ format: "pem", type: "pkcs8" }) as string, certificate: gatewayCertificate.toString("pem"), - certificateChain: caCertObj.toString("pem") + certificateChain: gatewayCertificateChain }; }; @@ -231,11 +384,11 @@ export const gatewayServiceFactory = ({ orgPermission.orgId ); ForbiddenError.from(permission).throwUnlessCan(OrgGatewayPermissionActions.Read, OrgPermissionSubjects.Gateway); - const rootCa = await orgGatewayRootCaDAL.findOne({ orgId: orgPermission.orgId }); - if (!rootCa) return []; + const orgGatewayConfig = await orgGatewayConfigDAL.findOne({ orgId: orgPermission.orgId }); + if (!orgGatewayConfig) return []; const gateways = await gatewayDAL.find({ - orgGatewayRootCaId: rootCa.id + orgGatewayRootCaId: orgGatewayConfig.id }); return gateways; }; @@ -249,10 +402,10 @@ export const gatewayServiceFactory = ({ orgPermission.orgId ); ForbiddenError.from(permission).throwUnlessCan(OrgGatewayPermissionActions.Read, OrgPermissionSubjects.Gateway); - const rootCa = await orgGatewayRootCaDAL.findOne({ orgId: orgPermission.orgId }); - if (!rootCa) throw new NotFoundError({ message: `Gateway with ID ${id} not found.` }); + const orgGatewayConfig = await orgGatewayConfigDAL.findOne({ orgId: orgPermission.orgId }); + if (!orgGatewayConfig) throw new NotFoundError({ message: `Gateway with ID ${id} not found.` }); - const [gateway] = await gatewayDAL.find({ id, orgGatewayRootCaId: rootCa.id }); + const [gateway] = await gatewayDAL.find({ id, orgGatewayRootCaId: orgGatewayConfig.id }); if (!gateway) throw new NotFoundError({ message: `Gateway with ID ${id} not found.` }); return gateway; }; @@ -266,10 +419,10 @@ export const gatewayServiceFactory = ({ orgPermission.orgId ); ForbiddenError.from(permission).throwUnlessCan(OrgGatewayPermissionActions.Delete, OrgPermissionSubjects.Gateway); - const rootCa = await orgGatewayRootCaDAL.findOne({ orgId: orgPermission.orgId }); - if (!rootCa) throw new NotFoundError({ message: `Gateway with ID ${id} not found.` }); + const orgGatewayConfig = await orgGatewayConfigDAL.findOne({ orgId: orgPermission.orgId }); + if (!orgGatewayConfig) throw new NotFoundError({ message: `Gateway with ID ${id} not found.` }); - const [gateway] = await gatewayDAL.delete({ id, orgGatewayRootCaId: rootCa.id }); + const [gateway] = await gatewayDAL.delete({ id, orgGatewayRootCaId: orgGatewayConfig.id }); if (!gateway) throw new NotFoundError({ message: `Gateway with ID ${id} not found.` }); return gateway; }; diff --git a/backend/src/ee/services/gateway/org-gateway-config-dal.ts b/backend/src/ee/services/gateway/org-gateway-config-dal.ts new file mode 100644 index 000000000..9d4f9384a --- /dev/null +++ b/backend/src/ee/services/gateway/org-gateway-config-dal.ts @@ -0,0 +1,10 @@ +import { TDbClient } from "@app/db"; +import { TableName } from "@app/db/schemas"; +import { ormify } from "@app/lib/knex"; + +export type TOrgGatewayConfigDALFactory = ReturnType; + +export const orgGatewayConfigDALFactory = (db: TDbClient) => { + const orm = ormify(db, TableName.OrgGatewayConfig); + return orm; +}; diff --git a/backend/src/ee/services/gateway/org-gateway-root-ca-dal.ts b/backend/src/ee/services/gateway/org-gateway-root-ca-dal.ts deleted file mode 100644 index 4730f20f8..000000000 --- a/backend/src/ee/services/gateway/org-gateway-root-ca-dal.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; -import { ormify } from "@app/lib/knex"; - -export type TOrgGatewayRootCaDALFactory = ReturnType; - -export const orgGatewayRootCaDALFactory = (db: TDbClient) => { - const orm = ormify(db, TableName.OrgGatewayRootCa); - return orm; -}; diff --git a/backend/src/keystore/keystore.ts b/backend/src/keystore/keystore.ts index 982dc21f9..76e93ce9f 100644 --- a/backend/src/keystore/keystore.ts +++ b/backend/src/keystore/keystore.ts @@ -1,13 +1,14 @@ import { Redis } from "ioredis"; import { Redlock, Settings } from "@app/lib/red-lock"; +import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext"; export const PgSqlLock = { BootUpMigration: 2023, SuperAdminInit: 2024, KmsRootKeyInit: 2025, - OrgGatewayRootCaInit: (orgId: string) => `org-gateway-root-ca:${orgId}`, - OrgGatewayCertExchange: (orgId: string) => `org-gateway-cert-exchange:${orgId}` + OrgGatewayRootCaInit: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-root-ca:${orgId}`), + OrgGatewayCertExchange: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-cert-exchange:${orgId}`) } as const; export type TKeyStoreFactory = ReturnType; diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index a286b4203..c51809849 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -187,6 +187,7 @@ const envSchema = z /* Gateway----------------------------------------------------------------------------- */ GATEWAY_INFISICAL_STATIC_IP_ADDRESS: zpStr(z.string().optional()), GATEWAY_RELAY_ADDRESS: zpStr(z.string().optional()), + GATEWAY_RELAY_REALM: zpStr(z.string().optional()), GATEWAY_RELAY_AUTH_SECRET: zpStr(z.string().optional()), /* ----------------------------------------------------------------------------- */ diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index fb8552744..ca6a16a6e 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -28,9 +28,8 @@ import { dynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secre import { externalKmsDALFactory } from "@app/ee/services/external-kms/external-kms-dal"; import { externalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service"; import { gatewayDALFactory } from "@app/ee/services/gateway/gateway-dal"; -import { gatewayInstanceConfigDALFactory } from "@app/ee/services/gateway/gateway-instance-config-dal"; import { gatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; -import { orgGatewayRootCaDALFactory } from "@app/ee/services/gateway/org-gateway-root-ca-dal"; +import { orgGatewayConfigDALFactory } from "@app/ee/services/gateway/org-gateway-config-dal"; import { groupDALFactory } from "@app/ee/services/group/group-dal"; import { groupServiceFactory } from "@app/ee/services/group/group-service"; import { userGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal"; @@ -397,8 +396,7 @@ export const registerRoutes = async ( const kmipOrgConfigDAL = kmipOrgConfigDALFactory(db); const kmipOrgServerCertificateDAL = kmipOrgServerCertificateDALFactory(db); - const gatewayInstanceConfigDAL = gatewayInstanceConfigDALFactory(db); - const orgGatewayRootCaDAL = orgGatewayRootCaDALFactory(db); + const orgGatewayConfigDAL = orgGatewayConfigDALFactory(db); const gatewayDAL = gatewayDALFactory(db); const permissionService = permissionServiceFactory({ @@ -639,7 +637,6 @@ export const registerRoutes = async ( authService: loginService, serverCfgDAL: superAdminDAL, kmsRootConfigDAL, - gatewayInstanceConfigDAL, orgService, keyStore, licenseService, @@ -1467,11 +1464,11 @@ export const registerRoutes = async ( }); const gatewayService = gatewayServiceFactory({ - orgGatewayRootCaDAL, permissionService, gatewayDAL, kmsService, - licenseService + licenseService, + orgGatewayConfigDAL }); await superAdminService.initServerCfg(); diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index 4359ef3fe..6ecebb274 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { GatewayInstanceConfigSchema, OrganizationsSchema, SuperAdminSchema, UsersSchema } from "@app/db/schemas"; +import { OrganizationsSchema, SuperAdminSchema, UsersSchema } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -12,13 +12,6 @@ import { getServerCfg } from "@app/services/super-admin/super-admin-service"; import { LoginMethod } from "@app/services/super-admin/super-admin-types"; import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; -const SanitizedInstanceGatewaySchema = GatewayInstanceConfigSchema.pick({ - isDisabled: true, - infisicalClientCaIssuedAt: true, - infisicalClientCaSerialNumber: true, - caKeyAlgorithm: true -}); - export const registerAdminRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", @@ -254,82 +247,6 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { } }); - server.route({ - method: "POST", - url: "/gateway", - config: { - rateLimit: writeLimit - }, - schema: { - response: { - 200: z.object({ - message: z.string() - }) - } - }, - onRequest: (req, res, done) => { - verifyAuth([AuthMode.JWT])(req, res, () => { - verifySuperAdmin(req, res, done); - }); - }, - handler: async () => { - await server.services.superAdmin.setupInstanceGateway(); - return { message: "Gateway setup completed" }; - } - }); - - server.route({ - method: "PATCH", - url: "/gateway", - config: { - rateLimit: writeLimit - }, - schema: { - body: z.object({ - isDisabled: z.boolean().optional() - }), - response: { - 200: z.object({ - message: z.string(), - gateway: SanitizedInstanceGatewaySchema - }) - } - }, - onRequest: (req, res, done) => { - verifyAuth([AuthMode.JWT])(req, res, () => { - verifySuperAdmin(req, res, done); - }); - }, - handler: async (req) => { - const gateway = await server.services.superAdmin.updateInstanceGateway(req.body); - return { message: "Gateway updated Successfully.", gateway }; - } - }); - - server.route({ - method: "GET", - url: "/gateway", - config: { - rateLimit: readLimit - }, - schema: { - response: { - 200: z.object({ - gateway: SanitizedInstanceGatewaySchema - }) - } - }, - onRequest: (req, res, done) => { - verifyAuth([AuthMode.JWT])(req, res, () => { - verifySuperAdmin(req, res, done); - }); - }, - handler: async () => { - const gateway = await server.services.superAdmin.getInstanceGateway(); - return { gateway }; - } - }); - server.route({ method: "POST", url: "/signup", diff --git a/backend/src/services/super-admin/super-admin-service.ts b/backend/src/services/super-admin/super-admin-service.ts index cf9c35425..9a6075423 100644 --- a/backend/src/services/super-admin/super-admin-service.ts +++ b/backend/src/services/super-admin/super-admin-service.ts @@ -1,9 +1,6 @@ -import * as x509 from "@peculiar/x509"; import bcrypt from "bcrypt"; -import crypto, { KeyObject } from "crypto"; import { TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas"; -import { TGatewayInstanceConfigDALFactory } from "@app/ee/services/gateway/gateway-instance-config-dal"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore"; import { getConfig } from "@app/lib/config/env"; @@ -13,8 +10,6 @@ import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { TAuthLoginFactory } from "../auth/auth-login-service"; import { AuthMethod } from "../auth/auth-type"; -import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "../certificate/certificate-types"; -import { createSerialNumber, keyAlgorithmToAlgCfg } from "../certificate-authority/certificate-authority-fns"; import { KMS_ROOT_CONFIG_UUID } from "../kms/kms-fns"; import { TKmsRootConfigDALFactory } from "../kms/kms-root-config-dal"; import { TKmsServiceFactory } from "../kms/kms-service"; @@ -36,7 +31,6 @@ type TSuperAdminServiceFactoryDep = { orgService: Pick; keyStore: Pick; licenseService: Pick; - gatewayInstanceConfigDAL: Pick; }; export type TSuperAdminServiceFactory = ReturnType; @@ -53,7 +47,6 @@ export let getServerCfg: () => Promise< const ADMIN_CONFIG_KEY = "infisical-admin-cfg"; const ADMIN_CONFIG_KEY_EXP = 60; // 60s const ADMIN_CONFIG_DB_UUID = "00000000-0000-0000-0000-000000000000"; -const GATEWAY_INSTANCE_CONFIG_UUID = "00000000-0000-0000-0000-000000000000"; export const superAdminServiceFactory = ({ serverCfgDAL, @@ -64,8 +57,7 @@ export const superAdminServiceFactory = ({ keyStore, kmsRootConfigDAL, kmsService, - licenseService, - gatewayInstanceConfigDAL + licenseService }: TSuperAdminServiceFactoryDep) => { const initServerCfg = async () => { // TODO(akhilmhdh): bad pattern time less change this later to me itself @@ -381,149 +373,6 @@ export const superAdminServiceFactory = ({ await kmsService.updateEncryptionStrategy(strategy); }; - const setupInstanceGateway = async () => { - if (!licenseService.onPremFeatures.gateway) { - throw new BadRequestError({ - message: "Failed to setup gateway ca due to plan restriction. Upgrade to Infisical's Enterprise plan." - }); - } - - const existingConfig = await gatewayInstanceConfigDAL.findById(GATEWAY_INSTANCE_CONFIG_UUID); - if (existingConfig) { - throw new BadRequestError({ - message: "Gateway has already been configured for the instance" - }); - } - - const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048); - // generate root CA - const infisicalClientRootCaSerialNumber = createSerialNumber(); - const infisicalClientRootCaKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); - const infisicalClientCaSkObj = KeyObject.from(infisicalClientRootCaKeys.privateKey); - const infisicalClientCaIssuedAt = new Date(); - const infisicalClientCaExpiration = new Date(new Date().setFullYear(new Date().getFullYear() + 25)); - - const infisicalClientCaCert = await x509.X509CertificateGenerator.createSelfSigned({ - name: "CN=Infisical Gateway Client Root CA", - serialNumber: infisicalClientRootCaSerialNumber, - notBefore: infisicalClientCaIssuedAt, - notAfter: infisicalClientCaExpiration, - signingAlgorithm: alg, - keys: infisicalClientRootCaKeys, - extensions: [ - // eslint-disable-next-line no-bitwise - new x509.KeyUsagesExtension(x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.cRLSign, true), - await x509.SubjectKeyIdentifierExtension.create(infisicalClientRootCaKeys.publicKey) - ] - }); - - const infisicalClientLeafCertserialNumber = createSerialNumber(); - const infisicalClientLeafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]); - const extensions: x509.Extension[] = [ - new x509.BasicConstraintsExtension(false), - await x509.AuthorityKeyIdentifierExtension.create(infisicalClientCaCert, false), - await x509.SubjectKeyIdentifierExtension.create(infisicalClientLeafKeys.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] | - x509.KeyUsageFlags[CertKeyUsage.KEY_AGREEMENT], - true - ), - new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage[CertExtendedKeyUsage.CLIENT_AUTH]], true) - ]; - - const infisicalClientLeafCert = await x509.X509CertificateGenerator.create({ - serialNumber: infisicalClientLeafCertserialNumber, - subject: `OU=infisical,CN=infisical`, - issuer: infisicalClientCaCert.issuer, - notBefore: infisicalClientCaIssuedAt, - notAfter: infisicalClientCaExpiration, - signingKey: infisicalClientRootCaKeys.privateKey, - publicKey: infisicalClientLeafKeys.publicKey, - signingAlgorithm: alg, - extensions - }); - - const infisicalClientLeafCertSkObj = KeyObject.from(infisicalClientLeafKeys.privateKey); - const encryptWithRootKey = kmsService.encryptWithRootKey(); - await gatewayInstanceConfigDAL.create({ - // @ts-expect-error id is kept as fixed for idempotence and to avoid race condition - id: GATEWAY_INSTANCE_CONFIG_UUID, - isDisabled: false, - caKeyAlgorithm: CertKeyAlgorithm.RSA_2048, - infisicalClientCaIssuedAt, - infisicalClientCaExpiration, - infisicalClientCaSerialNumber: infisicalClientRootCaSerialNumber, - encryptedInfisicalClientCaCertificate: encryptWithRootKey(Buffer.from(infisicalClientCaCert.rawData)), - encryptedInfisicalClientCaPrivateKey: encryptWithRootKey( - infisicalClientCaSkObj.export({ - type: "pkcs8", - format: "der" - }) - ), - infisicalClientCertIssuedAt: infisicalClientCaIssuedAt, - infisicalClientCertExpiration: infisicalClientCaExpiration, - infisicalClientCertSerialNumber: infisicalClientLeafCertserialNumber, - infisicalClientCertKeyAlgorithm: CertKeyAlgorithm.RSA_2048, - encryptedInfisicalClientCertificate: encryptWithRootKey(Buffer.from(infisicalClientLeafCert.rawData)), - encryptedInfisicalClientPrivateKey: encryptWithRootKey( - infisicalClientLeafCertSkObj.export({ - type: "pkcs8", - format: "der" - }) - ) - }); - }; - - const updateInstanceGateway = async ({ isDisabled }: { isDisabled?: boolean }) => { - if (!licenseService.onPremFeatures.gateway) { - throw new BadRequestError({ - message: "Failed to update gateway ca due to plan restriction. Upgrade to Infisical's Enterprise plan." - }); - } - - const existingConfig = await gatewayInstanceConfigDAL.findById(GATEWAY_INSTANCE_CONFIG_UUID); - if (!existingConfig) { - throw new NotFoundError({ - message: "Gateway instance config not found" - }); - } - - const updatedGatewayInstanceConfig = await gatewayInstanceConfigDAL.updateById(GATEWAY_INSTANCE_CONFIG_UUID, { - isDisabled - }); - return { - infisicalClientCaSerialNumber: updatedGatewayInstanceConfig.infisicalClientCaSerialNumber, - isDisabled: updatedGatewayInstanceConfig?.isDisabled, - caKeyAlgorithm: CertKeyAlgorithm.RSA_2048, - infisicalClientCaIssuedAt: updatedGatewayInstanceConfig.infisicalClientCaIssuedAt - }; - }; - - const getInstanceGateway = async () => { - if (!licenseService.onPremFeatures.gateway) { - throw new BadRequestError({ - message: "Failed to update gateway ca due to plan restriction. Upgrade to Infisical's Enterprise plan." - }); - } - - const existingConfig = await gatewayInstanceConfigDAL.findById(GATEWAY_INSTANCE_CONFIG_UUID); - if (!existingConfig) { - throw new NotFoundError({ - message: "Gateway instance config not found" - }); - } - - return { - infisicalClientCaSerialNumber: existingConfig.infisicalClientCaSerialNumber, - isDisabled: existingConfig?.isDisabled, - caKeyAlgorithm: CertKeyAlgorithm.RSA_2048, - infisicalClientCaIssuedAt: existingConfig.infisicalClientCaIssuedAt - }; - }; - return { initServerCfg, updateServerCfg, @@ -532,9 +381,6 @@ export const superAdminServiceFactory = ({ deleteUser, getAdminSlackConfig, updateRootEncryptionStrategy, - getConfiguredEncryptionStrategies, - setupInstanceGateway, - updateInstanceGateway, - getInstanceGateway + getConfiguredEncryptionStrategies }; };