From 2fb13463bcb7a651c0489cb9048feb0fbc8f8728 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 28 Aug 2025 18:21:51 +0800 Subject: [PATCH] misc: add schema for gateway --- ...1627_add-gateway-v2-pki-and-ssh-configs.ts | 23 +++++++++++++++++++ backend/src/db/schemas/models.ts | 3 ++- .../services/gateway-v2/gateway-v2-service.ts | 7 +++++- .../src/ee/services/proxy/proxy-service.ts | 10 ++++---- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/backend/src/db/migrations/20250825131627_add-gateway-v2-pki-and-ssh-configs.ts b/backend/src/db/migrations/20250825131627_add-gateway-v2-pki-and-ssh-configs.ts index 68aa15374..e35948ef1 100644 --- a/backend/src/db/migrations/20250825131627_add-gateway-v2-pki-and-ssh-configs.ts +++ b/backend/src/db/migrations/20250825131627_add-gateway-v2-pki-and-ssh-configs.ts @@ -104,6 +104,26 @@ export async function up(knex: Knex): Promise { 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 { @@ -118,4 +138,7 @@ export async function down(knex: Knex): Promise { await dropOnUpdateTrigger(knex, TableName.Proxy); await knex.schema.dropTableIfExists(TableName.Proxy); + + await dropOnUpdateTrigger(knex, TableName.GatewayV2); + await knex.schema.dropTableIfExists(TableName.GatewayV2); } diff --git a/backend/src/db/schemas/models.ts b/backend/src/db/schemas/models.ts index 99681b986..87ea9f8e5 100644 --- a/backend/src/db/schemas/models.ts +++ b/backend/src/db/schemas/models.ts @@ -184,7 +184,8 @@ export enum TableName { InstanceProxyConfig = "instance_proxy_config", OrgProxyConfig = "org_proxy_config", OrgGatewayConfigV2 = "org_gateway_config_v2", - Proxy = "proxies" + Proxy = "proxies", + GatewayV2 = "gateways_v2" } export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId"; diff --git a/backend/src/ee/services/gateway-v2/gateway-v2-service.ts b/backend/src/ee/services/gateway-v2/gateway-v2-service.ts index e55acbffa..ec7617c93 100644 --- a/backend/src/ee/services/gateway-v2/gateway-v2-service.ts +++ b/backend/src/ee/services/gateway-v2/gateway-v2-service.ts @@ -200,6 +200,9 @@ export const gatewayV2ServiceFactory = ({ 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); @@ -248,12 +251,14 @@ export const gatewayV2ServiceFactory = ({ extensions: gatewayServerCertExtensions }); - const proxyCredentials = await proxyService.generateSshCredentialsForGateway({ + const proxyCredentials = await proxyService.getCredentialsForGateway({ proxyName, orgId }); return { + // TODO: return gateway ID + proxyIp: proxyCredentials.proxyIp, pki: { serverCertificate: gatewayServerCertificate.toString("pem"), serverCertificateChain: constructPemChainFromCerts([gatewayServerCaCert, rootGatewayCaCert]), diff --git a/backend/src/ee/services/proxy/proxy-service.ts b/backend/src/ee/services/proxy/proxy-service.ts index 65ec9069e..9f6c45fe4 100644 --- a/backend/src/ee/services/proxy/proxy-service.ts +++ b/backend/src/ee/services/proxy/proxy-service.ts @@ -587,7 +587,7 @@ export const proxyServiceFactory = ({ }; }; - const generateSshCredentialsForGateway = async ({ proxyName, orgId }: { proxyName: string; orgId: string }) => { + const getCredentialsForGateway = async ({ proxyName, orgId }: { proxyName: string; orgId: string }) => { let proxy: TProxies | null; if (isInstanceProxy(proxyName)) { proxy = await proxyDAL.findOne({ @@ -616,12 +616,13 @@ export const proxyServiceFactory = ({ caPrivateKey: instanceCAs.instanceProxySshServerCaPrivateKey.toString("utf8"), clientPublicKey: proxyClientSshPublicKey, keyId: `proxy-client-${proxy.id}`, - principals: [orgId], + 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") @@ -639,6 +640,7 @@ export const proxyServiceFactory = ({ }); return { + proxyIp: proxy.ip, clientSshCert: proxyClientSshCert.signedPublicKey, clientSshPrivateKey: proxyClientSshPrivateKey, serverCAPublicKey: orgCAs.proxySshServerCaPublicKey.toString("utf8") @@ -723,7 +725,7 @@ export const proxyServiceFactory = ({ caPrivateKey: proxySshServerCaPrivateKey.toString("utf8"), clientPublicKey: proxyServerSshPublicKey, keyId: "proxy-server", - principals: [ip], + principals: [`${ip}:2222`], certType: SshCertType.HOST, requestedTtl: "30d" }); @@ -873,6 +875,6 @@ export const proxyServiceFactory = ({ return { registerProxy, - generateSshCredentialsForGateway + getCredentialsForGateway }; };