Skip to content

Commit 00ec4f9

Browse files
Merge pull request #4868 from Infisical/chore/unify-license-key
[ENG-4019] chore: unify license key env variables
2 parents 8eb257b + 68a5ae0 commit 00ec4f9

File tree

8 files changed

+100
-21
lines changed

8 files changed

+100
-21
lines changed

backend/src/ee/services/license/__mocks__/license-fns.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ export const getDefaultOnPremFeatures = () => {
3939
};
4040

4141
export const setupLicenseRequestWithStore = () => {};
42+
43+
export const getLicenseKeyConfig = () => {
44+
return {
45+
isValid: false
46+
};
47+
};

backend/src/ee/services/license/license-fns.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,56 @@
11
import axios, { AxiosError } from "axios";
22

33
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
4-
import { getConfig } from "@app/lib/config/env";
4+
import { getConfig, TEnvConfig } from "@app/lib/config/env";
55
import { request } from "@app/lib/config/request";
66
import { BadRequestError } from "@app/lib/errors";
77
import { logger } from "@app/lib/logger";
88
import { UserAliasType } from "@app/services/user-alias/user-alias-types";
99

10-
import { TFeatureSet } from "./license-types";
10+
import { LicenseType, TFeatureSet, TLicenseKeyConfig, TOfflineLicenseContents } from "./license-types";
11+
12+
export const isOfflineLicenseKey = (licenseKey: string): boolean => {
13+
try {
14+
const contents = JSON.parse(Buffer.from(licenseKey, "base64").toString("utf8")) as TOfflineLicenseContents;
15+
16+
return "signature" in contents && "license" in contents;
17+
} catch (error) {
18+
return false;
19+
}
20+
};
21+
22+
export const getLicenseKeyConfig = (
23+
config?: Pick<TEnvConfig, "LICENSE_KEY" | "LICENSE_KEY_OFFLINE">
24+
): TLicenseKeyConfig => {
25+
const cfg = config || getConfig();
26+
27+
if (!cfg) {
28+
return { isValid: false };
29+
}
30+
31+
const licenseKey = cfg.LICENSE_KEY;
32+
33+
if (licenseKey) {
34+
if (isOfflineLicenseKey(licenseKey)) {
35+
return { isValid: true, licenseKey, type: LicenseType.Offline };
36+
}
37+
38+
return { isValid: true, licenseKey, type: LicenseType.Online };
39+
}
40+
41+
const offlineLicenseKey = cfg.LICENSE_KEY_OFFLINE;
42+
43+
// backwards compatibility
44+
if (offlineLicenseKey) {
45+
if (isOfflineLicenseKey(offlineLicenseKey)) {
46+
return { isValid: true, licenseKey: offlineLicenseKey, type: LicenseType.Offline };
47+
}
48+
49+
return { isValid: false };
50+
}
51+
52+
return { isValid: false };
53+
};
1154

