dockerdockerfilegithub-actionsbuildxbuildkit

Docker Build does not pass secret via --mount=type=secret


Problem

I am using docker/build-push-action@v6 in a GitHub Actions pipeline to build a Docker image. I am trying to pass a pip.conf file as a secret during the build, but --mount=type=secret cannot find the file inside the container.

However, when I run the same command manually using docker buildx build, it works perfectly.


My Setup

GitHub Actions Workflow (.github/workflows/build.yml):

name: Build and push Docker images

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Configure Python
        run: |
          mkdir -p $GITHUB_WORKSPACE/.config/pip
          touch $GITHUB_WORKSPACE/.config/pip/pip.conf
          chmod 777 $GITHUB_WORKSPACE/.config/pip/pip.conf
          echo "[global]
          extra-index-url = ${{ secrets.CONF }}" > $GITHUB_WORKSPACE/.config/pip/pip.conf

      - name: Build and push Docker images
        uses: docker/build-push-action@v6
        with:
          context: python
          platforms: linux/amd64
          push: false
          pull: true
          tags: myrepo/myimage:latest
          build-args: |
            DOCKER_BUILDKIT=1
            BUILDKIT_INLINE_CACHE=1
          secrets: |
            id=pip,src=$GITHUB_WORKSPACE/.config/pip/pip.conf

Dockerfile

FROM python:3.11-slim

RUN --mount=type=secret,id=pip,target=/etc/pip.conf pip install --no-cache-dir -r requirements.txt

Expected Behavior

The python build should work with no issues.


Actual Behavior

The build failed because private dependencies cannot be found.


What I Have Checked

The pip.conf file exists in the build context and is not empty.
Running the command manually with docker buildx build works perfectly:

docker buildx build   
 --platform linux/amd64 \  
 --pull \
 --build-arg BUILDKIT_INLINE_CACHE=1 \  
 --secret id=pip,src=$GITHUB_WORKSPACE/.config/pip/pip.conf \   
 -t test:123 \  
 python

BuildKit is enabled (DOCKER_BUILDKIT=1).
Debugging with ls confirms that the file exists before the build starts.
This issue only happens with docker/build-push-action@v6.


Question

Why is the secret not passed to the build when using docker/build-push-action@v6, but it works fine with docker buildx build?
Are there known issues with how secrets: are passed in this GitHub Action?
Is there a better way to securely pass pip.conf to the Docker build in this setup?

Any insights would be appreciated. Thanks!

EDIT 20.Feb:

I have further analyzed the issue and found the following insights:

  1. Running docker buildx build directly → works.

The secret is passed correctly, /run/secrets/pip is available.

  1. **Using docker/build-push-action@v5 with secret-files: or

secrets: with the exact same path→ does not work.**
Error: Even though the file exists.

  1. Tried different Paths for the file:

    • $GITHUB_WORKSPACE/.config/pip/pip.conf
    • $GITHUB_WORKSPACE/python/pip.conf
    • $GITHUB_WORKSPACE/pip.conf
    • $HOME/pip.conf
    • /.config/pip/pip.conf
    • python/pip.conf
    • /pip.conf

    → Same Error even though the file exists at every place

I still have no idea what the problem is, and I am considering creating an issue on GitHub.


Solution

  • Solution: Why secrets and secret-files were not working in docker/build-push-action@v6

    After extensive debugging, I finally found the solution! The main issues were:

    1. Incorrect Path Resolution for Secrets

    2. Difference Between secrets and secret-files

    3. Fixing the Issue

    Solution 1: Use secret-files: with the Correct Path

    - name: Build and push Docker images
      uses: docker/build-push-action@v6
      with:
        context: python
        secret-files: |
          pip=${{ github.workspace }}/.config/pip/pip.conf
    

    This ensures that the file is correctly passed into BuildKit.

    Solution 2: Use secrets: to Pass File Content Directly

    If you don't want to create a file manually, you can pass the content directly:

    - name: Build and push Docker images
      uses: docker/build-push-action@v6
      with:
        context: python
        secrets: |
          "pip=[global]
          extra-index-url = ${{ secrets.PIP_CONF }}"
    

    This way, the content is injected directly as a secret, avoiding the need for a physical file.


    Final Thoughts