11.6. 보안 모델¶
Backend.AI GO의 컨테이너 실행은 심층 방어(defense-in-depth) 보안 모델로 설계되어, 서로 독립적인 여러 레이어가 함께 작동하면서 컨테이너를 명확히 정해진 경계 안에 묶어 둡니다.
보안 레이어¶
flowchart TD
REQ[컨테이너 실행 요청]
L1["레이어 1: 입력 검증\n(ID/이름/태그 검사)"]
L2["레이어 2: 마운트 허용 목록\n(경로 정규화 + 허용 목록 확인)"]
L3["레이어 3: 환경 변수 검사\n(승인된 환경 변수만 통과)"]
L4["레이어 4: 자격증명 프록시\n(실제 API 키가 컨테이너에 절대 유입되지 않음)"]
L5["레이어 5: IPC 권한\n(그룹 범위 전송/작업 권한)"]
L6["레이어 6: 보안 감사\n(실행 중인 컨테이너 주기적 감사)"]
CONT[컨테이너 실행]
REQ --> L1 --> L2 --> L3 --> L4 --> L5 --> CONT --> L6 레이어 1: 입력 검증¶
모든 컨테이너 식별자, 이미지 태그, 빌드 컨텍스트는 인수 주입 공격을 막기 위해 사용 전에 검증을 거칩니다.
컨테이너 ID와 이름¶
컨테이너 이름은 다음 조건을 만족해야 합니다:
- 비어 있지 않을 것
-로 시작하지 않을 것 (플래그로 해석되기 때문)- 영숫자와
_,.,-,:,/만 포함할 것
이미지 태그¶
이미지 태그는 다음 조건을 만족해야 합니다:
- 비어 있지 않을 것
-로 시작하지 않을 것[registry/]name[:tag][@digest]형식을 따를 것
추가 인수 차단 목록¶
다음과 같은 위험한 Docker 플래그는 extra_args를 통해 전달할 수 없습니다:
| 차단된 플래그 | 이유 |
|---|---|
--privileged | 호스트에 루트 수준 접근 권한 부여 |
--cap-add | Linux 기능 추가 |
--security-opt | seccomp/AppArmor 프로필 수정 |
--device | 호스트 장치 노출 |
--pid=host | 호스트 PID 네임스페이스 공유 |
--network=host | 호스트 네트워크 스택 공유 |
--userns=host | 사용자 네임스페이스 격리 비활성화 |
--ipc=host | 호스트 IPC 네임스페이스 공유 |
레이어 2: 마운트 보안¶
마운트 허용 목록은 파일시스템 접근에 기본 거부(deny-by-default) 정책을 적용합니다.
검증 단계¶
-
심볼릭 링크 해석: 호스트 경로의 심볼릭 링크를 모두 풀어 정규화해, 심볼릭 링크를 통한 경로 우회를 막습니다.
-
차단 패턴 확인: 경로의 모든 구성 요소를 차단 패턴 목록과 대조합니다 (대소문자 구분 없음):
패턴 보호 대상 .sshSSH 개인 키 .gnupgGPG 개인 키 .env시크릿이 포함된 환경 파일 .awsAWS 자격증명 .azureAzure 서비스 주체 자격증명 .gcloudGoogle Cloud 자격증명 .dockerDocker 레지스트리 자격증명 .kubeKubernetes 클러스터 자격증명 -
허용 목록 루트 확인: 정규화된 경로는 명시적으로 허용된 루트 중 적어도 하나의 하위 경로여야 하며, 관리자가 해당 경로를 포함하는 루트를 추가하지 않는 한 어떤 경로도 허용되지 않습니다.
-
컨테이너 경로 검사: 컨테이너 쪽 마운트 경로는
/workspace/extra/{name}으로 제한되며,..이 들어간 경로는 거부됩니다. -
비메인 그룹 강제 읽기 전용: 비메인 그룹의 에이전트는 요청한 모드와 관계없이 항상 읽기 전용 마운트를 받습니다.
실행 전 마운트 검증¶
curl -X POST http://localhost:55765/api/v1/container/mount/validate \
-H "Content-Type: application/json" \
-d '{
"hostPath": "/Users/alice/projects/myapp",
"containerPath": "/workspace/extra/myapp",
"readOnly": true
}'
검증에 성공한 경우의 응답:
{
"allowed": true,
"canonicalHostPath": "/Users/alice/projects/myapp",
"message": "Mount validated successfully"
}
차단된 경우의 응답:
{
"allowed": false,
"canonicalHostPath": "/Users/alice/.ssh",
"message": "Path contains blocked pattern: .ssh"
}
레이어 3: 환경 변수 검사¶
컨테이너는 엄격하게 통제된 환경에서 시작됩니다. 호스트의 환경 변수는 모두 제거되고, 승인된 일부만 그대로 전달되거나 값이 재정의됩니다:
| 변수 | 동작 |
|---|---|
ANTHROPIC_BASE_URL | 호스트에서 전달 (자격증명 프록시를 가리킴) |
ANTHROPIC_API_KEY | 항상 플레이스홀더로 재정의 (CREDENTIAL_PROXY_PLACEHOLDER) |
TZ | 올바른 시간대를 위해 호스트에서 전달 |
그 밖의 환경 변수는 컨테이너 안에서 보이지 않으므로, 호스트의 시크릿이 실수로든 악의적으로든 새어 나갈 길이 없습니다.
레이어 4: 자격증명 프록시¶
자격증명 프록시는 API 키 노출을 막는 주된 장치입니다.
동작 방식¶
sequenceDiagram
participant A as 컨테이너 에이전트
participant P as 자격증명 프록시 (localhost:3001)
participant U as 업스트림 API (api.anthropic.com)
A->>P: POST /v1/messages\nAuthorization: Bearer CREDENTIAL_PROXY_PLACEHOLDER
P->>P: 플레이스홀더 검증
P->>P: 실제 API 키로 대체
P->>U: POST /v1/messages\nAuthorization: Bearer sk-ant-...
U-->>P: 응답
P-->>A: 응답 전달 프록시 모드¶
| 모드 | 대체되는 헤더 |
|---|---|
| API 키 | x-api-key: CREDENTIAL_PROXY_PLACEHOLDER → x-api-key: {real_key} |
| OAuth Bearer | Authorization: Bearer CREDENTIAL_PROXY_PLACEHOLDER → Authorization: Bearer {real_token} |
업스트림 URL 검증¶
업스트림 URL은 등록 시점에 검증됩니다:
- HTTPS를 사용해야 합니다 (
localhost/127.0.0.1은 개발 용도에 한해 HTTP 허용) - 클라우드 메타데이터 엔드포인트(예:
169.254.169.254)는 대상으로 지정할 수 없습니다 - RFC1918 사설 주소도 대상으로 지정할 수 없습니다 (SSRF 공격 방지)
프록시 상태¶
레이어 5: IPC 권한¶
컨테이너는 파일 기반 IPC 채널로 호스트와 통신하는데, IPC 시스템이 그룹 단위 권한을 강제해 그룹 사이의 간섭을 차단합니다.
권한 모델¶
| 작업 | 메인 그룹 | 일반 그룹 |
|---|---|---|
| 임의의 채팅 JID로 메시지 전송 | 허용 | 차단 (자신의 채팅 JID만 가능) |
| 임의의 그룹에 작업 생성 | 허용 | 차단 (자신의 그룹만 가능) |
| 후속 메시지 수신 | 허용 | 허용 |
| 전역 지침 읽기 | 허용 | 허용 |
일반 그룹 컨테이너가 그룹 경계를 넘는 작업을 시도하면 그 시도는 보안 위반으로 기록되고 IPC 명령은 거부됩니다.
보안 이벤트¶
IPC 권한 검사가 일어날 때마다 보안 이벤트가 생성됩니다:
{
"id": "evt-abc123",
"severity": "violation",
"category": "ipc_permission",
"message": "Container 'aigo-squad-grp1-session42' attempted cross-group send to 'tg:9876'. Blocked.",
"containerId": "aigo-squad-grp1-session42",
"groupName": "grp1",
"timestamp": "2026-03-15T10:30:00Z"
}
레이어 6: 보안 감사¶
보안 감사는 120초 간격으로 주기적으로 돌면서, 실행 중인 컨테이너가 예상 구성과 일치하는지 확인합니다.
감사 검사¶
- 환경 변수:
ANTHROPIC_API_KEY가 실제 키가 아니라 플레이스홀더인지 확인 - 마운트 포인트: 마운트가 승인된 목록과 일치하는지 확인
- 새 권한 없음:
no-new-privileges보안 옵션이 설정되어 있는지 확인 (Docker만 해당)
감사 로그¶
보안 이벤트 로그¶
보안 이벤트 로그에는 최근 500개의 보안 이벤트가 보관됩니다:
보안 권장 사항¶
최소 권한 원칙
- 에이전트에게 실제로 필요한 최소한의 호스트 디렉터리만 마운트 허용 목록에 추가하세요.
- 에이전트가 쓸 필요가 없다면 읽기 전용 마운트를 사용하세요.
- 홈 디렉터리 루트(예:
/Users/alice)는 허용 목록에 추가하지 말고, 더 좁은 경로를 구체적으로 지정하세요.
Management API 보호
Management API는 자격증명 매핑을 포함한 모든 컨테이너 구성을 노출합니다. 항상 다음을 지키세요: * 설정 > 고급 > Management API에서 API 키 인증을 활성화하세요. * 원격 접근이 꼭 필요한 경우가 아니라면 Management API를 localhost에만 바인딩하세요 (기본값). * 원격 접근이 필요하다면 TLS를 사용하세요.
감사 로그 보존
보안 이벤트는 인메모리 링 버퍼에 최대 500개까지 보관됩니다. 규정 준수가 필요하다면 감사 로그 엔드포인트로 이벤트를 정기적으로 내보내 영구 로그 관리 시스템에 저장해 두세요.