1255
export const getDefaultOnPremFeatures = (): TFeatureSet => ({
1356
_id: null,

backend/src/ee/services/license/license-service.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ import { OrgPermissionBillingActions, OrgPermissionSubjects } from "../permissio
2222
import { TPermissionServiceFactory } from "../permission/permission-service-types";
2323
import { BillingPlanRows, BillingPlanTableHead } from "./licence-enums";
2424
import { TLicenseDALFactory } from "./license-dal";
25-
import { getDefaultOnPremFeatures, setupLicenseRequestWithStore } from "./license-fns";
25+
import { getDefaultOnPremFeatures, getLicenseKeyConfig, setupLicenseRequestWithStore } from "./license-fns";
2626
import {
2727
InstanceType,
28+
LicenseType,
2829
TAddOrgPmtMethodDTO,
2930
TAddOrgTaxIdDTO,
3031
TCreateOrgPortalSession,
@@ -77,6 +78,7 @@ export const licenseServiceFactory = ({
7778
let instanceType = InstanceType.OnPrem;
7879
let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures();
7980
let selfHostedLicense: TOfflineLicense | null = null;
81+
const licenseKeyConfig = getLicenseKeyConfig(envConfig);
8082

8183
const licenseServerCloudApi = setupLicenseRequestWithStore(
8284
envConfig.LICENSE_SERVER_URL || "",
@@ -85,10 +87,13 @@ export const licenseServiceFactory = ({
8587
envConfig.INTERNAL_REGION
8688
);
8789

90+
const onlineLicenseKey =
91+
licenseKeyConfig.isValid && licenseKeyConfig.type === LicenseType.Online ? licenseKeyConfig.licenseKey : "";
92+
8893
const licenseServerOnPremApi = setupLicenseRequestWithStore(
8994
envConfig.LICENSE_SERVER_URL || "",
9095
LICENSE_SERVER_ON_PREM_LOGIN,
91-
envConfig.LICENSE_KEY || "",
96+
onlineLicenseKey,
9297
envConfig.INTERNAL_REGION
9398
);
9499

@@ -131,7 +136,7 @@ export const licenseServiceFactory = ({
131136
return;
132137
}
133138

134-
if (envConfig.LICENSE_KEY) {
139+
if (licenseKeyConfig.isValid && licenseKeyConfig.type === LicenseType.Online) {
135140
const token = await licenseServerOnPremApi.refreshLicense();
136141
if (token) {
137142
await syncLicenseKeyOnPremFeatures(true);
@@ -142,10 +147,10 @@ export const licenseServiceFactory = ({
142147
return;
143148
}
144149

145-
if (envConfig.LICENSE_KEY_OFFLINE) {
150+
if (licenseKeyConfig.isValid && licenseKeyConfig.type === LicenseType.Offline) {
146151
let isValidOfflineLicense = true;
147152
const contents: TOfflineLicenseContents = JSON.parse(
148-
Buffer.from(envConfig.LICENSE_KEY_OFFLINE, "base64").toString("utf8")
153+
Buffer.from(licenseKeyConfig.licenseKey, "base64").toString("utf8")
149154
);
150155
const isVerified = await verifyOfflineLicense(JSON.stringify(contents.license), contents.signature);
151156

@@ -184,7 +189,7 @@ export const licenseServiceFactory = ({
184189
};
185190

186191
const initializeBackgroundSync = async () => {
187-
if (envConfig.LICENSE_KEY) {
192+
if (licenseKeyConfig?.isValid && licenseKeyConfig?.type === LicenseType.Online) {
188193
logger.info("Setting up background sync process for refresh onPremFeatures");
189194
const job = new CronJob("*/10 * * * *", syncLicenseKeyOnPremFeatures);
190195
job.start();

backend/src/ee/services/license/license-types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,18 @@ export type TDelOrgTaxIdDTO = TOrgPermission & { taxId: string };
136136
export type TOrgInvoiceDTO = TOrgPermission;
137137

138138
export type TOrgLicensesDTO = TOrgPermission;
139+
140+
export enum LicenseType {
141+
Offline = "offline",
142+
Online = "online"
143+
}
144+
145+
export type TLicenseKeyConfig =
146+
| {
147+
isValid: false;
148+
}
149+
| {
150+
isValid: true;
151+
licenseKey: string;
152+
type: LicenseType;
153+
};

backend/src/server/routes/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2431,6 +2431,7 @@ export const registerRoutes = async (
24312431
}
24322432
}
24332433

2434+
await kmsService.startService(hsmStatus);
24342435
await telemetryQueue.startTelemetryCheck();
24352436
await telemetryQueue.startAggregatedEventsJob();
24362437
await dailyResourceCleanUp.init();
@@ -2443,7 +2444,6 @@ export const registerRoutes = async (
24432444
await pkiSubscriberQueue.startDailyAutoRenewalJob();
24442445
await pkiAlertV2Queue.init();
24452446
await certificateV3Queue.init();
2446-
await kmsService.startService(hsmStatus);
24472447
await microsoftTeamsService.start();
24482448
await dynamicSecretQueueService.init();
24492449
await eventBusService.init();

backend/src/server/routes/v1/admin-router.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
SuperAdminSchema,
1010
UsersSchema
1111
} from "@app/db/schemas";
12+
import { getLicenseKeyConfig } from "@app/ee/services/license/license-fns";
13+
import { LicenseType } from "@app/ee/services/license/license-types";
1214
import { getConfig, overridableKeys } from "@app/lib/config/env";
1315
import { crypto } from "@app/lib/crypto/cryptography";
1416
import { BadRequestError } from "@app/lib/errors";
@@ -65,6 +67,9 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
6567
const config = await getServerCfg();
6668
const serverEnvs = getConfig();
6769

70+
const licenseKeyConfig = getLicenseKeyConfig();
71+
const hasOfflineLicense = licenseKeyConfig.isValid && licenseKeyConfig.type === LicenseType.Offline;
72+
6873
return {
6974
config: {
7075
...config,
@@ -73,7 +78,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
7378
isSecretScanningDisabled: serverEnvs.DISABLE_SECRET_SCANNING,
7479
kubernetesAutoFetchServiceAccountToken: serverEnvs.KUBERNETES_AUTO_FETCH_SERVICE_ACCOUNT_TOKEN,
7580
paramsFolderSecretDetectionEnabled: serverEnvs.PARAMS_FOLDER_SECRET_DETECTION_ENABLED,
76-
isOfflineUsageReportsEnabled: !!serverEnvs.LICENSE_KEY_OFFLINE
81+
isOfflineUsageReportsEnabled: hasOfflineLicense
7782
}
7883
};
7984
}

backend/src/services/offline-usage-report/offline-usage-report-service.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import crypto from "crypto";
22

3+
import { getLicenseKeyConfig } from "@app/ee/services/license/license-fns";
34
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
4-
import { getConfig } from "@app/lib/config/env";
5+
import { LicenseType } from "@app/ee/services/license/license-types";
56
import { BadRequestError } from "@app/lib/errors";
67

78
import { TOfflineUsageReportDALFactory } from "./offline-usage-report-dal";
@@ -30,10 +31,13 @@ export const offlineUsageReportServiceFactory = ({
3031
};
3132

3233
const generateUsageReportCSV = async () => {
33-
const cfg = getConfig();
34-
if (!cfg.LICENSE_KEY_OFFLINE) {
34+
const licenseKeyConfig = getLicenseKeyConfig();
35+
const hasOfflineLicense = licenseKeyConfig.isValid && licenseKeyConfig.type === LicenseType.Offline;
36+
37+
if (!hasOfflineLicense) {
3538
throw new BadRequestError({
36-
message: "Offline usage reports are not enabled. LICENSE_KEY_OFFLINE must be configured."
39+
message:
40+
"Offline usage reports are not enabled. Usage reports are only available for self-hosted offline instances"
3741
});
3842
}
3943

docs/self-hosting/ee.mdx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,32 @@ This guide walks through how you can use these paid features on a self-hosted in
1414
Once purchased, you will be issued a license key.
1515
</Step>
1616
<Step title="Activate the license">
17-
Depending on whether or not the environment where Infisical is deployed has internet access, you may be issued a regular license or an offline license.
17+
Set your license key as the value of the **LICENSE_KEY** environment variable within your Infisical instance.
1818

19-
2019
<Tabs>
2120
<Tab title="Regular License">
2221
- Assign the issued license key to the `LICENSE_KEY` environment variable in your Infisical instance.
2322

24-
- Your Infisical instance will need to communicate with the Infisical license server to validate the license key.
23+
- Your Infisical instance will need to communicate with the Infisical license server to validate the license key.
2524
If you want to limit outgoing connections only to the Infisical license server, you can use the following IP addresses: `13.248.249.247` and `35.71.190.59`
2625

2726
<Note>
2827
Ensure that your firewall or network settings allow outbound connections to these IP addresses to avoid any issues with license validation.
2928
</Note>
3029
</Tab>
3130
<Tab title="Offline License">
32-
- Assign the issued license key to the `LICENSE_KEY_OFFLINE` environment variable in your Infisical instance.
31+
- Assign the issued offline license key to the `LICENSE_KEY` environment variable in your Infisical instance.
32+
33+
- The system will automatically detect that it's an offline license based on the key format.
3334

3435
<Note>
35-
How you set the environment variable will depend on the deployment method you used. Please refer to the documentation of your deployment method for specific instructions.
36+
While the LICENSE_KEY_OFFLINE environment variable continues to be supported for compatibility with existing configurations, we recommend transitioning to LICENSE_KEY for all license types going forward.
3637
</Note>
3738
</Tab>
3839
</Tabs>
3940

40-
Once your instance starts up, the license key will be validated and youll be able to use the paid features.
41+
Once your instance starts up, the license key will be validated and you'll be able to use the paid features.
4142
However, when the license expires, Infisical will continue to run, but EE features will be disabled until the license is renewed or a new one is purchased.
4243
</Step>
43-
</Steps>
4444

45+
</Steps>

0 commit comments

Comments
 (0)