Merge pull request #23309 from rmcleay/secgroup_egress

Egress rule support for boto_secgroup
This commit is contained in:
Thomas S Hatch 2015-05-04 14:57:02 -06:00
commit e23e4f6ef8
3 changed files with 134 additions and 55 deletions

View file

@ -167,6 +167,42 @@ def _get_group(conn, name=None, vpc_id=None, group_id=None, region=None): # pyl
return None
def _parse_rules(sg, rules):
_rules = []
for rule in rules:
log.debug('examining rule {0} for group {1}'.format(rule, sg.id))
attrs = ['ip_protocol', 'from_port', 'to_port', 'grants']
_rule = odict.OrderedDict()
for attr in attrs:
val = getattr(rule, attr)
if not val:
continue
if attr == 'grants':
_grants = []
for grant in val:
log.debug('examining grant {0} for'.format(grant))
g_attrs = {'name': 'source_group_name',
'owner_id': 'source_group_owner_id',
'group_id': 'source_group_group_id',
'cidr_ip': 'cidr_ip'}
_grant = odict.OrderedDict()
for g_attr, g_attr_map in six.iteritems(g_attrs):
g_val = getattr(grant, g_attr)
if not g_val:
continue
_grant[g_attr_map] = g_val
_grants.append(_grant)
_rule['grants'] = _grants
elif attr == 'from_port':
_rule[attr] = int(val)
elif attr == 'to_port':
_rule[attr] = int(val)
else:
_rule[attr] = val
_rules.append(_rule)
return _rules
def get_group_id(name, vpc_id=None, region=None, key=None, keyid=None, profile=None):
'''
Get a Group ID given a Group Name or Group Name and VPC ID
@ -234,39 +270,10 @@ def get_config(name=None, group_id=None, region=None, key=None, keyid=None,
ret['owner_id'] = sg.owner_id
ret['description'] = sg.description
# TODO: add support for tags
_rules = []
for rule in sg.rules:
log.debug('examining rule {0} for group {1}'.format(rule, sg.id))
attrs = ['ip_protocol', 'from_port', 'to_port', 'grants']
_rule = odict.OrderedDict()
for attr in attrs:
val = getattr(rule, attr)
if not val:
continue
if attr == 'grants':
_grants = []
for grant in val:
log.debug('examining grant {0} for'.format(grant))
g_attrs = {'name': 'source_group_name',
'owner_id': 'source_group_owner_id',
'group_id': 'source_group_group_id',
'cidr_ip': 'cidr_ip'}
_grant = odict.OrderedDict()
for g_attr, g_attr_map in six.iteritems(g_attrs):
g_val = getattr(grant, g_attr)
if not g_val:
continue
_grant[g_attr_map] = g_val
_grants.append(_grant)
_rule['grants'] = _grants
elif attr == 'from_port':
_rule[attr] = int(val)
elif attr == 'to_port':
_rule[attr] = int(val)
else:
_rule[attr] = val
_rules.append(_rule)
_rules = _parse_rules(sg, sg.rules)
_rules_egress = _parse_rules(sg, sg.rules_egress)
ret['rules'] = _split_rules(_rules)
ret['rules_egress'] = _split_rules(_rules_egress)
return ret
else:
return None
@ -275,7 +282,7 @@ def get_config(name=None, group_id=None, region=None, key=None, keyid=None,
def create(name, description, vpc_id=None, region=None, key=None, keyid=None,
profile=None):
'''
Create an autoscale group.
Create a security group.
CLI example::
@ -296,7 +303,7 @@ def create(name, description, vpc_id=None, region=None, key=None, keyid=None,
def delete(name=None, group_id=None, region=None, key=None, keyid=None,
profile=None, vpc_id=None):
'''
Delete an autoscale group.
Delete a security group.
CLI example::
@ -324,7 +331,7 @@ def authorize(name=None, source_group_name=None,
source_group_owner_id=None, ip_protocol=None,
from_port=None, to_port=None, cidr_ip=None, group_id=None,
source_group_group_id=None, region=None, key=None,
keyid=None, profile=None, vpc_id=None):
keyid=None, profile=None, vpc_id=None, egress=False):
'''
Add a new rule to an existing security group.
@ -337,12 +344,19 @@ def authorize(name=None, source_group_name=None,
group = _get_group(conn, name, vpc_id, group_id, region)
if group:
try:
added = conn.authorize_security_group(
src_security_group_name=source_group_name,
src_security_group_owner_id=source_group_owner_id,
ip_protocol=ip_protocol, from_port=from_port, to_port=to_port,
cidr_ip=cidr_ip, group_id=group.id,
src_security_group_group_id=source_group_group_id)
added = None
if not egress:
added = conn.authorize_security_group(
src_security_group_name=source_group_name,
src_security_group_owner_id=source_group_owner_id,
ip_protocol=ip_protocol, from_port=from_port, to_port=to_port,
cidr_ip=cidr_ip, group_id=group.id,
src_security_group_group_id=source_group_group_id)
else:
added = conn.authorize_security_group_egress(
ip_protocol=ip_protocol, from_port=from_port, to_port=to_port,
cidr_ip=cidr_ip, group_id=group.id,
src_group_id=source_group_group_id)
if added:
log.info('Added rule to security group {0} with id {1}'
.format(group.name, group.id))
@ -367,7 +381,7 @@ def revoke(name=None, source_group_name=None,
source_group_owner_id=None, ip_protocol=None,
from_port=None, to_port=None, cidr_ip=None, group_id=None,
source_group_group_id=None, region=None, key=None,
keyid=None, profile=None, vpc_id=None):
keyid=None, profile=None, vpc_id=None, egress=False):
'''
Remove a rule from an existing security group.
@ -380,12 +394,20 @@ def revoke(name=None, source_group_name=None,
group = _get_group(conn, name, vpc_id, group_id, region)
if group:
try:
revoked = conn.revoke_security_group(
src_security_group_name=source_group_name,
src_security_group_owner_id=source_group_owner_id,
ip_protocol=ip_protocol, from_port=from_port, to_port=to_port,
cidr_ip=cidr_ip, group_id=group.id,
src_security_group_group_id=source_group_group_id)
revoked = None
if not egress:
revoked = conn.revoke_security_group(
src_security_group_name=source_group_name,
src_security_group_owner_id=source_group_owner_id,
ip_protocol=ip_protocol, from_port=from_port, to_port=to_port,
cidr_ip=cidr_ip, group_id=group.id,
src_security_group_group_id=source_group_group_id)
else:
revoked = conn.revoke_security_group_egress(
ip_protocol=ip_protocol, from_port=from_port, to_port=to_port,
cidr_ip=cidr_ip, group_id=group.id,
src_group_id=source_group_group_id)
if revoked:
log.info('Removed rule from security group {0} with id {1}.'
.format(group.name, group.id))

View file

@ -47,6 +47,17 @@ passed in as a dict, or as a string to pull from pillars or minion config:
cidr_ip:
- 10.0.0.0/0
- 192.168.0.0/0
- ip_protocol: icmp
from_port: -1
to_port: -1
source_group_name: mysecgroup
- rules_egress:
- ip_protocol: all
from_port: -1
to_port: -1
cidr_ip:
- 10.0.0.0/0
- 192.168.0.0/0
- region: us-east-1
- keyid: GKTADJGHEIQSXMKKRBJ08H
- key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
@ -94,6 +105,7 @@ def present(
description,
vpc_id=None,
rules=None,
rules_egress=None,
region=None,
key=None,
keyid=None,
@ -113,6 +125,9 @@ def present(
rules
A list of ingress rule dicts.
rules_egress
A list of egress rule dicts.
region
Region to connect to.
@ -137,7 +152,7 @@ def present(
return ret
if not rules:
rules = []
_ret = _rules_present(name, rules, vpc_id, region, key, keyid, profile)
_ret = _rules_present(name, rules, rules_egress, vpc_id, region, key, keyid, profile)
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
if not _ret['result']:
@ -259,10 +274,13 @@ def _get_rule_changes(rules, _rules):
raise SaltInvocationError('ip_protocol, to_port, and from_port are'
' required arguments for security group'
' rules.')
supported_protocols = ['tcp', 'udp', 'icmp', 'all']
supported_protocols = ['tcp', 'udp', 'icmp', 'all', '-1']
if ip_protocol not in supported_protocols:
msg = ('Invalid ip_protocol {0} specified in security group rule.')
raise SaltInvocationError(msg.format(ip_protocol))
# For the 'all' case, we need to change the protocol name to '-1'.
if ip_protocol == 'all':
rule['ip_protocol'] = '-1'
cidr_ip = rule.get('cidr_ip', None)
group_name = rule.get('source_group_name', None)
group_id = rule.get('source_group_group_id', None)
@ -307,6 +325,7 @@ def _get_rule_changes(rules, _rules):
def _rules_present(
name,
rules,
rules_egress,
vpc_id,
region,
key,
@ -318,6 +337,8 @@ def _rules_present(
2. delete/revoke or authorize/create rules
3. return 'old' and 'new' group rules
'''
import itertools
ret = {'result': True, 'comment': '', 'changes': {}}
sg = __salt__['boto_secgroup.get_config'](name, None, region, key, keyid,
profile, vpc_id)
@ -327,8 +348,9 @@ def _rules_present(
ret['result'] = False
return ret
rules = _split_rules(rules)
rules_egress = _split_rules(rules_egress)
if vpc_id:
for rule in rules:
for rule in itertools.chain(rules, rules_egress):
_source_group_name = rule.get('source_group_name', None)
if _source_group_name:
_group_id = __salt__['boto_secgroup.get_group_id'](
@ -343,7 +365,8 @@ def _rules_present(
# rules = rules that exist in salt state
# sg['rules'] = that exist in present group
to_delete, to_create = _get_rule_changes(rules, sg['rules'])
if to_create or to_delete:
to_delete_egress, to_create_egress = _get_rule_changes(rules_egress, sg['rules_egress'])
if to_create or to_delete or to_create_egress or to_delete_egress:
if __opts__['test']:
msg = 'Security group {0} set to have rules modified.'.format(name)
ret['comment'] = msg
@ -379,10 +402,43 @@ def _rules_present(
msg = 'Failed to create rules on {0} security group.'
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
ret['result'] = False
ret['changes']['old'] = {'rules': sg['rules']}
if to_delete_egress:
deleted = True
for rule in to_delete_egress:
_deleted = __salt__['boto_secgroup.revoke'](
name, vpc_id=vpc_id, region=region, key=key, keyid=keyid,
profile=profile, egress=True, **rule)
if not _deleted:
deleted = False
if deleted:
msg = 'Removed egress rules on {0} security group.'.format(name)
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
else:
msg = 'Failed to remove egress rules on {0} security group.'
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
ret['result'] = False
if to_create_egress:
created = True
for rule in to_create_egress:
_created = __salt__['boto_secgroup.authorize'](
name, vpc_id=vpc_id, region=region, key=key, keyid=keyid,
profile=profile, egress=True, **rule)
if not _created:
created = False
if created:
msg = 'Created egress rules on {0} security group.'
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
else:
msg = 'Failed to create egress rules on {0} security group.'
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
ret['result'] = False
ret['changes']['old'] = {'rules': sg['rules'], 'rules_egress': sg['rules_egress']}
sg = __salt__['boto_secgroup.get_config'](name, None, region, key,
keyid, profile, vpc_id)
ret['changes']['new'] = {'rules': sg['rules']}
ret['changes']['new'] = {'rules': sg['rules'], 'rules_egress': sg['rules_egress']}
return ret

View file

@ -207,7 +207,8 @@ class BotoSecgroupTestCase(TestCase):
expected_get_config_result = OrderedDict([('name', group.name), ('group_id', group.id), ('owner_id', u'111122223333'),
('description', group.description),
('rules', [{'to_port': to_port, 'from_port': from_port,
'ip_protocol': ip_protocol, 'cidr_ip': cidr_ip}])])
'ip_protocol': ip_protocol, 'cidr_ip': cidr_ip}]),
('rules_egress', [])])
secgroup_get_config_result = boto_secgroup.get_config(group_id=group.id, **conn_parameters)
self.assertEqual(expected_get_config_result, secgroup_get_config_result)