Merge "Update IPsec config generation for IPv6"

This commit is contained in:
Zuul 2024-05-03 15:29:27 +00:00 committed by Gerrit Code Review
commit 2aed6e9eed
4 changed files with 96 additions and 45 deletions

View File

@ -171,7 +171,9 @@ class Client(object):
data = msg['cert'].encode('utf-8')
if self.op_code == constants.OP_CODE_INITIAL_AUTH:
network = msg['network']
data = data + network.encode('utf-8')
unit_ip = msg['unit_ip']
floating_ip = msg['floating_ip']
data = data + (network + unit_ip + floating_ip).encode('utf-8')
if not utils.verify_signed_hash(ca_cert, digest, data):
msg = "Hash validation failed"
@ -193,7 +195,8 @@ class Client(object):
LOG.info("Generating config files and restart ipsec")
strong = config.StrongswanPuppet(self.hostname[constants.UNIT_HOSTNAME],
self.local_addr, network)
self.local_addr, network,
unit_ip, floating_ip)
strong.generate_file()
puppet_cf = subprocess.run(['puppet', 'apply', '-e',
'include ::platform::strongswan'],

View File

@ -4,10 +4,13 @@
# SPDX-License-Identifier: Apache-2.0
#
import os
import subprocess
import yaml
from oslo_log import log as logging
from sysinv.common import utils as cutils
from sysinv.ipsec_auth.common import constants
LOG = logging.getLogger(__name__)
@ -71,40 +74,23 @@ class SwanctlConf(object):
def __init__(self):
self.connections = {}
self.system_nodes = {}
self.local = {}
self.remote = {}
self.children = {}
self.node = {}
def add_system_nodes(self, key, value):
self.system_nodes[key] = value
def add_local(self, key, value):
self.local[key] = value
def add_remote(self, key, value):
self.remote[key] = value
def add_node(self, key, value):
self.node[key] = value
def add_connection(self, key, value):
self.connections[key] = value
def get_conf(self):
self.children[constants.CHILD_SA_NAME] = self.node
self.system_nodes['local'] = self.local
self.system_nodes['remote'] = self.remote
self.system_nodes['children'] = self.children
self.connections[constants.IKE_SA_NAME] = self.system_nodes
return self.connections
class StrongswanPuppet(object):
""" Class to encapsulate puppet operations for ipsec configuration. """
def __init__(self, hostname, local_addrs, network_addrs):
def __init__(self, hostname, local_addrs, network_addrs, unit_ip, floating_ip):
self.hostname = hostname
self.local_addrs = local_addrs
self.network_addrs = network_addrs
self.unit_ip = unit_ip
self.floating_ip = floating_ip
self.path = '/tmp/puppet/hieradata'
self.filename = 'ipsec.yaml'
@ -157,27 +143,81 @@ class StrongswanPuppet(object):
def get_swanctl_config(self):
swanctl = SwanctlConf()
# connection reauth_time 14400s (4h)
swanctl.add_system_nodes('reauth_time', '14400')
# connection rekey_time 3600s (1h)
swanctl.add_system_nodes('rekey_time', '3600')
swanctl.add_system_nodes('unique', 'never')
swanctl.add_system_nodes('local_addrs', self.local_addrs)
swanctl.add_system_nodes('remote_addrs', self.network_addrs)
# Add system-nodes connection, this is the connection between nodes.
if cutils.is_valid_ipv6_cidr(self.network_addrs):
remote_addrs = '%any6'
else:
remote_addrs = '%any'
certs = constants.CERT_NAME_PREFIX + self.hostname + '.crt'
swanctl.add_local('auth', 'pubkey')
cert = constants.CERT_NAME_PREFIX + self.hostname + '.crt'
swanctl.add_local('certs', cert)
conn = {
# connection reauth_time 14400s (4h)
'reauth_time': '14400',
'rekey_time': '3600',
'unique': 'never',
'mobike': 'no',
'local_addrs': self.local_addrs,
'remote_addrs': remote_addrs,
# swanctl.add_remote('id', 'CN=ipsec-*')
swanctl.add_remote('id', 'CN=*')
swanctl.add_remote('auth', 'pubkey')
swanctl.add_remote('cacerts', constants.TRUSTED_CA_CERT_FILES)
'local': {
'auth': 'pubkey',
'certs': certs,
},
'remote': {
'id': 'CN=*',
'auth': 'pubkey',
'cacerts': constants.TRUSTED_CA_CERT_FILE,
},
'children': {
constants.CHILD_SA_NAME: {
'mode': 'transport',
'start_action': 'trap',
'local_ts': self.network_addrs,
'remote_ts': self.network_addrs,
},
},
}
swanctl.add_connection(constants.IKE_SA_NAME, conn)
swanctl.add_node('mode', 'transport')
swanctl.add_node('start_action', 'trap')
swanctl.add_node('local_ts', self.network_addrs)
swanctl.add_node('remote_ts', self.network_addrs)
# Add local bypass connection to bypass local to local traffic,
# eg, traffic from unit IP to floating IP on active controller.
# Without this connection, "system host-list" and such will hang,
# because it's accessing services on floating IP from unit IP.
# Check if this node has the floating IP
cmd = 'ip addr | grep ' + self.floating_ip + '/'
output = subprocess.run(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
shell=True)
if output.returncode == 0:
conn = {
'children': {
'node-bypass': {
'mode': 'pass',
'start_action': 'trap',
'local_ts': self.unit_ip + ", " + self.floating_ip,
'remote_ts': self.unit_ip + ", " + self.floating_ip,
},
},
}
swanctl.add_connection('system-nodes-local', conn)
# Add ndp bypass connection for IPv6 only.
# Reference: https://wiki.strongswan.org/projects/strongswan/wiki/IPv6NDP/1
if cutils.is_valid_ipv6_cidr(self.network_addrs):
conn = {
'children': {
'icmpv6-bypass': {
'mode': 'pass',
'start_action': 'trap',
'local_ts': '\"::/0[ipv6-icmp]\"',
'remote_ts': '\"::/0[ipv6-icmp]\"',
},
},
}
swanctl.add_connection('ndp', conn)
return {
'platform::strongswan::params::swanctl': swanctl.get_conf()

View File

@ -75,7 +75,7 @@ def get_hw_addr(ifname):
LOG.exception("Error getting mac address: %s" % (e))
def get_client_hostname_and_mgmt_subnet(mac_addr):
def get_client_host_info_by_mac(mac_addr):
token = rest_api.get_token(constants.REGION_NAME)
sysinv_ihost_url = constants.PXECONTROLLER_URL + '/v1/ihosts/'
api_cmd = sysinv_ihost_url + mac_addr + '/mgmt_ip'
@ -99,6 +99,8 @@ def get_client_hostname_and_mgmt_subnet(mac_addr):
response['hostname'] = hostname
response['mgmt_subnet'] = mgmt_info['subnet']
response['unit_ip'] = mgmt_info['address']
response['floating_ip'] = mgmt_info['floating']
return response

View File

@ -159,9 +159,11 @@ class IPsecConnection(object):
"received in payload.")
raise ConnectionRefusedError(msg)
client_data = utils.get_client_hostname_and_mgmt_subnet(mac_addr)
client_data = utils.get_client_host_info_by_mac(mac_addr)
self.hostname = client_data['hostname']
self.mgmt_subnet = client_data['mgmt_subnet']
self.unit_ip = client_data['unit_ip']
self.floating_ip = client_data['floating_ip']
pub_key = self._generate_tmp_key_pair()
token = self.ots_token.get_content()
@ -209,7 +211,11 @@ class IPsecConnection(object):
data = bytes(self.signed_cert, 'utf-8')
if self.op_code == constants.OP_CODE_INITIAL_AUTH:
payload["network"] = self.mgmt_subnet
data = data + bytes(self.mgmt_subnet, 'utf-8')
payload["unit_ip"] = self.unit_ip
payload["floating_ip"] = self.floating_ip
data = data + bytes(self.mgmt_subnet +
self.unit_ip +
self.floating_ip, 'utf-8')
hash_payload = utils.hash_and_sign_payload(self.ca_key, data)