-
-
Save steder/1498451 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python | |
""" | |
Recipe for creating and updating security groups programmatically. | |
""" | |
import collections | |
import boto | |
# Follow instruction at http://www.datastax.com/docs/1.0/install/install_ami | |
# to define the cluster security group rules and client security group rules. | |
SecurityGroupRule = collections.namedtuple("SecurityGroupRule", ["ip_protocol", "from_port", "to_port", "cidr_ip", "src_group_name"]) | |
CASSANDRA_RULES = [ | |
SecurityGroupRule("tcp", "22", "22", "0.0.0.0/0", None), | |
SecurityGroupRule("tcp", "1024", "65535", "0.0.0.0/0", "Cassandra Cluster"), | |
SecurityGroupRule("tcp", "7000", "7000", "0.0.0.0/0", "Cassandra Cluster"), | |
SecurityGroupRule("tcp", "61620", "61621", "0.0.0.0/0", "Cassandra Cluster"), | |
SecurityGroupRule("tcp", "7199", "7199", "0.0.0.0/0", None), | |
SecurityGroupRule("tcp", "8888", "8888", "0.0.0.0/0", None), | |
SecurityGroupRule("tcp", "8983", "8983", "0.0.0.0/0", None), | |
SecurityGroupRule("tcp", "9160", "9160", "0.0.0.0/0", None), | |
] | |
TEST_RULES = [ | |
# ssh makes life possible | |
SecurityGroupRule("tcp", "22", "22", "0.0.0.0/0", None), | |
] | |
SECURITY_GROUPS = [("Cassandra Cluster", CASSANDRA_RULES), | |
("Test", TEST_RULES) | |
] | |
def get_or_create_security_group(c, group_name, description=""): | |
""" | |
""" | |
groups = [g for g in c.get_all_security_groups() if g.name == group_name] | |
group = groups[0] if groups else None | |
if not group: | |
print "Creating group '%s'..."%(group_name,) | |
group = c.create_security_group(group_name, "A group for %s"%(group_name,)) | |
return group | |
def modify_sg(c, group, rule, authorize=False, revoke=False): | |
src_group = None | |
if rule.src_group_name: | |
src_group = c.get_all_security_groups([rule.src_group_name,])[0] | |
if authorize and not revoke: | |
print "Authorizing missing rule %s..."%(rule,) | |
group.authorize(ip_protocol=rule.ip_protocol, | |
from_port=rule.from_port, | |
to_port=rule.to_port, | |
cidr_ip=rule.cidr_ip, | |
src_group=src_group) | |
elif not authorize and revoke: | |
print "Revoking unexpected rule %s..."%(rule,) | |
group.revoke(ip_protocol=rule.ip_protocol, | |
from_port=rule.from_port, | |
to_port=rule.to_port, | |
cidr_ip=rule.cidr_ip, | |
src_group=src_group) | |
def authorize(c, group, rule): | |
"""Authorize `rule` on `group`.""" | |
return modify_sg(c, group, rule, authorize=True) | |
def revoke(c, group, rule): | |
"""Revoke `rule` on `group`.""" | |
return modify_sg(c, group, rule, revoke=True) | |
def update_security_group(c, group, expected_rules): | |
""" | |
""" | |
print 'Updating group "%s"...'%(group.name,) | |
import pprint | |
print "Expected Rules:" | |
pprint.pprint(expected_rules) | |
current_rules = [] | |
for rule in group.rules: | |
if not rule.grants[0].cidr_ip: | |
current_rule = SecurityGroupRule(rule.ip_protocol, | |
rule.from_port, | |
rule.to_port, | |
"0.0.0.0/0", | |
rule.grants[0].name) | |
else: | |
current_rule = SecurityGroupRule(rule.ip_protocol, | |
rule.from_port, | |
rule.to_port, | |
rule.grants[0].cidr_ip, | |
None) | |
if current_rule not in expected_rules: | |
revoke(c, group, current_rule) | |
else: | |
current_rules.append(current_rule) | |
print "Current Rules:" | |
pprint.pprint(current_rules) | |
for rule in expected_rules: | |
if rule not in current_rules: | |
authorize(c, group, rule) | |
def create_security_groups(): | |
""" | |
attempts to be idempotent: | |
if the sg does not exist create it, | |
otherwise just check that the security group contains the rules | |
we expect it to contain and updates it if it does not. | |
""" | |
c = boto.connect_ec2() | |
for group_name, rules in SECURITY_GROUPS: | |
group = get_or_create_security_group(c, group_name) | |
update_security_group(c, group, rules) | |
if __name__=="__main__": | |
create_security_groups() |
This is very good! Thanks.
Thanks, it helps me a lot.
This post helped me a lot. Excellent post
It appears that this may no longer modify groups successfully. It can only create.
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='1024', to_port='65535', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster')...
Traceback (most recent call last):
File "./aws_sg_recipe-orig.py", line 132, in <module>
create_security_groups()
File "./aws_sg_recipe-orig.py", line 128, in create_security_groups
update_security_group(c, group, rules)
File "./aws_sg_recipe-orig.py", line 114, in update_security_group
authorize(c, group, rule)
File "./aws_sg_recipe-orig.py", line 73, in authorize
return modify_sg(c, group, rule, authorize=True)
File "./aws_sg_recipe-orig.py", line 61, in modify_sg
src_group=src_group)
File "/Library/Python/2.7/site-packages/boto/ec2/securitygroup.py", line 203, in authorize
dry_run=dry_run)
File "/Library/Python/2.7/site-packages/boto/ec2/connection.py", line 3192, in authorize_security_group
params, verb='POST')
File "/Library/Python/2.7/site-packages/boto/connection.py", line 1223, in get_status
raise self.ResponseError(response.status, response.reason, body)
boto.exception.EC2ResponseError: EC2ResponseError: 400 Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<Response><Errors><Error><Code>InvalidPermission.Duplicate</Code><Message>the specified rule "peer: sg-da510bbf, TCP, from port: 1024, to port: 65535, ALLOW" already exists</Message></Error></Errors>
Is this a boto configuration error or a problem with the calls being done to the APIs?
@gyoza what are your rules?
This seems to be working fine with my account with PowerUser access rights. Double check that you have permissions and that your ~/.boto configuration file is correct.
(aws)~/Projects/aws-snippets /master> python aws_sg_recipe.py
Creating group 'Cassandra Cluster'...
Updating group "Cassandra Cluster"...
Expected Rules:
[SecurityGroupRule(ip_protocol='tcp', from_port='22', to_port='22', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='1024', to_port='65535', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster'),
SecurityGroupRule(ip_protocol='tcp', from_port='7000', to_port='7000', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster'),
SecurityGroupRule(ip_protocol='tcp', from_port='61620', to_port='61621', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster'),
SecurityGroupRule(ip_protocol='tcp', from_port='7199', to_port='7199', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='8888', to_port='8888', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='8983', to_port='8983', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='9160', to_port='9160', cidr_ip='0.0.0.0/0', src_group_name=None)]
Current Rules:
[]
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='22', to_port='22', cidr_ip='0.0.0.0/0', src_group_name=None)...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='1024', to_port='65535', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster')...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='7000', to_port='7000', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster')...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='61620', to_port='61621', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster')...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='7199', to_port='7199', cidr_ip='0.0.0.0/0', src_group_name=None)...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='8888', to_port='8888', cidr_ip='0.0.0.0/0', src_group_name=None)...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='8983', to_port='8983', cidr_ip='0.0.0.0/0', src_group_name=None)...
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='9160', to_port='9160', cidr_ip='0.0.0.0/0', src_group_name=None)...
Creating group 'Test'...
Updating group "Test"...
Expected Rules:
[SecurityGroupRule(ip_protocol='tcp', from_port='22', to_port='22', cidr_ip='0.0.0.0/0', src_group_name=None)]
Current Rules:
[]
Authorizing missing rule SecurityGroupRule(ip_protocol='tcp', from_port='22', to_port='22', cidr_ip='0.0.0.0/0', src_group_name=None)...
(aws)~/Projects/aws-snippets /master> python aws_sg_recipe.py
Updating group "Cassandra Cluster"...
Expected Rules:
[SecurityGroupRule(ip_protocol='tcp', from_port='22', to_port='22', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='1024', to_port='65535', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster'),
SecurityGroupRule(ip_protocol='tcp', from_port='7000', to_port='7000', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster'),
SecurityGroupRule(ip_protocol='tcp', from_port='61620', to_port='61621', cidr_ip='0.0.0.0/0', src_group_name='Cassandra Cluster'),
SecurityGroupRule(ip_protocol='tcp', from_port='7199', to_port='7199', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='8888', to_port='8888', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='8983', to_port='8983', cidr_ip='0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol='tcp', from_port='9160', to_port='9160', cidr_ip='0.0.0.0/0', src_group_name=None)]
Current Rules:
[SecurityGroupRule(ip_protocol=u'tcp', from_port=u'1024', to_port=u'65535', cidr_ip='0.0.0.0/0', src_group_name=u'Cassandra Cluster'),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'7000', to_port=u'7000', cidr_ip='0.0.0.0/0', src_group_name=u'Cassandra Cluster'),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'61620', to_port=u'61621', cidr_ip='0.0.0.0/0', src_group_name=u'Cassandra Cluster'),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'22', to_port=u'22', cidr_ip=u'0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'7199', to_port=u'7199', cidr_ip=u'0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'8888', to_port=u'8888', cidr_ip=u'0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'8983', to_port=u'8983', cidr_ip=u'0.0.0.0/0', src_group_name=None),
SecurityGroupRule(ip_protocol=u'tcp', from_port=u'9160', to_port=u'9160', cidr_ip=u'0.0.0.0/0', src_group_name=None)]
Updating group "Test"...
Expected Rules:
[SecurityGroupRule(ip_protocol='tcp', from_port='22', to_port='22', cidr_ip='0.0.0.0/0', src_group_name=None)]
Current Rules:
[SecurityGroupRule(ip_protocol=u'tcp', from_port=u'22', to_port=u'22', cidr_ip=u'0.0.0.0/0', src_group_name=None)]
src_group_name format has been changed to sg-XXXXXXXX-owner_id
, but in your code, rule.grants[0].name
is always None
, so I got this error:
InvalidPermission.NotFound
The specified rule does not exist in this security group.
It is fine to create a new security group, then I see the same error as @gyoza, if I change one rule (for example, change a from_port).
Another issue is, cidr_ip can be list. This line need be fixed.
https://gist.github.com/steder/1498451#file-aws_sg_recipe-py-L100
Lines 89-101 should be:
for rule in group.rules:
for grant in rule.grants:
if not grant.cidr_ip:
current_rule = SecurityGroupRule(rule.ip_protocol,
rule.from_port,
rule.to_port,
"0.0.0.0/0",
grant.name)
else:
current_rule = SecurityGroupRule(rule.ip_protocol,
rule.from_port,
rule.to_port,
grant.cidr_ip,
None)
I am trying to run the update method, and I have received "AttributeError: 'tuple' object has no attribute 'name' ".
This is what I have tried:
update_security_group(boto.connect_ec2(), SECURITY_GROUPS[0], ["tcp", "5000", "5000", "0.0.0.0/0", "Test"])
Any reason why it's failing?
Thanks, this was a really useful guide