mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 15:26:20 +00:00
feat: pki and ssh setup for instance proxy
This commit is contained in:
Vendored
+2
@@ -31,6 +31,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
||||||
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-types";
|
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 { 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 { RateLimitConfiguration, TRateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-types";
|
||||||
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-types";
|
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-types";
|
||||||
import { TScimServiceFactory } from "@app/ee/services/scim/scim-types";
|
import { TScimServiceFactory } from "@app/ee/services/scim/scim-types";
|
||||||
@@ -303,6 +304,7 @@ declare module "fastify" {
|
|||||||
bus: TEventBusService;
|
bus: TEventBusService;
|
||||||
sse: TServerSentEventsService;
|
sse: TServerSentEventsService;
|
||||||
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
||||||
|
proxy: TProxyServiceFactory;
|
||||||
};
|
};
|
||||||
// this is exclusive use for middlewares in which we need to inject data
|
// this is exclusive use for middlewares in which we need to inject data
|
||||||
// everywhere else access using service layer
|
// everywhere else access using service layer
|
||||||
|
|||||||
Vendored
+16
@@ -179,6 +179,9 @@ import {
|
|||||||
TIncidentContacts,
|
TIncidentContacts,
|
||||||
TIncidentContactsInsert,
|
TIncidentContactsInsert,
|
||||||
TIncidentContactsUpdate,
|
TIncidentContactsUpdate,
|
||||||
|
TInstanceProxyConfig,
|
||||||
|
TInstanceProxyConfigInsert,
|
||||||
|
TInstanceProxyConfigUpdate,
|
||||||
TIntegrationAuths,
|
TIntegrationAuths,
|
||||||
TIntegrationAuthsInsert,
|
TIntegrationAuthsInsert,
|
||||||
TIntegrationAuthsUpdate,
|
TIntegrationAuthsUpdate,
|
||||||
@@ -233,6 +236,9 @@ import {
|
|||||||
TOrgMemberships,
|
TOrgMemberships,
|
||||||
TOrgMembershipsInsert,
|
TOrgMembershipsInsert,
|
||||||
TOrgMembershipsUpdate,
|
TOrgMembershipsUpdate,
|
||||||
|
TOrgProxyConfig,
|
||||||
|
TOrgProxyConfigInsert,
|
||||||
|
TOrgProxyConfigUpdate,
|
||||||
TOrgRoles,
|
TOrgRoles,
|
||||||
TOrgRolesInsert,
|
TOrgRolesInsert,
|
||||||
TOrgRolesUpdate,
|
TOrgRolesUpdate,
|
||||||
@@ -1254,5 +1260,15 @@ declare module "knex/types/tables" {
|
|||||||
TRemindersRecipientsInsert,
|
TRemindersRecipientsInsert,
|
||||||
TRemindersRecipientsUpdate
|
TRemindersRecipientsUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.InstanceProxyConfig]: KnexOriginal.CompositeTableType<
|
||||||
|
TInstanceProxyConfig,
|
||||||
|
TInstanceProxyConfigInsert,
|
||||||
|
TInstanceProxyConfigUpdate
|
||||||
|
>;
|
||||||
|
[TableName.OrgProxyConfig]: KnexOriginal.CompositeTableType<
|
||||||
|
TOrgProxyConfig,
|
||||||
|
TOrgProxyConfigInsert,
|
||||||
|
TOrgProxyConfigUpdate
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -57,6 +57,7 @@ export * from "./identity-token-auths";
|
|||||||
export * from "./identity-ua-client-secrets";
|
export * from "./identity-ua-client-secrets";
|
||||||
export * from "./identity-universal-auths";
|
export * from "./identity-universal-auths";
|
||||||
export * from "./incident-contacts";
|
export * from "./incident-contacts";
|
||||||
|
export * from "./instance-proxy-config";
|
||||||
export * from "./integration-auths";
|
export * from "./integration-auths";
|
||||||
export * from "./integrations";
|
export * from "./integrations";
|
||||||
export * from "./internal-certificate-authorities";
|
export * from "./internal-certificate-authorities";
|
||||||
@@ -76,6 +77,7 @@ export * from "./oidc-configs";
|
|||||||
export * from "./org-bots";
|
export * from "./org-bots";
|
||||||
export * from "./org-gateway-config";
|
export * from "./org-gateway-config";
|
||||||
export * from "./org-memberships";
|
export * from "./org-memberships";
|
||||||
|
export * from "./org-proxy-config";
|
||||||
export * from "./org-roles";
|
export * from "./org-roles";
|
||||||
export * from "./organizations";
|
export * from "./organizations";
|
||||||
export * from "./pki-alerts";
|
export * from "./pki-alerts";
|
||||||
|
|||||||
@@ -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,11 @@ export enum TableName {
|
|||||||
SecretScanningConfig = "secret_scanning_configs",
|
SecretScanningConfig = "secret_scanning_configs",
|
||||||
// reminders
|
// reminders
|
||||||
Reminder = "reminders",
|
Reminder = "reminders",
|
||||||
ReminderRecipient = "reminders_recipients"
|
ReminderRecipient = "reminders_recipients",
|
||||||
|
|
||||||
|
// gateway v2
|
||||||
|
InstanceProxyConfig = "instance_proxy_config",
|
||||||
|
OrgProxyConfig = "org_proxy_config"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
||||||
|
|||||||
@@ -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>>;
|
||||||
@@ -23,6 +23,7 @@ import { registerOrgRoleRouter } from "./org-role-router";
|
|||||||
import { registerPITRouter } from "./pit-router";
|
import { registerPITRouter } from "./pit-router";
|
||||||
import { registerProjectRoleRouter } from "./project-role-router";
|
import { registerProjectRoleRouter } from "./project-role-router";
|
||||||
import { registerProjectRouter } from "./project-router";
|
import { registerProjectRouter } from "./project-router";
|
||||||
|
import { registerProxyRouter } from "./proxy-router";
|
||||||
import { registerRateLimitRouter } from "./rate-limit-router";
|
import { registerRateLimitRouter } from "./rate-limit-router";
|
||||||
import { registerSamlRouter } from "./saml-router";
|
import { registerSamlRouter } from "./saml-router";
|
||||||
import { registerScimRouter } from "./scim-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(registerGatewayRouter, { prefix: "/gateways" });
|
||||||
|
await server.register(registerProxyRouter, { prefix: "/proxies" });
|
||||||
await server.register(registerGithubOrgSyncRouter, { prefix: "/github-org-sync-config" });
|
await server.register(registerGithubOrgSyncRouter, { prefix: "/github-org-sync-config" });
|
||||||
|
|
||||||
await server.register(
|
await server.register(
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
|
||||||
|
export const registerProxyRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
ip: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.any()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
return server.services.proxy.registerProxy(req.body);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -0,0 +1,464 @@
|
|||||||
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
|
import { PgSqlLock } from "@app/keystore/keystore";
|
||||||
|
import { crypto } from "@app/lib/crypto";
|
||||||
|
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 { 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";
|
||||||
|
|
||||||
|
export type TProxyServiceFactory = ReturnType<typeof proxyServiceFactory>;
|
||||||
|
|
||||||
|
const INSTANCE_PROXY_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
|
||||||
|
|
||||||
|
export const proxyServiceFactory = ({
|
||||||
|
instanceProxyConfigDAL,
|
||||||
|
orgProxyConfigDAL,
|
||||||
|
kmsService
|
||||||
|
}: {
|
||||||
|
instanceProxyConfigDAL: TInstanceProxyConfigDALFactory;
|
||||||
|
orgProxyConfigDAL: TOrgProxyConfigDALFactory;
|
||||||
|
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 rootCaKeyAlgorithm = CertKeyAlgorithm.RSA_2048;
|
||||||
|
const alg = keyAlgorithmToAlgCfg(rootCaKeyAlgorithm);
|
||||||
|
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 registerProxy = async ({ ip }: { ip: string }) => {
|
||||||
|
// initialize instance CAs if not yet initialized
|
||||||
|
const instanceCAs = await $getInstanceCAs();
|
||||||
|
|
||||||
|
// TODO: check if identity used already has an existing proxy. If the same IP, return the existing proxy. If not, create a new proxy and overwrite
|
||||||
|
|
||||||
|
// generate proxy server PKI certificate
|
||||||
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
|
const proxyServerCaCert = new x509.X509Certificate(instanceCAs.instanceProxyPkiServerCaCertificate);
|
||||||
|
const rootProxyCaCert = new x509.X509Certificate(instanceCAs.rootProxyPkiCaCertificate);
|
||||||
|
const proxyServerCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
||||||
|
key: instanceCAs.instanceProxyPkiServerCaPrivateKey,
|
||||||
|
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=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: instanceCAs.instanceProxySshServerCaPrivateKey.toString("utf8"),
|
||||||
|
clientPublicKey: proxyServerSshPublicKey,
|
||||||
|
keyId: "proxy-server",
|
||||||
|
principals: [ip],
|
||||||
|
certType: SshCertType.HOST,
|
||||||
|
requestedTtl: "30d"
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
pki: {
|
||||||
|
serverCertificate: proxyServerCertificate.toString("pem"),
|
||||||
|
serverCertificateChain: prependCertToPemChain(
|
||||||
|
proxyServerCaCert,
|
||||||
|
instanceCAs.instanceProxyPkiServerCaCertificateChain.toString("utf8")
|
||||||
|
),
|
||||||
|
serverPrivateKey: proxyServerCertPrivateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
||||||
|
clientCA: rootProxyCaCert.toString("pem")
|
||||||
|
},
|
||||||
|
ssh: {
|
||||||
|
serverCertificate: proxyServerSshCert.signedPublicKey,
|
||||||
|
serverPrivateKey: proxyServerSshPrivateKey,
|
||||||
|
clientCAPublicKey: instanceCAs.instanceProxySshClientCaPublicKey.toString("utf8")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
registerProxy
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -13,7 +13,8 @@ export const PgSqlLock = {
|
|||||||
SecretRotationV2Creation: (folderId: string) => pgAdvisoryLockHashText(`secret-rotation-v2-creation:${folderId}`),
|
SecretRotationV2Creation: (folderId: string) => pgAdvisoryLockHashText(`secret-rotation-v2-creation:${folderId}`),
|
||||||
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`),
|
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`),
|
||||||
CreateFolder: (envId: string, projectId: string) => pgAdvisoryLockHashText(`create-folder:${envId}-${projectId}`),
|
CreateFolder: (envId: string, projectId: string) => pgAdvisoryLockHashText(`create-folder:${envId}-${projectId}`),
|
||||||
SshInit: (projectId: string) => pgAdvisoryLockHashText(`ssh-bootstrap:${projectId}`)
|
SshInit: (projectId: string) => pgAdvisoryLockHashText(`ssh-bootstrap:${projectId}`),
|
||||||
|
InstanceProxyConfigInit: () => pgAdvisoryLockHashText("instance-proxy-config-init")
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// all the key prefixes used must be set here to avoid conflict
|
// all the key prefixes used must be set here to avoid conflict
|
||||||
|
|||||||
@@ -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 { 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 { 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 { 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 { rateLimitDALFactory } from "@app/ee/services/rate-limit/rate-limit-dal";
|
||||||
import { rateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-service";
|
import { rateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-service";
|
||||||
import { samlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
|
import { samlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
|
||||||
@@ -939,6 +942,9 @@ export const registerRoutes = async (
|
|||||||
const pkiSubscriberDAL = pkiSubscriberDALFactory(db);
|
const pkiSubscriberDAL = pkiSubscriberDALFactory(db);
|
||||||
const pkiTemplatesDAL = pkiTemplatesDALFactory(db);
|
const pkiTemplatesDAL = pkiTemplatesDALFactory(db);
|
||||||
|
|
||||||
|
const instanceProxyConfigDAL = instanceProxyConfigDalFactory(db);
|
||||||
|
const orgProxyConfigDAL = orgProxyConfigDalFactory(db);
|
||||||
|
|
||||||
const certificateService = certificateServiceFactory({
|
const certificateService = certificateServiceFactory({
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateBodyDAL,
|
certificateBodyDAL,
|
||||||
@@ -1960,6 +1966,12 @@ export const registerRoutes = async (
|
|||||||
appConnectionDAL
|
appConnectionDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const proxyService = proxyServiceFactory({
|
||||||
|
instanceProxyConfigDAL,
|
||||||
|
orgProxyConfigDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
// setup the communication with license key server
|
// setup the communication with license key server
|
||||||
await licenseService.init();
|
await licenseService.init();
|
||||||
|
|
||||||
@@ -2091,7 +2103,8 @@ export const registerRoutes = async (
|
|||||||
secretScanningV2: secretScanningV2Service,
|
secretScanningV2: secretScanningV2Service,
|
||||||
reminder: reminderService,
|
reminder: reminderService,
|
||||||
bus: eventBusService,
|
bus: eventBusService,
|
||||||
sse: sseService
|
sse: sseService,
|
||||||
|
proxy: proxyService
|
||||||
});
|
});
|
||||||
|
|
||||||
const cronJobs: CronJob[] = [];
|
const cronJobs: CronJob[] = [];
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ export const constructPemChainFromCerts = (certificates: x509.X509Certificate[])
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
|
export const prependCertToPemChain = (cert: x509.X509Certificate, pemChain: string) =>
|
||||||
|
`${cert.toString("pem")}\n${pemChain}`;
|
||||||
|
|
||||||
export const splitPemChain = (pemText: string) => {
|
export const splitPemChain = (pemText: string) => {
|
||||||
const re2Pattern = new RE2("-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----", "g");
|
const re2Pattern = new RE2("-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----", "g");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user