docker-py icon indicating copy to clipboard operation
docker-py copied to clipboard

login() not working when ~/.docker/config.json empty?

Open kkaiser opened this issue 3 years ago • 5 comments

Hi,

I'm using the latest version docker==5.0.3 and it seems like the login function doesn't work as expected. I tried to collect a minimal example but it only works when having setup an AWS account + credentials,

import base64
from pathlib import Path

import boto3
import docker


ecr_client = boto3.Session(profile_name="default").client("ecr")
ecr_credentials = ecr_client.get_authorization_token()["authorizationData"][0]
docker_credentials = base64.b64decode(ecr_credentials["authorizationToken"])
ecr_url = ecr_credentials["proxyEndpoint"]
ecr_username, ecr_password = docker_credentials.decode("utf-8").split(":", 1)

print(ecr_username, ecr_password)

docker_cfg = Path.home() / ".docker/config.json"
print(docker_cfg.as_posix())

docker_client = docker.from_env()
print(docker_client.version())
print(docker_client.info())
response = docker_client.login(
    username=ecr_username,
    password=ecr_password,
    registry=ecr_url,
    reauth=True,
    dockercfg_path=docker_cfg.as_posix(),
)
print(response)

with open(docker_cfg, "r") as fp:
    print(fp.read())

If the file is empty it stays empty if I delete the file it isn't created.

If I supply my user and password or use the recommended AWS CLI syntax

aws --profile cmcmd-dev ecr get-login-password | docker login --username AWS --password-stdin 123456789012.dkr.ecr.eu-central-1.amazonaws.com

WARNING! Your password will be stored unencrypted in /home/mysuser/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

I can see that the file is filled/created. But even though I have reauth=True set the credentials will stay the same as before. The file seems untouched.

Am I doing something wrong?

Here are all the print outputs. Most importantly it says "login succeeded"

