Skip to content

Support OS keychain [macos, linux, windows] #5

@Benehiko

Description

@Benehiko

Historically Docker has relied upon the docker-credential-helper which ships with Docker Desktop.

The docker-credential-helper is a separate binary and is always invoked as a separate binary due to the limitations of the OS keystore. As far as I am aware, macOS has a limitation that when writing a credential to the keystore it is only retrievable by the same binary. So storing a credential in the Docker CLI will only be retrievable by the Docker CLI.

With what does it integrate?

Depending on the OS, the docker-credential-helper integrates with:

In the past the docker-credential-helper used to integrate directly with the macOS Security/Security.h C library, but was swapped for the keybase/go-keychain library in this commit docker/docker-credential-helpers@4cdcdc2 due to deprecated SDK functions in osx docker/docker-credential-helpers#280.

The credential helper also usually ships the pass implementation and not the libsecret implementation. The pass implementation was added here docker/docker-credential-helpers#81 to support use cases where the user does not have a GUI installed (e.g. server environments).

Why not just use the credential helper?

The credential helper is very tied to the concept of a registry. Each credential stored is using a ServerURL to indicate which registry is saving the credential. You can see this in our schema defined for the libsecret implementation over here

Over time we have started moving away from registry authentication to other types of authentication like OAuth (Docker Hub login). This means that a login is based on a realm or namespace and multiple users could be saved under a realm / namespace.

Doing an exec out to the binary is annoying. It gives little control to the library implementing the credential-helper - we even have to rely on the user to install this (in certain environments) and we rely on the config specifying the correct credential-helper.

  • This is a confusing UX to the user
  • Other software can change the config
  • Requires installing another binary

Why in Secrets Engine?

We want a re-usable keystore library that can be consumed by tools within Docker. The Secrets engine will be the main point of contact for most tools within Docker as each tool will also have a provider interface with the Secrets Engine to retrieve secrets from a keystore.

We could do it in a separate repository, but keeping it here will enable us to be fast when iterating and we can always move it out when needed.

What do we want to use for MacOS?

Since we already know that keybase/go-keychain works with docker-credential-helper, possibly sticking with it would be OK. It is unclear if keybase/go-keychain is really maintained, but it is widely used, so we wouldn't be the only ones complaining if it breaks.

What do we want to use for Linux?

It seems like a safe bet is to use libsecret. It supports calling the freedesktop secrets service and falling back to an encrypted file if not available.

We should call org.freedesktop.secrets over DBUS using keybase/go-keychain. The fallback libsecret provides is still reliant on the user having a GUI because of the reliance on org.freedesktop.portal.

What do we want to use for Windows?

We'll use https://github.com/danieljoos/wincred

Fallback store

A fallback store should be self-contained, easy to use and secure. The current credential helper fails at providing a self-contained store, it relies on pass which relies on gpg and is only Linux based. Credentials should always be encrypted and shouldn't require any setup or init run to get started. Users should also not need any additional tools to use it.

A library that could fit this scenario is age. It is a well-known library for file encryption and can be extended to support more niche cases if we need to (e.g. support Yubikeys).

Prior Art

Some interesting issues on the Credential Helper

Sub-issues

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions