Search code examples
dockergithubgithub-actions

Invalid key format when building image in Github Actions using build-push-action


I created a github workflow (Build Image) that successfuly builds an image using a Dockerfile and secrets.SSH_KEY. But, my other workflow (Build and Upload Image) that should build and upload the image to github registry using same Dockerfile secrets.SSH_KEY fails with Load key "/root/.ssh/id_ed25519": invalid format error (see below).

I tried passing SSH_PRIVATE_KEY="${{ secrets.SSH_KEY }}" with and without quotes but I get same error. What can be the problem?

Build Image

name: Build Image
on:
  release:
    branches: [ "main" ]
    types: [published]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Build the Docker image
        run: docker build . --build-arg SSH_PRIVATE_KEY="${{ secrets.SSH_KEY }}" --file Dockerfile --tag my_image
        working-directory: ./docker

Build and Upload Image

name: Docker Image
on:
  push:
  release:
    branches: [ "main" ]
    types: [published]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: my_image

jobs:
  build-and-push-image:
    runs-on: ubuntu-latest

    permissions:
      contents: read
      packages: write

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

      - name: Log in to the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: ./docker
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            SSH_PRIVATE_KEY="${{ secrets.SSH_KEY }}"

Error

0.209 Cloning into 'my_repo'...
0.254 Warning: Permanently added the ECDSA host key for IP address '140.82.112.4' to the list of known hosts.
0.318 Load key "/root/.ssh/id_ed25519": invalid format
0.318 [email protected]: Permission denied (publickey).
0.320 fatal: Could not read from remote repository.

Dockerfile

FROM ubuntu:20.04

ARG SSH_PRIVATE_KEY
RUN mkdir /root/.ssh && chmod -R 700 /root/.ssh \
    && echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_ed25519 \
    && chmod 0400 /root/.ssh/id_ed25519 && echo "StrictHostKeyChecking no" > /root/.ssh/config \
    && ssh-keyscan github.com >> /root/.ssh/known_hosts

ARG WORKSPACE_DIR
RUN mkdir -p ${WORKSPACE_DIR}
WORKDIR ${WORKSPACE_DIR}

RUN git clone --depth 1 -b 0.1.0 [email protected]:private-repo/private-repo1.git \
    && git clone --depth 1 -b 0.1.0 [email protected]:private-repo/private-repo2.git \
    && git clone --depth 1 -b 0.21.0 https://github.com/public-repo/public-repo1.git

Solution

  • Had to dig fairly deep, but it seems the issue lies in a combination of how SSH keys should be formed and how GH actions / docker/build-push-actions is coded.

    Study

    After having a look at https://serverfault.com/a/854212, you can see from the comments that even a missing newline can cause the error invalid format. Since your build works just fine when building from command line, but not with the docker/build-push-action. I initially thought the issue could be something small like this.

    I was on the right track, but the issue was a bit bigger than just one newline missing. Inspecting the build log of the GH action gives a clue: it seems to expand the multiline variable too early:

    --build-arg SSH_PRIVATE_KEY="*** --build-arg *** --build-arg *** --build-arg *** --build-arg *** --build-arg *** --build-arg *** --build-arg *** --build-arg ***"
    

    This goes obviously wrong, and it seems to be the result how GH actions expands secrets / environment variables before they are inserted into the commands. This apparently parses all lines to a new build arg.

    Solution

    Surounding the whole build arg with quotations works:

              build-args: |
                "SSH_PRIVATE_KEY=${{secrets.SSH_KEY}}"
    

    Result in the build log

    /usr/bin/docker buildx build --build-arg SSH_PRIVATE_KEY=***
    ***
    ***
    ***
    ***
    ***
    ***
    ***
    *** --iidfile /home/runner/work/_temp/docker-actions-toolkit-L9DUvR/iidfile --tag latest --metadata-file /home/runner/work/_temp/docker-actions-toolkit-L9DUvR/metadata-file --push .
    

    I was able to pull the repository without an error with this format.