diff --git a/api/src/secure-startup.test.ts b/api/src/secure-startup.test.ts index c1558e85..e1291712 100644 --- a/api/src/secure-startup.test.ts +++ b/api/src/secure-startup.test.ts @@ -113,6 +113,18 @@ describe('hardened sandbox-runner startup config', () => { expect(() => validateHardenedSandboxStartup()).toThrow('REDIS_HOST'); }); + test('allows Lambda MicroVM image metadata while rejecting AWS credentials', () => { + setValidHardenedConfig(); + process.env.AWS_LAMBDA_MICROVM_IMAGE_ARN = 'arn:aws:lambda:us-east-1:123456789012:microvm-image:codeapi'; + process.env.AWS_LAMBDA_MICROVM_IMAGE_NAME = 'codeapi'; + process.env.AWS_LAMBDA_MICROVM_IMAGE_VERSION = '3'; + process.env.AWS_REGION = 'us-east-1'; + expect(() => validateHardenedSandboxStartup()).not.toThrow(); + + process.env.AWS_ACCESS_KEY_ID = 'access-key'; + expect(() => validateHardenedSandboxStartup()).toThrow('AWS_ACCESS_KEY_ID'); + }); + test('rejects missing manifest verifier and wrong forwarding target', () => { setValidHardenedConfig(); config.egress_gateway_url = ''; diff --git a/api/src/secure-startup.ts b/api/src/secure-startup.ts index 04f5638a..326bf810 100644 --- a/api/src/secure-startup.ts +++ b/api/src/secure-startup.ts @@ -1,6 +1,13 @@ import { config } from './config'; import { workspaceIsolationConfigErrors } from './workspace-isolation'; +const ALLOWED_LAMBDA_MICROVM_AWS_ENV = new Set([ + 'AWS_LAMBDA_MICROVM_IMAGE_ARN', + 'AWS_LAMBDA_MICROVM_IMAGE_NAME', + 'AWS_LAMBDA_MICROVM_IMAGE_VERSION', + 'AWS_REGION', +]); + export class SandboxSecureStartupError extends Error { constructor(message: string) { super(message); @@ -57,7 +64,7 @@ function forbiddenEnvNames(): string[] { if (name === 'CODEAPI_HARDENED_SANDBOX_MODE') continue; if (name.startsWith('CODEAPI_')) forbidden.push(name); if (name.startsWith('REDIS_')) forbidden.push(name); - if (name.startsWith('AWS_')) forbidden.push(name); + if (name.startsWith('AWS_') && !ALLOWED_LAMBDA_MICROVM_AWS_ENV.has(name)) forbidden.push(name); if (name.startsWith('S3_')) forbidden.push(name); if (name.startsWith('MINIO_')) forbidden.push(name); if (/(SECRET|TOKEN|PASSWORD|PRIVATE_KEY)/.test(name)) forbidden.push(name);