Allow blocking IPs from member addresses
This patch adds a configuration option for reserved IP addresses that cannot be used for load balancer member addresses. By default, this will include the nova metadata service address 169.254.169.254. Change-Id: I25de5ed5f6f35afc55dd1154c3e02934fddb100a Story: 2003413 Task: 24555
This commit is contained in:
parent
91fae05a7d
commit
1ad9fd7272
@ -161,6 +161,9 @@
|
|||||||
# List of network_ids that are valid for VIP creation.
|
# List of network_ids that are valid for VIP creation.
|
||||||
# If this field empty, no validation is performed.
|
# If this field empty, no validation is performed.
|
||||||
# valid_vip_networks =
|
# valid_vip_networks =
|
||||||
|
# List of reserved IP addresses that cannot be used for member addresses
|
||||||
|
# The default is the nova metadata service address
|
||||||
|
# reserved_ips = ['169.254.169.254']
|
||||||
|
|
||||||
[haproxy_amphora]
|
[haproxy_amphora]
|
||||||
# base_path = /var/lib/octavia
|
# base_path = /var/lib/octavia
|
||||||
|
@ -135,6 +135,9 @@ class MemberController(base.BaseController):
|
|||||||
"""Creates a pool member on a pool."""
|
"""Creates a pool member on a pool."""
|
||||||
member = member_.member
|
member = member_.member
|
||||||
context = pecan.request.context.get('octavia_context')
|
context = pecan.request.context.get('octavia_context')
|
||||||
|
|
||||||
|
validate.ip_not_reserved(member.address)
|
||||||
|
|
||||||
# Validate member subnet
|
# Validate member subnet
|
||||||
if member.subnet_id and not validate.subnet_exists(member.subnet_id):
|
if member.subnet_id and not validate.subnet_exists(member.subnet_id):
|
||||||
raise exceptions.NotFound(resource='Subnet',
|
raise exceptions.NotFound(resource='Subnet',
|
||||||
|
@ -165,6 +165,12 @@ networking_opts = [
|
|||||||
help=_('List of network_ids that are valid for VIP '
|
help=_('List of network_ids that are valid for VIP '
|
||||||
'creation. If this field is empty, no validation '
|
'creation. If this field is empty, no validation '
|
||||||
'is performed.')),
|
'is performed.')),
|
||||||
|
cfg.ListOpt('reserved_ips',
|
||||||
|
default=['169.254.169.254'],
|
||||||
|
item_type=cfg.types.IPAddress(),
|
||||||
|
help=_('List of IP addresses reserved from being used for '
|
||||||
|
'member addresses. IPv6 addresses should be in '
|
||||||
|
'expanded, uppercase form.')),
|
||||||
]
|
]
|
||||||
|
|
||||||
healthmanager_opts = [
|
healthmanager_opts = [
|
||||||
|
@ -19,11 +19,13 @@ Defined here so these can also be used at deeper levels than the API.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import ipaddress
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
import rfc3986
|
import rfc3986
|
||||||
|
import six
|
||||||
|
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
from octavia.common import exceptions
|
from octavia.common import exceptions
|
||||||
@ -322,3 +324,11 @@ def check_session_persistence(SP_dict):
|
|||||||
except Exception:
|
except Exception:
|
||||||
raise exceptions.ValidationException(detail=_(
|
raise exceptions.ValidationException(detail=_(
|
||||||
'Invalid session_persistence provided.'))
|
'Invalid session_persistence provided.'))
|
||||||
|
|
||||||
|
|
||||||
|
def ip_not_reserved(ip_address):
|
||||||
|
ip_address = (
|
||||||
|
ipaddress.ip_address(six.text_type(ip_address)).exploded.upper())
|
||||||
|
if ip_address in CONF.networking.reserved_ips:
|
||||||
|
raise exceptions.InvalidOption(value=ip_address,
|
||||||
|
option='member address')
|
||||||
|
@ -414,3 +414,31 @@ class TestValidations(base.TestCase):
|
|||||||
self.assertRaises(exceptions.ValidationException,
|
self.assertRaises(exceptions.ValidationException,
|
||||||
validate.check_session_persistence,
|
validate.check_session_persistence,
|
||||||
valid_cookie_name_dict)
|
valid_cookie_name_dict)
|
||||||
|
|
||||||
|
def test_ip_not_reserved(self):
|
||||||
|
self.conf.config(group="networking", reserved_ips=['198.51.100.4'])
|
||||||
|
|
||||||
|
# Test good address
|
||||||
|
validate.ip_not_reserved('203.0.113.5')
|
||||||
|
|
||||||
|
# Test IPv4 reserved address
|
||||||
|
self.assertRaises(exceptions.InvalidOption,
|
||||||
|
validate.ip_not_reserved,
|
||||||
|
'198.51.100.4')
|
||||||
|
|
||||||
|
self.conf.config(
|
||||||
|
group="networking",
|
||||||
|
reserved_ips=['2001:0DB8:0000:0000:0000:0000:0000:0005'])
|
||||||
|
|
||||||
|
# Test good IPv6 address
|
||||||
|
validate.ip_not_reserved('2001:0DB8::9')
|
||||||
|
|
||||||
|
# Test reserved IPv6 expanded
|
||||||
|
self.assertRaises(exceptions.InvalidOption,
|
||||||
|
validate.ip_not_reserved,
|
||||||
|
'2001:0DB8:0000:0000:0000:0000:0000:0005')
|
||||||
|
|
||||||
|
# Test reserved IPv6 short hand notation
|
||||||
|
self.assertRaises(exceptions.InvalidOption,
|
||||||
|
validate.ip_not_reserved,
|
||||||
|
'2001:0DB8::5')
|
||||||
|
6
releasenotes/notes/reserved-ips-7ef3a63ab0b6b28a.yaml
Normal file
6
releasenotes/notes/reserved-ips-7ef3a63ab0b6b28a.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
security:
|
||||||
|
- |
|
||||||
|
Adds a configuration option, "reserved_ips" that allows the operator to
|
||||||
|
block addresses from being used in load balancer members. The default
|
||||||
|
setting blocks the nova metadata service address.
|
Loading…
x
Reference in New Issue
Block a user