diff --git a/backend/src/ee/services/external-kms/external-kms-service.ts b/backend/src/ee/services/external-kms/external-kms-service.ts index 506472363..bda6310a7 100644 --- a/backend/src/ee/services/external-kms/external-kms-service.ts +++ b/backend/src/ee/services/external-kms/external-kms-service.ts @@ -6,6 +6,7 @@ import { alphaNumericNanoId } from "@app/lib/nanoid"; import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; +import { TLicenseServiceFactory } from "../license/license-service"; import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission"; import { TPermissionServiceFactory } from "../permission/permission-service"; import { TExternalKmsDALFactory } from "./external-kms-dal"; @@ -28,6 +29,7 @@ type TExternalKmsServiceFactoryDep = { >; kmsDAL: Pick; permissionService: Pick; + licenseService: Pick; }; export type TExternalKmsServiceFactory = ReturnType; @@ -35,6 +37,7 @@ export type TExternalKmsServiceFactory = ReturnType { @@ -56,6 +59,13 @@ export const externalKmsServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Kms); + const plan = await licenseService.getPlan(actorOrgId); + if (!plan.externalKms) { + throw new BadRequestError({ + message: "Failed to create external KMS due to plan restriction. Upgrade to the Enterprise plan." + }); + } + const kmsSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(8).toLowerCase()); let sanitizedProviderInput = ""; @@ -127,6 +137,14 @@ export const externalKmsServiceFactory = ({ actorOrgId ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Kms); + + const plan = await licenseService.getPlan(kmsDoc.orgId); + if (!plan.externalKms) { + throw new BadRequestError({ + message: "Failed to update external KMS due to plan restriction. Upgrade to the Enterprise plan." + }); + } + const kmsSlug = slug ? slugify(slug) : undefined; const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id }); diff --git a/backend/src/ee/services/license/licence-fns.ts b/backend/src/ee/services/license/licence-fns.ts index 3e30276cb..fc0fb54a7 100644 --- a/backend/src/ee/services/license/licence-fns.ts +++ b/backend/src/ee/services/license/licence-fns.ts @@ -39,7 +39,8 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ secretApproval: false, secretRotation: true, caCrl: false, - instanceUserManagement: false + instanceUserManagement: false, + externalKms: false }); export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => { diff --git a/backend/src/ee/services/license/license-types.ts b/backend/src/ee/services/license/license-types.ts index 1cdc9fa51..df85f008f 100644 --- a/backend/src/ee/services/license/license-types.ts +++ b/backend/src/ee/services/license/license-types.ts @@ -57,6 +57,7 @@ export type TFeatureSet = { secretRotation: true; caCrl: false; instanceUserManagement: false; + externalKms: false; }; export type TOrgPlansTableDTO = { diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index c249580bd..39fdd3c25 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -316,7 +316,8 @@ export const registerRoutes = async ( kmsDAL, kmsService, permissionService, - externalKmsDAL + externalKmsDAL, + licenseService }); const trustedIpService = trustedIpServiceFactory({ diff --git a/frontend/src/hooks/api/subscriptions/types.ts b/frontend/src/hooks/api/subscriptions/types.ts index 6a8b053b4..91901c8bc 100644 --- a/frontend/src/hooks/api/subscriptions/types.ts +++ b/frontend/src/hooks/api/subscriptions/types.ts @@ -40,4 +40,5 @@ export type SubscriptionPlan = { has_used_trial: boolean; caCrl: boolean; instanceUserManagement: boolean; + externalKms: boolean; }; diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx index a41bb3ed9..b39c04391 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx @@ -22,7 +22,12 @@ import { Tr, UpgradePlanModal } from "@app/components/v2"; -import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; +import { + OrgPermissionActions, + OrgPermissionSubjects, + useOrganization, + useSubscription +} from "@app/context"; import { withPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { useGetExternalKmsList, useRemoveExternalKms } from "@app/hooks/api"; @@ -34,6 +39,7 @@ import { UpdateExternalKmsForm } from "./UpdateExternalKmsForm"; export const OrgEncryptionTab = withPermission( () => { const { currentOrg } = useOrganization(); + const { subscription } = useSubscription(); const orgId = currentOrg?.id || ""; const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([ "upgradePlan", @@ -73,12 +79,11 @@ export const OrgEncryptionTab = withPermission( {(isAllowed) => (