mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #23309 from rmcleay/secgroup_egress
Egress rule support for boto_secgroup
This commit is contained in:
commit
e23e4f6ef8
3 changed files with 134 additions and 55 deletions
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue