Docker build secrets, bir build adımının ihtiyaç duyduğu parola, API token'ı ya da SSH anahtarı gibi bilgileri imaja yazmadan kullanmanızı sağlar. Sırrı docker build --secret id=... ile build'e verir, Dockerfile'da RUN --mount=type=secret,id=... ile yalnızca o adım süresince bir dosya ya da ortam değişkeni olarak açarsınız. SSH anahtarları ve agent soketleri için aynı işi --ssh ve RUN --mount=type=ssh yapar.

Bu yazıda sırların neden ARG ve ENV ile geçirilmemesi gerektiğini, secret mount kaynaklarını ve hedeflerini, özel Git depoları için hazır sırları, önbellekle ilişkisini ve aynı ayarların Compose ile GitHub Actions'ta nasıl yazıldığını resmî belgelere dayanarak anlatıyoruz. Container çalışırken kullanılan Compose sırları ayrı bir konudur ve Compose secrets ve configs yazısında anlatılıyor; serinin geri kalanı için Docker öğrenme rehberi sayfasına bakabilirsiniz.

ARG ve ENV neden sır taşıyamaz?

Belgelere göre build argümanları ve ortam değişkenleri sırları build'e geçirmek için uygun değildir, çünkü son imajda kalırlar. ENV ile verdiğiniz değer imajın yapılandırmasının parçasıdır ve imajdan başlatılan her container'da okunabilir. ARG değeri container'da bulunmasa da imaj metaverisinde, provenance attestation kayıtlarında ve imaj geçmişinde kalabilir. Belgeler bir de şunu gösterir: her ENV satırı bir katman oluşturur ve sonraki katmanda değişkeni kaldırmak önceki katmandaki değeri silmez. Aynı mantık dosyalar için de düşünülmelidir: bir token dosyasını COPY ile ekleyip sonraki bir adımda silmek, dosyayı onu ekleyen katmandan çıkarmaz.

Bu durum sunucu tarafında somut bir risktir. İmajı bir registry'ye gönderdiğinizde, imajı çekebilen herkes bu katmanlara ve metaveriye erişebilir. Özel npm kayıt token'ı, özel bir Git deposunun erişim anahtarı ya da bir bulut hesabının kimlik dosyası build sırasında gerekebilir; ama bunların hiçbiri imajın içinde ya da geçmişinde bulunmamalıdır.

Üç tür build sırrı

Üç tür build sırrı: Secret mount, SSH mount, Uzak context için Git kimlik doğrulaması
  • Secret mount: Genel amaçlıdır. Sırrı build istemcisinden alır ve yalnızca ilgili build talimatı süresince build container'ında kullanılabilir yapar. Özel bir yapıt sunucusuna ya da bir API'ye erişmek gibi durumlar içindir.
  • SSH mount: SSH soketlerini veya anahtarlarını build içinde kullanılabilir yapar. En yaygın kullanımı özel Git depolarını çekmektir.
  • Uzak context için Git kimlik doğrulaması: Özel bir Git deposunu build context'i olarak kullandığınızda builder'ın depoyu çekebilmesi için hazır sırlardır. Belgeler bunlara "pre-flight" sır der: bir build talimatında tüketilmezler, context'i getirmek için kullanılırlar.

Secret mount: iki adımlı kullanım

Secret ve SSH mount kullanımı iki adımdır: önce sırrı build komutuna verirsiniz, sonra Dockerfile'da tüketirsiniz. Komut satırında --secret bayrağı kullanılır; Bake dosyalarında karşılığı secret alanıdır ve Buildx Bake yazısında ele alınıyor.

bash
docker build --secret id=aws,src=$HOME/.aws/credentials .
dockerfile
RUN --mount=type=secret,id=aws \
    AWS_SHARED_CREDENTIALS_FILE=/run/secrets/aws \
    aws s3 cp ...

Sırrın kaynağı bir dosya ya da bir ortam değişkeni olabilir. CLI ve Bake türü otomatik algılar; isterseniz type=file veya type=env ile açıkça belirtirsiniz. --secret id=kube,env=KUBECONFIG, KUBECONFIG değişkeninin değerini kube kimliğiyle build'e verir. Ortam değişkeninin adı sır kimliğiyle aynıysa env parametresini atlayabilirsiniz: --secret id=API_TOKEN, API_TOKEN değişkeninin değerini /run/secrets/API_TOKEN dosyasına bağlar.

bash
docker build --secret id=kube,env=KUBECONFIG .
docker build --secret id=API_TOKEN .

Sır build içinde nerede görünür?

Sır build içinde nerede görünür?

Dockerfile'da tüketilen sır varsayılan olarak bir dosyaya bağlanır ve yolu /run/secrets/<id> olur. target seçeneği dosyayı başka bir konuma, env seçeneği ise sırrı dosya yerine bir ortam değişkenine bağlar. İkisi birlikte kullanılırsa sır hem dosya hem ortam değişkeni olarak açılır. Önemli olan, bu dosya ya da değişkenin yalnızca o RUN talimatı süresince var olmasıdır.

dockerfile
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
    aws s3 cp ...

RUN --mount=type=secret,id=aws-key-id,env=AWS_ACCESS_KEY_ID \
    --mount=type=secret,id=aws-secret-key,env=AWS_SECRET_ACCESS_KEY \
    --mount=type=secret,id=aws-session-token,env=AWS_SESSION_TOKEN \
    aws s3 cp ...

Özel bir npm kaydından paket kurmak sunucu tarafında sık karşılaşılan bir durumdur. GitHub Actions belgesindeki örnek, .npmrc dosyasını sır olarak bağlayıp npm ci adımında kullanır; dosya imaja kopyalanmaz. RUN adımı root olmayan bir kullanıcıyla çalışıyorsa, kullanıcının dosyayı okuyabilmesi için bağlamaya uid, gid veya mode verilmesi gerekir:

dockerfile
# syntax=docker/dockerfile:1
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci
COPY . .
RUN npm run build
dockerfile
RUN --mount=type=secret,id=npmrc,target=/home/node/.npmrc,uid=1000,gid=1000 \
    npm ci
bash
docker build --secret id=npmrc,src=$HOME/.npmrc .

SSH mount ile özel depolar

Build içinde kullanmanız gereken kimlik bir SSH agent soketi ya da anahtarıysa secret mount yerine SSH mount kullanılır. En kısa yol, Dockerfile'da özel depoyu SSH adresiyle ADD etmek ve build'e --ssh default vermektir; default değeri builder'ın yerel SSH agent'ına bağlanmasını sağlar. Bir RUN adımında SSH gerekiyorsa RUN --mount=type=ssh kullanılır; belirli bir anahtar için bir kimlik verip aynı kimlikle bağlarsınız.

dockerfile
# syntax=docker/dockerfile:1
FROM alpine
ADD git@github.com:me/myprivaterepo.git /src/
bash
docker buildx build --ssh default .

Özel Git context'i için GIT_AUTH_TOKEN ve GIT_AUTH_HEADER

Özel bir depoyu build context'i olarak kullanmak istediğinizde kimliksiz bir docker build başarısız olur; belgelerdeki örnekte builder kullanıcı adını soramadığı için Git, terminal istemlerinin kapalı olduğunu bildirir. BuildKit bu durum için iki hazır sır tanır. GIT_AUTH_TOKEN, kullanıcı adı sabit olarak x-access-token olan bir Basic kimlik doğrulama başlığı oluşturur; GitHub gibi bu deseni kabul eden sağlayıcılarla çalışır. GIT_AUTH_HEADER ise verdiğiniz değeri olduğu gibi Authorization başlığı olarak kullanır ve her sağlayıcıyla çalışabilir.

bash
export GIT_AUTH_TOKEN=$(gh auth token)
docker build \
  --secret id=GIT_AUTH_TOKEN \
  https://github.com/example/todo-app.git

Belgeler GitLab için özel bir not düşer: GIT_AUTH_TOKEN ve GIT_AUTH_HEADER, GitLab'ın CI_JOB_TOKEN değeriyle doğrudan uyumlu değildir, çünkü bu token gitlab-ci-token kullanıcı adıyla Basic kimlik ister, BuildKit ise her zaman x-access-token kullanır. Belgeler bu durumda kişisel erişim token'ı kullanmanızı önerir ve başlığı elle oluşturan bir GIT_AUTH_HEADER örneği de gösterir. Farklı sunucular için farklı kimlik gerekiyorsa sır kimliğine sunucu adını sonek olarak eklersiniz: GIT_AUTH_TOKEN.github.com ve GIT_AUTH_HEADER.gitlab.com gibi. GIT_AUTH_TOKEN, build içinde ADD ile özel bir HTTPS Git deposu çekerken de geçerlidir.

