login() not working when ~/.docker/config.json empty?
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'}
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?
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)
any other solution ?
any solution?