콘텐츠 트러스트 샌드박스에서 실습해 보기
콘텐츠 트러스트 샌드박스에서 실습해 보기
이 페이지에서는 트러스트(trust)를 직접 실험해 볼 수 있는 샌드박스 환경을 구성하고 사용하는 방법을 설명드릴게요. 샌드박스 덕분에 실제 운영 중인 이미지에 영향을 주지 않고, 로컬에서 트러스트 관련 작업을 설정하고 테스트할 수 있습니다. 실습을 시작하기 전에 먼저 트러스트 개요를 한번 읽어두시면 훨씬 수월합니다.
출처: 공식문서
본문
사전 준비 사항
이 실습은 Linux 또는 macOS 환경을 기준으로 합니다. 샌드박스는 로컬 머신이나 가상 머신(VM) 어디서든 실행할 수 있으며, 로컬 머신 또는 VM에서 docker 명령어를 실행할 권한이 있어야 합니다.
또한 이 샌드박스는 최신 Docker Engine과 Docker Compose가 설치되어 있어야 합니다. Docker Engine 설치는 지원 플랫폼 목록에서 선택할 수 있고, Docker Compose 설치는 Compose 설치 안내를 참고하세요.
샌드박스에는 무엇이 들어있나요?
평소에 Docker Hub에서 트러스트 기능을 바로 사용한다면 Docker Engine 클라이언트와 Docker Hub 접근 권한만 있으면 됩니다. 하지만 이 샌드박스는 실제 운영 환경과 유사한 트러스트 환경을 흉내 내기 위해 몇 가지 구성 요소를 추가로 설정합니다.
| 컨테이너 | 설명 |
|---|---|
trustsandbox |
최신 Docker Engine과 몇 가지 사전 구성된 인증서가 들어 있는 컨테이너입니다. 이 안에서 docker 클라이언트를 사용해 트러스트 작업을 테스트할 수 있습니다. |
Registry server |
로컬 레지스트리 서비스입니다. |
Notary server |
트러스트 관리를 실제로 처리하는 서비스입니다. |
즉, 여러분이 직접 콘텐츠 트러스트(Notary) 서버와 레지스트리를 실행하게 됩니다. Docker Hub만 사용한다면 이런 구성 요소가 필요 없습니다. Docker Hub에 이미 내장되어 있기 때문이죠. 하지만 샌드박스에서는 운영 환경을 흉내 낸 전체 환경을 직접 구축해 보는 겁니다.
trustsandbox 컨테이너 안에서는 Docker Hub 대신 로컬 레지스트리와 상호작용합니다. 따라서 여러분이 평소에 사용하는 이미지 저장소는 건드리지 않습니다. 실습하는 동안 안전하게 보호되는 거예요.
샌드박스에서 실습할 때는 루트 키와 저장소 키도 생성됩니다. 샌드박스는 모든 키와 파일을 trustsandbox 컨테이너 안에 저장하도록 설정되어 있습니다. 샌드박스에서 만든 키는 실습 전용이므로, 컨테이너를 삭제하면 키도 함께 삭제됩니다.
또한 trustsandbox 컨테이너로 docker-in-docker 이미지를 사용하기 때문에, 실제 Docker 데몬 캐시를 오염시키지 않습니다. 이미지들은 이 컨테이너에 연결된 익명 볼륨에 저장되며, 컨테이너를 삭제한 뒤 함께 정리할 수 있습니다.
샌드박스 구축하기
이번에는 Docker Compose를 사용해 trustsandbox 컨테이너, Notary 서버, Registry 서버를 어떻게 설정하고 연결할지 지정해 보겠습니다.
trustsandbox디렉터리를 새로 만들고 이동합니다.
$ mkdir trustsandbox
$ cd trustsandbox
- 좋아하는 편집기로
compose.yaml파일을 만듭니다. 예를 들어 vim을 사용한다면 이렇게요.
$ touch compose.yaml
$ vim compose.yaml
- 새 파일에 다음 내용을 추가합니다.
version: "2"
services:
notaryserver:
image: dockersecurity/notary_autobuilds:server-v0.5.1
volumes:
- notarycerts:/var/lib/notary/fixtures
networks:
- sandbox
environment:
- NOTARY_SERVER_STORAGE_TYPE=memory
- NOTARY_SERVER_TRUST_SERVICE_TYPE=local
sandboxregistry:
image: registry:3
networks:
- sandbox
container_name: sandboxregistry
trustsandbox:
image: docker:dind
networks:
- sandbox
volumes:
- notarycerts:/notarycerts
privileged: true
container_name: trustsandbox
entrypoint: ""
command: |-
sh -c '
cp /notarycerts/root-ca.crt /usr/local/share/ca-certificates/root-ca.crt &&
update-ca-certificates &&
dockerd-entrypoint.sh --insecure-registry sandboxregistry:5000'
volumes:
notarycerts:
external: false
networks:
sandbox:
external: false
-
파일을 저장하고 닫습니다.
-
로컬 시스템에서 컨테이너들을 실행합니다.
$ docker compose up -d
처음 실행할 때는 docker-in-docker, Notary 서버, 레지스트리 이미지를 Docker Hub에서 내려받습니다.
샌드박스에서 실습하기
이제 모든 준비가 끝났으니 trustsandbox 컨테이너 안으로 들어가서 Docker 콘텐츠 트러스트를 테스트해 볼 수 있습니다. 호스트 머신에서 다음 명령어로 trustsandbox 컨테이너 안에 셸을 얻습니다.
$ docker container exec -it trustsandbox sh
/ #
트러스트 작업 테스트하기
이제 trustsandbox 컨테이너 안에서 몇 가지 이미지를 내려받아 보겠습니다.
- 테스트에 사용할
docker이미지를 내려받습니다.
/ # docker pull docker/trusttest
docker pull docker/trusttest
Using default tag: latest
latest: Pulling from docker/trusttest
b3dbab3810fc: Pull complete
a9539b34a6ab: Pull complete
Digest: sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a
Status: Downloaded newer image for docker/trusttest:latest
- 샌드박스 레지스트리로 푸시할 수 있도록 태그를 지정합니다.
/ # docker tag docker/trusttest sandboxregistry:5000/test/trusttest:latest
- 콘텐츠 트러스트를 활성화합니다.
/ # export DOCKER_CONTENT_TRUST=1
- 트러스트 서버를 지정합니다.
/ # export DOCKER_CONTENT_TRUST_SERVER=https://notaryserver:4443
이 단계는 샌드박스가 자체 서버를 사용하기 때문에 필요한 것입니다. 보통 Docker Public Hub를 사용할 때는 이 단계가 필요 없습니다.
- 테스트 이미지를 내려받아 봅니다.
/ # docker pull sandboxregistry:5000/test/trusttest
Using default tag: latest
Error: remote trust data does not exist for sandboxregistry:5000/test/trusttest: notaryserver:4443 does not have trust data for sandboxregistry:5000/test/trusttest
아직 notaryserver에 이 콘텐츠에 대한 트러스트 데이터가 없기 때문에 오류가 발생합니다.
- 트러스트된 이미지를 푸시하고 서명합니다.
/ # docker push sandboxregistry:5000/test/trusttest:latest
The push refers to a repository [sandboxregistry:5000/test/trusttest]
5f70bf18a086: Pushed
c22f7bc058a9: Pushed
latest: digest: sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926 size: 734
Signing and pushing trust metadata
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID 27ec255:
Repeat passphrase for new root key with ID 27ec255:
Enter passphrase for new repository key with ID 58233f9 (sandboxregistry:5000/test/trusttest):
Repeat passphrase for new repository key with ID 58233f9 (sandboxregistry:5000/test/trusttest):
Finished initializing "sandboxregistry:5000/test/trusttest"
Successfully signed "sandboxregistry:5000/test/trusttest":latest
이 저장소를 처음 푸시하는 것이므로 Docker가 새로운 루트 키와 저장소 키를 생성하고, 키를 암호화할 passphrase를 입력하라고 요청합니다. 이후에 다시 푸시할 때는 저장소 키를 복호화하고 다시 서명하기 위해 저장소 passphrase만 요청합니다.
- 방금 푸시한 이미지를 다시 내려받아 보겠습니다.
/ # docker pull sandboxregistry:5000/test/trusttest
Using default tag: latest
Pull (1 of 1): sandboxregistry:5000/test/trusttest:latest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926: Pulling from test/trusttest
Digest: sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
Status: Downloaded newer image for sandboxregistry:5000/test/trusttest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
Tagging sandboxregistry:5000/test/trusttest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926 as sandboxregistry:5000 test/trusttest:latest
악성 이미지로 테스트하기
데이터가 손상되었을 때 트러스트를 활성화한 상태로 pull을 시도하면 어떤 일이 벌어질까요? 이번에는 sandboxregistry 컨테이너 안으로 들어가 데이터를 조작한 다음, 다시 pull을 시도해 보겠습니다.
-
trustsandbox셸과 컨테이너는 계속 실행된 상태로 둡니다. -
호스트에서 새 대화형 터미널을 열고
sandboxregistry컨테이너 안으로 셸을 얻습니다.
$ docker container exec -it sandboxregistry bash
root@65084fc6f047:/#
- 방금 푸시한
test/trusttest이미지의 레이어 목록을 확인합니다.
root@65084fc6f047:/# ls -l /var/lib/registry/docker/registry/v2/repositories/test/trusttest/_layers/sha256
total 12
drwxr-xr-x 2 root root 4096 Jun 10 17:26 a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
drwxr-xr-x 2 root root 4096 Jun 10 17:26 aac0c133338db2b18ff054943cee3267fe50c75cdee969aed88b1992539ed042
drwxr-xr-x 2 root root 4096 Jun 10 17:26 cc7629d1331a7362b5e5126beb5bf15ca0bf67eb41eab994c719a45de53255cd
- 그중 하나의 레이어에 대한 레지스트리 저장소로 이동합니다. 이 경로는 다른 디렉터리에 있습니다.
root@65084fc6f047:/# cd /var/lib/registry/docker/registry/v2/blobs/sha256/aa/aac0c133338db2b18ff054943cee3267fe50c75cdee969aed88b1992539ed042
trusttest레이어 중 하나에 악성 데이터를 추가합니다.
root@65084fc6f047:/# echo "Malicious data" > data
-
다시
trustsandbox터미널로 돌아갑니다. -
trusttest이미지 목록을 확인합니다.
/ # docker image ls | grep trusttest
REPOSITORY TAG IMAGE ID CREATED SIZE
docker/trusttest latest cc7629d1331a 11 months ago 5.025 MB
sandboxregistry:5000/test/trusttest latest cc7629d1331a 11 months ago 5.025 MB
sandboxregistry:5000/test/trusttest <none> cc7629d1331a 11 months ago 5.025 MB
- 로컬 캐시에서
trusttest:latest이미지를 삭제합니다.
/ # docker image rm -f cc7629d1331a
Untagged: docker/trusttest:latest
Untagged: sandboxregistry:5000/test/trusttest:latest
Untagged: sandboxregistry:5000/test/trusttest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
Deleted: sha256:cc7629d1331a7362b5e5126beb5bf15ca0bf67eb41eab994c719a45de53255cd
Deleted: sha256:2a1f6535dc6816ffadcdbe20590045e6cbf048d63fd4cc753a684c9bc01abeea
Deleted: sha256:c22f7bc058a9a8ffeb32989b5d3338787e73855bf224af7aa162823da015d44c
Docker는 이미 캐시된 이미지는 다시 내려받지 않습니다. 하지만 지금은 조작된 이미지를 레지스트리에서 내려받으려 시도하고, 그것이 유효하지 않기 때문에 거부되는 과정을 확인하려는 것입니다.
- 이미지를 다시 pull 합니다. 캐시에 없으므로 레지스트리에서 이미지를 내려받게 됩니다.
/ # docker pull sandboxregistry:5000/test/trusttest
Using default tag: latest
Pull (1 of 1): sandboxregistry:5000/test/trusttest:latest@sha256:35d5bc26fd358da8320c137784fe590d8fcf9417263ef261653e8e1c7f15672e
sha256:35d5bc26fd358da8320c137784fe590d8fcf9417263ef261653e8e1c7f15672e: Pulling from test/trusttest
aac0c133338d: Retrying in 5 seconds
a3ed95caeb02: Download complete
error pulling image configuration: unexpected EOF
트러스트 시스템이 이미지를 검증할 수 없었기 때문에 pull이 완료되지 않았습니다.
샌드박스에서 더 실습해 보기
이제 로컬 시스템에 완전한 Docker 콘텐츠 트러스트 샌드박스가 준비되었습니다. 자유롭게 이것저것 만져보면서 어떻게 동작하는지 확인해 보세요. Docker에서 보안 문제를 발견하시면 [email protected]으로 메일을 보내주시기 바랍니다.
샌드박스 정리하기
실습이 끝났다면, 시작했던 모든 서비스와 생성된 익명 볼륨을 정리하고 싶을 겁니다. Docker Compose 파일을 만든 디렉터리에서 다음 명령어를 실행하면 됩니다.
$ docker compose down -v