동적 스캔 실행기
manifest만 읽어서는 분석할 수 없는 프로젝트가 있습니다. 예를 들어 Android 앱은 cdxgen이 해석된 의존성 그래프를 보려면 먼저 Gradle 빌드를 실행해야 합니다. 동적 스캔 실행기는 SBOM 생성 단계(build-prep + cdxgen)를 알맞은 toolchain을 이미 갖춘 환경별 컨테이너 안에서 실행합니다. 빌드는 임의 코드 실행이므로, 이 문서는 대부분 격리에 관한 내용입니다.
온프레·단일 테넌트 포털을 운영하며 .env 편집과 docker-compose 실행에 익숙한 super_admin. 기본 실행기는 설정이 필요 없습니다 — SCAN_EXECUTOR=local_docker를 켤 때만 이 문서를 읽으십시오. 스캔 단위 라이프사이클은 스캔을 참고하십시오.
local_docker로는 더 이상 스캔하지 않습니다Docker API에 접근할 수 있는 워커는 이제 BomLens 엔진 작업 외에는 모두 거부하므로, 스캔 워커에서 SCAN_EXECUTOR=local_docker를 쓸 수 없습니다. 아래 1단계를 참고하십시오. 이 문서의 나머지는 참고용으로 실행기를 설명합니다.
두 가지 실행기
| 실행기 | 빌드를 실행하는 주체 | 사용 시점 |
|---|---|---|
inprocess(기본) | Celery 워커가 cdxgen을 워커 로컬 서브프로세스로 실행합니다(기존 동작 그대로). | 워커 이미지 안에서 빌드되는 모든 경우(npm, Maven, 워커 toolchain의 pip). |
local_docker | 워커가 호스트 Docker 소켓으로 환경별 사이드카 컨테이너(현재 Android SDK 이미지 sbom-scanner-android-sdk<API>)를 띄워 그 안에서 build-prep + cdxgen을 실행하고, 생성된 CycloneDX SBOM을 수집합니다. | 워커 이미지에 없는 toolchain이 프로젝트에 필요한 온프레 환경. |
local_docker는 라우팅된 이미지가 없는 환경과 Docker CLI가 없는 워커에서는 inprocess로 폴백합니다 — 그래서 이 기능을 켜도 기존에 동작하던 스캔이 깨지지 않습니다.
사이드카로 라우팅하는 환경
기본값은 SCAN_LOCAL_DOCKER_ENVS=android로, Android만 사이드카로 라우팅합니다. 의도한 설정입니다. 같은 프로젝트를 all-in-one 워커와 전용 cdxgen 언어 이미지로 각각 측정해 보니 node, go, rust, ruby, java, python, php, dotnet은 컴포넌트 수가 동일했습니다. 워커가 이미 해당 toolchain을 갖추고 있고, cdxgen이 전이 의존성 그래프를 같은 방식으로 해석하기 때문입니다. 진짜 공백은 Android 하나뿐입니다 — 워커에 Android SDK가 없어 Gradle 플러그인이 의존성 그래프를 해석하지 못해 컴포넌트가 0개가 나오는 반면, SDK 사이드카는 전체 그래프를 만들어 냅니다.
따라서 다른 언어를 사이드카로 라우팅해도 온프레 환경에서 검출이 좋아지지 않습니다. 그래도 언어별 빌드를 워커와 격리하고 싶다면 대상을 넓히십시오.
SCAN_LOCAL_DOCKER_ENVS=android,node,go,rust,ruby,java,python,php,dotnet
또는 환경을 하나씩 나열하는 대신 all 예약값으로 전부 라우팅할 수 있습니다.
SCAN_LOCAL_DOCKER_ENVS=all
스캔 대상 소스를 신뢰할 수 없을 때(예: 고객 자체 코드가 아니라 검증용으로 대량으로 가져온 공개 저장소 코호트) 쓰는 설정입니다. 손으로 나열한 목록은 언어 하나만 빠뜨려도 그 빌드가 격리 없이 워커에서 임의 코드를 실행하게 되고, all은 올인원 이미지로 처리되는 cpp·mixed·unknown까지 놓치지 않고 포함합니다.
라우팅한 언어는 처음 사용할 때 cdxgen 이미지를 받습니다(언어마다 수 GB). 언어 이미지는 CDXGEN_IMAGE_TAG(v12) 태그로 고정돼 있어 미고정 이미지 예외 없이 그대로 통과합니다. Android의 :latest만 SCAN_ANDROID_IMAGE_TAG 고정이 필요합니다.
local_docker는 워커에 호스트 Docker 소켓 접근을 부여하는데, 이는 호스트를 root 등가로 제어하는 권한입니다. 스캔하는 저장소는 신뢰할 수 없는 입력입니다 — 악의적인 build.gradle이나 Gradle 플러그인이 빌드의 일부로 실행됩니다. 멀티 테넌트나 인터넷에 노출된 배포에서는 절대 켜지 마십시오. 멀티 테넌트 SaaS 경로는 별도의 샌드박스 모델입니다(한계 참고).
빌드를 격리하는 요소
다음 기본값은 실행기가 코드에서 적용하므로, 설정하지 않아도 적용됩니다. 사이드카가 신뢰할 수 없는 빌드 코드를 실행하기 때문에 존재합니다.
- 볼륨 범위. 전략은 기본
named입니다. 사이드카는SCAN_WORKSPACE_VOLUME(스캔 트리)만 마운트하고 그 외에는 마운트하지 않습니다. 대안인volumes_from은 cosign SBOM 서명키를 포함한 모든 워커 볼륨을 신뢰할 수 없는 빌드에 다시 마운트합니다.SCAN_VOLUMES_FROM_ACK=1과SCAN_WORKER_CONTAINER를 모두 설정하지 않으면 거부됩니다.named로 두십시오. - capability. 사이드카는
--cap-drop=ALL로 실행하고 최소 집합(CHOWN,DAC_OVERRIDE,FOWNER,SETGID,SETUID)만 다시 추가하며, 빌드가 권한을 상승시킬 수 없도록--security-opt no-new-privileges를 함께 적용합니다. - 리소스 한도.
--memory 4g,--cpus 2,--pids-limit 4096이 기본으로 켜져 있습니다. 신뢰할 수 없는 빌드가 호스트를 OOM에 빠뜨리거나 fork bomb으로 공격할 수 없습니다. - 환경변수. 사이드카는
HOME,FETCH_LICENSE,CDXGEN_DEBUG_MODE만 받습니다. 워커 시크릿은 전달되지 않습니다. - 이미지 핀.
:latest태그는 거부됩니다(핵심 규칙 #9).SCAN_ANDROID_IMAGE_TAG를 semver(v1.0.0)나sha256:<digest>로 핀하십시오. 로컬 개발에서만SCAN_ALLOW_UNPINNED_IMAGE=1이 이 거부를 해제합니다. - 시크릿 마스킹. 사이드카 stderr에 나타나는 PEM private key 블록은 해당 줄이 스캔 로그에 도달하기 전에 마스킹됩니다.
켜는 법(옵트인)
워커 이미지에는 Docker CLI가 이미 포함되어 있으므로, 결정할 것은 워커가 Docker에 도달하는 방식과 사이드카 네트워크를 격리하는 방식뿐입니다.
1. 워커에 Docker 접근 부여
스캔을 실행하는 워커에서는 이 단계를 더 이상 적용할 수 없습니다. local_docker 사이드카를 실행하는 워커에는 Docker API가 필요한데, 같은 워커가 라우팅되지 않은 환경에서는 스캔 대상 프로젝트의 빌드를 실행하고, 다른 스캔 작업과 기본 큐 작업도 모두 실행합니다. Docker API에 접근할 수 있는 워커에서 스캔 대상 저장소의 코드가 실행되면 권한 있는 컨테이너를 만들어 호스트를 장악할 수 있으므로, TRUSCA는 이를 거부합니다.
DOCKER_HOST가 설정되어 있거나,/var/run/docker.sock또는/run/docker.sock에 Docker 소켓이 마운트되어 있거나,docker-socket-proxy이름이 해석되는 워커는 BomLens 엔진 작업만 실행합니다. 소스 스캔 작업을 포함한 다른 모든 작업은 그 이유와 함께 실패합니다.- 이런 워커에서는 빌드 준비, cdxgen, govulncheck가 시작하지 않습니다.
따라서 local_docker를 위해 스캔 워커에 소켓을 마운트했거나 DOCKER_HOST를 설정한 배포는 그 접근을 제거할 때까지 스캔이 멈춥니다. docker-compose.dev.yml도 더 이상 소켓을 마운트하지 않습니다. 빌드를 별도 컨테이너에서 격리해 실행하려면 Docker API를 전용 워커에만 두는 BomLens 엔진을 쓰십시오(스캔 엔진). local_docker는 어떤 배포에도 권장하지 않으며 이후 제거됩니다.
2. 사이드카 egress 격리
Gradle 빌드는 패키지 레지스트리(Google Maven, Maven Central)에 도달해야 하므로 사이드카는 인터넷 egress를 유지합니다 — 다만 postgres, redis, 백엔드에는 도달할 수 없어야 합니다. SCAN_SIDECAR_NETWORK를 전용 scan-egress 네트워크(compose에 정의)로 설정해 사이드카를 앱 서비스와 분리된 네트워크에 두십시오.
# 포털의 .env — <project>는 compose 프로젝트 prefix
SCAN_SIDECAR_NETWORK=<project>_scan-egress
SCAN_SIDECAR_NETWORK를 설정하지 않으면 사이드카가 기본 브리지에 올라가 내부 서비스에 도달할 수 있고, 워커가 시작 시 경고를 로그에 남깁니다. 프로덕션에서는 방화벽이나 egress 프록시로 필요한 레지스트리(Google, Maven)로만 egress를 더 제한하십시오.
3. 워크스페이스 볼륨과 이미지 핀
SCAN_WORKSPACE_VOLUME을 compose-prefixed 볼륨명으로 설정하고, 사이드카 이미지를 고정 버전으로 핀하십시오.
# 포털의 .env
SCAN_EXECUTOR=local_docker
SCAN_WORKSPACE_VOLUME=trustedoss-portal_scan-workspace # compose-prefixed 볼륨명
SCAN_ANDROID_IMAGE_TAG=v1.0.0 # semver 또는 sha256:<digest>
.env 편집 후 워커를 재시작하십시오 — 실행기 키는 런타임에 os.getenv로 읽힙니다.
동작 확인
- Android 프로젝트에 소스 스캔을 트리거합니다. 워커 로그에 실행기가 in-process cdxgen 서브프로세스가 아니라 사이드카로 라우팅되는 것이 보입니다(SBOM 단계 시작 시 해석된 이미지 태그와
local_docker전략이 로그에 남습니다).
- 스캔이 실행되는 동안
docker ps --filter label=trusca.role=scan-sidecar가 사이드카를 정확히 하나 표시합니다.docker inspect <id>로 들여다보면CapDrop: [ALL], 유일한 마운트인 named 워크스페이스 볼륨,scan-egress네트워크가 확인됩니다.
- 스캔이 비어 있지 않은 컴포넌트 수와 함께
succeeded에 도달하고, 완료 후 사이드카가docker ps에서 사라집니다.