-
Notifications
You must be signed in to change notification settings - Fork 8
/
aws_sg_migrate.py
224 lines (211 loc) · 10 KB
/
aws_sg_migrate.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
217
218
219
220
221
222
223
224
#!/usr/bin/python
import sys, os, stat, re, subprocess, getopt, json
############################## USAGE #########################################
def usage():
print("copysg.py [-h] [--profile=alt_profile] [--shell] [--vpc=vpcid] [-src=source_region] [--dest=dest_region]", end=" ")
print("sg_id")
print(" -h - help")
print(" --profile (or -p) - use alternate aws cli profile")
print(" --shell (or -s) - wrap commands in shell syntax to capture id")
print(" --vpc (or -v) - specify destination VPC ID for new SG")
print(" --src (or -sc) - specify source region for new SG")
print(" --dest (or -ds) - specify destination region for new SG")
############################### MAIN #######################################
def makesg(profile, sgid, vpcid, source, destin, shell):
# get regions
cmd = [ 'aws', 'ec2', 'describe-regions' ]
ap = subprocess.check_output(cmd)
data = json.loads(ap.decode('utf-8'))
# validating regions
if 'Regions' not in data:
print("Internal error: no Regions in return structure")
sys.exit(3)
# fetching regions from payload
regions_dict = data['Regions']
regions = list(map(lambda x : x['RegionName'], regions_dict))
vpcs = []
# creating VPCs
for region in regions_dict:
cmd = [ 'aws', 'ec2', 'describe-vpcs', '--region=%s' % region["RegionName"] ]
ap = subprocess.check_output(cmd)
data = json.loads(ap.decode('utf-8'))
vpcs_dict = data['Vpcs']
vpcs.append(vpcs_dict[0]['VpcId'])
regions_vpcs = dict(zip(regions, vpcs))
script = open('%s.sh' % sgid, 'w')
# creating security groups
cmd = [ 'aws', 'ec2', 'describe-security-groups', '--region=%s' % source, '--output=json', ]
if source:
cmd.append("--group-id=%s" % (sgid))
else:
cmd = [ 'aws', 'ec2', 'describe-security-groups', '--group-id=%s' % sgid, '--output=json', ]
# append profile if found in params
if profile:
cmd.append('--profile')
cmd.append(profile)
# fetch payload
ap = subprocess.check_output(cmd)
# decode payload
data = json.loads(ap.decode('utf-8'))
# validate security groups are there
if 'SecurityGroups' not in data:
print("Internal error: no SecurityGroups key in data")
sys.exit(3)
sg1 = data['SecurityGroups'][0]
groupName = sg1['GroupName'] #+ '_migrated'
groupDesc = sg1['Description']
groupTags = sg1.get('Tags')
# Sanity check
perms = sg1['IpPermissions'] + sg1['IpPermissionsEgress']
for ipp in perms:
if 'FromPort' not in ipp: continue
if 'IpProtocol' not in ipp: continue
if 'IpRanges' not in ipp: continue
if 'ToPort' not in ipp: continue
if len(ipp['UserIdGroupPairs']) > 0:
sys.stderr.write("Warning: ignoring User Id info\n")
for ipr in ipp['IpRanges']:
for k in ipr.keys():
if k != 'CidrIp' and k != 'Description':
sys.stderr.write("Error: Don't know how to handle")
sys.stderr.write("key %s in IpRanges\n" % (k))
sys.exit(4)
if shell:
print("# Commands auto-generated by the copysg.py script", file=script)
print(" ", file=script)
# get destionation regions
destinations = []
destinations = regions_vpcs
cmd.append("--filters=Name=group-name,Values='%s'" % (groupName))
# if destination region is specified in params
if destin is not None:
filtered = {dest:vpc for dest,vpc in destinations.items() if dest not in [source] and dest == destin}
else: # if not
filtered = {dest:vpc for dest,vpc in destinations.items() if dest not in [source]}
for dest,vpc in filtered.items():
ap = subprocess.check_output(cmd)
if ap is not None:
delete_cmd = "aws ec2 delete-security-group"
create_cmd = "aws ec2 create-security-group --vpc-id=%s" % (vpc)
cmd_existing = [ 'aws', 'ec2', 'describe-security-groups', '--region=%s' % dest, "--query=SecurityGroups[].GroupName" ]
ap = subprocess.check_output(cmd_existing)
sgNames = json.loads(ap)
# looping sec groups
if shell:
if ap is not None:
if groupName != 'default' and groupName in sgNames:
print("sgout=(`%s --group-name='%s' --region %s --output table`)" % (delete_cmd, groupName, dest), file=script)
print('if [ $? != 0 ]; then', file=script)
print(' echo "Error: %s failed"' % (delete_cmd), file=script)
print(' exit 1', file=script)
print('fi', file=script)
print("sgout=(`%s --group-name='%s' --region %s --description='%s' --output table`)" % (create_cmd, groupName, dest, groupDesc), file=script)
print('if [ $? != 0 ]; then', file=script)
print(' echo "Error: %s failed"' % (create_cmd), file=script)
print(' exit 1', file=script)
print('fi', file=script)
print('if [ "${sgout[6]}" != \'GroupId\' ]; then', file=script)
print(' echo "Error: expected \'GroupId\', got ${sgout[6]}"', file=script)
print(' exit 1', file=script)
print('fi', file=script)
print('SGID=${sgout[8]}', file=script)
else:
if groupName != 'default' and groupName in sgNames:
print("%s --group-name='%s' --region %s" % (delete_cmd, groupName, dest), file=script)
print("sgcreate=$(%s --group-name='%s' --region %s --description='%s')" % (create_cmd, groupName, dest, groupDesc), file=script)
print("sgid=$(echo $sgcreate|sed 's/{//g;s/}//g;s/\"//g'|cut -d ':' -f2)", file=script)
# writing permissions to file
for ipp in sg1['IpPermissions']:
if 'FromPort' not in ipp: continue
if 'IpProtocol' not in ipp: continue
if 'IpRanges' not in ipp: continue
if 'ToPort' not in ipp: continue
for ipr in ipp['IpRanges']:
cidr = ipr['CidrIp']
# writing inbound rules
auth_cmd = "aws ec2 authorize-security-group-ingress"
if shell:
print("%s --region %s --group-id=$SGID --protocol='%s'" % (auth_cmd, dest, ipp['IpProtocol']),end=" ", file=script)
else:
print("%s --region %s --group-name=%s --protocol='%s'" % (auth_cmd, dest, groupName, ipp['IpProtocol']),end=" ", file=script)
if ipp['ToPort'] < 0:
ipp['ToPort'] = ipp['FromPort']
if ipp['FromPort'] != ipp['ToPort']:
print("--port=%s-%s" % (ipp['FromPort'], ipp['ToPort']),end=" ", file=script)
else:
print("--port=%s" % (ipp['FromPort']),end=" ", file=script)
print("--cidr=%s" % (ipr['CidrIp']), file=script)
if shell:
print('if [ $? != 0 ]; then', file=script)
print(' echo "Error: %s failed"' % (auth_cmd), file=script)
print(' exit 1', file=script)
print('fi', file=script)
for ipp in sg1['IpPermissionsEgress']:
if 'FromPort' not in ipp: continue
if 'IpProtocol' not in ipp: continue
if 'IpRanges' not in ipp: continue
if 'ToPort' not in ipp: continue
for ipr in ipp['IpRanges']:
cidr = ipr['CidrIp']
# writing outbound rules
auth_cmd = "aws ec2 authorize-security-group-egress"
if shell:
print("%s --region %s --group-id=$SGID --protocol='%s'" % (auth_cmd, dest, ipp['IpProtocol']), end=" ", file=script)
else:
print("%s --region %s --group-id=$SGID --protocol='%s'" % (auth_cmd, dest, ipp['IpProtocol']), end=" ", file=script)
if ipp['ToPort'] < 0:
# ICMP ToPort was -1 ???
ipp['ToPort'] = ipp['FromPort']
if ipp['FromPort'] != ipp['ToPort']:
print("--port=%s-%s" % (ipp['FromPort'], ipp['ToPort']),end=" ", file=script)
else:
print("--port=%s" % (ipp['FromPort']),end=" ", file=script)
print("--cidr=%s" % (ipr['CidrIp']), file=script)
if shell:
print('if [ $? != 0 ]; then')
print(' echo "Error: %s failed"' % (auth_cmd))
print(' exit 1', file=script)
print('fi', file=script)
# writing tags
for tag in groupTags or []:
if shell:
print("aws ec2 create-tags --region %s --resources $SGID" % (dest), end=" ", file=script)
print('--tags "Key=%s,Value=%s"' % (tag['Key'], tag['Value']), file=script)
else:
print("aws ec2 create-tags --region %s --resources $sgid" % (dest), end=" ", file=script)
print('--tags "Key=%s,Value=%s"' % (tag['Key'], tag['Value']), file=script)
# setting script permissions
os.chmod(script.name, 0o755)
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "hp:sv:", [ "help", "profile=", "shell", "vpc=", "src=", "dest=", ])
except getopt.GetoptError:
usage()
sys.exit(2)
profile = None
vpcid = None
shell = False
source = None
destination = None
for o,a in opts:
if o in ("-h", "--help"):
usage()
return
if o in ("-p", "--profile"):
profile = a
if o in ("-s", "--shell"):
shell = True
if o in ("-sc", "--src"):
source = a
if o in ("-ds", "--dest"):
destination = a
if o in ("-v", "--vpc"):
vpcid = a
if len(args) != 1:
print("ERROR: You must give a security group id")
usage()
sys.exit(1)
sgid = args[0]
makesg(profile, sgid, vpcid, source, destination, shell)
if __name__ == '__main__':
main()