forked from gianlucaborello/aws-ssh-config
-
Notifications
You must be signed in to change notification settings - Fork 0
/
aws-ssh-config.py
executable file
·216 lines (176 loc) · 8.17 KB
/
aws-ssh-config.py
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/usr/bin/env python
import argparse
import re
import sys
import time
import boto.ec2
AMIS_TO_USER = {
'amzn' : 'ec2-user',
'ubuntu' : 'ubuntu',
'CentOS' : 'root',
'DataStax' : 'ubuntu',
'CoreOS' : 'core'
}
BLACKLISTED_REGIONS = [
'cn-north-1',
'us-gov-west-1'
]
def generate_id(instance, tags_filter, region, opsworks_filter, bastion_exclusions):
instance_id = ''
if tags_filter is not None:
for tag in tags_filter.split(','):
value = instance.tags.get(tag, None)
if tag == 'Name':
if opsworks_filter:
if value and " - " in value:
value = value.split(' - ',1)[1]
if value:
if not instance_id:
instance_id = value
else:
instance_id += '-' + value
else:
for tag, value in instance.tags.iteritems():
if not tag.startswith('aws'):
if tag == 'Name':
if opsworks_filter:
if ' - ' in value:
value = value.split(' - ',1)[1]
if not instance_id:
instance_id = value
else:
instance_id += '-' + value
if not instance_id:
instance_id = instance.id
if region:
instance_id += '-' + instance.placement
global exclude_bastion
if bastion_exclusions:
for excluded in bastion_exclusions:
if excluded in instance_id:
exclude_bastion = True
else:
exclude_bastion = False
else:
exclude_bastion = False
return instance_id
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--default-user', help='Default ssh username to use if it can\'t be detected from AMI name')
parser.add_argument('--keydir', default='~/.ssh/', help='Location of private keys')
parser.add_argument('--no-identities-only', action='store_true', help='Do not include IdentitiesOnly=yes in ssh config; may cause connection refused if using ssh-agent')
parser.add_argument('--prefix', default='', help='Specify a prefix to prepend to all host names')
parser.add_argument('--private', action='store_true', help='Use private IP addresses (public are used by default)')
parser.add_argument('--bastion', help='Use specified bastion host (Off by default)' )
parser.add_argument('--bastion-exclude', default='' ,help="Comma seperated list of hosts to exclude from bastion proxy.")
parser.add_argument('--bastion-user', default='', help="Used to connect to the bastion server.")
parser.add_argument('--no-opsworks-stack-name', action='store_true', help="Remove the stackname from ec2 tag \'Name\'")
parser.add_argument('--profile', help='Specify AWS credential profile to use')
parser.add_argument('--region', action='store_true', help='Append the region name at the end of the concatenation')
parser.add_argument('--strict-hostkey-checking', action='store_true', help='Do not include StrictHostKeyChecking=no in ssh config')
parser.add_argument('--tags', help='A comma-separated list of tag names to be considered for concatenation. If omitted, all tags will be used')
parser.add_argument('--user', help='Override the ssh username for all hosts')
parser.add_argument('--white-list-region', default='', help='Which regions must be included. If omitted, all regions are considered', nargs="+")
parser.add_argument('--default-ssh-key', help='Override the ssh key for all users.')
args = parser.parse_args()
instances = {}
counts_total = {}
counts_incremental = {}
amis = {}
print "# Generated on " + time.asctime(time.localtime(time.time()))
print "# " + " ".join(sys.argv)
print "# "
print
if args.bastion_exclude:
bastion_exclusions = args.bastion_exclude.split(',')
else:
bastion_exclusions = False
for region in boto.ec2.regions():
if args.white_list_region and region.name not in args.white_list_region:
continue
if region.name in BLACKLISTED_REGIONS:
continue
if args.profile:
conn = boto.ec2.connect_to_region(region.name, profile_name=args.profile)
else:
conn = boto.ec2.connect_to_region(region.name)
for instance in conn.get_only_instances():
if instance.state != 'running':
continue
if instance.platform == 'windows':
continue
if instance.key_name is None:
continue
if instance.launch_time not in instances:
instances[instance.launch_time] = []
instances[instance.launch_time].append(instance)
instance_id = generate_id(instance, args.tags, args.region, args.no_opsworks_stack_name, bastion_exclusions)
if instance_id not in counts_total:
counts_total[instance_id] = 0
counts_incremental[instance_id] = 0
counts_total[instance_id] += 1
if args.user:
amis[instance.image_id] = args.user
else:
if not instance.image_id in amis:
image = conn.get_image(instance.image_id)
for ami, user in AMIS_TO_USER.iteritems():
regexp = re.compile(ami)
if image and regexp.match(image.name):
amis[instance.image_id] = user
break
if instance.image_id not in amis:
amis[instance.image_id] = args.default_user
if args.default_user is None:
image_label = image.name if image is not None else instance.image_id
sys.stderr.write('Can\'t lookup user for AMI \'' + image_label + '\', add a rule to the script\n')
for k in sorted(instances):
for instance in instances[k]:
if args.private:
if instance.private_ip_address:
ip_addr = instance.private_ip_address
else:
if instance.ip_address:
ip_addr = instance.ip_address
elif instance.private_ip_address:
ip_addr = instance.private_ip_address
else:
sys.stderr.write('Cannot lookup ip address for instance %s, skipped it.' % instance.id)
continue
instance_id = generate_id(instance, args.tags, args.region, args.no_opsworks_stack_name, bastion_exclusions)
if counts_total[instance_id] != 1:
counts_incremental[instance_id] += 1
instance_id += '-' + str(counts_incremental[instance_id])
hostid = args.prefix + instance_id
hostid = hostid.replace(' ', '_') # get rid of spaces
print 'Host ' + hostid
print ' HostName ' + ip_addr
if args.bastion:
if not exclude_bastion:
if args.bastion_user:
bastion_user = args.bastion_user
else:
bastion_user = amis[instance.instance.image_id]
print ' ForwardAgent yes'
print ' ProxyCommand ssh -A ' + bastion_user + '@' + args.bastion + ' nc %h %p'
try:
if amis[instance.image_id] is not None:
print ' User ' + amis[instance.image_id]
except:
pass
if args.keydir:
keydir = args.keydir
else:
keydir = '~/.ssh/'
if args.default_ssh_key:
print ' IdentityFile ' + args.default_ssh_key
else:
print ' IdentityFile ' + keydir + instance.key_name.replace(' ', '_') + '.pem'
if not args.no_identities_only:
# ensure ssh-agent keys don't flood when we know the right file to use
print ' IdentitiesOnly yes'
if not args.strict_hostkey_checking:
print ' StrictHostKeyChecking no'
print
if __name__ == '__main__':
main()