mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 12:27:28 +00:00
misc: initial integration with local and pam proxy
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.GatewayV2, "encryptedPamSessionKey"))) {
|
||||||
|
await knex.schema.alterTable(TableName.GatewayV2, (t) => {
|
||||||
|
t.binary("encryptedPamSessionKey");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.GatewayV2, "encryptedPamSessionKey")) {
|
||||||
|
await knex.schema.alterTable(TableName.GatewayV2, (t) => {
|
||||||
|
t.dropColumn("encryptedPamSessionKey");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const GatewaysV2Schema = z.object({
|
export const GatewaysV2Schema = z.object({
|
||||||
@@ -15,7 +17,8 @@ export const GatewaysV2Schema = z.object({
|
|||||||
identityId: z.string().uuid(),
|
identityId: z.string().uuid(),
|
||||||
relayId: z.string().uuid().nullable().optional(),
|
relayId: z.string().uuid().nullable().optional(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
heartbeat: z.date().nullable().optional()
|
heartbeat: z.date().nullable().optional(),
|
||||||
|
encryptedPamSessionKey: zodBuffer.nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TGatewaysV2 = z.infer<typeof GatewaysV2Schema>;
|
export type TGatewaysV2 = z.infer<typeof GatewaysV2Schema>;
|
||||||
|
|||||||
@@ -67,11 +67,9 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
duration: z
|
duration: z
|
||||||
.string()
|
.string()
|
||||||
.nullable()
|
|
||||||
.optional()
|
.optional()
|
||||||
.transform((val, ctx) => {
|
.transform((val, ctx) => {
|
||||||
if (val === undefined) return undefined;
|
if (val === undefined) return undefined;
|
||||||
if (!val || val === "permanent") return null;
|
|
||||||
const parsedMs = ms(val);
|
const parsedMs = ms(val);
|
||||||
|
|
||||||
if (typeof parsedMs !== "number" || parsedMs <= 0) {
|
if (typeof parsedMs !== "number" || parsedMs <= 0) {
|
||||||
@@ -88,8 +86,12 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
|
|||||||
200: z.object({
|
200: z.object({
|
||||||
sessionId: z.string(),
|
sessionId: z.string(),
|
||||||
resourceType: z.nativeEnum(PamResource),
|
resourceType: z.nativeEnum(PamResource),
|
||||||
relayCertificate: z.string(),
|
relayClientCertificate: z.string(),
|
||||||
gatewayCertificate: z.string(),
|
relayClientPrivateKey: z.string(),
|
||||||
|
relayServerCertificateChain: z.string(),
|
||||||
|
gatewayClientCertificate: z.string(),
|
||||||
|
gatewayClientPrivateKey: z.string(),
|
||||||
|
gatewayServerCertificateChain: z.string(),
|
||||||
relayHost: z.string()
|
relayHost: z.string()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import z from "zod";
|
import z from "zod";
|
||||||
|
|
||||||
import { GatewaysV2Schema } from "@app/db/schemas";
|
import { GatewaysV2Schema } from "@app/db/schemas";
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -130,4 +131,25 @@ export const registerGatewayV2Router = async (server: FastifyZodProvider) => {
|
|||||||
return gateway;
|
return gateway;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/pam-session-key",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: zodBuffer
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const pamSessionKey = await server.services.gatewayV2.getPamSessionKey({
|
||||||
|
orgPermission: req.permission
|
||||||
|
});
|
||||||
|
|
||||||
|
return pamSessionKey;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export const GATEWAY_ROUTING_INFO_OID = "1.3.6.1.4.1.12345.100.1";
|
export const GATEWAY_ROUTING_INFO_OID = "1.3.6.1.4.1.12345.100.1";
|
||||||
export const GATEWAY_ACTOR_OID = "1.3.6.1.4.1.12345.100.2";
|
export const GATEWAY_ACTOR_OID = "1.3.6.1.4.1.12345.100.2";
|
||||||
|
export const PAM_INFO_OID = "1.3.6.1.4.1.12345.100.3";
|
||||||
|
|||||||
@@ -22,11 +22,12 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
|||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
|
import { PamResource } from "../pam-resource/pam-resource-enums";
|
||||||
import { OrgPermissionGatewayActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionGatewayActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TRelayDALFactory } from "../relay/relay-dal";
|
import { TRelayDALFactory } from "../relay/relay-dal";
|
||||||
import { TRelayServiceFactory } from "../relay/relay-service";
|
import { TRelayServiceFactory } from "../relay/relay-service";
|
||||||
import { GATEWAY_ACTOR_OID, GATEWAY_ROUTING_INFO_OID } from "./gateway-v2-constants";
|
import { GATEWAY_ACTOR_OID, GATEWAY_ROUTING_INFO_OID, PAM_INFO_OID } from "./gateway-v2-constants";
|
||||||
import { TGatewayV2DALFactory } from "./gateway-v2-dal";
|
import { TGatewayV2DALFactory } from "./gateway-v2-dal";
|
||||||
import { TOrgGatewayConfigV2DALFactory } from "./org-gateway-config-v2-dal";
|
import { TOrgGatewayConfigV2DALFactory } from "./org-gateway-config-v2-dal";
|
||||||
|
|
||||||
@@ -268,8 +269,7 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
const getPlatformConnectionDetailsByGatewayId = async ({
|
const getPlatformConnectionDetailsByGatewayId = async ({
|
||||||
gatewayId,
|
gatewayId,
|
||||||
targetHost,
|
targetHost,
|
||||||
targetPort,
|
targetPort
|
||||||
actorMetadata
|
|
||||||
}: {
|
}: {
|
||||||
gatewayId: string;
|
gatewayId: string;
|
||||||
targetHost: string;
|
targetHost: string;
|
||||||
@@ -361,9 +361,7 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
const actorExtension = new x509.Extension(
|
const actorExtension = new x509.Extension(
|
||||||
GATEWAY_ACTOR_OID,
|
GATEWAY_ACTOR_OID,
|
||||||
false,
|
false,
|
||||||
Buffer.from(
|
Buffer.from(JSON.stringify({ type: ActorType.PLATFORM }))
|
||||||
JSON.stringify(actorMetadata ? { type: ActorType.PLATFORM, ...actorMetadata } : { type: ActorType.PLATFORM })
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const clientCert = await x509.X509CertificateGenerator.create({
|
const clientCert = await x509.X509CertificateGenerator.create({
|
||||||
@@ -418,6 +416,176 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPAMConnectionDetails = async ({
|
||||||
|
gatewayId,
|
||||||
|
sessionId,
|
||||||
|
duration,
|
||||||
|
resourceType,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
actorMetadata
|
||||||
|
}: {
|
||||||
|
gatewayId: string;
|
||||||
|
sessionId: string;
|
||||||
|
resourceType: PamResource;
|
||||||
|
duration?: number;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
actorMetadata: { id: string; type: ActorType; name: string };
|
||||||
|
}) => {
|
||||||
|
const gateway = await gatewayV2DAL.findById(gatewayId);
|
||||||
|
if (!gateway) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const orgGatewayConfig = await orgGatewayConfigV2DAL.findOne({ orgId: gateway.orgId });
|
||||||
|
if (!orgGatewayConfig) {
|
||||||
|
throw new NotFoundError({ message: `Gateway Config for org ${gateway.orgId} not found.` });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gateway.relayId) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Gateway is not associated with a relay"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const orgLicensePlan = await licenseService.getPlan(orgGatewayConfig.orgId);
|
||||||
|
if (!orgLicensePlan.gateway) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Please upgrade your instance to Infisical's Enterprise plan to use gateways."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { decryptor: orgKmsDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId: orgGatewayConfig.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
|
|
||||||
|
const rootGatewayCaCert = new x509.X509Certificate(
|
||||||
|
orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgGatewayConfig.encryptedRootGatewayCaCertificate
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const gatewayClientCaCert = new x509.X509Certificate(
|
||||||
|
orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgGatewayConfig.encryptedGatewayClientCaCertificate
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const gatewayServerCaCert = new x509.X509Certificate(
|
||||||
|
orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgGatewayConfig.encryptedGatewayServerCaCertificate
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const gatewayClientCaPrivateKey = orgKmsDecryptor({
|
||||||
|
cipherTextBlob: orgGatewayConfig.encryptedGatewayClientCaPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const gatewayClientCaSkObj = crypto.nativeCrypto.createPrivateKey({
|
||||||
|
key: gatewayClientCaPrivateKey,
|
||||||
|
format: "der",
|
||||||
|
type: "pkcs8"
|
||||||
|
});
|
||||||
|
|
||||||
|
const importedGatewayClientCaPrivateKey = await crypto.nativeCrypto.subtle.importKey(
|
||||||
|
"pkcs8",
|
||||||
|
gatewayClientCaSkObj.export({ format: "der", type: "pkcs8" }),
|
||||||
|
alg,
|
||||||
|
true,
|
||||||
|
["sign"]
|
||||||
|
);
|
||||||
|
|
||||||
|
const clientCertIssuedAt = new Date();
|
||||||
|
const clientCertExpiration = new Date(new Date().getTime() + (duration ?? 5 * 60 * 1000));
|
||||||
|
const clientKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
const clientCertSerialNumber = createSerialNumber();
|
||||||
|
|
||||||
|
const routingInfo = {
|
||||||
|
targetHost: host,
|
||||||
|
targetPort: port
|
||||||
|
};
|
||||||
|
|
||||||
|
const routingExtension = new x509.Extension(
|
||||||
|
GATEWAY_ROUTING_INFO_OID,
|
||||||
|
false,
|
||||||
|
Buffer.from(JSON.stringify(routingInfo))
|
||||||
|
);
|
||||||
|
|
||||||
|
const pamInfoExtension = new x509.Extension(
|
||||||
|
PAM_INFO_OID,
|
||||||
|
false,
|
||||||
|
Buffer.from(
|
||||||
|
JSON.stringify({
|
||||||
|
sessionId,
|
||||||
|
resourceType
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const actorExtension = new x509.Extension(
|
||||||
|
GATEWAY_ACTOR_OID,
|
||||||
|
false,
|
||||||
|
Buffer.from(JSON.stringify({ type: actorMetadata.type, id: actorMetadata.id, name: actorMetadata.name }))
|
||||||
|
);
|
||||||
|
|
||||||
|
const clientCert = await x509.X509CertificateGenerator.create({
|
||||||
|
serialNumber: clientCertSerialNumber,
|
||||||
|
subject: `O=${orgGatewayConfig.orgId},OU=gateway-client,CN=${actorMetadata.type}:${gatewayId}`,
|
||||||
|
issuer: gatewayClientCaCert.subject,
|
||||||
|
notAfter: clientCertExpiration,
|
||||||
|
notBefore: clientCertIssuedAt,
|
||||||
|
signingKey: importedGatewayClientCaPrivateKey,
|
||||||
|
publicKey: clientKeys.publicKey,
|
||||||
|
signingAlgorithm: alg,
|
||||||
|
extensions: [
|
||||||
|
new x509.BasicConstraintsExtension(false),
|
||||||
|
await x509.AuthorityKeyIdentifierExtension.create(gatewayClientCaCert, 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),
|
||||||
|
routingExtension,
|
||||||
|
actorExtension,
|
||||||
|
pamInfoExtension
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const gatewayClientCertPrivateKey = crypto.nativeCrypto.KeyObject.from(clientKeys.privateKey);
|
||||||
|
|
||||||
|
const relayCredentials = await relayService.getCredentialsForClient({
|
||||||
|
relayId: gateway.relayId,
|
||||||
|
orgId: gateway.orgId,
|
||||||
|
orgName: gateway.orgName,
|
||||||
|
gatewayId,
|
||||||
|
gatewayName: gateway.name,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
relayHost: relayCredentials.relayHost,
|
||||||
|
gateway: {
|
||||||
|
clientCertificate: clientCert.toString("pem"),
|
||||||
|
clientPrivateKey: gatewayClientCertPrivateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
||||||
|
serverCertificateChain: constructPemChainFromCerts([gatewayServerCaCert, rootGatewayCaCert])
|
||||||
|
},
|
||||||
|
relay: {
|
||||||
|
clientCertificate: relayCredentials.clientCertificate,
|
||||||
|
clientPrivateKey: relayCredentials.clientPrivateKey,
|
||||||
|
serverCertificateChain: relayCredentials.serverCertificateChain
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const registerGateway = async ({
|
const registerGateway = async ({
|
||||||
orgId,
|
orgId,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -652,11 +820,59 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
return gatewayV2DAL.deleteById(gateway.id);
|
return gatewayV2DAL.deleteById(gateway.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPamSessionKey = async ({ orgPermission }: { orgPermission: OrgServiceActor }) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
orgPermission.type,
|
||||||
|
orgPermission.id,
|
||||||
|
orgPermission.orgId,
|
||||||
|
orgPermission.authMethod,
|
||||||
|
orgPermission.orgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionGatewayActions.CreateGateways,
|
||||||
|
OrgPermissionSubjects.Gateway
|
||||||
|
);
|
||||||
|
|
||||||
|
return gatewayV2DAL.transaction(async (tx) => {
|
||||||
|
const gateway = await gatewayV2DAL.findOne(
|
||||||
|
{
|
||||||
|
identityId: orgPermission.id
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!gateway) {
|
||||||
|
throw new NotFoundError({ message: "Gateway not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { encryptor, decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId: orgPermission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (gateway.encryptedPamSessionKey) {
|
||||||
|
return decryptor({ cipherTextBlob: gateway.encryptedPamSessionKey });
|
||||||
|
}
|
||||||
|
|
||||||
|
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.GatewayPamSessionKey(gateway.id)]);
|
||||||
|
|
||||||
|
const newPamSessionKey = crypto.randomBytes(32);
|
||||||
|
const { cipherTextBlob: encryptedPamSessionKey } = encryptor({ plainText: newPamSessionKey });
|
||||||
|
|
||||||
|
await gatewayV2DAL.updateById(gateway.id, { encryptedPamSessionKey }, tx);
|
||||||
|
|
||||||
|
return newPamSessionKey;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
listGateways,
|
listGateways,
|
||||||
registerGateway,
|
registerGateway,
|
||||||
getPlatformConnectionDetailsByGatewayId,
|
getPlatformConnectionDetailsByGatewayId,
|
||||||
|
getPAMConnectionDetails,
|
||||||
deleteGatewayById,
|
deleteGatewayById,
|
||||||
heartbeat
|
heartbeat,
|
||||||
|
getPamSessionKey
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { OrgServiceActor } from "@app/lib/types";
|
|||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service";
|
import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service";
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
@@ -51,7 +52,11 @@ type TPamResourceServiceFactoryDep = {
|
|||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
gatewayV2Service: Pick<TGatewayV2ServiceFactory, "getPlatformConnectionDetailsByGatewayId">;
|
gatewayV2Service: Pick<
|
||||||
|
TGatewayV2ServiceFactory,
|
||||||
|
"getPAMConnectionDetails" | "getPlatformConnectionDetailsByGatewayId"
|
||||||
|
>;
|
||||||
|
userDAL: TUserDALFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TPamResourceServiceFactory = ReturnType<typeof pamResourceServiceFactory>;
|
export type TPamResourceServiceFactory = ReturnType<typeof pamResourceServiceFactory>;
|
||||||
@@ -62,6 +67,7 @@ export const pamResourceServiceFactory = ({
|
|||||||
pamAccountDAL,
|
pamAccountDAL,
|
||||||
pamFolderDAL,
|
pamFolderDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
userDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
licenseService,
|
licenseService,
|
||||||
kmsService,
|
kmsService,
|
||||||
@@ -561,13 +567,19 @@ export const pamResourceServiceFactory = ({
|
|||||||
|
|
||||||
const { connectionDetails, gatewayId, resourceType } = await decryptResource(resource, actor.orgId, kmsService);
|
const { connectionDetails, gatewayId, resourceType } = await decryptResource(resource, actor.orgId, kmsService);
|
||||||
|
|
||||||
const gatewayConnectionDetails = await gatewayV2Service.getPlatformConnectionDetailsByGatewayId({
|
const user = await userDAL.findById(actor.id);
|
||||||
|
|
||||||
|
const gatewayConnectionDetails = await gatewayV2Service.getPAMConnectionDetails({
|
||||||
gatewayId,
|
gatewayId,
|
||||||
targetHost: connectionDetails.host,
|
duration,
|
||||||
targetPort: connectionDetails.port,
|
sessionId: session.id,
|
||||||
|
resourceType: resource.resourceType as PamResource,
|
||||||
|
host: connectionDetails.host,
|
||||||
|
port: connectionDetails.port,
|
||||||
actorMetadata: {
|
actorMetadata: {
|
||||||
sessionId: session.id,
|
id: actor.id,
|
||||||
resourceType: resource.resourceType
|
type: actor.type,
|
||||||
|
name: user.email ?? ""
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -578,8 +590,12 @@ export const pamResourceServiceFactory = ({
|
|||||||
return {
|
return {
|
||||||
sessionId: session.id,
|
sessionId: session.id,
|
||||||
resourceType,
|
resourceType,
|
||||||
relayCertificate: gatewayConnectionDetails.relay.clientCertificate,
|
relayClientCertificate: gatewayConnectionDetails.relay.clientCertificate,
|
||||||
gatewayCertificate: gatewayConnectionDetails.gateway.clientCertificate,
|
relayClientPrivateKey: gatewayConnectionDetails.relay.clientPrivateKey,
|
||||||
|
relayServerCertificateChain: gatewayConnectionDetails.relay.serverCertificateChain,
|
||||||
|
gatewayClientCertificate: gatewayConnectionDetails.gateway.clientCertificate,
|
||||||
|
gatewayClientPrivateKey: gatewayConnectionDetails.gateway.clientPrivateKey,
|
||||||
|
gatewayServerCertificateChain: gatewayConnectionDetails.gateway.serverCertificateChain,
|
||||||
relayHost: gatewayConnectionDetails.relayHost,
|
relayHost: gatewayConnectionDetails.relayHost,
|
||||||
projectId: account.projectId
|
projectId: account.projectId
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export type TAccessAccountDTO = {
|
|||||||
actorIp: string;
|
actorIp: string;
|
||||||
actorName: string;
|
actorName: string;
|
||||||
actorUserAgent: string;
|
actorUserAgent: string;
|
||||||
duration?: number | null;
|
duration?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resource factory
|
// Resource factory
|
||||||
|
|||||||
@@ -708,7 +708,8 @@ export const relayServiceFactory = ({
|
|||||||
relayPkiClientCaCertificate,
|
relayPkiClientCaCertificate,
|
||||||
relayPkiClientCaPrivateKey,
|
relayPkiClientCaPrivateKey,
|
||||||
relayPkiServerCaCertificate,
|
relayPkiServerCaCertificate,
|
||||||
relayPkiServerCaCertificateChain
|
relayPkiServerCaCertificateChain,
|
||||||
|
duration
|
||||||
}: {
|
}: {
|
||||||
gatewayId: string;
|
gatewayId: string;
|
||||||
gatewayName: string;
|
gatewayName: string;
|
||||||
@@ -718,6 +719,7 @@ export const relayServiceFactory = ({
|
|||||||
relayPkiClientCaPrivateKey: Buffer;
|
relayPkiClientCaPrivateKey: Buffer;
|
||||||
relayPkiServerCaCertificate: Buffer;
|
relayPkiServerCaCertificate: Buffer;
|
||||||
relayPkiServerCaCertificateChain: Buffer;
|
relayPkiServerCaCertificateChain: Buffer;
|
||||||
|
duration?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
const alg = keyAlgorithmToAlgCfg(CertKeyAlgorithm.RSA_2048);
|
||||||
const relayClientCaCert = new x509.X509Certificate(relayPkiClientCaCertificate);
|
const relayClientCaCert = new x509.X509Certificate(relayPkiClientCaCertificate);
|
||||||
@@ -737,7 +739,7 @@ export const relayServiceFactory = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const clientCertIssuedAt = new Date();
|
const clientCertIssuedAt = new Date();
|
||||||
const clientCertExpiration = new Date(new Date().getTime() + 5 * 60 * 1000);
|
const clientCertExpiration = new Date(new Date().getTime() + (duration ?? 5 * 60 * 1000));
|
||||||
const clientKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
const clientKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
const clientCertPrivateKey = crypto.nativeCrypto.KeyObject.from(clientKeys.privateKey);
|
const clientCertPrivateKey = crypto.nativeCrypto.KeyObject.from(clientKeys.privateKey);
|
||||||
const clientCertSerialNumber = createSerialNumber();
|
const clientCertSerialNumber = createSerialNumber();
|
||||||
@@ -866,13 +868,15 @@ export const relayServiceFactory = ({
|
|||||||
orgId,
|
orgId,
|
||||||
orgName,
|
orgName,
|
||||||
gatewayId,
|
gatewayId,
|
||||||
gatewayName
|
gatewayName,
|
||||||
|
duration
|
||||||
}: {
|
}: {
|
||||||
relayId: string;
|
relayId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
orgName: string;
|
orgName: string;
|
||||||
gatewayId: string;
|
gatewayId: string;
|
||||||
gatewayName: string;
|
gatewayName: string;
|
||||||
|
duration?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const relay = await relayDAL.findOne({
|
const relay = await relayDAL.findOne({
|
||||||
id: relayId
|
id: relayId
|
||||||
@@ -896,7 +900,8 @@ export const relayServiceFactory = ({
|
|||||||
relayPkiClientCaCertificate: instanceCAs.instanceRelayPkiClientCaCertificate,
|
relayPkiClientCaCertificate: instanceCAs.instanceRelayPkiClientCaCertificate,
|
||||||
relayPkiClientCaPrivateKey: instanceCAs.instanceRelayPkiClientCaPrivateKey,
|
relayPkiClientCaPrivateKey: instanceCAs.instanceRelayPkiClientCaPrivateKey,
|
||||||
relayPkiServerCaCertificate: instanceCAs.instanceRelayPkiServerCaCertificate,
|
relayPkiServerCaCertificate: instanceCAs.instanceRelayPkiServerCaCertificate,
|
||||||
relayPkiServerCaCertificateChain: instanceCAs.instanceRelayPkiServerCaCertificateChain
|
relayPkiServerCaCertificateChain: instanceCAs.instanceRelayPkiServerCaCertificateChain,
|
||||||
|
duration
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -914,7 +919,8 @@ export const relayServiceFactory = ({
|
|||||||
relayPkiClientCaCertificate: orgCAs.relayPkiClientCaCertificate,
|
relayPkiClientCaCertificate: orgCAs.relayPkiClientCaCertificate,
|
||||||
relayPkiClientCaPrivateKey: orgCAs.relayPkiClientCaPrivateKey,
|
relayPkiClientCaPrivateKey: orgCAs.relayPkiClientCaPrivateKey,
|
||||||
relayPkiServerCaCertificate: orgCAs.relayPkiServerCaCertificate,
|
relayPkiServerCaCertificate: orgCAs.relayPkiServerCaCertificate,
|
||||||
relayPkiServerCaCertificateChain: orgCAs.relayPkiServerCaCertificateChain
|
relayPkiServerCaCertificateChain: orgCAs.relayPkiServerCaCertificateChain,
|
||||||
|
duration
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export const PgSqlLock = {
|
|||||||
InstanceRelayConfigInit: () => pgAdvisoryLockHashText("instance-relay-config-init"),
|
InstanceRelayConfigInit: () => pgAdvisoryLockHashText("instance-relay-config-init"),
|
||||||
OrgGatewayV2Init: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-v2-init:${orgId}`),
|
OrgGatewayV2Init: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-v2-init:${orgId}`),
|
||||||
OrgRelayConfigInit: (orgId: string) => pgAdvisoryLockHashText(`org-relay-config-init:${orgId}`),
|
OrgRelayConfigInit: (orgId: string) => pgAdvisoryLockHashText(`org-relay-config-init:${orgId}`),
|
||||||
|
GatewayPamSessionKey: (gatewayId: string) => pgAdvisoryLockHashText(`gateway-pam-session-key:${gatewayId}`),
|
||||||
IdentityLogin: (identityId: string, nonce: string) => pgAdvisoryLockHashText(`identity-login:${identityId}:${nonce}`)
|
IdentityLogin: (identityId: string, nonce: string) => pgAdvisoryLockHashText(`identity-login:${identityId}:${nonce}`)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2130,7 +2130,8 @@ export const registerRoutes = async (
|
|||||||
permissionService,
|
permissionService,
|
||||||
licenseService,
|
licenseService,
|
||||||
kmsService,
|
kmsService,
|
||||||
gatewayV2Service
|
gatewayV2Service,
|
||||||
|
userDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
const pamSessionService = pamSessionServiceFactory({
|
const pamSessionService = pamSessionServiceFactory({
|
||||||
|
|||||||
Reference in New Issue
Block a user