Skip to content

microsoft/artifacts-keyring-nofuss

Repository files navigation

artifacts-keyring-nofuss

Minimal, pure-Python keyring backend for Azure DevOps Artifacts feeds.

Replaces the official artifacts-keyring (which wraps a ~100 MB .NET binary) with a no-fuss, pure-Python implementation — no .NET required.

Install

pip install artifacts-keyring-nofuss

Or for development:

pip install -e .

How it works

When pip, uv, twine, etc. query the keyring for credentials to an Azure DevOps Artifacts feed, this backend:

  1. Discovers the Azure AD tenant by making an unauthenticated request to the feed URL and parsing the WWW-Authenticate header.
  2. Obtains a bearer token using one of the supported auth flows (see below).
  3. For user tokens (Azure CLI): exchanges the bearer token for a narrower VssSessionToken scoped to vso.packaging.
  4. For service principal tokens (managed identity, SP, WIF): returns the Entra bearer token directly as Basic auth credentials.
  5. Returns the credentials to the caller.

Auth flows (priority order)

# Flow How it works
1 Azure CLI Runs az account get-access-token. Most common for local dev.
2 Azure Identity Uses DefaultAzureCredential from azure-identity. Handles managed identities (system + user-assigned), service principals (secret/cert), workload identity federation, and more.

Configuration

Select a specific flow

By default, providers are tried in the order above. To force a specific one:

# Environment variable
export ARTIFACTS_KEYRING_NOFUSS_PROVIDER=azure_cli  # or: azure_identity

Or in ~/.config/python_keyring/keyringrc.cfg:

[artifacts_keyring_nofuss]
provider = azure_cli

User-assigned managed identity

Set AZURE_CLIENT_ID to the client ID of the user-assigned managed identity:

export AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

When unset, system-assigned managed identity is used.

Service principal with secret

Set the standard Azure Identity environment variables:

export AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export AZURE_CLIENT_SECRET=your-secret

This requires the azure-identity package (included as a dependency). The service principal must have permissions on the Azure DevOps feed (e.g. Feed Reader).

Usage with pip

pip install --index-url https://pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/ my-package

The keyring backend is automatically discovered by pip. No extra flags needed.

Usage with uv

  1. Install keyring with this backend:
pip install keyring artifacts-keyring-nofuss
# or
uv tool install keyring --with artifacts-keyring-nofuss
  1. Configure uv to use keyring for authentication. Either add it to your project config:
# pyproject.toml or uv.toml
[tool.uv]
keyring-provider = "subprocess"

Or set the environment variable:

export UV_KEYRING_PROVIDER=subprocess
  1. Use uv as normal with your private feed. A username in the URL (e.g. __token__@) is required to trigger keyring lookup:
uv pip install my-package --index-url https://__token__@pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/

This also works with legacy subdomain-prefixed feed URLs:

uv pip install my-package --index-url https://__token__@myorg.pkgs.visualstudio.com/_packaging/{feed}/pypi/simple/

For pyproject.toml index configuration:

[[tool.uv.index]]
url = "https://__token__@pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/"
name = "my-feed"

Supported feed URLs

Any URL whose host matches one of (including subdomain-prefixed variants):

  • pkgs.dev.azure.com (e.g. https://pkgs.dev.azure.com/myorg/…)
  • pkgs.visualstudio.com (e.g. https://myorg.pkgs.visualstudio.com/…)
  • pkgs.codedev.ms
  • pkgs.vsts.me

URLs with userinfo (e.g. https://__token__@host/…) and bare hostnames without a scheme are also handled correctly.

Troubleshooting

Enable verbose debug output to see the full authentication flow:

ARTIFACTS_KEYRING_NOFUSS_DEBUG=1 pip install --index-url https://pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/ my-package

This prints the provider chain, token exchange steps, and any errors to stderr.

Security model

This package handles authentication tokens. Key security properties:

  • Endpoint validation: Discovery responses are validated against allowlists. The authorization_uri and VSTS authority must point to known hosts over HTTPS, with no non-default ports, userinfo, or deep paths. The authority must be a clean origin (https://host or https://host/). This prevents bearer token exfiltration via DNS hijacking or rogue proxy responses.
  • Short-lived tokens: Bearer tokens are not persisted to disk. In-memory caching has a 50-minute TTL (tokens typically live 60–75 minutes).
  • Narrow scope: User tokens (Azure CLI) are exchanged for session tokens scoped to vso.packaging (read-only). Service principal tokens (MI/SP/WIF) are returned directly — scope is determined by the identity's Azure DevOps permissions.
  • No CWD config: Provider configuration is read only from ~/.config/ or environment variables, never from the working directory.

About

Minimal, pure-Python keyring backend for Azure DevOps Artifacts feeds. Replaces the official artifacts-keyring (which wraps a ~100 MB .NET binary) with a no-fuss implementation that covers the most common Linux auth scenarios using raw HTTP — no msal, no azure-identity, no .NET.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages