-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathsign_key
More file actions
executable file
·161 lines (135 loc) · 4.96 KB
/
sign_key
File metadata and controls
executable file
·161 lines (135 loc) · 4.96 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python
"""Sign a user's SSH public key.
This script is used to sign a user's SSH public key using a certificate
authority's private key. The signed public key can be presented along with the
user's private key to get access to servers that trust the CA.
The final output of this script is an S3 URL containing the user's signed
certificate. The user needs to take this URL and download the file it points
at. The downloaded file should be named exactly like their private SSH key but
with the suffix "-cert.pub".
For example, if the user's key is ~/.ssh/id_rsa they should do something like
curl <THE URL> > ~/.ssh/id_rsa-cert.pub
"""
import argparse
import ConfigParser
import os
import sys
import tempfile
from contextlib import closing
import ssh_ca
import ssh_ca.s3
import ssh_ca.sqlite
ca_map = {
's3': ssh_ca.s3.S3Authority,
'sqlite': ssh_ca.sqlite.SqliteAuthority,
}
if __name__ == '__main__':
default_authority = os.getenv('SSH_CA_AUTHORITY', 's3')
default_config = os.path.expanduser(
os.getenv('SSH_CA_CONFIG', '~/.ssh_ca/config'))
parser = argparse.ArgumentParser(__doc__)
parser.add_argument('-a', '--authority',
dest='authority', default=default_authority,
choices=['s3', 'sqlite'],
help='Specify CA backing store type',
)
parser.add_argument('-c', '--config-file',
default=default_config,
help='The configuration file to use. Can also be '
'specified in the SSH_CA_CONFIG environment '
'variable. Default: %(default)s',
)
parser.add_argument('-e', '--environment',
required=True,
help='Environment name',
)
parser.add_argument('--principal',
action='append',
help='A principal (username) that the user is allowed to use',
)
parser.add_argument('-p',
dest='public_path',
help='Path to public key. If set we try to upload this. '
'Otherwise we try to download one.',
)
parser.add_argument('-u',
required=True, dest='username',
help='username / email address',
)
parser.add_argument('--upload',
dest='upload_only', action='store_true',
help='Only upload the public key',
)
parser.add_argument('-r', '--reason',
help='Specify the reason for the user needing this cert.',
)
parser.add_argument('-t', '--expires-in',
default='+2h',
help='Expires in. A relative time like +1w. Or YYYYMMDDHHMMSS. '
'Default: %(default)s',
)
args = parser.parse_args()
public_path = args.public_path
environment = args.environment
username = args.username
ssh_ca_section = 'ssh-ca-' + args.authority
config = None
if args.config_file:
config = ConfigParser.ConfigParser()
config.read(args.config_file)
# Get a valid CA key file
ca_key = ssh_ca.get_config_value(config, environment, 'private_key')
if ca_key:
ca_key = os.path.expanduser(ca_key)
else:
ca_key = os.path.expanduser('~/.ssh/ssh_ca_%s' % (environment,))
if not os.path.isfile(ca_key):
print 'CA key file %s does not exist.' % (ca_key,)
sys.exit(1)
try:
# Create our CA
ca = ca_map[args.authority](config, ssh_ca_section, ca_key)
except ssh_ca.SSHCAInvalidConfiguration, e:
print 'Issue with creating CA: %s' % e.message
sys.exit(1)
if args.upload_only:
if not public_path:
print 'Upload needs a public key specified.'
sys.exit(1)
ca.upload_public_key(username, public_path)
print 'Public key %s for username %s uploaded.' % (public_path,
username)
sys.exit(0)
# Figure out if we use a local new public key or an existing one
if public_path:
ca.upload_public_key(username, public_path)
delete_public_key = False
else:
public_key_contents = ca.get_public_key(username, environment)
if public_key_contents is None:
print 'Key for user %s not found.' % (username)
sys.exit(1)
(fd, public_path) = tempfile.mkstemp()
with closing(os.fdopen(fd, 'w')) as f:
f.write(public_key_contents)
delete_public_key = True
if args.reason:
reason = args.reason
else:
prompt = 'Specify the reason for the user needing this cert:\n'
reason = raw_input(prompt).strip()
if len(reason) > 256:
print 'Reason is way too long. Type less.'
sys.exit(1)
if args.principal:
principal = args.principal
else:
principal = ['ec2-user', 'ubuntu']
# Sign the key
cert_contents = ca.sign_public_user_key(
public_path, username, args.expires_in, reason, principal)
print
print 'Public key signed, certificate available for download here:'
print ca.upload_public_key_cert(username, cert_contents)
if delete_public_key:
os.remove(public_path)