Skip to content

'podman push' fails if GET/HEAD succeeds without authentication, but POST returns 401 #1009

Description

@ffplexim

Issue Description

I have a local container registry behind an nginx proxy that is configured as follows:

  • GET, HEAD, and OPTIONS requests do not require authentication;
  • every other HTTP method requires HTTP basic authentication.

The idea is that everyone can pull, but only authenticated users can push.

Now I've logged into the registry with podman login (that is always successful, also for wrong credentials, since the requests it does do not require authentication), but when I try to push an image with podman push it fails:

% podman --log-level=debug push myregistry.local/tests/hello-world:latest
INFO[0000] podman filtering at log level debug          
DEBU[0000] Called push.PersistentPreRunE(podman --log-level=debug push myregistry.local/tests/hello-world:latest) 
DEBU[0000] SSH Ident Key "/Users/me/.local/share/containers/podman/machine/machine" SHA256:21Nl633r+TBVZjIpNYTam9FgZHdNsuOJRNTCDIejQn4 ssh-ed25519 
DEBU[0000] DoRequest Method: GET URI: http://d/v6.0.1/libpod/_ping 
DEBU[0000] Found credentials for myregistry.local in credential helper containers-auth.json in file /Users/me/.config/containers/auth.json 
DEBU[0000] DoRequest Method: POST URI: http://d/v6.0.1/libpod/images/myregistry.local/tests/hello-world:latest/push 
Getting image source signatures
Copying blob sha256:55f6d36790cbd258a2173e1599268519414f9973696bcfc0f5193c1accee0951
Error: writing blob: initiating layer upload to /v2/tests/hello-world/blobs/uploads/ in myregistry.local: authentication required
DEBU[0000] Shutting down engines                        

The nginx log:

192.168.1.10 - - [22/Jul/2026:11:51:18 +0000] "GET /v2/ HTTP/1.1" 200 2 "-" "containers/5.34.1 (github.com/containers/image)" "-"
192.168.1.10 - - [22/Jul/2026:11:51:18 +0000] "HEAD /v2/tests/hello-world/blobs/sha256:55f6d36790cbd258a2173e1599268519414f9973696bcfc0f5193c1accee0951 HTTP/1.1" 404 0 "-" "containers/5.34.1 (github.com/containers/image)" "-"
192.168.1.10 - - [22/Jul/2026:11:51:18 +0000] "HEAD /v2/tests/hello-world/blobs/sha256:1ff9adeff4443b503b304e7aa4c37bb90762947125f4a522b370162a7492ff47 HTTP/1.1" 404 0 "-" "containers/5.34.1 (github.com/containers/image)" "-"
192.168.1.10 - - [22/Jul/2026:11:51:18 +0000] "POST /v2/tests/hello-world/blobs/uploads/ HTTP/1.1" 401 179 "-" "containers/5.34.1 (github.com/containers/image)" "-"

As you can see, the GET/HEAD requests just work, and from that podman apparently infers that the POST request should also just work. When the POST request returns 401, instead of re-trying with the stored credentials, it simply fails.

