-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathssh-copy-pubkeys
More file actions
executable file
·129 lines (100 loc) · 3.79 KB
/
ssh-copy-pubkeys
File metadata and controls
executable file
·129 lines (100 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/python
import sys
import os
import paramiko
import multiprocessing
import getpass
import optparse
import logging
import traceback
logging.basicConfig()
def main():
opts, hosts, password = get_options()
logger = logging.getLogger("main")
logger.setLevel({
0: logging.WARNING,
1: logging.INFO,
2: logging.DEBUG}.get(opts.verbosity, logging.DEBUG))
if opts.verbosity > 2:
multiprocessing.log_to_stderr().setLevel({
3: logging.INFO,
4: logging.DEBUG,
5: multiprocessing.SUBDEBUG}.get(
opts.verbosity, multiprocessing.SUBDEBUG))
print "Copying keys...."
copy_keys(hosts, opts.login_name, password, opts.pubkeys)
print "\n\nDone."
def get_options():
parser = optparse.OptionParser(usage="%prog [options] [HOSTFILE|HOST [HOST...]]")
parser.add_option("-k", "--pubkey",
action="append", dest="pubkeys", default=[],
metavar="FILE",
help=("The path to an SSH private key file. "
"Can be specified more than once."))
parser.add_option("-l", "--login-name",
action="store", dest="login_name", default=getpass.getuser(),
metavar="NAME",
help=("The username to use when authenticating to hosts"))
parser.add_option("-v", "--verbose",
action="count", dest="verbosity", default=0,
help=("Enable verbose output. Can be specified more than once."))
opts, args = parser.parse_args()
if not args:
hosts = (h.strip() for h in sys.stdin)
elif os.path.isfile(args[0]):
hosts = (h.strip() for h in file(args[0]))
else:
hosts = args
HOME = os.environ["HOME"]
opts.pubkeys = opts.pubkeys or filter(os.path.isfile,
[ "%s/.ssh/id_rsa.pub" % HOME,
"%s/.ssh/id_dsa.pub" % HOME,
"%s/.ssh/id_ecdsa.pub" % HOME, ])
if not opts.pubkeys:
parser.error("Could not find any public keys to copy.")
password = getpass.getpass()
return (opts, hosts, password)
def do_copy(host, username, password, keys):
logger = logging.getLogger("main")
logger.debug("Connecting to %s" % host)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(host, username=username, password=password, allow_agent=False)
logger.debug("Setting up sftp session")
sftp = client.open_sftp()
try:
sftp.stat(".ssh")
except IOError, e:
if e.errno != 2:
raise
logger.debug("Creating ~/.ssh/")
sftp.mkdir(".ssh", mode=0700)
authorized_keys = sftp.open(".ssh/authorized_keys", mode="a")
logger.info("Adding keys to %s" % host)
for key in keys:
logger.debug("Adding key %s to %s" % (key.strip(), host))
authorized_keys.write(file(key.strip()).read().strip()+"\n")
authorized_keys.close()
sftp.chmod(".ssh/authorized_keys", 0600)
sftp.close()
client.close()
def _do_copy_wrapper(args):
logger = logging.getLogger("main")
try:
do_copy(*args)
except Exception, e:
logger.error("Caught exception whilst copying keys to %s: %r\n" % (args[0], e))
logger.error(traceback.format_exc())
return 1
return 0
def copy_keys(hosts, username, password, keys):
logger = logging.getLogger("main")
pool = multiprocessing.Pool(processes=10)
results = pool.map(_do_copy_wrapper, ((h, username, password, keys) for h in hosts))
failure = reduce((lambda status, acc: acc or status), results, False)
if failure:
logger.warn("Some hosts failed to copy.")
pool.close()
pool.join()
if __name__ == '__main__':
main()