mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 20:27:12 +00:00
Merge pull request #1567 from Infisical/offline-license
Add EE license support for air-gapped / offline environments
This commit is contained in:
@@ -8,6 +8,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
|
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { verifyOfflineLicense } from "@app/lib/crypto";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
@@ -26,6 +27,7 @@ import {
|
|||||||
TFeatureSet,
|
TFeatureSet,
|
||||||
TGetOrgBillInfoDTO,
|
TGetOrgBillInfoDTO,
|
||||||
TGetOrgTaxIdDTO,
|
TGetOrgTaxIdDTO,
|
||||||
|
TOfflineLicenseContents,
|
||||||
TOrgInvoiceDTO,
|
TOrgInvoiceDTO,
|
||||||
TOrgLicensesDTO,
|
TOrgLicensesDTO,
|
||||||
TOrgPlanDTO,
|
TOrgPlanDTO,
|
||||||
@@ -96,6 +98,36 @@ export const licenseServiceFactory = ({
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appCfg.LICENSE_KEY_OFFLINE) {
|
||||||
|
let isValidOfflineLicense = true;
|
||||||
|
const contents: TOfflineLicenseContents = JSON.parse(
|
||||||
|
Buffer.from(appCfg.LICENSE_KEY_OFFLINE, "base64").toString("utf8")
|
||||||
|
);
|
||||||
|
const isVerified = await verifyOfflineLicense(JSON.stringify(contents.license), contents.signature);
|
||||||
|
|
||||||
|
if (!isVerified) {
|
||||||
|
isValidOfflineLicense = false;
|
||||||
|
logger.warn(`Infisical EE offline license verification failed`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contents.license.terminatesAt) {
|
||||||
|
const terminationDate = new Date(contents.license.terminatesAt);
|
||||||
|
if (terminationDate < new Date()) {
|
||||||
|
isValidOfflineLicense = false;
|
||||||
|
logger.warn(`Infisical EE offline license has expired`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValidOfflineLicense) {
|
||||||
|
onPremFeatures = contents.license.features;
|
||||||
|
instanceType = InstanceType.EnterpriseOnPrem;
|
||||||
|
logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`);
|
||||||
|
isValidLicense = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this means this is self hosted oss version
|
// this means this is self hosted oss version
|
||||||
// else it would reach catch statement
|
// else it would reach catch statement
|
||||||
isValidLicense = true;
|
isValidLicense = true;
|
||||||
|
|||||||
@@ -6,6 +6,21 @@ export enum InstanceType {
|
|||||||
Cloud = "cloud"
|
Cloud = "cloud"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TOfflineLicenseContents = {
|
||||||
|
license: TOfflineLicense;
|
||||||
|
signature: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TOfflineLicense = {
|
||||||
|
issuedTo: string;
|
||||||
|
licenseId: string;
|
||||||
|
customerId: string | null;
|
||||||
|
issuedAt: string;
|
||||||
|
expiresAt: string | null;
|
||||||
|
terminatesAt: string | null;
|
||||||
|
features: TFeatureSet;
|
||||||
|
};
|
||||||
|
|
||||||
export type TFeatureSet = {
|
export type TFeatureSet = {
|
||||||
_id: null;
|
_id: null;
|
||||||
slug: null;
|
slug: null;
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ const envSchema = z
|
|||||||
LICENSE_SERVER_URL: zpStr(z.string().optional().default("https://portal.infisical.com")),
|
LICENSE_SERVER_URL: zpStr(z.string().optional().default("https://portal.infisical.com")),
|
||||||
LICENSE_SERVER_KEY: zpStr(z.string().optional()),
|
LICENSE_SERVER_KEY: zpStr(z.string().optional()),
|
||||||
LICENSE_KEY: zpStr(z.string().optional()),
|
LICENSE_KEY: zpStr(z.string().optional()),
|
||||||
|
LICENSE_KEY_OFFLINE: zpStr(z.string().optional()),
|
||||||
|
|
||||||
// GENERIC
|
// GENERIC
|
||||||
STANDALONE_MODE: z
|
STANDALONE_MODE: z
|
||||||
|
|||||||
@@ -17,4 +17,5 @@ export {
|
|||||||
decryptSecrets,
|
decryptSecrets,
|
||||||
decryptSecretVersions
|
decryptSecretVersions
|
||||||
} from "./secret-encryption";
|
} from "./secret-encryption";
|
||||||
|
export { verifyOfflineLicense } from "./signing";
|
||||||
export { generateSrpServerKey, srpCheckClientProof } from "./srp";
|
export { generateSrpServerKey, srpCheckClientProof } from "./srp";
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN RSA PUBLIC KEY-----
|
||||||
|
MIIBCgKCAQEApchBY3BXTu4zWGBguB7nM/pjpVLY3V7VGZOAxmR5ueQTJOwiGM13
|
||||||
|
5HN3EM9fDlQnZu9VSc0OFqRM/bUeUaI1oLPE6WzTHjdHyKjDI/S+TLx3VGEsvhM1
|
||||||
|
uukZpYX+3KX2w4wzRHBaBWyglFy0CVNth9UJhhpD+KKfv7dzcRmsbyoUWi9wGfJu
|
||||||
|
wLYCwaCwZRXIt1sLGmMncPz14vfwdnm2a5Tj1Jbt0GTyBl+1/ZqLbO6SsslLg2G+
|
||||||
|
o7FfGS9z8OUTkvDdu16qxL+p2wCEFZMnOz5BB4oakuT2gS9iOO2l5AOPcT4WzPzy
|
||||||
|
PYbX3d7cN9BkOY9I5z0cX4wzqHjQTvGNLQIDAQAB
|
||||||
|
-----END RSA PUBLIC KEY-----
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import crypto, { KeyObject } from "crypto";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
export const verifySignature = (data: string, signature: Buffer, publicKey: KeyObject) => {
|
||||||
|
const verify = crypto.createVerify("SHA256");
|
||||||
|
verify.update(data);
|
||||||
|
verify.end();
|
||||||
|
return verify.verify(publicKey, signature);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const verifyOfflineLicense = async (licenseContents: string, signature: string) => {
|
||||||
|
const publicKeyPem = await fs.readFile(path.join(__dirname, "license_public_key.pem"), "utf8");
|
||||||
|
|
||||||
|
const publicKey = crypto.createPublicKey({
|
||||||
|
key: publicKeyPem,
|
||||||
|
format: "pem",
|
||||||
|
type: "pkcs1"
|
||||||
|
});
|
||||||
|
|
||||||
|
return verifySignature(licenseContents, Buffer.from(signature, "base64"), publicKey);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user