bash
docker build \
  --secret id=GIT_AUTH_TOKEN.github.com,env=GITHUB_TOKEN \
  --secret id=GIT_AUTH_HEADER.gitlab.com,env=GITLAB_AUTH_HEADER \
  https://github.com/example/todo-app.git

COPY ve ADD ile bir HTTP sunucusundan dosya alırken kimlik eklemek için de HTTP_AUTH_TOKEN_<host> ve HTTP_AUTH_HEADER_<host> sırları tanımlanabilir. Belgelerdeki örneğe göre HTTP_AUTH_TOKEN_127.0.0.1=token tanımı, 127.0.0.1 adresine giden isteklere Authorization: Bearer token başlığını ekler.

Sırlar ve build önbelleği

Önbellek geçersizleştirme sayfası iki kuralı birlikte verir. Sırların içeriği build önbelleğinin parçası değildir; sırrın değerini değiştirmek önbelleği geçersiz kılmaz. Ama sırrın kimliği ve bağlama yolu gibi özellikleri önbellek sağlama toplamına katılır ve değiştiklerinde önbellek bozulur. Sır değiştiğinde ilgili adımı yeniden çalıştırmak istiyorsanız, sırla birlikte değiştirdiğiniz rastgele bir build argümanı eklersiniz; build argümanları önbelleği geçersiz kılar.

dockerfile
FROM alpine
ARG CACHEBUST
RUN --mount=type=secret,id=TOKEN,env=TOKEN \
    some-command ...
bash
TOKEN="tkn_pat123456" docker build --secret id=TOKEN --build-arg CACHEBUST=1 .

Bu davranış pratikte şunu anlatır: token'ınızı yeniledikten sonra build, önceki önbelleğe alınmış adımı kullanabilir ve yeni token'la hiç çalışmayabilir. Bu genellikle istenen sonuçtur, çünkü adımın çıktısı token'dan bağımsızdır. Ama adımın token'la yeniden doğrulama yapması gerekiyorsa önbelleği bilinçli olarak bozmanız gerekir. Önbelleğin genel kuralları build cache yazısında.

Compose dosyasında build sırları

Compose'ta servisin build bölümüne secrets ve ssh alanları yazılır. Sırrın kaynağı dosyanın en üst düzeyindeki secrets bölümünde file ya da environment ile tanımlanır; environment kaynağı yalnızca Docker Compose tarafından desteklenir, docker stack deploy ile kullanılamaz. Üst düzeyde tanımlanan bir sır hiçbir servise otomatik verilmez: erişim her build için açıkça yazılmalıdır, aksi halde Compose tanımsız sır için hata bildirir. Uzun sözdiziminde target, Dockerfile'da kullanılan sır kimliğidir ve belirtilmezse source değerini alır; uid, gid ve mode da ayarlanabilir, varsayılan kip 0444'tür.

yaml
services:
  app:
    build:
      context: .
      secrets:
        - npmrc
        - source: api_token
          target: API_TOKEN
      ssh:
        - default
secrets:
  npmrc:
    file: ./npmrc.txt
  api_token:
    environment: API_TOKEN

Bu dosya Docker CLI 29.8.1, Docker Compose v5.5.1 ile docker compose config --quiet komutundan çıkış kodu 0 ile geçti. Dockerfile tarafında sırlar RUN --mount=type=secret,id=npmrc,... ve RUN --mount=type=secret,id=API_TOKEN,env=API_TOKEN ... ile tüketilir. ssh alanında default SSH agent'ına bağlanır; myproject=~/.ssh/myproject.pem gibi bir kimlik ve yol da verilebilir ve Dockerfile'da RUN --mount=type=ssh,id=myproject ile kullanılır.

Sır nereden okunur: istemci ve uzak builder

Belgelere göre secret mount sırrı build istemcisinden alır ve build container'ına geçici olarak verir. Bu ayrıntı uzak bir builder kullandığınızda önemlidir: src=$HOME/.npmrc gibi bir yol, BuildKit'in çalıştığı makinede değil docker build komutunu yazdığınız makinede okunur. Aynı şekilde env= ile verilen değişken de istemcinin ortamından gelir. Uzak tarball context'inde indirmenin builder tarafında yapılmasıyla karıştırılmamalıdır; sırlar her zaman istemci tarafındadır. Bu da sırrı yalnızca build'i başlatan makinede tutmanıza, build sunucusunun diskine hiç yazmamanıza imkân verir.

Küçük bir örnek: özel paket ve özel depo aynı build'de

