mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 07:30:20 +00:00
Revert "feat(super-admin): Environment Overrides"
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const hasColumn = await knex.schema.hasColumn(TableName.SuperAdmin, "encryptedEnvOverrides");
|
||||
if (!hasColumn) {
|
||||
await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
|
||||
t.binary("encryptedEnvOverrides").nullable();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
const hasColumn = await knex.schema.hasColumn(TableName.SuperAdmin, "encryptedEnvOverrides");
|
||||
if (hasColumn) {
|
||||
await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
|
||||
t.dropColumn("encryptedEnvOverrides");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -34,8 +34,7 @@ export const SuperAdminSchema = z.object({
|
||||
encryptedGitHubAppConnectionClientSecret: zodBuffer.nullable().optional(),
|
||||
encryptedGitHubAppConnectionSlug: zodBuffer.nullable().optional(),
|
||||
encryptedGitHubAppConnectionId: zodBuffer.nullable().optional(),
|
||||
encryptedGitHubAppConnectionPrivateKey: zodBuffer.nullable().optional(),
|
||||
encryptedEnvOverrides: zodBuffer.nullable().optional()
|
||||
encryptedGitHubAppConnectionPrivateKey: zodBuffer.nullable().optional()
|
||||
});
|
||||
|
||||
export type TSuperAdmin = z.infer<typeof SuperAdminSchema>;
|
||||
|
||||
@@ -2,7 +2,6 @@ import { z } from "zod";
|
||||
|
||||
import { QueueWorkerProfile } from "@app/lib/types";
|
||||
|
||||
import { BadRequestError } from "../errors";
|
||||
import { removeTrailingSlash } from "../fn";
|
||||
import { CustomLogger } from "../logger/logger";
|
||||
import { zpStr } from "../zod";
|
||||
@@ -342,11 +341,8 @@ const envSchema = z
|
||||
|
||||
export type TEnvConfig = Readonly<z.infer<typeof envSchema>>;
|
||||
let envCfg: TEnvConfig;
|
||||
let originalEnvConfig: TEnvConfig;
|
||||
|
||||
export const getConfig = () => envCfg;
|
||||
export const getOriginalConfig = () => originalEnvConfig;
|
||||
|
||||
// cannot import singleton logger directly as it needs config to load various transport
|
||||
export const initEnvConfig = (logger?: CustomLogger) => {
|
||||
const parsedEnv = envSchema.safeParse(process.env);
|
||||
@@ -356,115 +352,10 @@ export const initEnvConfig = (logger?: CustomLogger) => {
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
const config = Object.freeze(parsedEnv.data);
|
||||
envCfg = config;
|
||||
|
||||
if (!originalEnvConfig) {
|
||||
originalEnvConfig = config;
|
||||
}
|
||||
|
||||
envCfg = Object.freeze(parsedEnv.data);
|
||||
return envCfg;
|
||||
};
|
||||
|
||||
// A list of environment variables that can be overwritten
|
||||
export const overwriteSchema: {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
fields: { key: keyof TEnvConfig; description?: string }[];
|
||||
};
|
||||
} = {
|
||||
azure: {
|
||||
name: "Azure",
|
||||
fields: [
|
||||
{
|
||||
key: "INF_APP_CONNECTION_AZURE_CLIENT_ID",
|
||||
description: "The Application (Client) ID of your Azure application."
|
||||
},
|
||||
{
|
||||
key: "INF_APP_CONNECTION_AZURE_CLIENT_SECRET",
|
||||
description: "The Client Secret of your Azure application."
|
||||
}
|
||||
]
|
||||
},
|
||||
google_sso: {
|
||||
name: "Google SSO",
|
||||
fields: [
|
||||
{
|
||||
key: "CLIENT_ID_GOOGLE_LOGIN",
|
||||
description: "The Client ID of your GCP OAuth2 application."
|
||||
},
|
||||
{
|
||||
key: "CLIENT_SECRET_GOOGLE_LOGIN",
|
||||
description: "The Client Secret of your GCP OAuth2 application."
|
||||
}
|
||||
]
|
||||
},
|
||||
github_sso: {
|
||||
name: "GitHub SSO",
|
||||
fields: [
|
||||
{
|
||||
key: "CLIENT_ID_GITHUB_LOGIN",
|
||||
description: "The Client ID of your GitHub OAuth application."
|
||||
},
|
||||
{
|
||||
key: "CLIENT_SECRET_GITHUB_LOGIN",
|
||||
description: "The Client Secret of your GitHub OAuth application."
|
||||
}
|
||||
]
|
||||
},
|
||||
gitlab_sso: {
|
||||
name: "GitLab SSO",
|
||||
fields: [
|
||||
{
|
||||
key: "CLIENT_ID_GITLAB_LOGIN",
|
||||
description: "The Client ID of your GitLab application."
|
||||
},
|
||||
{
|
||||
key: "CLIENT_SECRET_GITLAB_LOGIN",
|
||||
description: "The Secret of your GitLab application."
|
||||
},
|
||||
{
|
||||
key: "CLIENT_GITLAB_LOGIN_URL",
|
||||
description:
|
||||
"The URL of your self-hosted instance of GitLab where the OAuth application is registered. If no URL is passed in, this will default to https://gitlab.com."
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export const overridableKeys = new Set(
|
||||
Object.values(overwriteSchema).flatMap(({ fields }) => fields.map(({ key }) => key))
|
||||
);
|
||||
|
||||
export const validateOverrides = (config: Record<string, string>) => {
|
||||
const allowedOverrides = Object.fromEntries(
|
||||
Object.entries(config).filter(([key]) => overridableKeys.has(key as keyof z.input<typeof envSchema>))
|
||||
);
|
||||
|
||||
const tempEnv: Record<string, unknown> = { ...process.env, ...allowedOverrides };
|
||||
const parsedResult = envSchema.safeParse(tempEnv);
|
||||
|
||||
if (!parsedResult.success) {
|
||||
const errorDetails = parsedResult.error.issues
|
||||
.map((issue) => `Key: "${issue.path.join(".")}", Error: ${issue.message}`)
|
||||
.join("\n");
|
||||
throw new BadRequestError({ message: errorDetails });
|
||||
}
|
||||
};
|
||||
|
||||
export const overrideEnvConfig = (config: Record<string, string>) => {
|
||||
const allowedOverrides = Object.fromEntries(
|
||||
Object.entries(config).filter(([key]) => overridableKeys.has(key as keyof z.input<typeof envSchema>))
|
||||
);
|
||||
|
||||
const tempEnv: Record<string, unknown> = { ...process.env, ...allowedOverrides };
|
||||
const parsedResult = envSchema.safeParse(tempEnv);
|
||||
|
||||
if (parsedResult.success) {
|
||||
envCfg = Object.freeze(parsedResult.data);
|
||||
}
|
||||
};
|
||||
|
||||
export const formatSmtpConfig = () => {
|
||||
const tlsOptions: {
|
||||
rejectUnauthorized: boolean;
|
||||
|
||||
@@ -2045,10 +2045,6 @@ export const registerRoutes = async (
|
||||
cronJobs.push(adminIntegrationsSyncJob);
|
||||
}
|
||||
}
|
||||
const configSyncJob = await superAdminService.initializeEnvConfigSync();
|
||||
if (configSyncJob) {
|
||||
cronJobs.push(configSyncJob);
|
||||
}
|
||||
|
||||
server.decorate<FastifyZodProvider["store"]>("store", {
|
||||
user: userDAL,
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
SuperAdminSchema,
|
||||
UsersSchema
|
||||
} from "@app/db/schemas";
|
||||
import { getConfig, overridableKeys } from "@app/lib/config/env";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { invalidateCacheLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||
@@ -42,8 +42,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
encryptedGitHubAppConnectionClientSecret: true,
|
||||
encryptedGitHubAppConnectionSlug: true,
|
||||
encryptedGitHubAppConnectionId: true,
|
||||
encryptedGitHubAppConnectionPrivateKey: true,
|
||||
encryptedEnvOverrides: true
|
||||
encryptedGitHubAppConnectionPrivateKey: true
|
||||
}).extend({
|
||||
isMigrationModeOn: z.boolean(),
|
||||
defaultAuthOrgSlug: z.string().nullable(),
|
||||
@@ -111,14 +110,11 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
.refine((content) => DOMPurify.sanitize(content) === content, {
|
||||
message: "Page frame content contains unsafe HTML."
|
||||
})
|
||||
.optional(),
|
||||
envOverrides: z.record(z.enum(Array.from(overridableKeys) as [string, ...string[]]), z.string()).optional()
|
||||
.optional()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
config: SuperAdminSchema.omit({
|
||||
encryptedEnvOverrides: true
|
||||
}).extend({
|
||||
config: SuperAdminSchema.extend({
|
||||
defaultAuthOrgSlug: z.string().nullable()
|
||||
})
|
||||
})
|
||||
@@ -385,41 +381,6 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/env-overrides",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
response: {
|
||||
200: z.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
name: z.string(),
|
||||
fields: z
|
||||
.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
hasEnvEntry: z.boolean(),
|
||||
description: z.string().optional()
|
||||
})
|
||||
.array()
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
onRequest: (req, res, done) => {
|
||||
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
|
||||
verifySuperAdmin(req, res, done);
|
||||
});
|
||||
},
|
||||
handler: async () => {
|
||||
const envOverrides = await server.services.superAdmin.getEnvOverridesOrganized();
|
||||
return envOverrides;
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "DELETE",
|
||||
url: "/user-management/users/:userId",
|
||||
|
||||
@@ -5,13 +5,7 @@ import jwt from "jsonwebtoken";
|
||||
import { IdentityAuthMethod, OrgMembershipRole, TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
|
||||
import {
|
||||
getConfig,
|
||||
getOriginalConfig,
|
||||
overrideEnvConfig,
|
||||
overwriteSchema,
|
||||
validateOverrides
|
||||
} from "@app/lib/config/env";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||
import { generateUserSrpKeys, getUserPrivateKey } from "@app/lib/crypto/srp";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
@@ -39,7 +33,6 @@ import { TInvalidateCacheQueueFactory } from "./invalidate-cache-queue";
|
||||
import { TSuperAdminDALFactory } from "./super-admin-dal";
|
||||
import {
|
||||
CacheType,
|
||||
EnvOverrides,
|
||||
LoginMethod,
|
||||
TAdminBootstrapInstanceDTO,
|
||||
TAdminGetIdentitiesDTO,
|
||||
@@ -241,45 +234,6 @@ export const superAdminServiceFactory = ({
|
||||
adminIntegrationsConfig = config;
|
||||
};
|
||||
|
||||
const getEnvOverrides = async () => {
|
||||
const serverCfg = await serverCfgDAL.findById(ADMIN_CONFIG_DB_UUID);
|
||||
|
||||
if (!serverCfg || !serverCfg.encryptedEnvOverrides) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const decrypt = kmsService.decryptWithRootKey();
|
||||
|
||||
const overrides = JSON.parse(decrypt(serverCfg.encryptedEnvOverrides).toString()) as Record<string, string>;
|
||||
|
||||
return overrides;
|
||||
};
|
||||
|
||||
const getEnvOverridesOrganized = async (): Promise<EnvOverrides> => {
|
||||
const overrides = await getEnvOverrides();
|
||||
const ogConfig = getOriginalConfig();
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(overwriteSchema).map(([groupKey, groupDef]) => [
|
||||
groupKey,
|
||||
{
|
||||
name: groupDef.name,
|
||||
fields: groupDef.fields.map(({ key, description }) => ({
|
||||
key,
|
||||
description,
|
||||
value: overrides[key] || "",
|
||||
hasEnvEntry: !!(ogConfig as unknown as Record<string, string | undefined>)[key]
|
||||
}))
|
||||
}
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
const $syncEnvConfig = async () => {
|
||||
const config = await getEnvOverrides();
|
||||
overrideEnvConfig(config);
|
||||
};
|
||||
|
||||
const updateServerCfg = async (
|
||||
data: TSuperAdminUpdate & {
|
||||
slackClientId?: string;
|
||||
@@ -292,7 +246,6 @@ export const superAdminServiceFactory = ({
|
||||
gitHubAppConnectionSlug?: string;
|
||||
gitHubAppConnectionId?: string;
|
||||
gitHubAppConnectionPrivateKey?: string;
|
||||
envOverrides?: Record<string, string>;
|
||||
},
|
||||
userId: string
|
||||
) => {
|
||||
@@ -421,17 +374,6 @@ export const superAdminServiceFactory = ({
|
||||
gitHubAppConnectionSettingsUpdated = true;
|
||||
}
|
||||
|
||||
let envOverridesUpdated = false;
|
||||
if (data.envOverrides !== undefined) {
|
||||
// Verify input format
|
||||
validateOverrides(data.envOverrides);
|
||||
|
||||
const encryptedEnvOverrides = encryptWithRoot(Buffer.from(JSON.stringify(data.envOverrides)));
|
||||
updatedData.encryptedEnvOverrides = encryptedEnvOverrides;
|
||||
updatedData.envOverrides = undefined;
|
||||
envOverridesUpdated = true;
|
||||
}
|
||||
|
||||
const updatedServerCfg = await serverCfgDAL.updateById(ADMIN_CONFIG_DB_UUID, updatedData);
|
||||
|
||||
await keyStore.setItemWithExpiry(ADMIN_CONFIG_KEY, ADMIN_CONFIG_KEY_EXP, JSON.stringify(updatedServerCfg));
|
||||
@@ -440,10 +382,6 @@ export const superAdminServiceFactory = ({
|
||||
await $syncAdminIntegrationConfig();
|
||||
}
|
||||
|
||||
if (envOverridesUpdated) {
|
||||
await $syncEnvConfig();
|
||||
}
|
||||
|
||||
if (
|
||||
updatedServerCfg.encryptedMicrosoftTeamsAppId &&
|
||||
updatedServerCfg.encryptedMicrosoftTeamsClientSecret &&
|
||||
@@ -876,18 +814,6 @@ export const superAdminServiceFactory = ({
|
||||
return job;
|
||||
};
|
||||
|
||||
const initializeEnvConfigSync = async () => {
|
||||
logger.info("Setting up background sync process for environment overrides");
|
||||
|
||||
await $syncEnvConfig();
|
||||
|
||||
// sync every 5 minutes
|
||||
const job = new CronJob("*/5 * * * *", $syncEnvConfig);
|
||||
job.start();
|
||||
|
||||
return job;
|
||||
};
|
||||
|
||||
return {
|
||||
initServerCfg,
|
||||
updateServerCfg,
|
||||
@@ -907,9 +833,6 @@ export const superAdminServiceFactory = ({
|
||||
getOrganizations,
|
||||
deleteOrganization,
|
||||
deleteOrganizationMembership,
|
||||
initializeAdminIntegrationConfigSync,
|
||||
initializeEnvConfigSync,
|
||||
getEnvOverrides,
|
||||
getEnvOverridesOrganized
|
||||
initializeAdminIntegrationConfigSync
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { TEnvConfig } from "@app/lib/config/env";
|
||||
|
||||
export type TAdminSignUpDTO = {
|
||||
email: string;
|
||||
password: string;
|
||||
@@ -76,10 +74,3 @@ export type TAdminIntegrationConfig = {
|
||||
privateKey: string;
|
||||
};
|
||||
};
|
||||
|
||||
export interface EnvOverrides {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
fields: { key: keyof TEnvConfig; value: string; hasEnvEntry: boolean; description?: string }[];
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user