mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 15:29:46 +00:00
feat(audit-log-stream): azure support
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
AzureProviderListItemSchema,
|
||||
SanitizedAzureProviderSchema
|
||||
} from "@app/ee/services/audit-log-stream/azure/azure-provider-schemas";
|
||||
import {
|
||||
CustomProviderListItemSchema,
|
||||
SanitizedCustomProviderSchema
|
||||
@@ -19,13 +23,15 @@ import { AuthMode } from "@app/services/auth/auth-type";
|
||||
const SanitizedAuditLogStreamSchema = z.union([
|
||||
SanitizedCustomProviderSchema,
|
||||
SanitizedDatadogProviderSchema,
|
||||
SanitizedSplunkProviderSchema
|
||||
SanitizedSplunkProviderSchema,
|
||||
SanitizedAzureProviderSchema
|
||||
]);
|
||||
|
||||
const ProviderOptionsSchema = z.discriminatedUnion("provider", [
|
||||
CustomProviderListItemSchema,
|
||||
DatadogProviderListItemSchema,
|
||||
SplunkProviderListItemSchema
|
||||
SplunkProviderListItemSchema,
|
||||
AzureProviderListItemSchema
|
||||
]);
|
||||
|
||||
export const registerAuditLogStreamRouter = async (server: FastifyZodProvider) => {
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { LogProvider } from "@app/ee/services/audit-log-stream/audit-log-stream-enums";
|
||||
import {
|
||||
CreateAzureProviderLogStreamSchema,
|
||||
SanitizedAzureProviderSchema,
|
||||
UpdateAzureProviderLogStreamSchema
|
||||
} from "@app/ee/services/audit-log-stream/azure/azure-provider-schemas";
|
||||
import {
|
||||
CreateCustomProviderLogStreamSchema,
|
||||
SanitizedCustomProviderSchema,
|
||||
@@ -21,6 +26,15 @@ export * from "./audit-log-stream-router";
|
||||
|
||||
export const AUDIT_LOG_STREAM_REGISTER_ROUTER_MAP: Record<LogProvider, (server: FastifyZodProvider) => Promise<void>> =
|
||||
{
|
||||
[LogProvider.Azure]: async (server: FastifyZodProvider) => {
|
||||
registerAuditLogStreamEndpoints({
|
||||
server,
|
||||
provider: LogProvider.Azure,
|
||||
sanitizedResponseSchema: SanitizedAzureProviderSchema,
|
||||
createSchema: CreateAzureProviderLogStreamSchema,
|
||||
updateSchema: UpdateAzureProviderLogStreamSchema
|
||||
});
|
||||
},
|
||||
[LogProvider.Custom]: async (server: FastifyZodProvider) => {
|
||||
registerAuditLogStreamEndpoints({
|
||||
server,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum LogProvider {
|
||||
Azure = "azure",
|
||||
Datadog = "datadog",
|
||||
Splunk = "splunk",
|
||||
Custom = "custom"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { LogProvider } from "./audit-log-stream-enums";
|
||||
import { TAuditLogStreamCredentials, TLogStreamFactory } from "./audit-log-stream-types";
|
||||
import { AzureProviderFactory } from "./azure/azure-provider-factory";
|
||||
import { CustomProviderFactory } from "./custom/custom-provider-factory";
|
||||
import { DatadogProviderFactory } from "./datadog/datadog-provider-factory";
|
||||
import { SplunkProviderFactory } from "./splunk/splunk-provider-factory";
|
||||
@@ -7,6 +8,7 @@ import { SplunkProviderFactory } from "./splunk/splunk-provider-factory";
|
||||
type TLogStreamFactoryImplementation = TLogStreamFactory<TAuditLogStreamCredentials>;
|
||||
|
||||
export const LOG_STREAM_FACTORY_MAP: Record<LogProvider, TLogStreamFactoryImplementation> = {
|
||||
[LogProvider.Azure]: AzureProviderFactory as TLogStreamFactoryImplementation,
|
||||
[LogProvider.Datadog]: DatadogProviderFactory as TLogStreamFactoryImplementation,
|
||||
[LogProvider.Splunk]: SplunkProviderFactory as TLogStreamFactoryImplementation,
|
||||
[LogProvider.Custom]: CustomProviderFactory as TLogStreamFactoryImplementation
|
||||
|
||||
@@ -3,14 +3,18 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
|
||||
import { TAuditLogStream, TAuditLogStreamCredentials } from "./audit-log-stream-types";
|
||||
import { getAzureProviderListItem } from "./azure/azure-provider-fns";
|
||||
import { getCustomProviderListItem } from "./custom/custom-provider-fns";
|
||||
import { getDatadogProviderListItem } from "./datadog/datadog-provider-fns";
|
||||
import { getSplunkProviderListItem } from "./splunk/splunk-provider-fns";
|
||||
|
||||
export const listProviderOptions = () => {
|
||||
return [getDatadogProviderListItem(), getSplunkProviderListItem(), getCustomProviderListItem()].sort((a, b) =>
|
||||
a.name.localeCompare(b.name)
|
||||
);
|
||||
return [
|
||||
getDatadogProviderListItem(),
|
||||
getSplunkProviderListItem(),
|
||||
getCustomProviderListItem(),
|
||||
getAzureProviderListItem()
|
||||
].sort((a, b) => a.name.localeCompare(b.name));
|
||||
};
|
||||
|
||||
export const encryptLogStreamCredentials = async ({
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { TAuditLogs } from "@app/db/schemas";
|
||||
|
||||
import { LogProvider } from "./audit-log-stream-enums";
|
||||
import { TAzureProvider, TAzureProviderCredentials } from "./azure/azure-provider-types";
|
||||
import { TCustomProvider, TCustomProviderCredentials } from "./custom/custom-provider-types";
|
||||
import { TDatadogProvider, TDatadogProviderCredentials } from "./datadog/datadog-provider-types";
|
||||
import { TSplunkProvider, TSplunkProviderCredentials } from "./splunk/splunk-provider-types";
|
||||
|
||||
export type TAuditLogStream = TDatadogProvider | TSplunkProvider | TCustomProvider;
|
||||
export type TAuditLogStream = TDatadogProvider | TSplunkProvider | TCustomProvider | TAzureProvider;
|
||||
|
||||
export type TAuditLogStreamCredentials =
|
||||
| TDatadogProviderCredentials
|
||||
| TSplunkProviderCredentials
|
||||
| TCustomProviderCredentials;
|
||||
| TCustomProviderCredentials
|
||||
| TAzureProviderCredentials;
|
||||
|
||||
export type TCreateAuditLogStreamDTO = {
|
||||
provider: LogProvider;
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import { RawAxiosRequestHeaders } from "axios";
|
||||
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
||||
|
||||
import { AUDIT_LOG_STREAM_TIMEOUT } from "../../audit-log/audit-log-queue";
|
||||
import { TLogStreamFactoryStreamLog, TLogStreamFactoryValidateCredentials } from "../audit-log-stream-types";
|
||||
import { TAzureProviderCredentials } from "./azure-provider-types";
|
||||
|
||||
function createPayload(event: { createdAt?: Date | string } & Record<string, unknown>) {
|
||||
return [
|
||||
{
|
||||
...event,
|
||||
TimeGenerated: (event.createdAt ? new Date(event.createdAt) : new Date()).toISOString()
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
async function getAzureToken(tenantId: string, clientId: string, clientSecret: string) {
|
||||
const { data } = await request.post<{ access_token: string }>(
|
||||
`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
|
||||
new URLSearchParams({
|
||||
grant_type: "client_credentials",
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
scope: "https://monitor.azure.com/.default"
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return data.access_token;
|
||||
}
|
||||
|
||||
export const AzureProviderFactory = () => {
|
||||
const validateCredentials: TLogStreamFactoryValidateCredentials<TAzureProviderCredentials> = async ({
|
||||
credentials
|
||||
}) => {
|
||||
const { tenantId, clientId, clientSecret, dceUrl, dcrId, cltName } = credentials;
|
||||
|
||||
await blockLocalAndPrivateIpAddresses(dceUrl);
|
||||
|
||||
const token = await getAzureToken(tenantId, clientId, clientSecret);
|
||||
|
||||
const streamHeaders: RawAxiosRequestHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`
|
||||
};
|
||||
|
||||
await request
|
||||
.post(
|
||||
`${dceUrl}/dataCollectionRules/${dcrId}/streams/Custom-${cltName}_CL?api-version=2023-01-01`,
|
||||
createPayload({ ping: "ok" }),
|
||||
{
|
||||
headers: streamHeaders,
|
||||
timeout: AUDIT_LOG_STREAM_TIMEOUT,
|
||||
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
throw new BadRequestError({ message: `Failed to connect with Azure: ${(err as Error)?.message}` });
|
||||
});
|
||||
|
||||
return credentials;
|
||||
};
|
||||
|
||||
const streamLog: TLogStreamFactoryStreamLog<TAzureProviderCredentials> = async ({ credentials, auditLog }) => {
|
||||
const { tenantId, clientId, clientSecret, dceUrl, dcrId, cltName } = credentials;
|
||||
|
||||
await blockLocalAndPrivateIpAddresses(dceUrl);
|
||||
|
||||
const token = await getAzureToken(tenantId, clientId, clientSecret);
|
||||
|
||||
const streamHeaders: RawAxiosRequestHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`
|
||||
};
|
||||
|
||||
await request.post(
|
||||
`${dceUrl}/dataCollectionRules/${dcrId}/streams/Custom-${cltName}_CL?api-version=2023-01-01`,
|
||||
createPayload(auditLog),
|
||||
{
|
||||
headers: streamHeaders,
|
||||
timeout: AUDIT_LOG_STREAM_TIMEOUT,
|
||||
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
validateCredentials,
|
||||
streamLog
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
import { LogProvider } from "../audit-log-stream-enums";
|
||||
|
||||
export const getAzureProviderListItem = () => {
|
||||
return {
|
||||
name: "Azure" as const,
|
||||
provider: LogProvider.Azure as const
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import RE2 from "re2";
|
||||
import { z } from "zod";
|
||||
|
||||
import { LogProvider } from "../audit-log-stream-enums";
|
||||
import { BaseProviderSchema } from "../audit-log-stream-schemas";
|
||||
|
||||
export const AzureProviderCredentialsSchema = z.object({
|
||||
tenantId: z.string().trim().uuid(),
|
||||
clientId: z.string().trim().uuid(),
|
||||
clientSecret: z.string().trim().length(40),
|
||||
|
||||
// Data Collection Endpoint URL
|
||||
dceUrl: z.string().trim().url().min(1).max(255),
|
||||
|
||||
// Data Collection Rule Immutable ID
|
||||
dcrId: z
|
||||
.string()
|
||||
.trim()
|
||||
.refine((val) => new RE2(/^dcr-[0-9a-f]{32}$/).test(val), "DCR ID must be in dcr-*** format"),
|
||||
|
||||
// Custom Log Table Name
|
||||
cltName: z.string().trim().min(1).max(255)
|
||||
});
|
||||
|
||||
const BaseAzureProviderSchema = BaseProviderSchema.extend({ provider: z.literal(LogProvider.Azure) });
|
||||
|
||||
export const AzureProviderSchema = BaseAzureProviderSchema.extend({
|
||||
credentials: AzureProviderCredentialsSchema
|
||||
});
|
||||
|
||||
export const SanitizedAzureProviderSchema = BaseAzureProviderSchema.extend({
|
||||
credentials: AzureProviderCredentialsSchema.pick({
|
||||
tenantId: true,
|
||||
clientId: true,
|
||||
dceUrl: true,
|
||||
dcrId: true,
|
||||
cltName: true
|
||||
})
|
||||
});
|
||||
|
||||
export const AzureProviderListItemSchema = z.object({
|
||||
name: z.literal("Azure"),
|
||||
provider: z.literal(LogProvider.Azure)
|
||||
});
|
||||
|
||||
export const CreateAzureProviderLogStreamSchema = z.object({
|
||||
credentials: AzureProviderCredentialsSchema
|
||||
});
|
||||
|
||||
export const UpdateAzureProviderLogStreamSchema = z.object({
|
||||
credentials: AzureProviderCredentialsSchema
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { AzureProviderCredentialsSchema, AzureProviderSchema } from "./azure-provider-schemas";
|
||||
|
||||
export type TAzureProvider = z.infer<typeof AzureProviderSchema>;
|
||||
|
||||
export type TAzureProviderCredentials = z.infer<typeof AzureProviderCredentialsSchema>;
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Cluster, Redis } from "ioredis";
|
||||
|
||||
import { buildRedisFromConfig, TRedisConfigKeys } from "@app/lib/config/redis";
|
||||
import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext";
|
||||
import { applyJitter } from "@app/lib/dates";
|
||||
import { delay as delayMs } from "@app/lib/delay";
|
||||
import { ExecutionResult, Redlock, Settings } from "@app/lib/red-lock";
|
||||
import { Redis, Cluster } from "ioredis";
|
||||
|
||||
export const PgSqlLock = {
|
||||
BootUpMigration: 2023,
|
||||
|
||||
Reference in New Issue
Block a user