내부 builder 인증과 실행 허용 목록 및 자원 경계를 적용한다

This commit is contained in:
2026-10-09 04:31:44 +09:00
parent 6d05c01a76
commit f78ab77850
13 changed files with 979 additions and 205 deletions
+9 -1
View File
@@ -14,6 +14,14 @@ export const validateComposeModel = (model, mode) => {
const caddy = model?.services?.caddy;
if (!builder) errors.push('builder service is missing');
if (!caddy) errors.push('caddy service is missing');
for (const [name, service] of [['runtime', runtime], ['builder', builder]]) {
const target = '/run/secrets/release_builder_token';
if (service?.environment?.RELEASE_BUILDER_TOKEN_FILE !== target) errors.push(`${name} must use the mounted builder token file`);
const mount = (service?.volumes ?? []).find((entry) => entry.target === target);
if (!mount || mount.type !== 'bind' || mount.read_only !== true) errors.push(`${name} builder token mount must be read-only`);
}
if ((builder?.ports ?? []).length) errors.push('builder must not publish host ports');
const requiredImageEnvironment = {
GATEWAY_IMAGE_UPLOAD_SECRET_FILE: '/run/secrets/image_upload_core2026_secret',
@@ -120,7 +128,7 @@ export const validateComposeModel = (model, mode) => {
errors.push('builder Rayon thread count must be between 1 and 4');
}
for (const name of Object.keys(builder.environment ?? {})) {
if (/(?:SECRET|TOKEN|PASSWORD|DATABASE_URL|REDIS_URL)/i.test(name)) {
if (name !== 'RELEASE_BUILDER_TOKEN_FILE' && /(?:SECRET|TOKEN|PASSWORD|DATABASE_URL|REDIS_URL)/i.test(name)) {
errors.push(`builder must not receive sensitive environment variable ${name}`);
}
}