You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Podman can't remove a secret that was created using --driver=pass if the gnupg and password-store storages corresponding to podman secret inspect no longer exist.
Is there no way to force removal (--force ...?)
Steps to reproduce the issue
This proof demonstrates the issue using nested podman containers (podman-in-podman):
The test proceeds as follows within a container:
A secret ('secret-1') is created and successfully removed while its driver directories exist.
A second secret ('secret-2') is created.
The 'pass' driver's storage and GPG directories are manually deleted.
podman secret rm secret-2 is executed and is expected to fail,
demonstrating the issue.
Caution
This example was developed using nested Podman containers to safely demonstrate the issue, without
interacting with real gnupg or password-store storages.
However, only use it if you know what you are doing.
Click too see the code
podman run -it --rm --privileged \
registry.fedoraproject.org/fedora:43 \
/bin/bash -c ' set -e echo; echo "------ Create test script ------"; echo cat << \EODRIVERSH > /tmp/proof.sh#!/usr/bin/env bashset -e pushd $(pwd) > /dev/nulltrap "popd > /dev/null" EXIT# Podman secret namePODMAN_SECRET_NAME="${1:-driver_pass_test}"# GPG key ID used by `pass`GPG_KEY_EMAIL="local@local.secret"## Name for the new key if the ID does not existGPG_KEY_NAME="Podman Secret"# Configure `gpg`: GPG key directory (will be created if it does not exist)GNUPGDIR="$(pwd)/.gnupg-podman"# Configure `pass`:## `pass` storage directory (sub-dir "podman"). (will be created if it does not exist)PASSWORD_STORE_DIR="$(pwd)/.password-store-podman/podman"## `gpg` options used by `pass` when getting keysPASSWORD_STORE_GPG_OPTS="--homedir $GNUPGDIR"# Export for `pass` usageexport PASSWORD_STORE_DIRexport PASSWORD_STORE_GPG_OPTS# gpg wrapper with --homedirgpg() { command gpg --homedir "$GNUPGDIR" "$@"}# Create example credentials filecat << \EOF > "$(pwd)/cred-example.json"{ "id": 1, "pass": "secret_pass"}EOF# Ensure the GPG key exists (create if necessary)if ! gpg --list-keys "$GPG_KEY_EMAIL" &>/dev/null; then mkdir -m 700 "$GNUPGDIR" # These options set a blank password and inhibit the prompt: --batch --yes --pinentry-mode loopback --passphrase "" if gpg --batch --yes --pinentry-mode loopback --passphrase "" --quick-gen-key "$GPG_KEY_NAME <$GPG_KEY_EMAIL>"; then echo "Key successfully created in $GNUPGDIR" fielse echo "Key already exists for $GPG_KEY_EMAIL in $GNUPGDIR"fi# Ensure `pass` storage existsif ! pass ls &> /dev/null; then # The PASSWORD_STORE_DIR directory will be created if it does not exist # Initialize the `pass` storage, assigning a "gpg-id" to a specific "podman" sub-storage pass init "$GPG_KEY_EMAIL" 2> /dev/nullfi# Create a podman secret protected by `pass` (--driver=pass) from the credentials file.# The `pass` driver considers the GNUPGDIR and PASSWORD_STORE_DIR settings for the GPG_KEY_EMAIL keypodman secret create --replace --driver=pass \ "--driver-opts=root=$PASSWORD_STORE_DIR" \ "--driver-opts=gpghomedir=$GNUPGDIR" \ "--driver-opts=key=$GPG_KEY_EMAIL" \ "$PODMAN_SECRET_NAME" /tmp/cred-example.json# End of scriptEODRIVERSH [[ $? -eq 0 ]] && echo "Script created: /tmp/proof.sh" chmod +x /tmp/proof.sh && echo "Script executable: /tmp/proof.sh" # --- LOGS --- GREEN="\033[0;32m" RED="\033[0;31m" NC="\033[0m" # No Color log_success() { echo -e "${GREEN}[PASS]${NC} $1"; } log_error() { echo -e "${RED}[FAIL]${NC} $1"; } echo; echo "----- Container Installs and environment config-----"; echo echo "Installs: podman pass gnupg2 pinentry" dnf install -y podman pass gnupg2 pinentry # Use "vfs" for improved compatibility with podman-in-podman. sudo tee /etc/containers/storage.conf > /dev/null << \EOVFS[storage]driver = "vfs"EOVFS podman system reset -f echo; echo "------ Prepare Tests ------"; echo cd /tmp # create secret with driver=pass from non default gpg and pass root directories ./proof.sh "secret-1" > /dev/null # create secret with driver=pass from non default gpg and pass root directories ./proof.sh "secret-2" > /dev/null echo; echo ".......... Tests ..........."; echo podman secret exists "secret-1" && log_success "Secret exists: secret-1" || log_error "Secret not exists: secret-1 " podman secret rm "secret-1" &> /dev/null && log_success "Can remove secret: secret-1" || log_error "Can not remove secret: secret-1" ! podman secret exists "secret-1" && log_success "Secret no more exists: secret-1" || log_error "Secret still exists: secret-1" podman secret exists "secret-2" && log_success "Secret exists: secret-2 " || log_error "Secret not exists: secret-2 " rm -rf /tmp/.gnu* /tmp/.pass* > /dev/null && log_success "Success to remove: /tmp/.gnu* /tmp/.pass*" || log_error "Fail to remove: /tmp/.gnu* /tmp/.pass*" podman secret rm "secret-2" &> /dev/null && log_success "Can remove secret: secret-2" || log_error "Can not remove secret: secret-2" ! podman secret exists "secret-2" && log_success "Secret no more exists: secret-2 " || log_error "Secret still exists: secret-2 " # Interactive /bin/bash'
Describe the results you received
.......... Tests ...........
[PASS] Secret exists: secret-1
[PASS] Can remove secret: secret-1
[PASS] Secret no more exists: secret-1
[PASS] Secret exists: secret-2
[PASS] Success to remove: /tmp/.gnu* /tmp/.pass*
[FAIL] Can not remove secret: secret-2
[FAIL] Secret still exists: secret-2
Describe the results you expected
.......... Tests ...........
[PASS] Secret exists: secret-1
[PASS] Can remove secret: secret-1
[PASS] Secret no more exists: secret-1
[PASS] Secret exists: secret-2
[PASS] Success to remove: /tmp/.gnu* /tmp/.pass*
[PASS] Can remove secret: secret-2
[PASS] Secret no more exists: secret-2
podman info output
host:
arch: amd64buildahVersion: 1.42.0cgroupControllers: []cgroupManager: cgroupfscgroupVersion: v2conmon:
package: conmon-2.1.13-2.fc43.x86_64path: /usr/bin/conmonversion: 'conmon version 2.1.13, commit: 'cpuUtilization:
idlePercent: 96.49systemPercent: 0.9userPercent: 2.62cpus: 8databaseBackend: sqlitedistribution:
distribution: fedoravariant: containerversion: "43"eventLogger: filefreeLocks: 2048hostname: dd113fd30f13idMappings:
gidmap: nulluidmap: nullkernel: 6.14.0-36-genericlinkmode: dynamiclogDriver: journaldmemFree: 966803456memTotal: 6211403776networkBackend: netavarknetworkBackendInfo:
backend: netavarkdns:
package: aardvark-dns-1.17.0-1.fc43.x86_64path: /usr/libexec/podman/aardvark-dnsversion: aardvark-dns 1.17.0package: netavark-1.17.0-1.fc43.x86_64path: /usr/libexec/podman/netavarkversion: netavark 1.17.0ociRuntime:
name: crunpackage: crun-1.25.1-1.fc43.x86_64path: /usr/bin/crunversion: |- crun version 1.25.1 commit: 156ae065d4a322d149c7307034f98d9637aa92a2 rundir: /run/crun spec: 1.0.0 +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +LIBKRUN +WASM:wasmedge +YAJLos: linuxpasta:
executable: /usr/bin/pastapackage: passt-0^20250919.g623dbf6-1.fc43.x86_64version: | pasta 0^20250919.g623dbf6-1.fc43.x86_64 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: truepath: /run/podman/podman.sockrootlessNetworkCmd: pastasecurity:
apparmorEnabled: falsecapabilities: 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_CHROOTrootless: falseseccompEnabled: trueseccompProfilePath: /usr/share/containers/seccomp.jsonselinuxEnabled: falseserviceIsRemote: falseslirp4netns:
executable: ""package: ""version: ""swapFree: 16123498496swapTotal: 17179860992uptime: 10h 55m 27.00s (Approximately 0.42 days)variant: ""plugins:
authorization: nulllog:
- k8s-file
- none
- passthrough
- journaldnetwork:
- bridge
- macvlan
- ipvlanvolume:
- localregistries:
search:
- registry.fedoraproject.org
- registry.access.redhat.com
- docker.iostore:
configFile: /etc/containers/storage.confcontainerStore:
number: 0paused: 0running: 0stopped: 0graphDriverName: vfsgraphOptions: {}graphRoot: /var/lib/containers/storagegraphRootAllocated: 80107012096graphRootUsed: 11603017728graphStatus: {}imageCopyTmpDir: /var/tmpimageStore:
number: 0runRoot: /run/containers/storagetransientStore: falsevolumePath: /var/lib/containers/storage/volumesversion:
APIVersion: 5.7.0BuildOrigin: Fedora ProjectBuilt: 1762819200BuiltTime: Tue Nov 11 00:00:00 2025GitCommit: 0370128fc8dcae93533334324ef838db8f8da8cbGoVersion: go1.25.4 X:nodwarf5Os: linuxOsArch: linux/amd64Version: 5.7.0
Issue Description
Podman can't remove a secret that was created using
--driver=passif thegnupgandpassword-storestorages corresponding topodman secret inspectno longer exist.Is there no way to force removal (
--force...?)Steps to reproduce the issue
This proof demonstrates the issue using nested podman containers (podman-in-podman):
The test proceeds as follows within a container:
podman secret rm secret-2is executed and is expected to fail,demonstrating the issue.
Caution
This example was developed using nested Podman containers to safely demonstrate the issue, without
interacting with real
gnupgorpassword-storestorages.However, only use it if you know what you are doing.
Click too see the code
Describe the results you received
Describe the results you expected
podman info output
Podman in a container
Yes
Privileged Or Rootless
Privileged
Upstream Latest Release
Yes
Additional environment details
Additional environment details
Additional information
No response