Inspect Docker Swarm Secrets Without Exposing Their Contents
docker secret inspect reads only metadata, but names, labels and timestamps can still say more about your deployment than you meant to share. This covers reading that metadata for one or more secrets, pulling a single field with a Go template, and recognising the errors that mean you are on the wrong node or typed the wrong name. About ten minutes if you already have manager access.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide describes Docker CLI 29.8.1, provided here by docker-ce-cli 5:29.8.1-1~ubuntu.24.04~noble. The command's shape is stable enough to be useful elsewhere, but check exact fields against your own installed help on other releases.
1. Check the installed command
Start with read-only checks. Neither changes Docker state, and neither normally needs sudo:
$ command -v docker
/usr/bin/docker
$ docker --version
Docker version 29.8.1, build 4a63305
$ docker secret inspect --help
Usage: docker secret inspect [OPTIONS] SECRET [SECRET...]
Display detailed information on one or more secrets
A secret can be identified by name or ID. This is a Docker Swarm command, not ordinary standalone-container administration, which matters before you spend time debugging what looks like a wrong name.
2. Confirm the client reaches a Swarm manager
Inspecting a Swarm secret is a cluster-management operation. Run:
$ docker info --format '{{.Swarm.LocalNodeState}} {{.Swarm.ControlAvailable}}'
active true
Expect active true on a manager. Wording can differ across Docker versions and contexts, but the facts that matter are that Swarm is active and this node has manager control. If Docker says this node is not a manager, switch context rather than run docker swarm init, which changes cluster state and belongs to a different guide entirely.
Checkpoint
Confirm the target context before inspecting anything sensitive:
$ docker context show
default
$ docker info --format 'server={{.ServerVersion}} swarm={{.Swarm.LocalNodeState}} manager={{.Swarm.ControlAvailable}}'
server=29.8.1 swarm=active manager=true
Your context name and server version will differ. If the context points at a production manager, treat every name, label and timestamp you get back as production information.
3. Inspect one secret by name or ID
Use a real name from your approved inventory. Listing is also read-only:
$ docker secret ls
ID NAME DRIVER CREATED UPDATED
eo7jnzguqgtpdah3cm5srfb97 app-config <none> 3 minutes ago 3 minutes ago
$ SECRET_NAME='app-config'
$ docker secret inspect "$SECRET_NAME"
[
{
"ID": "eo7jnzguqgtpdah3cm5srfb97",
"Version": { "Index": 17 },
"CreatedAt": "2017-03-24T08:15:09.735271783Z",
"UpdatedAt": "2017-03-24T08:15:09.735271783Z",
"Spec": {
"Name": "app-config",
"Labels": { "env": "dev" }
}
}
]
Those timestamps, the ID and the version are examples of shape, not values to expect on your own host. The CLI renders results as a JSON array by default, even for one object: identity, version, timestamps, name and labels. There is no command for reading the payload, so do not try to substitute a host file path or a container environment variable for the secret name.
4. Select one field for scripts
Use --format or -f when a script needs one value rather than the whole document. Docker runs the supplied Go template against each match:
$ docker secret inspect --format '{{.Spec.Name}}' "$SECRET_NAME"
app-config
$ docker secret inspect --format '{{.CreatedAt}}' "$SECRET_NAME"
2017-03-24 08:15:09.735271783 +0000 UTC
That timestamp is illustrative; yours will hold whatever the manager actually stored. Keep the template quoted so the shell passes braces and spaces through unchanged. Need several fields? Emit one deliberately simple, machine-readable line and handle escaping in the consuming program rather than parsing the human-facing JSON with a chain of fragile text filters.
The special value json asks Docker to print JSON for each result:
$ docker secret inspect --format json "$SECRET_NAME"
{"ID":"eo7jnzguqgtpdah3cm5srfb97","Version":{"Index":17},"CreatedAt":"2017-03-24T08:15:09.735271783Z","UpdatedAt":"2017-03-24T08:15:09.735271783Z","Spec":{"Name":"app-config","Labels":{"env":"dev"}}}
Tip
--pretty gives a friendlier display during an incident. It is still metadata, not content, and less suited to a script.
5. Inspect several secrets carefully
Pass multiple names or IDs after the options:
$ docker secret inspect --format '{{.Spec.Name}} {{.UpdatedAt}}' app-config api-token
app-config 2017-03-24 08:15:09.735271783 +0000 UTC
api-token 2017-03-24 08:16:11.735271783 +0000 UTC
A missing name fails the whole command, so partial output is not proof every requested secret was found. For an automated check, capture the exit status and count returned records against requested identifiers. Avoid broad output capture in shared terminals and CI logs: names and labels can disclose deployment structure even with the payload staying protected.
6. Diagnose the common failures
None of these change state:
$ docker secret inspect definitely-not-a-real-secret
Error response from daemon: secret definitely-not-a-real-secret not found
$ printf 'exit status: %s\n' "$?"
exit status: 1
- Not found: exact wording varies by release, but a non-zero status means check the spelling, the current context, and whether the object actually exists in this Swarm. A secret from another cluster will not appear just because the name looks familiar.
- Not a manager: switch to an approved manager context. Do not run
docker swarm initon a host already in another environment. - Access denied: ask for the narrowly scoped manager permission you actually need. Do not join a broad administrative group just to inspect one secret.
- Daemon unreachable: fix the Docker context or service access first. Changing the secret is not a connectivity test.
Done means
- Checked the command and Docker CLI version locally.
- Confirmed the active context reaches a Swarm manager, or recorded the manager-context blocker.
- Identified the requested secret by an approved name or ID.
- Chose default JSON, a selected field, or
--prettyfor the actual reader. - Kept the secret payload out of every command, transcript and log.
- Checked the exit status, especially when inspecting several secrets at once.