시크릿 확산: 유출된 412개의 토큰을 해결한 방법
3월 3일 오전 2시 13분, CI 파이프라인이 실패했습니다. 37개의 저장소에서 412개의 유출된 API 토큰을 발견했습니다. 이 오류로 인해 잠재적인 침해 비용 120만 달러가 위험에 처했습니다.
대부분의 팀은 Vault가 모든 것을 해결해 줄 것이라고 생각합니다. 하지만 실제로 Vault는 지연 시간(latency) 측면에서 단일 장애점(single point of failure)이 될 수 있습니다. 토큰이 Vault 외부에서 관리될 때, 하드코딩된 값이나 환경 변수를 사용하게 됩니다. 이러한 대체 방식(fallbacks)은 감사 로그(audit logs)에 나타나지 않습니다.
우리의 지표는 이러한 확산의 비용을 보여주었습니다:
- 일반적인 시크릿 조회: 요청당 48ms.
- 유출 발생 시: 요청당 187ms.
빌드 에이전트는 멀리 떨어진 Vault 클러스터에서 작업당 12개의 토큰을 가져왔습니다. 이로 인해 타임아웃이 발생했고 개발자들은 수동으로 변경 사항을 롤백해야 했습니다. 지연 시간은 단순히 프로세스가 느려지는 문제가 아닙니다. 이는 클라우드 비용을 부풀리고 개발 속도를 늦추는 비용 센터(cost center)입니다.
스테이징 저장소에서 유출된 AWS 키 하나가 공격자에게 이용될 경우 시간당 120달러의 비용이 발생할 수 있습니다. 단 한 시간의 오용 비용이 분기별 보안 감사 비용보다 더 큽니다.
정적 스캐너(Static scanners)는 우리를 실망시켰습니다. 토큰의 78%를 놓쳤습니다. 왜일까요? 해당 토큰들이 소스 코드가 아닌 빌드 아티팩트(build artifacts) 내에서 실시간으로 생성되었기 때문입니다. 하나의 GitHub Actions 단계에서 토큰을 Docker 레이어에 기록했습니다. 스캐너는 아무것도 발견하지 못했지만, 그 토큰은 몇 주 동안 우리 레지스트리에 남아 있었습니다.
단순한 정적 검사가 아닌 런타임 가시성(runtime visibility)이 필요합니다.
이를 해결하기 위해 Lambda 엔진을 구축했습니다. 이 엔진은 CloudTrail을 모니터링하여 새로운 시크릿을 감지하고 이를 Vault와 비교합니다. 새로운 워크플로우는 다음과 같습니다:
- 웹훅을 통해 시크릿 감지.
- Vault에서 메타데이터 쿼리.
- 제공자 API를 통해 토큰 무효화.
- 파일에서 시크릿을 제거하기 위한 PR 생성.
- CI를 통과하면 PR 자동 병합.
이 엔진은 27분 만