(I also temporarily changed the nginx log output to debug format, and it explicitly confirmed no user/password was provided for basic authentication for the POST - so it explicitly wasn't a typo in the credentials, but simply no Authorization header got sent.)

Steps to reproduce the issue

Steps to reproduce the issue

  1. Set up a registry where GET/HEAD/OPTIONS can be done by any user, but other HTTP methods require authorization
  2. Log into the registry with podman login
  3. Try to push an image with podman push

Describe the results you received

podman push fails, and the HTTP server log shows that podman simply gave up after retrieving a 401, despite it having credentials it can use.

Describe the results you expected

I can push the image. (Or at least I would get a step further, namely that after the 401 podman push tries again with an Authorization header.)

podman info output

(I also tried this with a different podman version on a Linux box, with the same result.)

Client:
  APIVersion: 6.0.2
  BuildOrigin: brew
  Built: 1784664683
  BuiltTime: Tue Jul 21 22:11:23 2026
  GitCommit: ""
  GoVersion: go1.26.5
  Os: darwin
  OsArch: darwin/arm64
  Version: 6.0.2
host:
  arch: arm64
  buildahVersion: 1.39.2
  cdiSpecDirs: null
  cgroupControllers:
  - cpuset
  - cpu
  - io
  - memory
  - pids
  - rdma
  - misc
  cgroupManager: systemd
  cgroupVersion: v2
  conmon:
    package: conmon-2.1.12-3.fc41.aarch64
    path: /usr/bin/conmon
    version: 'conmon version 2.1.12, commit: '
  cpuUtilization:
    idlePercent: 96.9
    systemPercent: 1.84
    userPercent: 1.26
  cpus: 6
  databaseBackend: sqlite
  distribution:
    distribution: fedora
    variant: coreos
    version: "41"
  eventLogger: journald
  freeLocks: 2047
  hostname: localhost.localdomain
  idMappings:
    gidmap: null
    uidmap: null
  kernel: 6.12.13-200.fc41.aarch64
  linkmode: dynamic
  logDriver: journald
  memFree: 3015950336
  memTotal: 3791691776
  networkBackend: netavark
  networkBackendInfo:
    backend: netavark
    dns:
      package: aardvark-dns-1.14.0-1.fc41.aarch64
      path: /usr/libexec/podman/aardvark-dns
      version: aardvark-dns 1.14.0
    package: netavark-1.14.0-1.fc41.aarch64
    path: /usr/libexec/podman/netavark
    version: netavark 1.14.0
  ociRuntime:
    name: crun
    package: crun-1.20-2.fc41.aarch64
    path: /usr/bin/crun
    version: |-
      crun version 1.20
      commit: 9c9a76ac11994701dd666c4f0b869ceffb599a66
      rundir: /run/crun
      spec: 1.0.0
      +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +LIBKRUN +WASM:wasmedge +YAJL
  os: linux
  pasta:
    executable: /usr/bin/pasta
    package: passt-0^20250121.g4f2c8e7-2.fc41.aarch64
    version: |
      pasta 0^20250121.g4f2c8e7-2.fc41.aarch64-pasta
      Copyright Red Hat
      GNU General Public License, version 2 or later
        <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
      This is free software: you are free to change and redistribute it.
      There is NO WARRANTY, to the extent permitted by law.
  remoteSocket:
    exists: true
    path: unix:///run/podman/podman.sock
  rootlessNetworkCmd: pasta
  rootlessPortForwarder: ""
  security:
    apparmorEnabled: false
    capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
    rootless: false
    seccompEnabled: true
    seccompProfilePath: /usr/share/containers/seccomp.json
    selinuxEnabled: true
  serviceIsRemote: true
  swapFree: 0
  swapTotal: 0
  uptime: 0h 0m 28.00s
  variant: v8
plugins:
  authorization: null
  log:
  - k8s-file
  - none
  - passthrough
  - journald
  network:
  - bridge
  - macvlan
  - ipvlan
  volume:
  - local
registries:
  search:
  - docker.io
store:
  containerStore:
    number: 1
    paused: 0
    running: 0
    stopped: 1
  graphDriverName: overlay
  graphOptions:
    overlay.additionalImageStores:
    - /usr/lib/containers/storage
    overlay.imagestore: /usr/lib/containers/storage
    overlay.mountopt: nodev,metacopy=on
  graphRoot: /var/lib/containers/storage
  graphRootAllocated: 98899800064
  graphRootUsed: 8574558208
  graphStatus:
    Backing Filesystem: xfs
    Native Overlay Diff: "false"
    Supports d_type: "true"
    Supports shifting: "true"
    Supports volatile: "true"
    Using metacopy: "true"
  imageCopyTmpDir: /var/tmp
  imageStore:
    number: 16
  runRoot: /run/containers/storage
  transientStore: false
  volumePath: /var/lib/containers/storage/volumes
version:
  APIVersion: 5.4.1
  BuildOrigin: Fedora Project
  Built: 1741651200
  BuiltTime: Tue Mar 11 01:00:00 2025
  GitCommit: b79bc8afe796cba51dd906270a7e1056ccdfcf9e
  GoVersion: go1.23.7
  Os: linux
  OsArch: linux/arm64
  Version: 5.4.1

Podman in a container

No

Privileged Or Rootless

Rootless

Upstream Latest Release

Yes

Additional environment details

Additional information

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions