컨테이너 보안 · 시크릿 취급 · 실습
환경변수와 파일 마운트, 무엇이 다른가
이 실습은 진짜 VM 에서 돕니다
이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker exec 도 docker logs 도 그대로 동작합니다.
예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라
컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어
보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.
알아 둘 것이 둘 있습니다.
- 처음 뜨는 데 1분 남짓 걸립니다. VM 이 부팅하고 도커를 설치하기
- 브라우저 미리보기가 없습니다. VM 으로 들어오는 연결은 채점 포트
때문입니다. 파드 실습(보통 40초)보다 느립니다.
하나만 열려 있습니다. 웹 서버를 띄웠다면 VM 안에서 curl 로 확인하세요.
목표
같은 시크릿을 환경변수와 파일 마운트 두 방식으로 전달해 보고, docker inspect
노출 여부와 재시작 없는 로테이션 가능 여부를 직접 재어 비교표로 정리합니다.
마지막에는 간단한 시크릿 탐지 스크립트를 작성합니다.
왜 중요한가
환경변수는 저장 위치가 아니라 전달 방식입니다. /proc/<pid>/environ 은 프로세스가
사는 동안 계속 읽히고, 컨테이너 환경변수는 데몬에 접근할 수 있는 누구에게나docker inspect 로 그대로 보입니다. 그래서 ".env 를 로드하고 지웠으니 괜찮다"는
안심은 근거가 없습니다. 더 중요한 것은 로테이션입니다. 환경변수는 프로세스 시작
시점에 고정되므로 값을 바꾸려면 반드시 재시작이 필요하고, 파일 마운트는 같은
inode 를 덮어쓰면 재시작 없이 새 값이 보입니다. 이 차이가 사고 대응 시간을
가릅니다 — 자격증명이 공개됐다고 가정할 때 폐기하고 교체해 서비스를 정상화하는
데 몇 분이 걸리는지가 곧 그 팀의 시크릿 관리 수준입니다.
단계
1. /root/sec3 디렉터리를 만들고 /root/sec3/app.env 에 API_KEY=labhub-env-key-v1 한 줄을 적은 뒤, 파일 권한을 600 으로 바꿉니다.
2. alpine:3.20 으로 sec3-env 컨테이너를 --env-file /root/sec3/app.env 를 써서 백그라운드 실행합니다. 컨테이너의 API_KEY 가 파일의 값과 같아야 합니다.
3. docker inspect sec3-env 로 읽어낸 API_KEY 값을 그대로 /root/sec3/leak-proof.txt 에 저장합니다.
4. /root/sec3/secret.txt 에 labhub-file-key-v1 을 적고, 그 파일을 sec3-file 컨테이너의 /run/secrets/api_key 경로에 읽기 전용으로 바인드 마운트해 백그라운드 실행합니다. 마운트 원본은 정확히 /root/sec3/secret.txt 여야 합니다.
5. sec3-file 컨테이너의 환경변수에 API_KEY 도, 시크릿 값 자체도 들어 있지 않아야 합니다.
6. 컨테이너를 재시작하지 않은 채 /root/sec3/secret.txt 의 내용을 labhub-rotated-v2 로 덮어씁니다. sec3-file 이 새 값을 보게 되고, sec3-env 의 환경변수 값은 옛 값 그대로여야 합니다. 그리고 /root/sec3/rotate.md 에 어느 방식이 재시작을 필요로 하는지 결론을 적습니다(재시작 또는 restart 라는 말이 들어가야 합니다).
7. 실행 권한이 있는 /root/sec3/find-secrets.sh 를 작성합니다. 첫 번째 인자로 받은 디렉터리를 뒤져서 AKIA 로 시작하는 액세스 키나 PRIVATE KEY 블록이 있으면 0 이 아닌 종료코드로 끝나면서 어느 파일에서 찾았는지 경로를 출력하고, 아무것도 없으면 종료코드 0 으로 끝나야 합니다.
8. /root/sec3/secrets.md 에 환경변수 방식과 파일 마운트 방식을 비교하는 내용을 적고, 다음 네 줄을 정확히 이 형식으로 포함시킵니다.
env_visible_in_inspect=yesmount_visible_in_inspect=noenv_needs_restart=yesmount_needs_restart=no
참고
- 파일 권한 변경은
chmod 600 <파일>, 확인은stat -c %a <파일>입니다. - 파일 하나를 읽기 전용으로 붙이려면
-v /호스트/경로:/컨테이너/경로:ro형식을 씁니다. - 컨테이너 환경변수 확인은
docker inspect <이름> | jq -r '.[0].Config.Env[]'입니다. - 6단계에서 파일을 덮어쓸 때는
printf '%s' labhub-rotated-v2 > /root/sec3/secret.txt처럼 제자리 덮어쓰기를 쓰세요. - 흔한 실수 1: 6단계에서
sed -i나 파일을 지웠다 다시 만드는 방식을 쓰면 inode 가 바뀌어 컨테이너가 옛 값을 계속 봅니다. - 흔한 실수 2: 4단계에서
sec3-file에-e API_KEY=...를 함께 주면 5단계가 실패합니다. 파일 마운트로 바꿨으면 환경변수는 빼세요. - 흔한 실수 3: 6단계에서
sec3-env를 다시 만들거나 app.env 를 함께 고치면 대조군이 사라져 실패합니다.sec3-env는 그대로 두세요.
단계 8개
- 시크릿 파일과 권한 600
- env-file 로 주입하기
- 환경변수는 inspect 에 그대로 보인다
- 파일로 마운트하기
- 환경변수에는 남기지 않기
- 재시작 없이 로테이션하기
- 시크릿 탐지 스크립트
- 전달 방식 비교표