Secret interface

The secret interface lets an SDK use a credential, such as an API key, that stays in the user’s host keyring. Neither the SDK definition nor the workshop definition needs to contain the value, and neither does anything else that ships with the SDK or the project.

The interface splits the job between the two people involved. The SDK author knows that the SDK needs a credential, so the SDK declares a secret plug. Only the user knows where their credential is kept, so the workshop definition must add a secret slot that tells Workshop how to find it in the host keyring. Connecting the plug to the slot lets processes in the workshop request the value whenever they need it.

Secret interface plug

A secret plug declares that the SDK needs one credential. Only regular SDKs can declare it; the system SDK can’t. The plug takes any valid plug name and carries no attributes, so it describes the need, not the value or where to find it:

sdkcraft.yaml
plugs:
  api-key:
    interface: secret

The plug’s name affects how the SDK asks for the value. Inside the workshop, the secret is identified as SDK.PLUG, which is secret-demo.api-key for the plug above in an SDK named secret-demo. Both the SDK’s commands and its systemd units request the value by that identifier.

Secret interface slot

A secret slot describes one item in the host keyring. Only the system SDK can have secret slots; each slot carries the lookup details:

workshop.yaml
sdks:
  - name: system
    slots:
      demo-key:
        interface: secret
        attributes:
          service: secret-demo
          account: test
  - name: secret-demo

The slot carries lookup details only, never the value. Its attributes are the name and value pairs that the keyring item was stored with; a lookup succeeds only when exactly one keyring item carries all of them.

An optional collection selects the keyring collection to search; the keyring’s default collection is used if the slot doesn’t name one. A non-default value is matched against collection labels and must identify exactly one collection. For the full grammar, see Interfaces.

When the workshop is launched or refreshed, Workshop validates the slot’s keys and their types, but it doesn’t look in the keyring. Whether a matching item exists is only known when a process requests the value.

Connection

Workshop never connects a secret plug on its own: a secret reaches a workshop only by a user’s explicit decision. The interface policy denies auto-connection outright, so listing the pair in the workshop definition’s connections doesn’t connect it either; see Auto-connection. Users connect and disconnect the plug with workshop connect and workshop disconnect:

$ workshop connect dev/secret-demo:api-key dev/system:demo-key
$ workshop disconnect dev/secret-demo:api-key

The connection is listed as manual:

$ workshop connections dev

  INTERFACE  PLUG                     SLOT                 NOTES
  ...
  secret     dev/secret-demo:api-key  dev/system:demo-key  manual

Connecting reads nothing from the keyring and puts nothing in the workshop; it only permits later requests.

After the connection is established, workshop refresh keeps it as long as the slot’s attributes and collection stay the same. A refresh that changes either of them will disconnect the plug and report a warning, because the new lookup can match a different item; connecting the plug again approves the new lookup. A workshop restore drops the connection, and so does a refresh that removes the plug from the SDK or the slot from the workshop definition; see Connections across refresh and restore.

How a value reaches the workshop

Workshop looks the value up in the host keyring each time a process in the workshop requests it. A direct command request writes the value to standard output; a systemd request makes it available as a credential file to the unit’s user and root. Workshop doesn’t persist the value; it handles the value only transiently while fulfilling the request.

Because every request is a fresh lookup, the keyring stays in control: a value changed in the keyring takes effect on the next request, and a request made while the keyring is locked fails. Workshop looks the item up through the user’s D-Bus session bus, where a keyring service implementing the freedesktop.org Secret Service, such as GNOME Keyring, must be running. Workshop doesn’t unlock the keyring or prompt for a password; the user unlocks it in their session.

A process can request the value in two ways.

Command requests

A command runs workshopctl get-secret <SDK>.<PLUG>, typically in a wrapper script that a secret-consuming SDK ships. workshopctl passes the request to Workshop on the host, which checks that the plug is connected, looks up the item described by the connected slot, and returns the value. workshopctl writes it to its standard output, so the value goes wherever that output goes: normally into the wrapper that captures it, but also to a terminal, a file, or a log if the output is sent there.

When the request fails, workshopctl prints a short message that names the plug and the cause: an unconnected plug, a locked keyring, no matching item or several of them, or another failure. The workshopctl get-secret reference lists the exit statuses. For a failure that Workshop doesn’t classify, the message only says internal error, because the underlying error can include details of the host or the keyring; those details stay in the request’s record on the host.

Service requests

A long-running service receives the value as a systemd credential. Every workshop runs a secret socket, and runtime hooks get its path in SDK_SYSTEMD_SECRET_SOCKET. A hook that installs a unit names the credential SDK.PLUG, here secret-demo.api-key, and points it at that socket:

LoadCredential=secret-demo.api-key:${SDK_SYSTEMD_SECRET_SOCKET}

When systemd starts the unit, it connects to the socket, and Workshop looks the value up as it does for a command and returns it to systemd, which places it in the unit’s credentials directory. The request happens on every start of the unit, and only then.

A request that yields no value doesn’t stop the unit: systemd starts it with an empty credential, and the service decides how to handle the missing value. This happens when the plug isn’t connected, and when the lookup fails because the keyring is locked or no item matches; the workshop-secret@ journal names the cause.

Expect an empty credential at launch, where a service can start before the user has connected the plug, and during a refresh, where services and setup-base hooks run before Workshop restores preserved connections. Give the unit a restart policy, or restart it once the plug is connected; How to use secrets in an SDK shows both. If a refresh leaves the plug disconnected, connect it again, then restart the service.

Request records

Every request, whether from a command or a service, creates a Retrieve secret change named after the workshop, SDK, and plug, such as Retrieve secret "dev/secret-demo:api-key". A Done change means that Workshop retrieved the value; it doesn’t confirm that the requesting process received it. An Error change means that the retrieval failed, and its task log names the cause. Neither the change nor its tasks contain the value.

These records answer whether and when a secret was requested, and why a request failed, even when the SDK doesn’t pass the error on. They are troubleshooting history, not a durable audit trail, because Workshop prunes ready changes. See Troubleshoot failed lookups for how to read them.

What a connection exposes

A connection exposes the secret to the entire workshop, not to one SDK or one process. While the plug is connected, any process in the workshop, including commands that don’t belong to the SDK and units installed by other SDKs, can request the value by naming the plug’s SDK.PLUG.

A systemd credential is a file under /run/credentials/<UNIT> in the workshop’s filesystem, readable by the unit’s user and root for as long as the unit runs. Because ordinary workshop commands and services share the workshop user, other processes running as that user can read the credential file of such a service while it runs.

Once a process receives the value, Workshop has no further control over it. The process can keep it in its environment, pass it to its child processes, or write it somewhere; how far the value travels depends on how the SDK hands it on, as compared in How to use secrets in an SDK.

Disconnecting the plug stops new requests, but it can’t withdraw a value that a process has already received.

See also

Explanation:

How-to guides:

Reference: