From 52856a016d00e64fae1e840e67b05f90c2e8ba1c Mon Sep 17 00:00:00 2001 From: kranthi guttikonda Date: Wed, 24 Mar 2021 15:08:40 -0400 Subject: [PATCH 1/2] adding an option for remote registry --- README.md | 6 +++ docker_push_ssh/cli.py | 118 +++++++++++++++++++++++------------------ 2 files changed, 72 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index dbeea48..a3cddc5 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ Tested on OS X with "Docker for Mac". Adding `localhost:5000` to your client's insecure registries is inconvenient but a side-effect of docker's design. It only needs to be done once from each machine using `docker-push-ssh`. This allows the tool to push through the ssh tunnel at `localhost:5000` to the temporary registry on your remote host, without needing ssl certificates for your server. +If the remote registry already exists then update /etc/hosts/ with the remote registry name to 127.0.0.1 and add the +same to host docker insecure registries. An exmaple: +cat /etc/hosts +127.0.0.1 localhost remote-private-registry ## Usage: @@ -54,6 +58,8 @@ optional arguments: -p SSH_PORT, --ssh-port SSH_PORT [optional] Port on ssh host to connect to. (Default is 22) + -rr REGISTRY, --registry REGISTRY + [optional] if the registry already exists remotely -r REGISTRY_PORT, --registry-port REGISTRY_PORT [optional] Remote registry port on ssh host to forward to. (Default is 5000) diff --git a/docker_push_ssh/cli.py b/docker_push_ssh/cli.py index 0a88f57..56b06e3 100644 --- a/docker_push_ssh/cli.py +++ b/docker_push_ssh/cli.py @@ -49,24 +49,34 @@ def waitForSshTunnelInit(retries=20, delay=1.0): return False -def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages, registryPort): - # Setup remote docker registry - print("Setting up secure private registry... ") - registryCommandResult = Command("ssh", [ - "-i", sshIdentityFile, - "-p", sshPort, - "-o", "StrictHostKeyChecking=no", - "-o", "UserKnownHostsFile=/dev/null", - sshHost, - "sh -l -c \"docker run -d -v /etc/docker-push-ssh/registry:/var/lib/registry " + - "--name docker-push-ssh-registry -p 127.0.0.1:{0}:5000 registry\"".format(registryPort) - ]).execute() - - if registryCommandResult.failed(): - print("ERROR") - print(registryCommandResult.stdout) - print(registryCommandResult.stderr) - return False +def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages, registryPort, registry): + if registry == "localhost": + # Setup remote docker registry + print("Setting up secure private registry... ") + registryCommandResult = Command("ssh", [ + "-i", sshIdentityFile, + "-p", sshPort, + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + sshHost, + "sh -l -c \"docker run -d -v /etc/docker-push-ssh/registry:/var/lib/registry " + + "--name docker-push-ssh-registry -p 127.0.0.1:{0}:5000 registry\"".format(registryPort) + ]).execute() + + if registryCommandResult.failed(): + print("ERROR") + print(registryCommandResult.stdout) + print(registryCommandResult.stderr) + print("Cleanup the registry") + Command("ssh", [ + "-i", sshIdentityFile, + "-p", sshPort, + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + sshHost, + "sh -l -c \"docker rm -f docker-push-ssh-registry\"" + ]).execute() + return False try: # Establish ssh tunnel @@ -75,7 +85,7 @@ def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages sshTunnelCommandResult = Command("docker", [ "run", "-d", "--name", "docker-push-ssh-tunnel", - "-p", "127.0.0.1:5000:5000", + "-p", "0.0.0.0:5000:5000", "-v", "{0}:/etc/ssh_key_file".format(sshIdentityFile), "brthornbury/docker-alpine-ssh", "ssh", @@ -136,7 +146,7 @@ def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages tagCommandResult = Command("docker", [ "tag", dockerImageTag, - "localhost:5000/{0}".format(dockerImageTag) + "{2}:{1}/{0}".format(dockerImageTag, registryPort, registry) ]).environment_dict(os.environ).execute() if tagCommandResult.failed(): @@ -149,7 +159,7 @@ def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages for dockerImageTag in dockerImageTagList: pushDockerImageCommandResult = Command("docker", [ "push", - "localhost:5000/{0}".format(dockerImageTag) + "{2}:{1}/{0}".format(dockerImageTag, registryPort, registry) ]).environment_dict(os.environ).execute() if pushDockerImageCommandResult.failed(): @@ -164,37 +174,39 @@ def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages return False print("Pushed Image {0} Successfully...".format(dockerImageTag)) - - print("Pulling and Retagging Image on remote host...") - for dockerImageTag in dockerImageTagList: - pullDockerImageCommandResult = Command("ssh", [ - "-i", sshIdentityFile, - "-p", sshPort, - "-o", "StrictHostKeyChecking=no", - "-o", "UserKnownHostsFile=/dev/null", - sshHost, - "sh -l -c \"docker pull " + "localhost:{1}/{0}".format(dockerImageTag, registryPort) + - " && docker tag localhost:{1}/{0} {0}\"".format(dockerImageTag, registryPort) - ]).execute() - - if pullDockerImageCommandResult.failed(): - print("ERROR") - print(pullDockerImageCommandResult.stdout) - print(pullDockerImageCommandResult.stderr) - return False - - print("Pulled Image {0} Successfully...".format(dockerImageTag)) + + if registry == "localhost": + print("Pulling and Retagging Image on remote host...") + for dockerImageTag in dockerImageTagList: + pullDockerImageCommandResult = Command("ssh", [ + "-i", sshIdentityFile, + "-p", sshPort, + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + sshHost, + "sh -l -c \"docker pull " + "localhost:{1}/{0}".format(dockerImageTag, registryPort) + + " && docker tag localhost:{1}/{0} {0}\"".format(dockerImageTag, registryPort) + ]).execute() + + if pullDockerImageCommandResult.failed(): + print("ERROR") + print(pullDockerImageCommandResult.stdout) + print(pullDockerImageCommandResult.stderr) + return False + + print("Pulled Image {0} Successfully...".format(dockerImageTag)) finally: - print("Cleaning up...") - Command("ssh", [ - "-i", sshIdentityFile, - "-p", sshPort, - "-o", "StrictHostKeyChecking=no", - "-o", "UserKnownHostsFile=/dev/null", - sshHost, - "sh -l -c \"docker rm -f docker-push-ssh-registry\"" - ]).execute() + if registry == "localhost": + print("Cleaning up...") + Command("ssh", [ + "-i", sshIdentityFile, + "-p", sshPort, + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + sshHost, + "sh -l -c \"docker rm -f docker-push-ssh-registry\"" + ]).execute() Command("docker", [ "rm", "-f", "docker-push-ssh-tunnel" @@ -224,7 +236,9 @@ def main(): "Required, password auth not supported. (ex. ~/.ssh/id_rsa)") parser.add_argument("-p", "--ssh-port", type=str, help="[optional] Port on ssh host to connect to. (Default is 22)", default="22") - + + parser.add_argument("-rr", "--registry", type=str, + help="[optional] Remote registry name. this will skip registry creation remotely", default="localhost") parser.add_argument("-r", "--registry-port", type=str, help="[optional] Remote registry port on ssh host to forward to. (Default is 5000)", default="5000") @@ -239,7 +253,7 @@ def main(): print("[REQUIRED] Ensure localhost:5000 is added to your insecure registries.") success = pushImage(args.docker_image, args.ssh_host, sshIdentityFileAbsolutePath, - args.ssh_port, args.prime_image, args.registry_port) + args.ssh_port, args.prime_image, args.registry_port, args.registry) if not success: sys.exit(1) From 15e4c97cdc7f30a0041edce60a1cf13bce66b3dd Mon Sep 17 00:00:00 2001 From: kranthi guttikonda Date: Wed, 24 Mar 2021 17:25:06 -0400 Subject: [PATCH 2/2] add docker basic auth as an optional parameter --- docker_push_ssh/cli.py | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/docker_push_ssh/cli.py b/docker_push_ssh/cli.py index 56b06e3..78bad86 100644 --- a/docker_push_ssh/cli.py +++ b/docker_push_ssh/cli.py @@ -15,6 +15,7 @@ import os import socket import sys +import base64 import time import urllib2 import httplib @@ -34,12 +35,15 @@ def getLocalIp(): return localIp -def waitForSshTunnelInit(retries=20, delay=1.0): +def waitForSshTunnelInit(url, base64string=None, retries=20, delay=1.0): for _ in range(retries): time.sleep(delay) - try: - response = urllib2.urlopen("http://localhost:5000/v2/", timeout=5) + request = urllib2.Request(url) + if base64string is not None: + request.add_header("Authorization", "Basic %s" % base64string) + response = urllib2.urlopen(request, timeout=5) + print response except (socket.error, urllib2.URLError, httplib.BadStatusLine): continue @@ -49,7 +53,7 @@ def waitForSshTunnelInit(retries=20, delay=1.0): return False -def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages, registryPort, registry): +def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages, registryPort, registry, userpass): if registry == "localhost": # Setup remote docker registry print("Setting up secure private registry... ") @@ -105,8 +109,24 @@ def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages return False print("Waiting for SSH Tunnel Initialization...") - - if not waitForSshTunnelInit(): + if userpass is not None: + creds=userpass.split(":", 1) + dockerLogingCommandResult = Command("docker", [ + "login", "-u={0}".format(creds[0]), + "-p={0}".format(creds[1]), "{0}:{1}".format(registry, registryPort) + ]).environment_dict(os.environ).execute() + base64string = base64.encodestring('%s:%s' % (creds[0], creds[1])).replace('\n', '') + if dockerLogingCommandResult.failed(): + print("ERROR") + print(dockerLogingCommandResult.stdout) + print(dockerLogingCommandResult.stderr) + return False + else: + base64string = None + + url="http://%s:%s/v2" % (registry, registryPort) + + if not waitForSshTunnelInit(url, base64string): print("ERROR") print("SSH Tunnel failed to initialize.") @@ -132,7 +152,7 @@ def pushImage(dockerImageTagList, sshHost, sshIdentityFile, sshPort, primeImages "-o", "UserKnownHostsFile=/dev/null", sshHost, "sh -l -c \"docker pull {0}".format(primeImage) + - " && docker tag {0} localhost:{1}/{0} && docker push localhost:{1}/{0}\"".format(primeImage, registryPort) + " && docker tag {0} {2}:{1}/{0} && docker push {2}:{1}/{0}\"".format(primeImage, registryPort, registry) ]).execute() if primingCommand.failed(): @@ -236,7 +256,9 @@ def main(): "Required, password auth not supported. (ex. ~/.ssh/id_rsa)") parser.add_argument("-p", "--ssh-port", type=str, help="[optional] Port on ssh host to connect to. (Default is 22)", default="22") - + + parser.add_argument("-u", "--userpass", type=str, help="[optional] docker registry username:password") + parser.add_argument("-rr", "--registry", type=str, help="[optional] Remote registry name. this will skip registry creation remotely", default="localhost") parser.add_argument("-r", "--registry-port", type=str, @@ -253,7 +275,7 @@ def main(): print("[REQUIRED] Ensure localhost:5000 is added to your insecure registries.") success = pushImage(args.docker_image, args.ssh_host, sshIdentityFileAbsolutePath, - args.ssh_port, args.prime_image, args.registry_port, args.registry) + args.ssh_port, args.prime_image, args.registry_port, args.registry, args.userpass) if not success: sys.exit(1)