CI/CD 시크릿 관리는 저장 위치보다 회전 속도가 중요하다
깃 저장소, 액션 로그, 배포 환경에 흩어진 시크릿을 줄이고 짧은 수명 토큰으로 전환하는 방법을 설명한다. CI/CD·Secrets·DevSecOps 관점에서 기본 개념부터 구현 순서, 검증 방법, 문제가 생겼을 때 되돌리는 절차까지 설명한다.
핵심 요약
CI/CD 시크릿은 안전한 저장소에 넣는 것만으로 충분하지 않다. 노출됐다고 가정했을 때 몇 분 안에 폐기할 수 있는지, 어떤 파이프라인과 환경이 영향을 받는지, 짧은 수명 자격 증명으로 대체할 수 있는지가 운영 성숙도를 결정한다.
CI/CD 파이프라인은 소스코드 저장소, 패키지 레지스트리, 클라우드, 컨테이너 레지스트리, 배포 대상에 동시에 접근한다. 이 연결을 위해 만든 토큰 하나가 장기간 유지되고 여러 저장소에서 공유되면, 워크플로 한 곳의 실수가 운영 환경 전체로 번질 수 있다.
시크릿 관리 논의는 보통 “어디에 저장할 것인가”에서 시작한다. 저장소의 암호화와 접근 제어는 중요하지만 그것만으로 노출을 막을 수는 없다.
로그 출력, 디버그 아티팩트, 빌드 캐시, 포크 PR, 자체 호스팅 러너, 잘못된 셸 인용, 외부 액션이 시크릿을 읽을 수 있다. 따라서 목표는 완벽하게 숨기는 것이 아니라 필요한 순간에 최소 권한으로 발급하고, 짧게 쓰고, 빠르게 폐기하는 것이어야 한다.
먼저 시크릿이 들어오는 모든 경로를 그린다
인벤토리는 비밀값 자체를 수집하는 작업이 아니다. 식별자, 소유자, 사용처, 권한, 수명, 회전 방법을 기록한다.
| 위치 | 흔한 예 | 확인할 질문 |
|---|---|---|
| 저장소 설정 | 저장소·조직 시크릿 | 어떤 워크플로가 읽을 수 있나 |
| CI 변수 | 보호 변수, 환경 변수 | 브랜치·환경 범위가 제한됐나 |
| 워크플로 파일 | 하드코딩 값, 기본 인자 | 포크와 PR이 실행할 수 있나 |
| 러너 | 로컬 파일, 자격 증명 캐시 | 작업 종료 후 남는가 |
| 빌드 | 이미지 레이어, 빌드 인자 | 최종 이미지와 캐시에 포함되나 |
| 로그·아티팩트 | 디버그 출력, 환경 덤프 | 누가 얼마나 오래 열람하나 |
| 배포 환경 | ConfigMap, 인스턴스 변수 | 런타임 신원으로 바꿀 수 있나 |
| 외부 서비스 | 레지스트리·SaaS 토큰 | 폐기 API와 감사 로그가 있나 |
각 항목에 credential_id, 소유 팀, 발급자, 권한 범위, 사용 저장소, 사용 환경, 마지막 사용, 만료일, 회전 런북을 붙인다. “공용 배포 키”처럼 소유자와 사용처가 불분명한 항목부터 줄인다.
장기 키보다 워크로드 신원을 우선한다
가능한 경우 CI 시스템이 외부 서비스에 자신의 워크로드 신원을 증명하고 짧은 수명 토큰을 받도록 한다. 예를 들어 GitHub Actions는 OIDC 토큰으로 클라우드 역할을 요청할 수 있다. 그러면 장기 클라우드 접근 키를 저장소 시크릿으로 보관하지 않아도 된다.
짧은 수명 자격 증명의 설계 항목은 다음과 같다.
- 발급 대상 저장소와 조직
- 허용 브랜치·태그·환경
- 워크플로 또는 작업 식별 조건
- 대상 클라우드 계정과 역할
- 토큰 수명과 재발급 조건
- 승인된 배포 환경과 보호 규칙
- 발급·거부·사용 감사 로그
OIDC를 도입했다고 자동으로 최소 권한이 되는 것은 아니다. 신뢰 정책이 모든 저장소, 모든 브랜치, 모든 워크플로를 허용하면 장기 키 하나를 광범위한 연합 신뢰로 바꾼 것뿐이다. 배포 단위와 환경을 조건으로 좁힌다.
시크릿 범위는 네 단계로 줄인다
- 조직보다 저장소: 여러 저장소가 정말 같은 자격 증명을 써야 하는지 확인한다.
- 저장소보다 환경: 개발·스테이징·운영 자격 증명을 분리한다.
- 환경보다 작업: 빌드 작업은 배포 권한을 가지지 않게 한다.
- 작업보다 단계: 시크릿이 필요한 명령에만 전달하고 전체 프로세스 환경에 노출하지 않는다.
읽기와 쓰기 권한도 나눈다. 패키지 다운로드 토큰이 게시 권한을 가질 이유가 없고, 이미지 푸시 작업이 운영 클러스터 관리자 권한을 가질 이유가 없다. SLSA 프로비넌스로 빌드 산출물 신뢰를 증명하는 법의 출처·권한 경계와 함께 검토한다.
노출되기 쉬운 실패 모드
포크 PR과 신뢰하지 않는 코드
외부 기여자의 PR은 공격자가 작성한 코드라고 가정한다. 테스트 스크립트, 패키지 설치 후크, 빌드 도구가 환경 변수를 읽고 외부로 전송할 수 있다. 시크릿이 필요한 작업과 신뢰하지 않는 코드를 실행하는 작업을 분리하고, PR 이벤트 유형과 체크아웃 대상이 무엇인지 검토한다.
로그 마스킹에 대한 과신
CI의 마스킹 기능은 등록된 문자열과 정확히 일치할 때만 가릴 수 있다. 인코딩, 분할 출력, 일부 문자열, JSON 변환, 파생 토큰은 남을 수 있다. set -x, 전체 환경 출력, HTTP 디버그, 오류 객체 직렬화를 운영 워크플로에서 금지하거나 제한한다.
자체 호스팅 러너 잔존
작업 공간, 도커 레이어, 패키지 캐시, 프로세스, 임시 파일에 시크릿이 남을 수 있다. 신뢰 수준이 다른 저장소가 같은 러너를 공유하면 후속 작업이 잔존 데이터를 읽을 수 있다. 고위험 배포는 작업마다 새로 만드는 일회성 러너를 우선하고, 네트워크 목적지와 인스턴스 역할도 제한한다.
빌드 이미지와 아티팩트 포함
ARG나 환경 변수로 전달한 값이 이미지 히스토리와 레이어에 남을 수 있다. 인증 파일을 복사한 뒤 삭제해도 이전 레이어에는 존재할 수 있다. 빌드 시스템의 전용 secret mount 기능을 사용하고 최종 이미지, SBOM, 캐시, 아티팩트를 검사한다.
공용 봇 계정과 토큰 공유
여러 팀이 하나의 봇 토큰을 쓰면 사용자를 추적하기 어렵고 회전 영향이 커진다. 서비스·환경별 신원을 만들고 사람이 쓰는 계정과 분리한다. 토큰 이름에 소유 팀과 목적이 드러나게 하되 비밀값은 넣지 않는다.
회전 가능성을 먼저 시험한다
시크릿을 안전하게 저장했는지보다 바꿔도 배포가 계속되는지를 확인해야 한다. 회전 리허설은 다음 순서로 진행한다.
- 시크릿 사용처와 마지막 사용 시간을 조회한다.
- 새 자격 증명을 발급하고 최소 권한을 적용한다.
- 비운영 환경에서 새 값을 사용해 읽기·쓰기 동작을 검증한다.
- 운영 파이프라인을 새 값으로 전환한다.
- 배포 성공, 레지스트리 접근, 클라우드 감사 로그를 확인한다.
- 구 자격 증명을 폐기하거나 비활성화한다.
- 의도적으로 구 값으로 작업해 실패하는지 확인한다.
- 인벤토리, 런북, 다음 회전일을 갱신한다.
서비스가 두 키를 동시에 허용하지 않으면 준비-전환-폐기 단계를 더 짧게 나누고 서비스 특성에 맞는 임시 호환 절차를 적용한다. 회전이 수동 연락과 기억에 의존하면 사고 때 속도가 나오지 않는다.
노출 사고의 첫 대응
깃 기록에서 문자열을 지우는 것보다 자격 증명을 먼저 폐기한다. 공개된 키는 이미 복제됐다고 가정한다.
1. 영향 자격 증명을 비활성화하거나 권한을 제거한다.
2. 동일 값과 파생 자격 증명의 사용처를 확인한다.
3. 새 자격 증명을 최소 권한으로 발급한다.
4. 감사 로그에서 발급 전후의 비정상 사용을 조사한다.
5. 워크플로·로그·아티팩트·캐시에서 노출 경로를 제거한다.
6. 저장소 기록 정리는 폐기 이후에 수행한다.
7. 탐지 규칙과 재발 방지 테스트를 추가한다.
운영 배포가 멈출 수 있다는 이유로 구 키를 유지하려면 보안 책임자와 서비스 소유자가 시간 제한 예외를 승인해야 한다. 권한 축소, 네트워크 제한, 추가 모니터링 같은 보완 통제를 붙이고 만료 시 자동 차단한다.
탐지 신호
- 만료일이 없거나 90일 이상 사용된 장기 자격 증명
- 여러 저장소·환경에서 동일한
credential_id사용 - 평소와 다른 저장소·브랜치·러너에서 토큰 사용
- 배포 시간대 밖의 레지스트리 푸시나 클라우드 변경
- 새 국가·네트워크·사용자 에이전트에서 API 호출
- 시크릿 접근 후 외부 네트워크 요청 증가
- 로그 마스킹 경고, 환경 덤프, 디버그 모드 활성화
- 폐기된 자격 증명으로 반복되는 인증 실패
발급자 감사 로그와 CI 실행 ID를 연결하면 어떤 워크플로가 어떤 권한을 사용했는지 추적하기 쉽다. 토큰 원문은 로그에 남기지 않고 자격 증명 식별자와 역할, 저장소, 작업 ID를 남긴다.
운영 지표
저장된 시크릿 개수만 줄이는 것은 충분하지 않다. 다음 지표를 함께 본다.
| 지표 | 의미 |
|---|---|
| 장기 자격 증명 수 | OIDC·워크로드 신원 전환 진척 |
| 평균·최대 자격 증명 수명 | 노출 시 피해 지속 시간 |
| 회전 완료 시간 | 실제 사고 대응 가능성 |
| 소유자 없는 시크릿 비율 | 책임 경계 공백 |
| 다중 환경 공유 비율 | 피해 범위와 결합도 |
| 폐기 후 사용 시도 | 숨은 의존성과 악용 가능성 |
| 로그·아티팩트 노출 건수 | 파이프라인 위생 상태 |
월별로 가장 오래된 자격 증명과 가장 넓은 권한을 가진 항목을 리뷰한다. 목표는 일괄적인 주기 회전보다 장기 키 제거와 자동 폐기 가능성 확대다.
배포 파이프라인 체크리스트
- 저장소·조직·러너·빌드·아티팩트의 시크릿 인벤토리가 있다.
- 개발·스테이징·운영 자격 증명이 분리됐다.
- 빌드 작업과 배포 작업의 권한이 다르다.
- 가능한 외부 서비스는 OIDC 또는 워크로드 신원을 사용한다.
- 포크 PR과 신뢰하지 않는 코드는 시크릿 없는 작업에서 실행된다.
- 자체 호스팅 러너는 신뢰 경계별로 분리되고 작업 후 초기화된다.
- 로그, 이미지 레이어, 캐시, 아티팩트에 대한 누출 검사가 있다.
- 모든 장기 자격 증명에 소유자, 만료일, 폐기 방법이 있다.
- 분기마다 실제 회전과 구 키 거부 테스트를 수행한다.
- 노출 사고 런북이 보안팀과 개발팀 모두에게 접근 가능하다.
참고 기준
- OWASP Secrets Management Cheat Sheet
- GitHub Docs: OpenID Connect
- GitHub Docs: Security hardening for GitHub Actions
- NIST SP 800-218: Secure Software Development Framework
- SLSA Specification
CI/CD 시크릿 관리의 핵심은 가장 좋은 금고가 아니라 가장 짧은 수명과 가장 작은 권한이다. 워크로드 신원으로 장기 키를 없애고, 환경·작업별 범위를 줄이며, 실제 회전과 폐기를 반복해서 시험하면 파이프라인 침해가 운영 전체로 확산되는 시간을 줄일 수 있다.
전체 댓글 0개