GitLab Secrets Manager로 CI/CD 시크릿 유출 막기

GitLab의 CI/CD 변수에 시크릿을 넣고 'Mask variable'을 체크해 두셨나요? 로그에 값이 그대로 찍히지 않으면 안전해 보일 수 있는데요. 그러나 마스킹된 변수는 생각만큼 안전하지 않습니다.
마스킹은 등록된 원본 값과 정확히 일치하는 문자열만 가립니다. 따라서 시크릿을 base64로 인코딩해 출력하면 다른 문자열이 되어 그대로 로그에 찍히고, 이를 디코딩하면 원래 시크릿이 드러나죠. 게다가 이 변수는 요청하지 않은 job에도 주어지는데요. CI/CD 변수가 기본적으로 모든 job에 사용 가능하기 때문입니다.
경험 많은 분이라면 여기까지는 이미 아실 겁니다. 많이들 하시는 다음 선택은 전용 Vault를 붙이는 건데요. 시크릿을 CI 설정 밖으로 빼 주지만 인증할 시스템 하나, 유지할 접근 모델 하나, 사고 때 대조할 감사 스트림 하나가 늘어나는 상시 운영 비용이 수반됩니다.
GitLab은 이 번거로움을 해결할 수단으로 최근 Secrets Manager라는 기능을 내놓았습니다. 이 기능은 OpenBao 기반의 시크릿 매니저로, GitLab 19.0(2026년 5월)에서 퍼블릭 베타로 전환됐고요. GA(General Availability)를 앞두고 있습니다. 출시 직후이자 GA 전환을 앞둔 지금은 Secrets Manager 활용을 검토하기에 좋은 시점이죠.
이 글은 CI/CD 시크릿 유출의 양상과 원인을 짚고요. GitLab Secrets Manager의 문제 해결 방식, 유사 도구 비교, 활용법, 유의 사항을 살펴보겠습니다.
시크릿은 어떻게 유출되는가
마스킹이 완벽한 방어가 아니라면, 정작 시크릿은 어디서, 왜 유출되는 걸까요? 유출 지점부터 구조적 원인, 방치 시 위험까지 차례로 알아보겠습니다.
CI/CD 시크릿은 어디서 유출되는가
시크릿이 유출되는 지점은 크게 네 곳입니다.

