I recently found myself wanting to use a private cargo registry to build something in a docker container, and noticed a lack of resources (apart from a sad unresolved forum post) on how to securely share an authentication token from the host machine into the container, for cargo to use. The straightforward solution is to pass the token as the environment variable CARGO_REGISTRIES_<name>_TOKEN, but this is neither particularly secure nor friction-less, hence we'll use libsecret through D-Bus and assume a Linux host.
Project config
If using a custom registry, it should be added to the project's .cargo/config.toml, as detailed here, setting credential-provider to cargo:libsecret.
[registry.<name>] credential-provider = "cargo:libsecret" ...
Or for the default registry, just use the following.
[registry] credential-provider = "cargo:libsecret"
Host
A password manager with libsecret support should be installed, such as GNOME Keyring, KDE Wallet Manager, or KeePassXC.
Container
Building
Install libsecret into your docker image (libsecret-1.0 and libsecret on Debian and Fedora respectively).
In addition to that, you'll need to make sure the D-Bus connection can be established. D-Bus will refuse connections unless the host's and container's users have matching UIDs or the host unsafely relaxes their permissions, meaning that you'll have to modify your container to create a user with the same UID as the host.
If your docker image doesn't support this, you can add the following snippet to it, or consult the Visual Studio docs for more details. This is already in-place for all Microsoft-supplied devcontainer images.
ARG USERNAME=user-name-goes-here ARG USER_UID=1000 ARG USER_GID=$USER_UID # Create the user RUN groupadd --gid $USER_GID $USERNAME \ && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ # # [Optional] Add sudo support. Omit if you don't need to install software after connecting. && apt-get update \ && apt-get install -y sudo \ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ && chmod 0440 /etc/sudoers.d/$USERNAME # ******************************************************** # * Anything else you want to do like clean up goes here * # ******************************************************** # [Optional] Set the default user. Omit if you want to keep the default as root. USER $USERNAME
And set the arguments when building your image, unless you're using devcontainers, in which case this is done automatically.
docker image build \ --build-arg "USER_UID=$(id -u)" \ --build-arg "USER_GID=$(id -g)"
Running
Now you can run your image, mounting the host's D-Bus socket and pointing all processes that try to use D-Bus inside the container to the socket. This can be done as follows for devcontainers.
{
"mounts": [
"type=bind,source=${localEnv:XDG_RUNTIME_DIR}/bus,target=/tmp/host-dbus/bus"
],
"containerEnv": {
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/tmp/host-dbus/bus"
}
}
Or as follows when running the container directly with a docker command.
docker run \ --mount "type=bind,source=/run/user/$(id -u)/bus,target=/tmp/host-dbus/bus" \ --env "DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/host-dbus/bus" ...
Login
The initial login can be performed either on the host or inside the container by running the following command.
cargo login --registry <name>
Conclusion
And that's it, no more awkward environment variables, and cargo authentication should just work securely and seamlessly inside your container.