Docker 빌드에 비밀키 전달하는 법: ARG·ENV 대신 BuildKit 시크릿 사용하는 기준

Docker 빌드에 비밀키를 전달할 때는 ARG·ENV 대신 BuildKit 시크릿을 사용하는 것이 기본이다. 비공개 패키지나 저장소 인증에 필요한 값은 빌드 명령이 실행되는 동안만 제공하고, 완성된 이미지에는 남기지 않아야 한다. 핵심은 클라이언트에서 --secret으로 전달한 뒤 Dockerfile의 필요한 RUN에서만 마운트하는 것이다.

빌드 중 인증 오류가 나면 토큰을 Dockerfile에 직접 넣고 싶어지지만, 빌드 성공과 비밀값 보호는 별개의 문제다. 아래 내용은 2026년 11월 확인한 Docker 공식 문서를 기준으로 하며, 명령 예제는 Linux 컨테이너와 Bash 계열 셸을 전제로 한다.

1. Docker 빌드 시크릿과 ARG·ENV의 사용 기준 정하기

빌드 시크릿은 이미지 생성 과정에서 잠시 필요한 비밀번호·API 토큰·인증 파일 같은 민감정보다. 의존성 버전처럼 공개해도 되는 설정은 ARG에, 애플리케이션의 일반 실행 설정은 ENV에 둘 수 있다. 반면 유출 시 외부 서비스나 저장소 접근 권한을 주는 값은 시크릿으로 분리해야 한다.

ARG는 자동으로 실행 컨테이너의 환경변수가 되지는 않지만, 사용 방식에 따라 이미지 이력이나 출처 증명에 남을 수 있다. ENV는 이미지 설정에 저장되고 해당 이미지로 만든 컨테이너에도 이어진다. 빌드가 끝난 뒤 변수 값을 지우는 방식으로는 이미 기록된 정보를 확실히 제거할 수 없다.

Compose로 실행 컨테이너에 환경변수를 주입하는 문제와도 구분해야 한다. 이미지 빌드 중 패키지를 내려받는 단계에서 발생한 인증 실패는 해당 빌드 단계에 자격 증명을 전달해야 해결된다. 실행 시점에만 쓰는 데이터베이스 비밀번호라면 빌드 입력으로 제공할 이유가 없다.

이 구분의 근거는 Docker의 Build variables 문서다. 실무에서는 “이 값이 설정인가, 접근 권한인가”를 먼저 판단하면 전달 방식을 고르기 쉽다.

📌 핵심 요약

  • API·패키지 인증은 필요한 RUN에 시크릿 마운트를 연결한다.
  • Git의 SSH 인증은 SSH 마운트, 원격 HTTPS Git 컨텍스트 인증은 사전 정의 시크릿을 검토한다.
  • 마운트가 안전해도 명령이 비밀값을 출력하거나 복사하면 로그·이미지에 유출될 수 있다.

2. docker build --secret으로 인증 파일 전달하기

파일 방식은 인증 도구가 설정 파일 경로를 지원할 때 편하다. Docker 공식 가이드의 절차는 CLI에서 전달하고 Dockerfile에서 사용하는 2단계다. 두 곳의 id를 일치시켜야 하며, 비밀 파일 자체를 빌드 컨텍스트에 복사할 필요는 없다.

  1. 빌드 머신에 인증 파일을 준비하고 필요한 권한만 부여한다.
  2. docker build --secret id=aws,src=파일경로 .로 파일을 전달한다.
  3. 인증이 필요한 RUN에 같은 ID의 마운트를 선언한다.

다음은 AWS 자격 증명 파일을 전달하는 예제다. AWS CLI가 설치된 빌드 스테이지에서 아래 명령을 사용하고, 버킷 이름과 객체 경로는 접근 권한이 있는 실제 대상으로 바꾼다.

docker build \
  --secret id=aws,src="$HOME/.aws/credentials" \
  -t private-artifact-build .
# Dockerfile 첫 줄
# syntax=docker/dockerfile:1

# AWS CLI가 설치된 스테이지에서 실행
RUN --mount=type=secret,id=aws,required=true \
    AWS_SHARED_CREDENTIALS_FILE=/run/secrets/aws \
    aws s3 cp s3://YOUR_BUCKET/build/input.tar.gz /tmp/input.tar.gz

AWS_SHARED_CREDENTIALS_FILE에 들어가는 값은 비밀키가 아니라 마운트 경로다. 해당 명령은 경로의 인증 파일을 읽어 다운로드하며, 원본 시크릿 마운트는 그 RUN이 끝나면 유지되지 않는다. 다만 다운로드한 파일은 빌드 결과에 남을 수 있으므로 포함해도 되는 자료인지 따로 판단해야 한다.

출처: Docker Build secrets의 전달·사용 절차 및 AWS 예제.

기본 파일 권한과 required=true 확인