- 코드와 설정 파일: 시크릿이 유출되는 가장 흔한 출발점입니다. API 키를 소스 코드에 하드코딩하거나
.env파일을 코드와 함께 커밋하면서 시작되죠. 한 번 저장소 이력에 들어가면 이후 파일을 지워도 커밋 기록에는 남아 과거 이력에서 값을 되살릴 수 있습니다. - CI/CD 변수: 코드보다 나아 보이지만 변수 역시 안전한 보관소는 아닙니다. 변수 값은 프로젝트·그룹 설정에 저장되며, 보호 변수로 지정하지 않는 한 보호 브랜치 외 파이프라인에도 그대로 제공되죠. 설정 접근 권한이 있는 사용자가 값을 열람하거나 덮어쓸 수 있고, 값이 모든 job에 주입돼 파이프라인 접근 권한이 있는 누구나 읽을 수 있습니다.
- 로그: Job 로그도 유출 지점입니다. 많은 팀이 'Mask variable'에 기대고, GitLab도 18.3에서 변수 기본값을 Masked로 바꿨는데요. 그러나 마스킹은 정확히 일치하는 문자열만 잡아내기 때문에 스크립트가 값을 base64로 인코딩하거나 다른 방식으로 변형하면 변형된 형태는 가려지지 않습니다.
- 상시·고아 크리덴셜: 시간이 지나면서 쌓이는 위험입니다. CI 변수는 프로젝트 설정에 무기한 읽을 수 있는 상태로 남고, 자동 회전이나 폐기 절차가 없으면 퇴사자나 폐기된 통합의 크리덴셜이 그대로 살아남습니다. 누구의 것인지조차 불분명한 고아 크리덴셜은 공격자에게 ‘유출의 잊힌 출입문’이 됩니다.
왜 이런 일이 반복되는가: 자동화가 만든 구조
이 문제를 개인의 책임으로만 돌리면 핵심을 놓칩니다. 최근 개발 방식이 자동화되면서 시크릿을 많이 만들고, 널리 노출하며, 오래 방치하도록 구조화되고 있는데요. 여기에 빠른 배포가 우선시되면서 문제 구조가 좀처럼 바로잡히지 않고 있습니다.
- 자동화 증가: 시크릿의 절대량이 늘어나는 건 자동화가 증가하고 있기 때문입니다. 마이크로서비스가 서로 통신하고, 파이프라인이 돌고, 외부 통합이 추가될 때마다 새 크리덴셜이 필요한데요. 인증할 대상이 늘면 크리덴셜도 비례해 늘어 사람이 일일이 추적하기 어려울 정도가 될 수 있습니다.
- '보안 < 편의' 도구 기본값: 시크릿이 안전한 자리를 못 찾는 건 도구에 그 자리가 없기 때문입니다. CI 시스템의 변수 기능은 설정값을 편하게 주입하려고 만들어진 것이라 시크릿을 특정 job으로 한정한다는 개념이 설계에 없습니다(환경 스코프가 있으나 이는 환경 단위이지 job 단위가 아닙니다). 게다가 시크릿을 위한 전용 보관소도 기본으로 주어지지 않죠. 안전한 기본 경로가 없으니 사용자가 편의를 택하는 건 부주의가 아니라 도구가 그렇게 유도한 결과입니다.
- 만들기 쉽고 지우기 어려운 크리덴셜: 안 쓰는 크리덴셜이 쌓이는 건 회수를 강제하는 장치가 없기 때문입니다. 발급은 클릭 한 번이면 끝나지만, 회전·폐기·오프보딩을 의무화하거나 자동화하는 장치는 어디에도 걸려 있지 않죠. 따라서 정리할 동력이 생기지 않고, 한번 만든 크리덴셜은 누군가 의식적으로 지우지 않는 한 그대로 남습니다. 앞서 언급한 고아 크리덴셜이 바로 이 비대칭의 산물입니다.
- '보안 < 속도' 우선순위: 이 구조가 교정되지 않는 건 늘 속도가 우선 취급되기 때문입니다. 파이프라인의 존재 이유는 빠른 빌드와 배포이기에 시크릿을 제대로 보관하고 권한을 좁히는 일은 후순위로 밀리기 쉽습니다. 일단 파이프라인을 돌아가게 한 뒤 보안은 나중으로 미뤄지고, 그 나중은 좀처럼 실행되지 않죠.
방치하면 무엇이 문제인가
시크릿 유출 위험을 키우는 구조를 그대로 두면 다음 세 가지 비용을 치러야 할 수 있습니다.

-
직접 침해와 측면 이동: 유출된 시크릿 하나가 인프라 전체의 문제로 확산될 수 있습니다. CI/CD 파이프라인에는 프로덕션을 여는 크리덴셜이 몰려 있어 클라우드 키·레지스트리 토큰·배포 키가 한 러너에 함께 주어집니다. 따라서 러너나 워크플로가 한번 뚫리면 공격자는 그 크리덴셜이 가진 권한을 그대로 물려받을 수 있죠. 공격자는 탈취한 토큰으로 컨테이너 레지스트리를 덮어쓰거나, 클라우드 콘솔로 들어가 스토리지를 털고, 프로덕션을 삭제하거나 랜섬웨어를 심을 수 있습니다.
-
감사와 대응의 실패: 사고가 나도 추적이 어렵습니다. 누가, 언제, 어떤 시크릿을 썼는지 기록이 없으면, 침해 대응 시 그 크리덴셜이 거쳐 간 경로를 CI·시크릿 도구·IdP 로그를 일일이 대조해 손으로 재구성해야 하는데요. 어디까지 노출됐는지 모르니 무엇을 회전하고 무엇을 닫아야 할지도 불확실해 대응은 늦어지고 피해 범위는 넓어질 수 있습니다.
-
국내 규제 증빙의 어려움: 기업에는 규제 부담이 커질 수 있습니다. 특히 금융회사·전자금융업자는 전자금융감독규정에 따라 망분리와 접근통제를, 일일평균 이용자 100만 명 이상인 대규모 개인정보처리자는 개인정보보호법에 따라 망분리를 원칙적으로 적용해야 합니다. 최근 이 망분리 규제는 일괄 의무에서 위험기반으로 옮겨가고 있지만, 고위험 정보 영역에는 여전히 강하게 적용되죠. ISMS·ISMS-P 인증과 개인정보보호법은 공통적으로 '누가·언제·무엇에 접근했는가'의 접속 기록을 요구하고요.
더구나 최근 규제는 세세한 규칙보다 자율보안과 결과 책임을 강조하는 방향이라 사고가 나면 그 책임을 더 무겁게 묻습니다. 시크릿이 변수와 로그로 흩어져 이 기록을 맞추지 못하면 입증 부담은 더 커질 수 있죠. 데이터 주권 때문에 self-managed GitLab을 직접 운영하는 조직이라면, 시크릿 관리가 곧 자체 인프라의 감사·통제 책임으로 직결됩니다.
GitLab Secrets Manager란 무엇인가
지금까지 살펴본 문제는 결국 ‘시크릿을 둘만한 안전한 자리가 없다’로 모입니다. GitLab은 이를 별도 도구가 아니라 플랫폼 안에서 자체 기능으로 해결하는데요. GitLab Secrets Manager가 그 핵심입니다.
정의와 구조
GitLab Secrets Manager는 시크릿을 GitLab 안에 암호화해 저장하고, 파이프라인의 job이 필요할 때만 받아 쓰도록 하는 GitLab 네이티브 시크릿 저장소입니다. 변수가 모든 job에 노출되고, 상시로 남으며, 누가 썼는지 추적되지 않는 구조를 job 단위로 좁히고, 요청할 때만 내주며, 접근을 기록하는 방식으로 바꾸죠.
이 기능의 기반은 OpenBao입니다. OpenBao는 HashiCorp Vault에서 갈라져 나온 오픈 소스 시크릿 관리 솔루션인데요. GitLab Secrets Manager는 검증된 Vault의 모델을 따르되, 시크릿을 GitLab 밖의 별도 시스템이 아니라 기존 프로젝트·그룹 구조 안에 둡니다. 따라서 권한과 격리 경계를 그대로 물려받고, 별도 Vault를 따로 세워 인증·접근 모델·감사를 이중으로 운영할 필요가 없죠.
현재 GitLab Secrets Manager는 Premium·Ultimate 사용자를 대상으로 한 퍼블릭 베타고요. GA를 앞두고 있어 앞으로 기능이 더 안정화될 거로 예상됩니다.
GitLab Secrets Manager는 어떻게 동작하는가
GitLab Secrets Manager의 동작 핵심은 'job이 요청할 때만, 신원을 증명하고 받아온다'는 것입니다. 변수처럼 미리 모든 job에 뿌려 두는 게 아니라, 필요한 job이 그 순간에 자기 자격을 증명하고 해당 시크릿만 가져갑니다. 동작 흐름은 이렇습니다.

- 기능 활성화: 프로젝트나 그룹에서 Secrets Manager를 켜면 전용 OpenBao 저장소가 프로비저닝되고, 이때부터 등록되는 시크릿은 암호화되어 저장됩니다.
- 시크릿 선언: 해당 시크릿이 필요한 job에서만
.gitlab-ci.yml에secrets:와gitlab_secrets_manager키워드로 어떤 시크릿을 쓸지 명시합니다. 기본적으로 항상 모든 job에 주어지는 변수와 달리 시크릿은 job이 명시적으로 요청해야만 받습니다. - 신원 증명과 수령: 파이프라인이 돌면 러너(19.0 이상)가 그 job의 파이프라인 신원(JWT)으로 OpenBao에 인증하고, 그 job이 명시적으로 요청한 시크릿만 받아옵니다. 요청하지 않은 시크릿에는 접근하지 못합니다.
- 주입과 폐기: 받아온 시크릿은 기본적으로 값 자체가 아니라 임시 파일의 경로를 환경 변수로 넘기고, job이 끝나면 폐기됩니다. 값이 로그에 출력되면
[MASKED]로 대체되긴 하지만, 이 마스킹은 변수와 동일한 메커니즘이라 같은 한계(base64 등으로 변형 시 우회)를 가집니다. Secrets Manager의 핵심 방어는 마스킹이 아니라 애초에 그 job만·그 실행 동안만 시크릿을 갖게 하는 범위 축소와 미잔존입니다.
GitLab Secrets Manager의 핵심 특징
GitLab Secrets Manager의 특징은 네 가지입니다. 가장 큰 차이인 거버넌스부터 짚고, 나머지 셋이 어떻게 문제를 푸는지 살펴보겠습니다.
1. 거버넌스를 새로 만들지 않습니다. 기존 그룹·프로젝트 구조를 시크릿 격리 경계로 그대로 쓰기에 따로 만들고 유지할 접근 모델이 없습니다. 별도 시크릿 매니저라면 GitLab에 이미 모델링한 팀·권한 경계를 시크릿 도구에 다시 구성하고, 사람이 들어오고 역할이 바뀌고 떠날 때마다 양쪽을 동기화해야 하는데요. 두 시스템이 어긋나는 순간은 '상시·고아 크리덴셜'이 생기는 지점이죠. Secrets Manager는 그 병행 자체를 없애고, 권한도 코드와 똑같은 통제로 사용자·그룹·역할별 read/write/delete를 부여합니다.
2. 한 곳이 뚫려도 위험이 확산되지 않습니다. Job이 요청한 시크릿만, 그 job에만 주어지기에 침해 반경이 좁습니다. 변수는 하나가 모든 job에 노출돼 한 job이 뚫리면 그 파이프라인의 모든 시크릿이 함께 위험해지지만, Secrets Manager는 각 시크릿을 필요한 job으로 한정하죠. 게다가 시크릿마다 타깃 환경·실행 브랜치·보호 브랜치 여부를 조합해 스코프를 걸 수 있어 '보호 브랜치에서 production을 타깃하는 job만 수령'처럼 좁힐 수 있습니다. 측면 이동의 반경을, 침해된 크리덴셜이 실제로 닿을 수 있던 범위로 줄입니다.
3. 사고 추적을 손으로 꿰맞출 필요가 없습니다. 시크릿의 생성·수정·삭제와 파이프라인의 읽기가 모두 플랫폼의 한 감사 추적에 남습니다. 읽기는 원본 파이프라인·job ID와 함께 기록되고요. 따라서 사고 시 CI·시크릿 도구·IdP 로그를 일일이 대조하던 작업이 한 추적 안에서 해결될 수 있습니다.
4. 방치된 크리덴셜에 갱신 시점을 부여합니다. 시크릿마다 회전 주기를 정해두면(최소 7일) 그 시점에 회전하라는 이메일 알림을 보냅니다. 상시로 남아 잊히던 크리덴셜에 '갱신해야 할 시점'을 거는 장치죠. 다만 이는 알림일 뿐 자동 회전은 아닙니다.
Vault·클라우드 시크릿 매니저와 무엇이 다른가
GitLab Secrets Manager는 범용 전사 Vault가 아니라 CI/CD 플랫폼에 내장된 시크릿 저장소입니다. 따라서 'Vault보다 강력한가'보다 통합·거버넌스·운영 부담을 기준으로 기능을 비교하면 차이를 명확하게 이해할 수 있습니다.
| 비교 항목 | GitLab Secrets Manager | HashiCorp Vault / OpenBao | 클라우드 네이티브 (AWS·Azure·GCP) | Infisical | Akeyless |
|---|---|---|---|---|---|
| 기반·배포 모델 | OpenBao 기반, GitLab 내장 (SaaS·self-managed) | self-host 또는 HCP 관리형 | 해당 클라우드 관리형 | OSS self-host·SaaS | SaaS, vaultless(DFC) |
| 동적 시크릿 / 회전 | 정적 중심, 회전 알림 | 완전 동적(가장 성숙) | 회전 지원(클라우드별 상이), 동적은 아님 | 동적(Enterprise)·회전, 범위 성숙 중 | 동적·자동 회전·JIT |
| CI 네이티브 통합 | 네이티브 (job 단위 명시 요청) | OIDC·API 연동(별도 구성) | IAM·OIDC 연동 | GitLab CI·GitHub Actions 등 네이티브 | 게이트웨이 연동 |
| 접근·거버넌스 | GitLab 그룹·프로젝트 권한 재사용 | 강력한 정책 엔진(학습·운영 필요) | 클라우드 IAM | RBAC·SSO | RBAC·SSO·제로지식 |
| 적합 대상 | GitLab 표준화 팀의 CI/CD 시크릿 | 멀티클라우드·동적 시크릿 | 단일 클라우드 표준화 | 오픈소스·셀프호스트 선호 | Vault 운영 없이 멀티클라우드 동적 |
상황별로 적합한 도구는 저마다 다릅니다.
- CI/CD 시크릿을 GitLab 안에서 끝내고 별도 시스템·권한 모델을 늘리고 싶지 않다면 GitLab Secrets Manager를 권장합니다. 동적 시크릿이 필요하면 다른 도구들과 양자택일이 아니라 병행해 사용할 수 있습니다. GitLab은 HashiCorp Vault·AWS·Azure·GCP 통합을 함께 지원하기에 동적이 필요한 시크릿은 그곳에 두고 조직 일정에 맞춰 도입하면 됩니다.
- 전사·멀티클라우드에 동적 시크릿이 핵심이면 HashiCorp Vault/OpenBao가 적절합니다. 단, 정책 엔진 학습과 클러스터 운영 부담을 감수해야 합니다.
- 단일 클라우드에 표준화돼 있다면 그 클라우드의 네이티브 시크릿 매니저가 적합합니다. 대신 동적 시크릿은 없고 멀티클라우드로 확장하면 모델은 갈라집니다.
- 오픈소스·셀프호스트가 요건이면 Infisical이 개발자 경험과 라이선스 면에서 강력합니다. 동적 시크릿은 Enterprise 티어에서 제공됩니다.
- Vault 운영 자체를 피하면서 멀티클라우드 동적 시크릿이 필요하면 Akeyless가 대안입니다. SaaS·vaultless라 클러스터가 없지만, 외부 SaaS에 의존해야 합니다.
GitLab Secrets Manager 사용법: 마스킹 변수에서 옮기기
앞서 살펴본 내용을 직접 확인해 보겠습니다. 마스킹된 변수가 어떻게 뚫리는지 재현한 뒤, GitLab Secrets Manager가 같은 문제를 어떻게 다루는지 공식 문서를 기준으로 정리합니다.
1단계: 마스킹은 왜 안전장치가 아닌가
흔한 방식부터 그대로 재현해 봅니다. 변수에 시크릿을 넣고 마스킹을 켠 뒤, 로그에 노출되는지 확인하는 과정입니다.
-
마스킹 변수 등록
프로젝트에서 Settings > CI/CD > Variables로 이동해 변수를 추가합니다.
- Key:
DB_PASSWORD - Value:
supersecret123 - Visibility:
Masked(마스킹)
- Key:
-
파이프라인 작성·실행
.gitlab-ci.yml을 작성해 파이프라인을 실행합니다. 핵심만 추리면 다음과 같습니다.yamlscript: - echo "그냥 출력 - $DB_PASSWORD" - echo "$DB_PASSWORD" | base64 -
결과 확인
마스킹된 값이 base64로 변형돼 로그에 그대로 노출된 모습
직접 출력한 줄은 마스킹이 작동해
[MASKED]로 가려집니다. 그러나 base64로 인코딩한 줄은 다릅니다. 마스킹은 등록된 원본 값과 정확히 일치하는 문자열만 가리기 때문에 변형돼 다른 문자열이 되면 그대로 로그에 남습니다. 실제로 이 값을base64 -d로 디코딩하면 원래 시크릿supersecret123이 복원됩니다.마스킹은 우발적 노출을 줄이는 장치일 뿐, 악의적 접근을 막는 보안 통제가 아닙니다. 게다가 이 변수는 요청하지 않은 job에도 주입돼 파이프라인 접근 권한이 있으면 누구나 읽을 수 있습니다. 본론에서 짚은 문제가 그대로 재현된 것입니다.
2단계: GitLab Secrets Manager라면 무엇이 달라지는가
아래는 GitLab 공식 문서를 기준으로 한 절차입니다. GitLab Secrets Manager는 GitLab.com Premium·Ultimate에서 퍼블릭 베타로 제공되지만 단계적으로 배포 중이라, 계정에 따라 아직 활성화되지 않았을 수 있습니다. 프로젝트라면 Settings > General > Visibility, project features, permissions, 그룹이라면 Settings > General > Permissions and group features 섹션에 'Secrets manager' 토글이 보이지 않는다면 아직 노출 대상이 아닌 것입니다. 기능이 열린 뒤에야 사용할 수 있습니다.
같은 시크릿을 GitLab Secrets Manager로 옮기면, 모든 job에 뿌려지던 방식이 '요청한 job만 받는' 방식으로 달라집니다.
-
기능 활성화
프로젝트나 그룹의 Settings > General에서 해당 섹션(프로젝트는 Visibility, project features, permissions, 그룹은 Permissions and group features)을 펼쳐 Secrets manager 토글을 켭니다. 전용 OpenBao 저장소가 프로비저닝되며, 이 작업에는 Owner 역할이 필요합니다.
-
시크릿 등록
Secure > Secrets manager에서 Add secret을 눌러 시크릿을 등록합니다. 이름과 값을 입력하고, 이 시크릿을 사용할 환경이나 브랜치로 범위를 한정할 수 있습니다.
-
파이프라인에서 사용
.gitlab-ci.yml에서 그 시크릿이 필요한 job에만secrets:키워드로 선언합니다.yamljob: secrets: DB_PASSWORD: gitlab_secrets_manager: name: db-password script: - echo "이 job만 시크릿을 받습니다"CI/CD 변수와 달리, 시크릿은 이렇게 명시적으로 요청한 job에만 전달됩니다. 러너(19.0 이상)가 그 job의 파이프라인 신원(JWT)으로 인증하고 요청한 시크릿만 받아오며, 값은 기본적으로 임시 파일 경로로 주입되고 job이 끝나면 폐기됩니다. 1단계에서 변수가 모든 job에 자동으로 주입된 것과 달리 한 job이 침해돼도 다른 시크릿으로 위험이 번지지 않습니다.
다만 이때도 로그에 값이 출력되면
[MASKED]로 대체되는데요. 이는 1단계와 동일한 마스킹이라 base64 등으로 변형하면 똑같이 우회됩니다. Secrets Manager의 핵심 방어는 마스킹이 아니라 시크릿을 그 job으로 좁히고 실행 후 남기지 않는 데 있습니다.
GitLab Secrets Manager 도입 전 점검 사항
GitLab Secrets Manager는 만능이 아닙니다. 도입 전에 한계와 적정 적용 범위를 정확히 이해하고 도입해야 기능을 목적에 맞게 활용할 수 있습니다.
- 마스킹에 기대지 마세요. Secrets Manager의 로그 가림도 변수와 같은 마스킹이라 정확히 일치하는 문자열만 가립니다. base64 등으로 변형하면 그대로 노출되죠. 이 기능의 가치는 로그를 가리는 데 있지 않고, 명시적 요청·범위 한정·권한·감사·중앙화에 있습니다.
- 단기·Keyless 크리덴셜은 OIDC로 보완하세요. Secrets Manager는 정적 시크릿 저장소이고, 회전은 자동이 아니라 알림입니다. 특히 클라우드 인증처럼 매번 새로 발급되는 단기 자격이 필요하면, GitLab의 OIDC ID 토큰을 함께 써야 합니다. 둘은 역할이 다른 보완 관계입니다.
- 범위 밖 영역의 문제는 다른 도구로 해결하세요. 이 기능은 CI/CD 시크릿을 위한 것이라 서버·Kubernetes·데이터베이스 같은 인프라 접근과 런타임 NHI(비인간 신원) 관리 문제는 여기서 해결하기 어렵습니다. 이 영역은 별도 솔루션의 몫입니다.
- 아직 베타임을 고려하세요. 현재 퍼블릭 베타 단계라 GA 전까지 기능·동작이 바뀔 수 있고, GA 후에는 GitLab Credits로 과금됩니다. 또 Premium·Ultimate 전용이라 Free 티어에서는 쓰기 어렵습니다.
- 자체 관리형은 운영 부담을 먼저 따져보세요. GitLab.com(SaaS)에서는 GitLab이 OpenBao를 운영하지만, Self-managed에서는 관리자가 직접 설치하고 별도 PostgreSQL을 둬야 합니다. 게다가 OpenBao는 단일 활성 노드로 동작하고 추가 노드는 고가용성 페일오버용이라 국내처럼 self-managed 비중이 높은 환경에서는 고가용성·재해 복구 요건을 도입 전에 확인해야 합니다.
- 비활성화는 신중히 하세요. 프로젝트나 그룹에서 Secrets Manager를 끄면 저장된 모든 시크릿이 복구 불가능하게 영구 삭제됩니다. 프로젝트 이전이나 정리 작업 전에 반드시 이 점을 고려해야 합니다.
맺음말
지금까지 CI/CD 시크릿이 유출되는 양상과 원인을 짚고, GitLab Secrets Manager의 해결 방식을 살펴본 뒤, 마스킹 변수의 한계를 직접 재현해 봤습니다. 요점은 다음과 같은데요.
- 마스킹은 보안 통제가 아닙니다. 정확히 일치하는 문자열만 가리기에 base64로 변형하면 그대로 노출되고, 변수는 요청하지 않은 job에도 주입됩니다. 이런 유출은 부주의보다 자동화로 시크릿이 늘고 속도가 우선되는 구조의 산물이며, 방치하면 침해 확산·감사 실패·규제 증빙 부담으로 이어집니다.
- GitLab Secrets Manager는 시크릿을 job 단위로 좁힙니다. OpenBao 기반으로, 명시적으로 요청한 job에만 시크릿을 내주고 실행 후 폐기합니다. 별도 Vault를 이중 운영하지 않고 기존 권한을 그대로 쓰며, 접근이 한 감사 추적에 남습니다.
- 실습으로 마스킹의 한계를 확인했습니다. 마스킹된 값도 base64로 인코딩하면 로그에 남고 디코딩하면 복원됐습니다. 핵심 방어는 가림이 아니라, 시크릿을 좁히고 남기지 않는 데 있습니다.
- 도입 전 유의할 점이 있습니다. 단기·Keyless 자격은 OIDC로 보완하고, 인프라 접근 등 범위 밖은 다른 도구의 몫입니다. GitLab Secrets Manager는 아직 베타라 동작이 바뀔 수 있고 Premium·Ultimate 전용이며, 자체 관리형 운영 부담과 비활성화 시 영구 삭제를 따져봐야 합니다.
시크릿 사고는 추적해야 막을 수 있습니다
시크릿이 변수와 로그로 흩어지면, 정작 사고가 났을 때 어디까지 뚫렸는지 알 수 없습니다. 인포그랩이 시크릿을 한곳에 모으고 추적까지 가능한 GitLab 환경 구축을 돕습니다
참고 자료
- "GitLab Secrets Manager", GitLab Docs, https://docs.gitlab.com/ci/secrets/secrets_manager/
- "GitLab Secrets Manager (OpenBao)", GitLab Docs, https://docs.gitlab.com/administration/secrets_manager/
- Joe Randazzo·Mark Settle, "Manage CI/CD credentials with GitLab Secrets Manager", GitLab, 2026-05-21, https://about.gitlab.com/blog/secrets-manager-in-public-beta/
- "CI/CD variables", GitLab Docs, https://docs.gitlab.com/ci/variables/
- "Use AWS Secrets Manager secrets in GitLab CI/CD", GitLab Docs, https://docs.gitlab.com/ci/secrets/aws_secrets_manager/
- "Use external secrets in CI/CD", GitLab Docs, https://docs.gitlab.com/ci/secrets/
- "OpenBao chart", GitLab Docs, https://docs.gitlab.com/charts/charts/openbao/
- OpenBao 공식 문서, https://openbao.org/docs/
이 글이 도움이 되셨나요?
인포그랩 전문가가 맞춤 상담을 도와드립니다.
관련 글

GitLab Pipeline Execution Policy로 DevOps 보안 자동화하기
GitLab의 Pipeline Execution Policy 기능을 사용하면, 모든 변경 사항이 컴플라이언스 요구 사항을 충족하도록 손쉽게 강제하고, 그 결과를 확인할 수 있습니다. 이 글은 Pipeline Execution Policy의 개념, 구성 방법, 정책 적용 확인 방법을 실습 예제와 함께 다뤘습니다.

CI/CD job 실패 원인 찾는 Root Cause Analysis 알아보기
GitLab의 Root Cause Analysis 기능은 실패한 CI/CD 파이프라인의 근본 원인을 파악하고, 해결 방법을 제안하는 AI 기반 기능입니다. 이 기능은 조직이 소프트웨어를 더 안전하고, 더 빨리 릴리즈하도록 돕습니다. 이 글은 Root Cause Analysis 기능의 개념과 사용 방법, 동작 방식을 살펴보고, 엔지니어 관점에서 기능을 논평했습니다.

파이프라인 개발 간소화 핵심! GitLab CI/CD 컴포넌트, 카탈로그 잘 써먹기
CI/CD 컴포넌트는 GitLab CI/CD 템플릿의 차세대로, 재사용 가능한 단일 파이프라인 구성 단위입니다. CI/CD 카탈로그는 공개된 CI/CD 컴포넌트가 있는 프로젝트 목록입니다. GitLab에서 CI/CD 컴포넌트와 CI/CD 카탈로그를 활용하면 파이프라인 개발을 간소화할 수 있습니다. 이 글은 두 기능의 사용 방법을 다뤘습니다.