docs: archive entra materials and simplify deployment docs
This commit is contained in:
@@ -44,31 +44,10 @@ const envSchema = z.object({
|
||||
EIDAS_PROVIDER_URL: z.string().url().optional(),
|
||||
EIDAS_API_KEY: z.string().optional(),
|
||||
|
||||
// Microsoft Entra VerifiedID
|
||||
ENTRA_TENANT_ID: z.string().optional(),
|
||||
ENTRA_CLIENT_ID: z.string().optional(),
|
||||
ENTRA_CLIENT_SECRET: z.string().optional(),
|
||||
ENTRA_CREDENTIAL_MANIFEST_ID: z.string().optional(),
|
||||
ENTRA_MANIFESTS: z.string().optional(), // JSON object mapping manifest names to IDs
|
||||
// Entra Rate Limiting
|
||||
ENTRA_RATE_LIMIT_ISSUANCE: z.string().optional(),
|
||||
ENTRA_RATE_LIMIT_VERIFICATION: z.string().optional(),
|
||||
ENTRA_RATE_LIMIT_STATUS_CHECK: z.string().optional(),
|
||||
ENTRA_RATE_LIMIT_GLOBAL: z.string().optional(),
|
||||
// Credential Display/Images
|
||||
ENTRA_CREDENTIAL_LOGO_URI: z.string().url().optional(),
|
||||
ENTRA_CREDENTIAL_BG_COLOR: z.string().optional(),
|
||||
ENTRA_CREDENTIAL_TEXT_COLOR: z.string().optional(),
|
||||
|
||||
// Credential Rate Limiting
|
||||
CREDENTIAL_RATE_LIMIT_PER_USER: z.string().optional(),
|
||||
CREDENTIAL_RATE_LIMIT_PER_IP: z.string().optional(),
|
||||
|
||||
// Azure Logic Apps
|
||||
AZURE_LOGIC_APPS_WORKFLOW_URL: z.string().url().optional(),
|
||||
AZURE_LOGIC_APPS_ACCESS_KEY: z.string().optional(),
|
||||
AZURE_LOGIC_APPS_MANAGED_IDENTITY_CLIENT_ID: z.string().optional(),
|
||||
|
||||
// CORS
|
||||
CORS_ORIGIN: z.string().optional(),
|
||||
|
||||
@@ -135,12 +114,7 @@ const envSchema = z.object({
|
||||
DSB_SCHEMA_REGISTRY_URL: z.string().url().optional(),
|
||||
|
||||
// Secrets Management
|
||||
SECRETS_PROVIDER: z.enum(['aws', 'azure', 'env']).optional(),
|
||||
AZURE_KEY_VAULT_URL: z.string().url().optional(),
|
||||
AZURE_TENANT_ID: z.string().optional(),
|
||||
AZURE_CLIENT_ID: z.string().optional(),
|
||||
AZURE_CLIENT_SECRET: z.string().optional(),
|
||||
AZURE_MANAGED_IDENTITY_CLIENT_ID: z.string().optional(),
|
||||
SECRETS_PROVIDER: z.enum(['aws', 'gcp', 'env']).optional(),
|
||||
SECRETS_CACHE_TTL: z.string().transform(Number).pipe(z.number().int().positive()).optional(),
|
||||
});
|
||||
|
||||
@@ -175,4 +149,3 @@ export function getEnv(): Env {
|
||||
* Validate environment variables on module load
|
||||
*/
|
||||
getEnv();
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ export * from './auth';
|
||||
export * from './rate-limit-credential';
|
||||
export * from './rate-limiting';
|
||||
export * from './graceful-shutdown';
|
||||
export * from './rate-limit-entra';
|
||||
export * from './authorization';
|
||||
export * from './compliance';
|
||||
export * from './retry';
|
||||
@@ -22,4 +21,3 @@ export * from './timeout';
|
||||
|
||||
// Re-export types
|
||||
export type { AuthUser } from './auth';
|
||||
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/**
|
||||
* Entra VerifiedID API rate limiting
|
||||
* Specific rate limits for Entra VerifiedID endpoints to prevent API quota exhaustion
|
||||
*/
|
||||
|
||||
import { FastifyInstance, FastifyRequest } from 'fastify';
|
||||
import fastifyRateLimit from '@fastify/rate-limit';
|
||||
import { getEnv } from './env';
|
||||
|
||||
export interface EntraRateLimitConfig {
|
||||
issuance?: {
|
||||
max: number;
|
||||
timeWindow: string | number;
|
||||
};
|
||||
verification?: {
|
||||
max: number;
|
||||
timeWindow: string | number;
|
||||
};
|
||||
statusCheck?: {
|
||||
max: number;
|
||||
timeWindow: string | number;
|
||||
};
|
||||
global?: {
|
||||
max: number;
|
||||
timeWindow: string | number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Entra VerifiedID-specific rate limiting
|
||||
*/
|
||||
export async function registerEntraRateLimit(
|
||||
server: FastifyInstance,
|
||||
config?: EntraRateLimitConfig
|
||||
): Promise<void> {
|
||||
const env = getEnv();
|
||||
|
||||
// Default configuration - conservative limits to avoid API quota issues
|
||||
const defaultConfig: Required<EntraRateLimitConfig> = {
|
||||
issuance: {
|
||||
max: parseInt(env.ENTRA_RATE_LIMIT_ISSUANCE || '10', 10),
|
||||
timeWindow: '1 minute',
|
||||
},
|
||||
verification: {
|
||||
max: parseInt(env.ENTRA_RATE_LIMIT_VERIFICATION || '20', 10),
|
||||
timeWindow: '1 minute',
|
||||
},
|
||||
statusCheck: {
|
||||
max: parseInt(env.ENTRA_RATE_LIMIT_STATUS_CHECK || '30', 10),
|
||||
timeWindow: '1 minute',
|
||||
},
|
||||
global: {
|
||||
max: parseInt(env.ENTRA_RATE_LIMIT_GLOBAL || '50', 10),
|
||||
timeWindow: '1 minute',
|
||||
},
|
||||
};
|
||||
|
||||
const finalConfig = { ...defaultConfig, ...config };
|
||||
|
||||
// Global Entra API rate limit
|
||||
await server.register(fastifyRateLimit, {
|
||||
max: finalConfig.global.max,
|
||||
timeWindow: finalConfig.global.timeWindow,
|
||||
keyGenerator: (request: FastifyRequest) => {
|
||||
// Rate limit by IP for Entra endpoints
|
||||
return `entra:global:${request.ip}`;
|
||||
},
|
||||
errorResponseBuilder: (_request, context) => {
|
||||
return {
|
||||
error: {
|
||||
code: 'ENTRA_RATE_LIMIT_EXCEEDED',
|
||||
message: `Entra API rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
|
||||
},
|
||||
};
|
||||
},
|
||||
skipOnError: false,
|
||||
});
|
||||
|
||||
// Issuance-specific rate limit
|
||||
await server.register(fastifyRateLimit, {
|
||||
max: finalConfig.issuance.max,
|
||||
timeWindow: finalConfig.issuance.timeWindow,
|
||||
keyGenerator: (request: FastifyRequest) => {
|
||||
const userId = (request as any).user?.id || 'anonymous';
|
||||
return `entra:issuance:${userId}:${request.ip}`;
|
||||
},
|
||||
errorResponseBuilder: (_request, context) => {
|
||||
return {
|
||||
error: {
|
||||
code: 'ENTRA_ISSUANCE_RATE_LIMIT_EXCEEDED',
|
||||
message: `Entra issuance rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
|
||||
},
|
||||
};
|
||||
},
|
||||
skipOnError: false,
|
||||
});
|
||||
|
||||
// Verification-specific rate limit
|
||||
await server.register(fastifyRateLimit, {
|
||||
max: finalConfig.verification.max,
|
||||
timeWindow: finalConfig.verification.timeWindow,
|
||||
keyGenerator: (request: FastifyRequest) => {
|
||||
return `entra:verification:${request.ip}`;
|
||||
},
|
||||
errorResponseBuilder: (_request, context) => {
|
||||
return {
|
||||
error: {
|
||||
code: 'ENTRA_VERIFICATION_RATE_LIMIT_EXCEEDED',
|
||||
message: `Entra verification rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
|
||||
},
|
||||
};
|
||||
},
|
||||
skipOnError: false,
|
||||
});
|
||||
|
||||
// Status check-specific rate limit
|
||||
await server.register(fastifyRateLimit, {
|
||||
max: finalConfig.statusCheck.max,
|
||||
timeWindow: finalConfig.statusCheck.timeWindow,
|
||||
keyGenerator: (request: FastifyRequest) => {
|
||||
const requestId = (request.params as any)?.requestId || (request.query as any)?.requestId || 'unknown';
|
||||
return `entra:status:${requestId}`;
|
||||
},
|
||||
errorResponseBuilder: (_request, context) => {
|
||||
return {
|
||||
error: {
|
||||
code: 'ENTRA_STATUS_CHECK_RATE_LIMIT_EXCEEDED',
|
||||
message: `Entra status check rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
|
||||
},
|
||||
};
|
||||
},
|
||||
skipOnError: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Entra rate limit plugin
|
||||
*/
|
||||
export function createEntraRateLimitPlugin(config?: EntraRateLimitConfig) {
|
||||
return async function (server: FastifyInstance) {
|
||||
await registerEntraRateLimit(server, config);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user