diff --git a/actions/helpers/terraform_helper.py b/actions/helpers/terraform_helper.py index 561c057804be0baaf36136c48d9951f3684b42d2..72960ee49ef168434fb3c9ff097f8a7b749d21df 100644 --- a/actions/helpers/terraform_helper.py +++ b/actions/helpers/terraform_helper.py @@ -3,9 +3,11 @@ import pathlib import json import sys +from hcl2 import loads TFVARS_DIR = pathlib.Path("terraform") TFVARS_FILE = TFVARS_DIR / "config.tfvars.json" +TF_DEFAULTS_FILE = pathlib.Path("managed-k8s/terraform/00-variables.tf") def get_current_config(): @@ -37,3 +39,14 @@ def deploy_terraform_config(terraform_config): TFVARS_DIR.mkdir(exist_ok=True) with open(TFVARS_FILE, "w") as fout: json.dump(terraform_config, fout, indent=2) + + +def get_default_value_in_tf_vars(key, file_path=TF_DEFAULTS_FILE): + with open(file_path, 'r') as file: + content = file.read() + try: + for var in loads(content)['variable']: + if key in var: + return var[key]['default'] + finally: + return None diff --git a/actions/helpers/wireguard_helper.py b/actions/helpers/wireguard_helper.py index c8e5052f49a960afb91d59f06b7afe3a60f19b7e..7d276891aca9d7561e360550394e9b77b5f43afe 100644 --- a/actions/helpers/wireguard_helper.py +++ b/actions/helpers/wireguard_helper.py @@ -563,3 +563,29 @@ def generate_wireguard_config( ], key=lambda p: p['ident']) return wireguard_config + + +def is_ipnet_disjoint( + ipnet_string: str, + wireguard_config: typing.MutableMapping +) -> bool: + try: + ipnet = ipaddress.ip_network(ipnet_string) + except ValueError: + raise ValueError("Invalid IP network string") + + wg_nets = _get_endpoints_from_config(wireguard_config) + + for wg_net in wg_nets: + if wg_net['enabled']: + # IPv4 + if isinstance(ipnet, ipaddress.IPv4Network) and 'ip_cidr' in wg_net: + if (ipnet.subnet_of(wg_net['ip_cidr']) or + wg_net['ip_cidr'].subnet_of(ipnet)): + return False + # IPv6 + elif isinstance(ipnet, ipaddress.IPv6Network) and 'ipv6_cidr' in wg_net: + if (ipnet.subnet_of(wg_net['ipv6_cidr']) or + wg_net['ipv6_cidr'].subnet_of(ipnet)): + return False + return True diff --git a/actions/update_inventory.py b/actions/update_inventory.py index 26754314a664e844c2ffc4d7146cde56e1308ab8..ec75582527eae50069d70115694f752de3a07b0a 100755 --- a/actions/update_inventory.py +++ b/actions/update_inventory.py @@ -328,6 +328,52 @@ def main(): # only if wireguard is desired if (os.getenv('WG_USAGE', 'true') == 'true'): print_process_state("Wireguard") + ip_networks = [] + tf_ipv4_string = None + tf_ipv6_string = None + + # Getting IPv4 cluster network + if (os.getenv('wg_user') == 'gitlab-ci-runner'): # if in gitlab ci + tf_ipv4_string = os.getenv('TF_VAR_subnet_cidr') + elif 'subnet_cidr' in tf_config: + tf_ipv4_string = tf_config['subnet_cidr'] + else: + tf_ipv4_string = ( + terraform_helper.get_default_value_in_tf_vars('subnet_cidr') + ) + + if tf_ipv4_string: + ip_networks.append(tf_ipv4_string) + else: + raise ValueError("No `subnet_cidr` for ipv4 cluster network found") + + # Getting IPv6 cluster network + if ( + 'dualstack_support' in tf_config and + tf_config['dualstack_support'] == 'true' + ): + if 'subnet_v6_cidr' in tf_config: + tf_ipv6_string = tf_config['subnet_v6_cidr'] + else: + tf_ipv6_string = ( + terraform_helper.get_default_value_in_tf_vars('subnet_v6_cidr') + ) + + if tf_ipv6_string: + ip_networks.append(tf_ipv6_string) + else: + raise ValueError("No `subnet_v6_cidr` for ipv6 cluster network found") + + # Proofing whether cluster networks are in conflict with wg networks + for ip_network in ip_networks: + if not wireguard_helper.is_ipnet_disjoint( + ip_network, config.get("wireguard") + ): + raise ValueError( + f"The network `{tf_ipv4_string}` is in conflict " + "with one of the wireguard networks." + ) + wg_ansible_inventory_path = ( ANSIBLE_INVENTORY_BASEPATH / "gateways" / "wireguard.yaml" ) diff --git a/docs/_releasenotes/1049.change.proof-networks-disjuction b/docs/_releasenotes/1049.change.proof-networks-disjuction new file mode 100644 index 0000000000000000000000000000000000000000..e4c9f9d6b7fa3f30b0cce50570d7efd8e9cef99f --- /dev/null +++ b/docs/_releasenotes/1049.change.proof-networks-disjuction @@ -0,0 +1 @@ +Proof whether the WireGuard networks and the cluster network are disjoint diff --git a/poetry.lock b/poetry.lock index 08b073dc4e7bbad12c8f73322f330546f4e0cfc4..cfadfd59e3c61cbe98e046a07b30b90e6956eea1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1005,6 +1005,23 @@ PyYAML = "*" referencing = "*" typing-extensions = "*" +[[package]] +name = "lark" +version = "1.1.9" +description = "a modern parsing library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "lark-1.1.9-py3-none-any.whl", hash = "sha256:a0dd3a87289f8ccbb325901e4222e723e7d745dbfc1803eaf5f3d2ace19cf2db"}, + {file = "lark-1.1.9.tar.gz", hash = "sha256:15fa5236490824c2c4aba0e22d2d6d823575dcaf4cdd1848e34b6ad836240fba"}, +] + +[package.extras] +atomic-cache = ["atomicwrites"] +interegular = ["interegular (>=0.3.1,<0.4.0)"] +nearley = ["js2py"] +regex = ["regex"] + [[package]] name = "loguru" version = "0.7.2" @@ -1733,6 +1750,20 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "python-hcl2" +version = "4.3.2" +description = "A parser for HCL2" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "python-hcl2-4.3.2.tar.gz", hash = "sha256:7122661438be27ccd8b8f3db71969d8ef2cce3b3cf183e88f8172575e7405a65"}, + {file = "python_hcl2-4.3.2-py3-none-any.whl", hash = "sha256:e958fe52ca0519e3500eb621caa16be6be9c27870cbcd1879d8c538fb85067ea"}, +] + +[package.dependencies] +lark = ">=1,<2" + [[package]] name = "python-keystoneclient" version = "5.4.0" @@ -2960,4 +2991,4 @@ tests = ["build", "coverage", "mypy", "ruff", "wheel"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "b12e7f7910a6943e84ce56c15bdb9fe9fbe2ad5ed7e347a8283f135efc091b69" +content-hash = "b051de5b921b0b2dc37f049cbc369b52ab38e5c8d429b7ed07d73c77bce51df5" diff --git a/pyproject.toml b/pyproject.toml index bd146981f28792a6b2a7efbc7b413f892af7fbcb..efd38ef408bde152e86ce3c0117dd3b4d333b294 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ hvac = "^2.0.0" boto3 = "^1.26.155" pre-commit = "^3.3.3" yq = "^3.4.1" +python-hcl2 = "^4.3.2" [tool.poetry.group.ci] optional = true