oras-project / oras-py

ORAS Python SDK
https://oras-project.github.io/oras-py/
Apache License 2.0
34 stars 26 forks source link

Support for `config.json` credHelpers #142

Open hanikesn opened 3 weeks ago

hanikesn commented 3 weeks ago

A lot of legacy clients and for example the oras cli support credHelpers from ~/.docker/config.json. Support for those would be very helpful.

vsoch commented 3 weeks ago

This should already be supported here: https://github.com/oras-project/oras-py/blob/fd8a83ccb56f8779760648b09dee68c600b13d94/oras/provider.py#L188-L207 in that the DockerClient looks for that path. https://github.com/oras-project/oras-py/blob/fd8a83ccb56f8779760648b09dee68c600b13d94/oras/utils/request.py#L63

hanikesn commented 3 weeks ago

I don't have a username or password, so client.login() will interactively ask for those. I'm using docker-credential-gcloud helper though, which doesn't need either.

I solved this by doing the following override in my registry:

    def load_configs(self, container: container_type, configs: Optional[list] = None):
        if self._basic_auth:
            return
        config = docker.auth.load_config()
        hostname = docker.auth.convert_to_hostname(self.hostname)
        auth = config.resolve_authconfig(hostname)
        self.set_basic_auth(username=auth['Username'], password=auth['Password'])
vsoch commented 3 weeks ago

We have a new set of auth backends for this purpose:

https://github.com/oras-project/oras-py/blob/main/oras/auth/base.py

What you'd do is subclass that base, and update the load_configs to be that (and edit the other functions if needed for google cloud). Would you be open to doing a PR with these changes? Then you could specify your auth backend and it should just work.

wosc commented 2 weeks ago

I have the same usecase (access google cloud registry while the local docker client already has all the authentication set up). My guess is, using the new "base" auth code structure, the basic idea would look something like this (have not thought about error handling yet though):

import docker.auth
import oras.auth

class DockerClientAuth(oras.auth.BasicAuth):
    def _load_auth(self, hostname: str) -> bool:
        if super()._load_auth(hostname):
            return True
        config = docker.auth.load_config()
        hostname = docker.auth.convert_to_hostname(hostname)
        a = config.resolve_authconfig(hostname)
        self.set_basic_auth(username=a['Username'], password=a['Password'])
        return True

oras.auth.auth_backends['docker'] = DockerClientAuth

registry = Registry(auth_backend='docker')
filenames = registry.pull('europe-west3-docker.pkg.dev/myproject/myrepo:tag')

This of course depends on the https://pypi.org/project/docker/ package being installed.

vsoch commented 2 weeks ago

In case you missed the message above, we already have the docker client included and "login" is called from it:

https://github.com/oras-project/oras-py/blob/fd8a83ccb56f8779760648b09dee68c600b13d94/oras/utils/request.py#L63

I would be open to review a PR to address this need, from either of you.