From f9edd90d19f374c62fea1a8744462a6210205750 Mon Sep 17 00:00:00 2001 From: Garrick James Date: Fri, 4 May 2018 23:50:05 -0700 Subject: [PATCH] add -w option Providing passwords via command line is insecure. Adding an option to read the password from the TTY or stdin. When reading from a TTY, getpass() is used so that the password is not displayed as it is entered. Getpass() also displays a prompt, since TTY usage is typically interactive. When reading from something other than a TTY (e.g. from a pipe or input redirection), a plain read from stdin is done (without getpass(); without any promting). This allows the user to pipe the password from some type of password management/entry tool to registry.py. --- registry.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/registry.py b/registry.py index 4dec4f1..23d76cf 100755 --- a/registry.py +++ b/registry.py @@ -8,9 +8,11 @@ import pprint import base64 import re import sys +import os import argparse import www_authenticate from datetime import timedelta, datetime as dt +from getpass import getpass # this is a registry manipulator, can do following: # - list all images (including layers) @@ -383,10 +385,20 @@ for more detail on garbage collection read here: """)) parser.add_argument( '-l', '--login', - help="Login and password to access to docker registry", + help="Login and password for access to docker registry", required=False, metavar="USER:PASSWORD") + parser.add_argument( + '-w', '--read-password', + help="Read password from stdin (and prompt if stdin is a TTY); " + + "the final line-ending character(s) will be removed; " + + "the :PASSWORD portion of the -l option is not required and " + + "will be ignored", + action='store_const', + default=False, + const=True) + parser.add_argument( '-r', '--host', help="Hostname for registry server, e.g. https://example.com:5000", @@ -581,6 +593,33 @@ def main_loop(args): if args.no_validate_ssl: requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + if args.read_password: + if args.login is None: + print("Please provide -l when using -w") + exit(1) + + if ':' in args.login: + (username, password) = args.login.split(':', 1) + else: + username = args.login + + if sys.stdin.isatty(): + # likely interactive usage + password = getpass() + + else: + # allow password to be piped or redirected in + password = sys.stdin.read() + + if len(password) == 0: + print("Password was not provided") + exit(1) + + if password[-(len(os.linesep)):] == os.linesep: + password = password[0:-(len(os.linesep))] + + args.login = username + ':' + password + registry = Registry.create(args.host, args.login, args.no_validate_ssl) registry.auth_schemes = get_auth_schemes(registry,'/v2/_catalog')