Linux 컨테이너의 기본값을 알아두면 “파일은 있는데 읽을 수 없다”는 문제를 빠르게 좁힐 수 있다. 특히 Dockerfile에서 USER를 바꾼 뒤 시크릿을 읽는다면 소유권을 확인해야 한다.

옵션 기본값과 의미
target파일 마운트 기본 경로는 /run/secrets/<id>
mode0400: 소유자에게 읽기 권한 부여
uid / gid각각 0 / 0
required기본 false, true 지정 시 시크릿이 없는 명령 실행을 오류 처리

예를 들어 UID 1000으로 실행하는 도구라면 uid=1000처럼 실제 사용자에 맞춰 지정할 수 있다. 읽기 오류를 해결하려고 인증 파일을 모든 사용자에게 공개하기보다 필요한 프로세스에만 권한을 맞추는 편이 적절하다. 출처: Docker Dockerfile reference의 시크릿 마운트 옵션.

3. 환경변수의 API 토큰을 BuildKit 시크릿으로 연결하기

CI에 토큰이 환경변수로 저장되어 있다면 중간 파일 없이 전달할 수 있다. 여기서는 호스트에서 값을 읽는 옵션과 빌드 안에서 값을 제공하는 옵션을 구분하는 것이 중요하다. 양쪽 모두 env라는 이름을 쓰지만 역할이 다르다.

# CI의 비밀 저장소가 API_TOKEN을 주입한 상태
docker build \
  --secret id=TOKEN,env=API_TOKEN \
  -t api-build .

CLI의 env=API_TOKEN은 빌드 머신의 환경변수를 읽어 TOKEN이라는 시크릿으로 전달한다. Dockerfile에서는 이를 파일로 읽거나, 해당 명령의 환경변수로 제공할 수 있다. 파일로 쓴다면 /run/secrets/TOKEN을 읽도록 도구를 설정하면 된다.

# syntax=docker/dockerfile:1
FROM python:3.13-slim

RUN --mount=type=secret,id=TOKEN,env=API_TOKEN,required=true \
    python -c 'import os; assert os.environ.get("API_TOKEN"), "API_TOKEN is empty"'

위 코드는 비밀값을 출력하지 않고 환경변수 전달과 빈 값 여부만 확인하는 최소 예제다. 실제 빌드에서는 Python 확인 명령을 토큰을 사용하는 다운로드·설치 도구로 바꾸면 된다. Dockerfile의 env=API_TOKEN은 그 RUN에 값을 제공하며, 영구적인 ENV API_TOKEN=... 선언과 다르다.

시크릿 마운트의 환경변수 대상 옵션은 Dockerfile 프런트엔드 v1.10.0부터 지원한다. 이는 Docker Engine의 버전 번호가 아니므로 구문 오류가 나면 빌더와 Dockerfile 프런트엔드 지원 여부를 함께 확인해야 한다. 출처: Docker Dockerfile reference.

4. 비공개 Git 인증: GIT_AUTH_TOKEN과 SSH 마운트 선택하기

비공개 Git 저장소는 인증이 필요한 시점부터 살펴봐야 한다. Dockerfile의 RUN git clone이 실패한 것인지, Dockerfile을 읽기도 전에 원격 빌드 컨텍스트를 가져오지 못한 것인지에 따라 해결 위치가 달라진다.

terminal prompts disabled는 Docker 공식 문서에도 등장하는 인증 실패 문구다. 자동 빌드에서는 사용자 이름이나 비밀번호를 대화형으로 입력받을 수 없다는 뜻이며, 이 문구만으로 토큰 만료를 확정할 수는 없다. 우선 실패 단계와 인증 정보 전달 여부를 확인해야 한다.

GitHub의 비공개 HTTPS 저장소 자체를 빌드 컨텍스트로 쓴다면, 유효한 토큰을 GIT_AUTH_TOKEN 환경변수에 준비한 뒤 다음처럼 전달한다. PRIVATE_GIT_CONTEXT에는 대상 저장소의 HTTPS 주소가 설정되어 있어야 한다.

docker build \
  --secret id=GIT_AUTH_TOKEN,env=GIT_AUTH_TOKEN \
  "$PRIVATE_GIT_CONTEXT"

이 인증은 빌드 컨텍스트를 확보하는 사전 단계에 사용되므로 별도의 RUN --mount=type=secret 선언으로 처리하지 않는다. Docker는 원격 Git 인증용으로 GIT_AUTH_TOKEN과 GIT_AUTH_HEADER를 제공하며, 일반적인 RUN git clone에 자동 적용되는 만능 토큰 설정으로 이해하면 안 된다.

반면 SSH 주소로 저장소를 가져오고 이미 SSH 에이전트를 운영한다면 docker build --ssh default .와 RUN --mount=type=ssh,required=true를 연결하는 방식이 적합하다. Git·SSH 클라이언트 설치, 에이전트의 키 등록, 검증된 호스트 키를 담은 known_hosts도 준비해야 한다. 호스트 확인을 끄는 방식으로 인증 오류를 우회하지 않는 것이 좋다.