{'Platform': {'Name': 'Docker Engine - Community'}, 'Components': [{'Name': 'Engine', 'Version': '20.10.12', 'Details': {'ApiVersion': '1.41', 'Arch': 'amd64', 'BuildTime': '2021-12-13T11:43:42.000000000+00:00', 'Experimental': 'false', 'GitCommit': '459d0df', 'GoVersion': 'go1.16.12', 'KernelVersion': '5.11.0-1028-aws', 'MinAPIVersion': '1.12', 'Os': 'linux'}}, {'Name': 'containerd', 'Version': '1.4.12', 'Details': {'GitCommit': '7b11cfaabd73bb80907dd23182b9347b4245eb5d'}}, {'Name': 'runc', 'Version': '1.0.2', 'Details': {'GitCommit': 'v1.0.2-0-g52b36a2'}}, {'Name': 'docker-init', 'Version': '0.19.0', 'Details': {'GitCommit': 'de40ad0'}}], 'Version': '20.10.12', 'ApiVersion': '1.41', 'MinAPIVersion': '1.12', 'GitCommit': '459d0df', 'GoVersion': 'go1.16.12', 'Os': 'linux', 'Arch': 'amd64', 'KernelVersion': '5.11.0-1028-aws', 'BuildTime': '2021-12-13T11:43:42.000000000+00:00'}
{'ID': 'B6PY:JRIJ:G3BM:2QXO:6JP2:EKEH:WGHU:PZC7:QJUH:U54L:HHB4:E6VY', 'Containers': 0, 'ContainersRunning': 0, 'ContainersPaused': 0, 'ContainersStopped': 0, 'Images': 0, 'Driver': 'overlay2', 'DriverStatus': [['Backing Filesystem', 'extfs'], ['Supports d_type', 'true'], ['Native Overlay Diff', 'true'], ['userxattr', 'false']], 'Plugins': {'Volume': ['local'], 'Network': ['bridge', 'host', 'ipvlan', 'macvlan', 'null', 'overlay'], 'Authorization': None, 'Log': ['awslogs', 'fluentd', 'gcplogs', 'gelf', 'journald', 'json-file', 'local', 'logentries', 'splunk', 'syslog']}, 'MemoryLimit': True, 'SwapLimit': True, 'KernelMemory': True, 'KernelMemoryTCP': True, 'CpuCfsPeriod': True, 'CpuCfsQuota': True, 'CPUShares': True, 'CPUSet': True, 'PidsLimit': True, 'IPv4Forwarding': True, 'BridgeNfIptables': True, 'BridgeNfIp6tables': True, 'Debug': False, 'NFd': 26, 'OomKillDisable': True, 'NGoroutines': 36, 'SystemTime': '2022-03-02T18:26:27.990595844Z', 'LoggingDriver': 'json-file', 'CgroupDriver': 'cgroupfs', 'CgroupVersion': '1', 'NEventsListener': 0, 'KernelVersion': '5.11.0-1028-aws', 'OperatingSystem': 'Ubuntu 20.04.3 LTS', 'OSVersion': '20.04', 'OSType': 'linux', 'Architecture': 'x86_64', 'IndexServerAddress': 'https://index.docker.io/v1/', 'RegistryConfig': {'AllowNondistributableArtifactsCIDRs': [], 'AllowNondistributableArtifactsHostnames': [], 'InsecureRegistryCIDRs': ['127.0.0.0/8'], 'IndexConfigs': {'docker.io': {'Name': 'docker.io', 'Mirrors': [], 'Secure': True, 'Official': True}}, 'Mirrors': []}, 'NCPU': 4, 'MemTotal': 16632930304, 'GenericResources': None, 'DockerRootDir': '/var/lib/docker', 'HttpProxy': '', 'HttpsProxy': '', 'NoProxy': '', 'Name': 'ip-10-78-214-7', 'Labels': [], 'ExperimentalBuild': False, 'ServerVersion': '20.10.12', 'Runtimes': {'io.containerd.runc.v2': {'path': 'runc'}, 'io.containerd.runtime.v1.linux': {'path': 'runc'}, 'runc': {'path': 'runc'}}, 'DefaultRuntime': 'runc', 'Swarm': {'NodeID': '', 'NodeAddr': '', 'LocalNodeState': 'inactive', 'ControlAvailable': False, 'Error': '', 'RemoteManagers': None}, 'LiveRestoreEnabled': False, 'Isolation': '', 'InitBinary': 'docker-init', 'ContainerdCommit': {'ID': '7b11cfaabd73bb80907dd23182b9347b4245eb5d', 'Expected': '7b11cfaabd73bb80907dd23182b9347b4245eb5d'}, 'RuncCommit': {'ID': 'v1.0.2-0-g52b36a2', 'Expected': 'v1.0.2-0-g52b36a2'}, 'InitCommit': {'ID': 'de40ad0', 'Expected': 'de40ad0'}, 'SecurityOptions': ['name=apparmor', 'name=seccomp,profile=default'], 'Warnings': None}


{'IdentityToken': '', 'Status': 'Login Succeeded'}

kkaiser avatar Mar 02 '22 18:03 kkaiser

After reverse engineering I found out it's because you never dump the config anywhere you just store it in a dict. I could json dump it myself using docker_client.api._auth_configs but is that really intended?

kkaiser avatar Mar 02 '22 19:03 kkaiser

I made a function that I call after docker.login()

import json
from collections import defaultdict
from pathlib import Path


def _dump_docker_config(credentials: str, domain: str, docker_cfg: Path):
    """Dump the docker auth config to the specified file.

    docker.login() doesn't dump the config compared to the docker CLI tool.
    See: https://github.com/docker/docker-py/issues/2960
    """
    auth_dict = defaultdict(dict)
    if docker_cfg.is_file() and not docker_cfg.stat().st_size == 0:
        with open(docker_cfg, "r", encoding="utf-8") as file_pointer:
            auth_dict = json.load(file_pointer)

    auth_dict["auths"][domain] = {"auth": credentials}

    with open(docker_cfg, "w", encoding="utf-8") as file_pointer:
        json.dump(auth_dict, file_pointer, indent=4)

kkaiser avatar Mar 03 '22 08:03 kkaiser

any other solution ?

sphomme avatar Jul 26 '22 19:07 sphomme

any solution?

ViniciusBastosTR avatar May 29 '23 22:05 ViniciusBastosTR