Sunucuda sık görülen bir senaryoyu birleştirelim: uygulama özel bir npm kaydından paket kurar ve build sırasında özel bir Git deposundan ek bir modül çeker. Dockerfile'da npm adımı .npmrc sırrını /root/.npmrc konumuna bağlar, modül ise ADD git@github.com:... ile SSH üzerinden alınır. Build komutu iki kaynağı birlikte verir: docker buildx build --secret id=npmrc,src=$HOME/.npmrc --ssh default .. Sonuçta ne npm token'ı ne SSH anahtarı imaja ya da imaj geçmişine girer. Token'ı yenilediğinizde npm adımı önbellekten gelebileceği için, yeniden doğrulama istiyorsanız yukarıda anlatılan CACHEBUST yöntemini kullanırsınız. Aynı build'i Compose ile yapmak için build.secrets ve build.ssh alanları yeterlidir.

GitHub Actions'ta sır kaynakları

docker/build-push-action sırları üç girdiyle alır ve her biri bir Buildx seçeneğine karşılık gelir. Dockerfile tarafı değişmez; sırrın değerinin nereden geldiğini iş akışı, nasıl tüketildiğini Dockerfile belirler. İş akışının kendisi GitHub Actions rehberinde anlatılıyor.

Action girdisiKaynakBuildx karşılığı
secrets: MY_SECRET=valueİş akışındaki metin değeri--secret id=MY_SECRET,src=geçici dosya
secret-envs: MY_SECRET=MY_ENV_VARRunner üzerindeki ortam değişkeni--secret id=MY_SECRET,env=MY_ENV_VAR
secret-files: MY_SECRET=./secret.txtRunner üzerindeki dosya--secret id=MY_SECRET,src=./secret.txt

Sık yapılan hatalar

Sık yapılan hatalar: Token'ı --build-arg ile geçirmek, Kimlik dosyasını COPY ile ekleyip sonraki adımda silmek, Sırrı bağlayan RUN adımında değeri bir dosyaya yazmak, Root olmayan...
  • Token'ı --build-arg ile geçirmek: değer imaj geçmişinde ve provenance kayıtlarında kalabilir.
  • Kimlik dosyasını COPY ile ekleyip sonraki adımda silmek: dosya onu ekleyen katmanda kalır.
  • Sırrı bağlayan RUN adımında değeri bir dosyaya yazmak: o dosya katmanın parçası olur.
  • Root olmayan kullanıcıyla çalışan adımda uid/gid vermemek: kullanıcı sır dosyasını okuyamaz.
  • Compose'ta sırrı yalnızca üst düzeyde tanımlayıp build.secrets altında servise vermemek.
  • Sır değiştiğinde adımın kendiliğinden yeniden çalışacağını beklemek: sır içeriği önbelleğe girmez.
  • GitLab CI job token'ını doğrudan GIT_AUTH_TOKEN olarak vermek.

Sık Sorulan Sorular

Build sırrı son imajda kalır mı?

Hayır. Secret mount sırrı yalnızca ilgili build talimatı süresince kullanılabilir yapar. Ancak o talimatın içinde sırrı bir dosyaya kopyalarsanız, kopyalanan dosya katmanda kalır.

Sır dosya yerine ortam değişkeni olabilir mi?

Evet. RUN --mount=type=secret,id=...,env=AD ile sır yalnızca o adımda geçerli bir ortam değişkenine bağlanır. target ile birlikte kullanırsanız hem dosya hem değişken olur.

Özel bir Git deposunu context olarak nasıl kullanırım?

SSH adresi için --ssh default, HTTPS adresi için --secret id=GIT_AUTH_TOKEN verin. Farklı sağlayıcılar için kimliğe sunucu adını sonek olarak ekleyebilirsiniz.

Bake dosyasında sır nasıl tanımlanır?

Hedefin secret listesine CLI ile aynı biçimde yazılır. Belgelerdeki örnek, HOME değişkenini Bake değişkeni olarak tanımlar ve sırrı ondan türetir:

hcl
variable "HOME" {
  default = null
}

target "default" {
  secret = [
    "id=aws,src=${HOME}/.aws/credentials"
  ]
}

Compose build sırları ile çalışma zamanı sırları aynı mı?

Kaynak tanımı aynı üst düzey secrets bölümünü kullanır, ama build.secrets yalnızca build'e, servis düzeyindeki secrets ise çalışan container'a erişim verir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · ARG ve ENV farkı · Compose secrets ve configs · Build context ve .dockerignore · Buildx Bake · GitHub Actions CI/CD rehberi