EC2 Security Groups for the Web-UI Challenged
February 14, 2012 Leave a Comment
Anybody that has used the AWS-Console console has run across security groups when you create your AMIs, but until this weekend (when I wrote another simple script I hadn’t to interrogate them via Python Boto) I really had only scratched the surface.
So I knew (unlike traditional firewall rules) all you have is ACCEPT’s in the case of security groups. No blocks.
I also knew that these rules applied to all traffic destined for your AMIs, not just Internet traffic. I also knew that Rackspace Cloud servers has nothing like this, so you are left to manage the individual IPtables rules on all your services.
Here are some things that I should have known, but only discovered after digging deeper:
- You can use security groups as a source to allow, not just CIDR blocks
- You can use your customer ID as a source to allow. Not sure I’d want to use that.
- The SecurityGroup API allows you to identify AMI’s that belong to the security group
For this blog I created for different security groups:
- bastion – a host that I use to SSH to get to my other AMI
- web – obviously the web servers that serve up 80/443
- database – MySQL servers that accept connections, hopefully from non-PHP web application servers.
You could create additional groups for you monitoring servers (which agent or SNMP based) to allow only communications on those ports. Pretty simple, eh?
So when I run my script (with no arguments) I can identify all my running hosts, as well as the rules that are included in the group.
mfranz@mfranz-x60s:~/Documents/Coding/awstools/ec2$ ./ec2fw.py Connecting to EC2... --- default/sg-c28f6aab --- [Instance Members] [Rules] SRC: [0.0.0.0/0] DST: tcp/22 SRC: [0.0.0.0/0] DST: tcp/80 SRC: [0.0.0.0/0] DST: icmp/-1 --- web/sg-04a5696c --- [Instance Members] ec2-23-20-91-155.compute-1.amazonaws.com (10.209.122.118) [Rules] SRC: [bastion-ZZZZZZZZZ] DST: tcp/22 SRC: [0.0.0.0/0] DST: tcp/80 SRC: [0.0.0.0/0] DST: tcp/443 SRC: [0.0.0.0/0] DST: icmp/-1 --- bastion/sg-dea468b6 --- [Instance Members] ec2-23-20-83-159.compute-1.amazonaws.com (10.194.250.137) [Rules] SRC: [0.0.0.0/0] DST: tcp/22 SRC: [0.0.0.0/0] DST: icmp/-1 --- database/sg-26cd014e --- [Instance Members] ec2-107-22-124-9.compute-1.amazonaws.com (10.208.138.83) [Rules] SRC: [bastion-ZZZZZZZZZZZ] DST: tcp/22 SRC: [web-ZZZZZZZZZ] DST: tcp/3306
I obviously obfuscated my customer id. And since the only thing I like better than Python is generating .dot files with python, I added a plot option to output.
mfranz@mfranz-x60s:~/Documents/Coding/awstools/ec2$ ./ec2fw.py plot Connecting to EC2... "0.0.0.0/0"->"web"[label="tcp/80 tcp/443 icmp/-1"]; "bastion"->"database"[label="tcp/22"]; "0.0.0.0/0"->"default"[label="tcp/22 tcp/80 icmp/-1"]; "web"->"database"[label="tcp/3306"]; "bastion"->"web"[label="tcp/22"]; "0.0.0.0/0"->"bastion"[label="tcp/22 icmp/-1"];
Which when rendered, produces this output.
So I was shocked to find very few examples of using Boto to manage security groups. Because it is so easy?
I doubt it.
So here is an excerpt.
e = boto.connect_ec2()
for s in e.get_all_security_groups():
print "\n --- %s/%s ---" % (s.name,s.id)
print "[Instance Members]"
for i in s.instances():
print "\t%s (%s)" % (i.public_dns_name, i.private_ip_address)
print "[Rules]"
for r in s.rules:
print "\t SRC: %s DST: %s/%s " % (r.grants,r.ip_protocol,r.to_port)
Grants contains the list of sources that are allowed. Because the __repr__ inside the class will include the CIDR block or the security group name, stripped out my customer id:
for g in r.grants:
if settings['sanitize']:
if g.__repr__().find('-') > -1:
src = g.__repr__().split('-')[0]
else:
src = g.__repr__()
Then I create a tuple for the source and destination security groups and then add the rules.
p = (src, s.name)
if p[0]:
if p not in pairs:
pairs.append(p)
flows[p] = []
flows[p].append(r.ip_protocol + "/" + r.to_port)
This allows me to then generate the .dot output quite easily.
for f in flows.keys():
rules = " ".join(flows[f])
label = '[label="' + rules + '"];'
print quotify(f[0]) + "->" + quotify(f[1]) + label