선택 기준은 명확하다. API 호출과 패키지 인증에는 일반 시크릿 마운트, SSH Git 접근에는 SSH 마운트, 원격 HTTPS Git 컨텍스트에는 사전 정의 Git 인증 시크릿을 우선 검토한다. 출처: Docker Build secrets의 SSH 및 원격 Git 인증 설명.

5. 토큰 교체 후 Docker 빌드 캐시를 다시 실행하기

토큰을 바꿨는데 빌드가 즉시 끝나면 새 인증 정보가 검증됐다고 생각하기 쉽다. 그러나 시크릿 내용의 변경만으로는 빌드 캐시가 무효화되지 않는다. 기존 결과를 재사용했다면 실제 네트워크 인증은 수행되지 않았을 수 있다.

재실행이 필요할 때는 시크릿을 사용하는 스테이지에서 별도의 공개 가능한 빌드 인자를 선언하고 값을 변경할 수 있다. 앞선 Dockerfile 예제에서는 해당 RUN 앞에 ARG CACHEBUST를 추가하면 된다.

ARG CACHEBUST
RUN --mount=type=secret,id=TOKEN,env=API_TOKEN,required=true \
    python -c 'import os; assert os.environ.get("API_TOKEN"), "API_TOKEN is empty"'
docker build \
  --secret id=TOKEN,env=API_TOKEN \
  --build-arg CACHEBUST=2 .

CACHEBUST에는 증가하는 번호 등 비밀이 아닌 값을 넣는다. 토큰 원문이나 토큰에서 계산한 값을 캐시 무효화용 인자로 넘길 필요는 없다. 시크릿 ID와 마운트 경로의 변경은 캐시 판정에 반영되며, 필요에 따라 --no-cache로 재실행할 수도 있다.

운영 관점에서는 “캐시로 빌드가 성공했다”와 “현재 자격 증명이 유효하다”를 별도로 판단해야 한다. 토큰 교체 검증이라면 실제 인증 명령을 다시 실행하고, 결과물의 재현성이 목적이라면 의존성 버전과 내려받는 대상도 고정하는 편이 효과적이다. 출처: Docker Build cache invalidation.

6. 이미지·빌드 로그에 비밀키를 남기지 않는 체크리스트

BuildKit은 시크릿을 일시적으로 제공하지만, 실행한 프로그램의 출력과 파일 저장까지 자동으로 정리하지는 않는다. 마운트 파일을 다른 경로로 복사하거나 토큰을 포함한 설정 파일을 생성하면 그 결과가 이미지 레이어에 남을 수 있다. 나중 단계에서 삭제하는 방식보다 처음부터 기록하지 않는 설계가 중요하다.

  • 로그 출력 확인: echo, printenv, set -x와 도구의 디버그 출력이 토큰을 드러내지 않는지 확인한다.
  • 파일 생성 확인: 패키지 관리자가 인증 설정·캐시·로그에 자격 증명을 저장하는지 살펴본다.
  • 빌드 컨텍스트 확인: 로컬 비밀 파일을 컨텍스트 밖에 두고, 필요한 경우 .dockerignore로 제외한다. Git 추적 제외도 별도로 확인한다.
  • 권한 범위 확인: 다운로드만 필요하면 읽기 권한의 토큰을 사용하고, 관련 없는 저장소 접근 권한은 부여하지 않는다.
  • 누락·빈 값 확인: 필수 마운트에는 required=true를 적용하고, 빈 값 검사는 비밀값을 출력하지 않는 방식으로 수행한다.

Docker의 SecretsUsedInArgOrEnv 빌드 검사는 민감정보를 뜻하는 ARG·ENV 이름을 찾아 위반을 보고한다. 다만 이름을 바꿔 경고를 없애도 전달 방식의 위험은 그대로다. 이 검사는 검토를 돕는 신호로 활용하고, 경고가 없다는 사실을 비밀값 부재의 증거로 삼지 않아야 한다.

2026년 공식 문서를 기준으로 한 실무적 판단은 전달 경로·사용 범위·생성 결과를 함께 검토하는 것이다. 시크릿 마운트로 입력을 분리하고, 인증이 필요한 명령에만 연결한 뒤, 그 명령이 남긴 로그와 파일을 점검해야 보호가 완성된다. 실제 비밀값이 로그나 이미지에 노출됐다면 삭제 작업과 함께 해당 자격 증명의 폐기·재발급도 진행해야 한다.

출처: Docker SecretsUsedInArgOrEnv. 빌드 적용 후에는 토큰 원문을 출력하지 않는 전달 확인부터 수행하고, 실제 인증 명령을 캐시 없이 검증한 다음 이미지에 포함된 설정과 산출물을 확인하는 순서가 적절하다.