diff --git a/roles/azure_controllers/README.md b/roles/azure_controllers/README.md index 5a9cc4d..5c94f46 100644 --- a/roles/azure_controllers/README.md +++ b/roles/azure_controllers/README.md @@ -47,6 +47,7 @@ The `azure_controllers` role automates the deployment of Cisco SD-WAN controller - `az_vmanage_vm_size`, `az_vbond_vm_size`, `az_vsmart_vm_size`: Azure VM sizes for vManage, vBond, and vSmart instances. - `site_id_vmanage`, `site_id_vbond`, `site_id_vsmart`: Default site IDs for vManage, vBond, and vSmart instances. - `vmanage_instances`, `vbond_instances`, `vsmart_instances`: Lists for instance configurations. +- `ipv6_strict_control`: Control if ipv6-strict-control is enabled. ### Vars (`vars/main.yml`) diff --git a/roles/azure_controllers/defaults/main.yml b/roles/azure_controllers/defaults/main.yml index 24de968..bc9d93f 100644 --- a/roles/azure_controllers/defaults/main.yml +++ b/roles/azure_controllers/defaults/main.yml @@ -24,22 +24,30 @@ az_vn_address_prefixes_cidr: 10.0.0.0/16 az_subnets: | {% filter from_yaml %} - name: "{{ az_resources_prefix }}-mgmt-subnet-512" - cidr: "10.0.1.0/24" + cidr: + - "10.0.1.0/24" + - "fd00:0:0:1::/64" VPN: 512 type: mgmt - name: "{{ az_resources_prefix }}-transport-subnet-0" - cidr: "10.0.2.0/24" + cidr: + - "10.0.2.0/24" + - "fd00:0:0:2::/64" VPN: 0 type: transport {% if vmanage_instances is defined and vmanage_instances | length > 2 %} - name: "{{ az_resources_prefix }}-cluster-subnet-0" - cidr: "10.0.3.0/24" + cidr: + - "10.0.3.0/24" + - "fd00:0:0:3::/64" VPN: 0 type: cluster {% endif %} {% if ux20_deployment is defined and ux20_deployment == true %} - name: "{{ az_resources_prefix }}-service-subnet-10" - cidr: "10.0.4.0/24" # default ips from official Cisco guides + cidr: + - "10.0.4.0/24" # default ips from official Cisco guides + - "fd00:0:0:4::/64" VPN: 10 type: service {% endif %} @@ -49,6 +57,11 @@ az_subnets: | az_network_security_group: "{{ az_resources_prefix }}-nsg" +# Private DNS zone +az_private_dns_zone: "{{ az_resources_prefix }}.internal" +az_vbond_address: "vbond.{{ az_private_dns_zone }}" + + # VPN subnets from which we can connect to Azure EIPs (Network Security Group config) az_allowed_subnets: null @@ -63,6 +76,7 @@ admin_password: null # pragma: allowlist secret admin_ssh_keys: [] vbond_port: 12346 default_vbond_ip: 192.168.1.199 +ipv6_strict_control: true # vpn0_interface_color: default diff --git a/roles/azure_controllers/tasks/azure_vbond_vm.yml b/roles/azure_controllers/tasks/azure_vbond_vm.yml index 6411ca0..f1e4b9a 100644 --- a/roles/azure_controllers/tasks/azure_vbond_vm.yml +++ b/roles/azure_controllers/tasks/azure_vbond_vm.yml @@ -19,6 +19,7 @@ Machine: "{{ hostname }}" VPN: "{{ subnet_item.VPN }}" Subnet: "{{ subnet_item.name }}" + sku: standard loop: - "{{ mgmt_subnet }}" - "{{ transport_subnet }}" @@ -26,6 +27,26 @@ loop_var: subnet_item register: public_ip_addresses +- name: "Create public IPv6 addresses for machine: {{ hostname }}" + azure.azcollection.azure_rm_publicipaddress: + resource_group: "{{ az_resource_group }}" + allocation_method: static + name: "public-ipv6-{{ hostname }}-vpn-{{ subnet_item.VPN }}" + tags: + Name: "public-ipv6-{{ hostname }}" + Creator: "{{ az_tag_creator }}" + Machine: "{{ hostname }}" + VPN: "{{ subnet_item.VPN }}" + Subnet: "{{ subnet_item.name }}" + version: ipv6 + sku: standard + loop: + - "{{ mgmt_subnet }}" + - "{{ transport_subnet }}" + loop_control: + loop_var: subnet_item + register: public_ipv6_addresses + - name: "Get info about NSG: {{ az_network_security_group }}" azure.azcollection.azure_rm_securitygroup_info: resource_group: "{{ az_resource_group }}" @@ -49,7 +70,7 @@ Name: "{{ az_network_security_group }}" Creator: "{{ az_tag_creator }}" Organization: "{{ organization_name }}" - loop: "{{ public_ip_addresses.results }}" + loop: "{{ public_ip_addresses.results + public_ipv6_addresses.results }}" loop_control: loop_var: public_ip_state index_var: my_idx @@ -67,6 +88,10 @@ - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}" public_ip_address_name: "{{ public_ip_state.state.name }}" private_ip_allocation_method: "Dynamic" + - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}-ipv6" + public_ip_address_name: "{{ public_ipv6_addresses.results | json_query(_public_ip_query) | first }}" + private_ip_allocation_method: "Dynamic" + private_ip_address_version: IPv6 tags: Name: "nic-{{ hostname }}-vpn-{{ public_ip_state.state.tags.VPN }}" Creator: "{{ az_tag_creator }}" @@ -78,30 +103,41 @@ index_var: my_idx label: public_ip_state.state.name register: vbond_nics + vars: + _public_ip_query: "[?to_number(state.tags.VPN)==`{{ public_ip_state.state.tags.VPN }}`].state.name" - name: Set az_network_interfaces_vbond fact with a list of interfaces for vBond ansible.builtin.set_fact: az_network_interfaces_vbond: "{{ vbond_nics.results | map(attribute='state') | list }}" - az_public_ip_addresses_vbond: "{{ public_ip_addresses.results | map(attribute='state') | list }}" + az_public_ip_addresses_vbond: "{{ (public_ip_addresses.results + public_ipv6_addresses.results) | map(attribute='state') | list }}" - name: Filter az_network_interfaces_vbond for instance creation. Set az_mgmt_nic and az_transport_nic facts ansible.builtin.set_fact: az_mgmt_nic: "{{ az_network_interfaces_vbond | selectattr('tags.VPN', 'equalto', '512') | list | first }}" az_transport_nic: "{{ az_network_interfaces_vbond | selectattr('tags.VPN', 'equalto', '0') | list | first }}" - az_mgmt_public_ip: "{{ az_public_ip_addresses_vbond | selectattr('tags.VPN', 'equalto', '512') | list | first }}" - az_transport_public_ip: "{{ az_public_ip_addresses_vbond | selectattr('tags.VPN', 'equalto', '0') | list | first }}" + az_mgmt_public_ip: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_transport_public_ip: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_mgmt_public_ipv6: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + az_transport_public_ipv6: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + vars: + _mgmt_public_ips: "{{ az_public_ip_addresses_vbond | selectattr('tags.VPN', 'equalto', '512') }}" + _transport_public_ips: "{{ az_public_ip_addresses_vbond | selectattr('tags.VPN', 'equalto', '0') }}" # vbond_mgmt_private_ip - name: "Set ip addresses vbond facts" ansible.builtin.set_fact: - vbond_mgmt_private_ip: "{{ az_mgmt_nic.ip_configuration.private_ip_address }}" - vbond_transport_private_ip: "{{ az_transport_nic.ip_configuration.private_ip_address }}" + vbond_mgmt_private_ip: "{{ (az_mgmt_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv4`]') | first).private_ip_address }}" + vbond_mgmt_private_ipv6: "{{ (az_mgmt_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv6`]') | first).private_ip_address }}" + vbond_transport_private_ip: "{{ (az_transport_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv4`]') | first).private_ip_address }}" + vbond_transport_private_ipv6: "{{ (az_transport_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv6`]') | first).private_ip_address }}" vbond_mgmt_public_ip: "{{ az_mgmt_public_ip.ip_address }}" vbond_transport_public_ip: "{{ az_transport_public_ip.ip_address }}" + vbond_mgmt_public_ipv6: "{{ az_mgmt_public_ipv6.ip_address }}" + vbond_transport_public_ipv6: "{{ az_transport_public_ipv6.ip_address }}" - name: "Set vpn0_default_gateway fact from VPN 0 subnet value" ansible.builtin.set_fact: - vpn0_default_gateway: "{{ subnet_item.cidr | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" + vpn0_default_gateway: "{{ subnet_item.cidr[0] | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" loop: - "{{ mgmt_subnet }}" - "{{ transport_subnet }}" @@ -178,9 +214,26 @@ admin_password: "{{ admin_password }}" mgmt_public_ip: "{{ vbond_mgmt_public_ip }}" transport_public_ip: "{{ vbond_transport_public_ip }}" + mgmt_public_ipv6: "{{ vbond_mgmt_public_ipv6 }}" + transport_public_ipv6: "{{ vbond_transport_public_ipv6 }}" changed_when: true notify: Show deployment_facts +- name: DNS records + azure.azcollection.azure_rm_privatednsrecordset: + resource_group: "{{ az_resource_group }}" + zone_name: "{{ az_private_dns_zone }}" + relative_name: "vbond" + record_type: "{{ item.type }}" + records: "{{ item.records }}" + loop: + - type: 'A' + records: + - entry: "{{ vbond_transport_public_ip }}" + - type: 'AAAA' + records: + - entry: "{{ vbond_transport_public_ipv6 }}" + - name: Update deployment facts - vBond - that will be consumed by vManage-client in Ansible ansible.builtin.set_fact: deployment_facts: diff --git a/roles/azure_controllers/tasks/azure_vmanage_vm.yml b/roles/azure_controllers/tasks/azure_vmanage_vm.yml index e6d4a1e..f8c7c53 100644 --- a/roles/azure_controllers/tasks/azure_vmanage_vm.yml +++ b/roles/azure_controllers/tasks/azure_vmanage_vm.yml @@ -21,6 +21,7 @@ VPN: "{{ subnet_item.VPN }}" Subnet: "{{ subnet_item.name }}" type: "{{ subnet_item.type }}" + sku: standard loop: - "{{ mgmt_subnet }}" - "{{ transport_subnet }}" @@ -28,6 +29,27 @@ loop_var: subnet_item register: public_ip_addresses +- name: "Create public IPv6 addresses for machine: {{ hostname }}" + azure.azcollection.azure_rm_publicipaddress: + resource_group: "{{ az_resource_group }}" + allocation_method: static + name: "public-ipv6-{{ hostname }}-vpn-{{ subnet_item.VPN }}" + tags: + Name: "public-ipv6-{{ hostname }}" + Creator: "{{ az_tag_creator }}" + Machine: "{{ hostname }}" + VPN: "{{ subnet_item.VPN }}" + Subnet: "{{ subnet_item.name }}" + type: "{{ subnet_item.type }}" + version: ipv6 + sku: standard + loop: + - "{{ mgmt_subnet }}" + - "{{ transport_subnet }}" + loop_control: + loop_var: subnet_item + register: public_ipv6_addresses + - name: "Get info about NSG: {{ az_network_security_group }}" azure.azcollection.azure_rm_securitygroup_info: resource_group: "{{ az_resource_group }}" @@ -51,7 +73,7 @@ Name: "{{ az_network_security_group }}" Creator: "{{ az_tag_creator }}" Organization: "{{ organization_name }}" - loop: "{{ public_ip_addresses.results }}" + loop: "{{ public_ip_addresses.results + public_ipv6_addresses.results }}" loop_control: loop_var: public_ip_state index_var: my_idx @@ -71,6 +93,10 @@ - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}" public_ip_address_name: "{{ public_ip_state.state.name }}" private_ip_allocation_method: "Dynamic" + - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}-ipv6" + public_ip_address_name: "{{ public_ipv6_addresses.results | json_query(_public_ip_query) | first }}" + private_ip_allocation_method: "Dynamic" + private_ip_address_version: IPv6 tags: Name: "nic-{{ hostname }}-{{ public_ip_state.state.tags.type }}-vpn-{{ public_ip_state.state.tags.VPN }}" Creator: "{{ az_tag_creator }}" @@ -85,6 +111,8 @@ register: vmanage_nics when: - public_ip_state.state is defined + vars: + _public_ip_query: "[?to_number(state.tags.VPN)==`{{ public_ip_state.state.tags.VPN }}`].state.name" - name: "Create virtual network interface card if cluster deployment" azure.azcollection.azure_rm_networkinterface: @@ -140,15 +168,22 @@ - name: Set az_network_interfaces_vmanage fact with a list of interfaces for vmanage ansible.builtin.set_fact: az_network_interfaces_vmanage: "{{ (vmanage_nics.results + [cluster_vmanage_nic]) | selectattr('state', 'defined') | map(attribute='state') | list }}" - az_public_ip_addresses_vmanage: "{{ public_ip_addresses.results | selectattr('state', 'defined') | map(attribute='state') | list }}" + az_public_ip_addresses_vmanage: "{{ _public_ip_addresses | selectattr('state', 'defined') | map(attribute='state') | list }}" + vars: + _public_ip_addresses: "{{ public_ip_addresses.results + public_ipv6_addresses.results }}" - name: Filter az_network_interfaces_vmanage for instance creation. Set az_mgmt_nic and az_transport_nic facts ansible.builtin.set_fact: az_mgmt_nic: "{{ az_network_interfaces_vmanage | selectattr('tags.type', 'equalto', 'mgmt') | list | first }}" az_transport_nic: "{{ az_network_interfaces_vmanage | selectattr('tags.type', 'equalto', 'transport') | list | first }}" az_cluster_nic: "{{ az_network_interfaces_vmanage | selectattr('tags.type', 'equalto', 'cluster') | list | first | default(omit) }}" - az_mgmt_public_ip: "{{ az_public_ip_addresses_vmanage | selectattr('tags.type', 'equalto', 'mgmt') | list | first }}" - az_transport_public_ip: "{{ az_public_ip_addresses_vmanage | selectattr('tags.type', 'equalto', 'transport') | list | first }}" + az_mgmt_public_ip: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_transport_public_ip: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_mgmt_public_ipv6: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + az_transport_public_ipv6: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + vars: + _mgmt_public_ips: "{{ az_public_ip_addresses_vmanage | selectattr('tags.VPN', 'equalto', '512') }}" + _transport_public_ips: "{{ az_public_ip_addresses_vmanage | selectattr('tags.VPN', 'equalto', '0') }}" - name: Prepare nics_ids_list variable for VM creation ansible.builtin.set_fact: @@ -169,11 +204,18 @@ - name: "Set vmanage facts" ansible.builtin.set_fact: - vmanage_mgmt_private_ip: "{{ az_mgmt_nic.ip_configuration.private_ip_address }}" - vmanage_transport_private_ip: "{{ az_transport_nic.ip_configuration.private_ip_address }}" + vmanage_mgmt_private_ip: "{{ (az_mgmt_nic.ip_configurations | json_query(_ipv4_query) | first).private_ip_address }}" + vmanage_mgmt_private_ipv6: "{{ (az_mgmt_nic.ip_configurations | json_query(_ipv6_query) | first).private_ip_address }}" + vmanage_transport_private_ip: "{{ (az_transport_nic.ip_configurations | json_query(_ipv4_query) | first).private_ip_address }}" + vmanage_transport_private_ipv6: "{{ (az_transport_nic.ip_configurations | json_query(_ipv6_query) | first).private_ip_address }}" vmanage_mgmt_public_ip: "{{ az_mgmt_public_ip.ip_address }}" vmanage_transport_public_ip: "{{ az_transport_public_ip.ip_address }}" + vmanage_mgmt_public_ipv6: "{{ az_mgmt_public_ipv6.ip_address }}" + vmanage_transport_public_ipv6: "{{ az_transport_public_ipv6.ip_address }}" vmanage_persona: "{{ persona | default(vmanage_default_persona) }}" + vars: + _ipv4_query: "[?private_ip_address_version==`IPv4`]" + _ipv6_query: "[?private_ip_address_version==`IPv6`]" - name: "Set vmanage cluster related facts" ansible.builtin.set_fact: @@ -185,7 +227,7 @@ - name: "Set vpn0_default_gateway fact from VPN 0 subnet value" ansible.builtin.set_fact: - vpn0_default_gateway: "{{ subnet.cidr | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" + vpn0_default_gateway: "{{ subnet.cidr[0] | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" loop: "{{ az_subnets }}" loop_control: loop_var: subnet @@ -254,6 +296,8 @@ admin_password: "{{ admin_password }}" mgmt_public_ip: "{{ vmanage_mgmt_public_ip }}" transport_public_ip: "{{ vmanage_transport_public_ip }}" + mgmt_public_ipv6: "{{ vmanage_mgmt_public_ipv6 }}" + transport_public_ipv6: "{{ vmanage_transport_public_ipv6 }}" cluster_private_ip: "{{ vmanage_cluster_private_ip | default(omit) }}" persona: "{{ vmanage_persona }}" changed_when: true diff --git a/roles/azure_controllers/tasks/azure_vsmart_vm.yml b/roles/azure_controllers/tasks/azure_vsmart_vm.yml index ba7d587..ff6312f 100644 --- a/roles/azure_controllers/tasks/azure_vsmart_vm.yml +++ b/roles/azure_controllers/tasks/azure_vsmart_vm.yml @@ -19,6 +19,7 @@ Machine: "{{ hostname }}" VPN: "{{ subnet_item.VPN }}" Subnet: "{{ subnet_item.name }}" + sku: standard loop: - "{{ mgmt_subnet }}" - "{{ transport_subnet }}" @@ -26,6 +27,26 @@ loop_var: subnet_item register: public_ip_addresses +- name: "Create public IPv6 addresses for machine: {{ hostname }}" + azure.azcollection.azure_rm_publicipaddress: + resource_group: "{{ az_resource_group }}" + allocation_method: static + name: "public-ipv6-{{ hostname }}-vpn-{{ subnet_item.VPN }}" + tags: + Name: "public-ipv6-{{ hostname }}" + Creator: "{{ az_tag_creator }}" + Machine: "{{ hostname }}" + VPN: "{{ subnet_item.VPN }}" + Subnet: "{{ subnet_item.name }}" + version: ipv6 + sku: standard + loop: + - "{{ mgmt_subnet }}" + - "{{ transport_subnet }}" + loop_control: + loop_var: subnet_item + register: public_ipv6_addresses + - name: "Get info about NSG: {{ az_network_security_group }}" azure.azcollection.azure_rm_securitygroup_info: resource_group: "{{ az_resource_group }}" @@ -49,7 +70,7 @@ Name: "{{ az_network_security_group }}" Creator: "{{ az_tag_creator }}" Organization: "{{ organization_name }}" - loop: "{{ public_ip_addresses.results }}" + loop: "{{ public_ip_addresses.results + public_ipv6_addresses.results }}" loop_control: loop_var: public_ip_state index_var: my_idx @@ -67,6 +88,10 @@ - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}" public_ip_address_name: "{{ public_ip_state.state.name }}" private_ip_allocation_method: "Dynamic" + - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}-ipv6" + public_ip_address_name: "{{ public_ipv6_addresses.results | json_query(_public_ip_query) | first }}" + private_ip_allocation_method: "Dynamic" + private_ip_address_version: IPv6 tags: Name: "nic-{{ hostname }}-vpn-{{ public_ip_state.state.tags.VPN }}" Creator: "{{ az_tag_creator }}" @@ -78,29 +103,40 @@ index_var: my_idx label: public_ip_state.state.name register: vsmart_nics + vars: + _public_ip_query: "[?to_number(state.tags.VPN)==`{{ public_ip_state.state.tags.VPN }}`].state.name" - name: "Set az_network_interfaces_vsmart fact with a list of interfaces for vSmart" ansible.builtin.set_fact: az_network_interfaces_vsmart: "{{ vsmart_nics.results | map(attribute='state') | list }}" - az_public_ip_addresses_vsmart: "{{ public_ip_addresses.results | map(attribute='state') | list }}" + az_public_ip_addresses_vsmart: "{{ (public_ip_addresses.results + public_ipv6_addresses.results) | map(attribute='state') | list }}" - name: "Filter az_network_interfaces_vsmart for instance creation. Set az_mgmt_nic and az_transport_nic facts" ansible.builtin.set_fact: az_mgmt_nic: "{{ az_network_interfaces_vsmart | selectattr('tags.VPN', 'equalto', '512') | list | first }}" az_transport_nic: "{{ az_network_interfaces_vsmart | selectattr('tags.VPN', 'equalto', '0') | list | first }}" - az_mgmt_public_ip: "{{ az_public_ip_addresses_vsmart | selectattr('tags.VPN', 'equalto', '512') | list | first }}" - az_transport_public_ip: "{{ az_public_ip_addresses_vsmart | selectattr('tags.VPN', 'equalto', '0') | list | first }}" + az_mgmt_public_ip: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_transport_public_ip: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_mgmt_public_ipv6: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + az_transport_public_ipv6: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + vars: + _mgmt_public_ips: "{{ az_public_ip_addresses_vsmart | selectattr('tags.VPN', 'equalto', '512') }}" + _transport_public_ips: "{{ az_public_ip_addresses_vsmart | selectattr('tags.VPN', 'equalto', '0') }}" - name: "Set vsmart facts" ansible.builtin.set_fact: - vsmart_mgmt_private_ip: "{{ az_mgmt_nic.ip_configuration.private_ip_address }}" - vsmart_transport_private_ip: "{{ az_transport_nic.ip_configuration.private_ip_address }}" + vsmart_mgmt_private_ip: "{{ (az_mgmt_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv4`]') | first).private_ip_address }}" + vsmart_mgmt_private_ipv6: "{{ (az_mgmt_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv6`]') | first).private_ip_address }}" + vsmart_transport_private_ip: "{{ (az_transport_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv4`]') | first).private_ip_address }}" + vsmart_transport_private_ipv6: "{{ (az_transport_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv6`]') | first).private_ip_address }}" vsmart_mgmt_public_ip: "{{ az_mgmt_public_ip.ip_address }}" vsmart_transport_public_ip: "{{ az_transport_public_ip.ip_address }}" + vsmart_mgmt_public_ipv6: "{{ az_mgmt_public_ipv6.ip_address }}" + vsmart_transport_public_ipv6: "{{ az_transport_public_ipv6.ip_address }}" - name: "Set vpn0_default_gateway fact from VPN 0 subnet value" ansible.builtin.set_fact: - vpn0_default_gateway: "{{ subnet_item.cidr | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" + vpn0_default_gateway: "{{ subnet_item.cidr[0] | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" loop: - "{{ mgmt_subnet }}" - "{{ transport_subnet }}" @@ -165,6 +201,8 @@ admin_password: "{{ admin_password }}" mgmt_public_ip: "{{ vsmart_mgmt_public_ip }}" transport_public_ip: "{{ vsmart_transport_public_ip }}" + mgmt_public_ipv6: "{{ vsmart_mgmt_public_ipv6 }}" + transport_public_ipv6: "{{ vsmart_transport_public_ipv6 }}" changed_when: true notify: Show deployment_facts diff --git a/roles/azure_controllers/templates/userdata_vbond.j2 b/roles/azure_controllers/templates/userdata_vbond.j2 index c75e9ba..7c18a74 100644 --- a/roles/azure_controllers/templates/userdata_vbond.j2 +++ b/roles/azure_controllers/templates/userdata_vbond.j2 @@ -31,6 +31,7 @@ write_files: + true {{ admin_username }} @@ -46,6 +47,9 @@ write_files: true + + true + ipsec @@ -76,6 +80,9 @@ write_files: true + + true + false diff --git a/roles/azure_controllers/templates/userdata_vmanage.j2 b/roles/azure_controllers/templates/userdata_vmanage.j2 index 523b8d4..dafc755 100644 --- a/roles/azure_controllers/templates/userdata_vmanage.j2 +++ b/roles/azure_controllers/templates/userdata_vmanage.j2 @@ -45,7 +45,7 @@ write_files: {{ organization_name }} {{ site_id }} - {{ vbond_transport_public_ip | default(default_vbond_ip) }} + {{ az_vbond_address }} local @@ -57,6 +57,8 @@ write_files: netadmin + {{ ipv6_strict_control | lower }} + true @@ -66,6 +68,9 @@ write_files: true + + true + true @@ -95,6 +100,9 @@ write_files: true + + true + false diff --git a/roles/azure_controllers/templates/userdata_vsmart.j2 b/roles/azure_controllers/templates/userdata_vsmart.j2 index 7c198f8..8356173 100644 --- a/roles/azure_controllers/templates/userdata_vsmart.j2 +++ b/roles/azure_controllers/templates/userdata_vsmart.j2 @@ -27,7 +27,7 @@ write_files: {{ organization_name }} {{ site_id }} - {{ vbond_transport_public_ip | default(default_vbond_ip) }} + {{ az_vbond_address }} @@ -35,6 +35,8 @@ write_files: {{ admin_password }} + {{ ipv6_strict_control | lower }} + true @@ -44,6 +46,9 @@ write_files: true + + true + ipsec @@ -74,6 +79,9 @@ write_files: true + + true + false diff --git a/roles/azure_edges/README.md b/roles/azure_edges/README.md index 718fc2d..4229103 100644 --- a/roles/azure_edges/README.md +++ b/roles/azure_edges/README.md @@ -46,6 +46,7 @@ Variables with default values that can be overridden by the user: - `vbond_port`, `default_vbond_ip`: Default configurations for vBond. - `az_cedge_vm_size`: Default Azure VM size for cEdge instances. - `edge_instances`: List of cEdge instance configurations. If not provided, instances will be created based on PnP Portal information. +- `ipv6_strict_control`: Control if ipv6-strict-control is enabled. ### Vars (`vars/main.yml`) diff --git a/roles/azure_edges/defaults/main.yml b/roles/azure_edges/defaults/main.yml index 7224173..61265dd 100644 --- a/roles/azure_edges/defaults/main.yml +++ b/roles/azure_edges/defaults/main.yml @@ -63,6 +63,7 @@ admin_password: example_password # pragma: allowlist secret admin_ssh_keys: [] vbond_port: 12346 default_vbond_ip: 192.168.1.199 +ipv6_strict_control: true # vpn0_interface_color: default ################################ diff --git a/roles/azure_edges/tasks/azure_cedge_vm.yml b/roles/azure_edges/tasks/azure_cedge_vm.yml index ed24b9c..f7f4ebe 100644 --- a/roles/azure_edges/tasks/azure_cedge_vm.yml +++ b/roles/azure_edges/tasks/azure_cedge_vm.yml @@ -20,6 +20,7 @@ VPN: "{{ subnet_item.VPN }}" Subnet: "{{ subnet_item.name }}" type: "{{ subnet_item.type }}" + sku: standard loop: - "{{ mgmt_subnet }}" - "{{ transport_subnet }}" @@ -27,6 +28,27 @@ loop_var: subnet_item register: public_ip_addresses +- name: "Create public IPv6 addresses for machine: {{ hostname }}" + azure.azcollection.azure_rm_publicipaddress: + resource_group: "{{ az_resource_group }}" + allocation_method: static + name: "public-ipv6-{{ hostname }}-vpn-{{ subnet_item.VPN }}" + tags: + Name: "public-ipv6-{{ hostname }}" + Creator: "{{ az_tag_creator }}" + Machine: "{{ hostname }}" + VPN: "{{ subnet_item.VPN }}" + Subnet: "{{ subnet_item.name }}" + type: "{{ subnet_item.type }}" + version: ipv6 + sku: standard + loop: + - "{{ mgmt_subnet }}" + - "{{ transport_subnet }}" + loop_control: + loop_var: subnet_item + register: public_ipv6_addresses + - name: "Get info about NSG: {{ az_network_security_group }}" azure.azcollection.azure_rm_securitygroup_info: resource_group: "{{ az_default_resource_group }}" @@ -50,7 +72,7 @@ Name: "{{ az_network_security_group }}" Creator: "{{ az_tag_creator }}" Organization: "{{ organization_name }}" - loop: "{{ public_ip_addresses.results }}" + loop: "{{ public_ip_addresses.results + public_ipv6_addresses.results }}" loop_control: loop_var: public_ip_state index_var: my_idx @@ -68,6 +90,10 @@ - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}" public_ip_address_name: "{{ public_ip_state.state.name }}" private_ip_allocation_method: "Dynamic" + - name: "ipconfig-vpn-{{ public_ip_state.state.tags.VPN }}-ipv6" + public_ip_address_name: "{{ public_ipv6_addresses.results | json_query(_public_ip_query) | first }}" + private_ip_allocation_method: "Dynamic" + private_ip_address_version: IPv6 tags: Name: "nic-{{ hostname }}-vpn-{{ public_ip_state.state.tags.VPN }}" Creator: "{{ az_tag_creator }}" @@ -80,6 +106,8 @@ index_var: my_idx label: public_ip_state.state.name register: cedge_nics + vars: + _public_ip_query: "[?to_number(state.tags.VPN)==`{{ public_ip_state.state.tags.VPN }}`].state.name" - name: "Create private virtual network interface cards" azure.azcollection.azure_rm_networkinterface: @@ -109,7 +137,7 @@ ansible.builtin.set_fact: az_network_interfaces_cedge: "{{ cedge_nics.results | map(attribute='state') | list }}" az_private_network_interfaces_cedge: "{{ cedge_private_nics.results | selectattr('state', 'defined') | map(attribute='state') | list | default([]) }}" - az_public_ip_addresses_cedge: "{{ public_ip_addresses.results | map(attribute='state') | list }}" + az_public_ip_addresses_cedge: "{{ (public_ip_addresses.results + public_ipv6_addresses.results) | map(attribute='state') | list }}" - name: Append to az_network_interfaces_cedge ansible.builtin.set_fact: @@ -120,16 +148,25 @@ az_mgmt_nic: "{{ az_network_interfaces_cedge | selectattr('tags.type', 'equalto', 'mgmt') | list | first }}" az_transport_nic: "{{ az_network_interfaces_cedge | selectattr('tags.type', 'equalto', 'transport') | list | first }}" az_service_nics: "{{ az_network_interfaces_cedge | selectattr('tags.type', 'equalto', 'service') | list | default(omit) }}" - az_mgmt_public_ip: "{{ az_public_ip_addresses_cedge | selectattr('tags.type', 'equalto', 'mgmt') | list | first }}" - az_transport_public_ip: "{{ az_public_ip_addresses_cedge | selectattr('tags.type', 'equalto', 'transport') | list | first }}" + az_mgmt_public_ip: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_transport_public_ip: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv4') | list | first }}" + az_mgmt_public_ipv6: "{{ _mgmt_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + az_transport_public_ipv6: "{{ _transport_public_ips | selectattr('public_ip_address_version', 'equalto', 'ipv6') | list | first }}" + vars: + _mgmt_public_ips: "{{ az_public_ip_addresses_cedge | selectattr('tags.VPN', 'equalto', '512') }}" + _transport_public_ips: "{{ az_public_ip_addresses_cedge | selectattr('tags.VPN', 'equalto', '0') }}" # cedge_mgmt_private_ip - name: "Set ip addresses cedge facts" ansible.builtin.set_fact: - cedge_mgmt_private_ip: "{{ az_mgmt_nic.ip_configuration.private_ip_address }}" - cedge_transport_private_ip: "{{ az_transport_nic.ip_configuration.private_ip_address }}" + cedge_mgmt_private_ip: "{{ (az_mgmt_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv4`]') | first).private_ip_address }}" + cedge_mgmt_private_ipv6: "{{ (az_mgmt_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv6`]') | first).private_ip_address }}" + cedge_transport_private_ip: "{{ (az_transport_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv4`]') | first).private_ip_address }}" + cedge_transport_private_ipv6: "{{ (az_transport_nic.ip_configurations | json_query('[?private_ip_address_version==`IPv6`]') | first).private_ip_address }}" cedge_mgmt_public_ip: "{{ az_mgmt_public_ip.ip_address }}" cedge_transport_public_ip: "{{ az_transport_public_ip.ip_address }}" + cedge_mgmt_public_ipv6: "{{ az_mgmt_public_ipv6.ip_address }}" + cedge_transport_public_ipv6: "{{ az_transport_public_ipv6.ip_address }}" - name: "Set vpn0_default_gateway fact from VPN 0 subnet value" ansible.builtin.set_fact: @@ -219,6 +256,8 @@ admin_password: "{{ admin_password }}" mgmt_public_ip: "{{ cedge_mgmt_public_ip }}" transport_public_ip: "{{ cedge_transport_public_ip }}" + mgmt_public_ipv6: "{{ cedge_mgmt_public_ipv6 }}" + transport_public_ipv6: "{{ cedge_transport_public_ipv6 }}" service_interfaces: "{{ service_interfaces | default(omit) }}" uuid: "{{ uuid }}" site_id: "{{ site_id }}" diff --git a/roles/azure_edges/templates/userdata_cedge.j2 b/roles/azure_edges/templates/userdata_cedge.j2 index bfaf4df..76928f4 100644 --- a/roles/azure_edges/templates/userdata_cedge.j2 +++ b/roles/azure_edges/templates/userdata_cedge.j2 @@ -52,7 +52,8 @@ Content-Disposition: attachment; filename="config-{{ uuid }}.txt" config-template-name Default_Azure_vWAN_C8000V_Template_V01 no on-demand enable on-demand idle-timeout 10 - vbond {{ vbond }} port {{ vbond_port }} + vbond {{ vbond_transport_hostname }} port {{ vbond_port }} + ipv6-strict-control {{ ipv6_strict_control | lower }} ! bfd color lte hello-interval 1000 @@ -186,6 +187,10 @@ Content-Disposition: attachment; filename="config-{{ uuid }}.txt" no shutdown arp timeout 1200 ip address dhcp client-id GigabitEthernet1 + ipv6 address dhcp + ipv6 enable + ipv6 nd autoconfig prefix + ipv6 nd autoconfig default-route no ip redirects ip dhcp client default-router distance 1 ip mtu 1500 @@ -197,6 +202,10 @@ Content-Disposition: attachment; filename="config-{{ uuid }}.txt" no shutdown arp timeout 1200 ip address dhcp client-id GigabitEthernet2 + ipv6 address dhcp + ipv6 enable + ipv6 nd autoconfig prefix + ipv6 nd autoconfig default-route no ip redirects ip dhcp client default-router distance 1 ip mtu 1500 @@ -210,6 +219,7 @@ Content-Disposition: attachment; filename="config-{{ uuid }}.txt" no shutdown ip unnumbered GigabitEthernet1 no ip redirects + ipv6 enable ipv6 unnumbered GigabitEthernet1 no ipv6 redirects tunnel source GigabitEthernet1 diff --git a/roles/azure_network_infrastructure/defaults/main.yml b/roles/azure_network_infrastructure/defaults/main.yml index 2fb157e..30d5016 100644 --- a/roles/azure_network_infrastructure/defaults/main.yml +++ b/roles/azure_network_infrastructure/defaults/main.yml @@ -19,28 +19,38 @@ az_resource_group: "{{ az_resources_prefix }}-rg" # Virtual Network az_virtual_network: "{{ az_resources_prefix }}-vn" -az_vn_address_prefixes_cidr: 10.0.0.0/16 +az_vn_address_prefixes_cidr: + - 10.0.0.0/16 + - "fd00::/48" # Subnets az_subnets: | {% filter from_yaml %} - name: "{{ az_resources_prefix }}-mgmt-subnet-512" - cidr: "10.0.1.0/24" + cidr: + - "10.0.1.0/24" + - "fd00:0:0:1::/64" VPN: 512 type: mgmt - name: "{{ az_resources_prefix }}-transport-subnet-0" - cidr: "10.0.2.0/24" + cidr: + - "10.0.2.0/24" + - "fd00:0:0:2::/64" VPN: 0 type: transport {% if vmanage_instances is defined and vmanage_instances | length > 2 %} - name: "{{ az_resources_prefix }}-cluster-subnet-0" - cidr: "10.0.3.0/24" + cidr: + - "10.0.3.0/24" + - "fd00:0:0:3::/64" VPN: 0 type: cluster {% endif %} {% if ux20_deployment is defined and ux20_deployment == true %} - name: "{{ az_resources_prefix }}-service-subnet-10" - cidr: "10.0.4.0/24" # default ips from official Cisco guides + cidr: + - "10.0.4.0/24" # default ips from official Cisco guides + - "fd00:0:0:4::/64" VPN: 10 type: service {% endif %} @@ -50,5 +60,10 @@ az_subnets: | az_network_security_group: "{{ az_resources_prefix }}-nsg" +# Private DNS zone +az_private_dns_zone: "{{ az_resources_prefix }}.internal" +az_private_network_link: "{{ az_resources_prefix }}-pnl" + + # VPN subnets from which we can connect to Azure EIPs (Network Security Group config) az_allowed_subnets: null diff --git a/roles/azure_network_infrastructure/tasks/azure_network_infrastructure.yml b/roles/azure_network_infrastructure/tasks/azure_network_infrastructure.yml index 768868f..b704fdc 100644 --- a/roles/azure_network_infrastructure/tasks/azure_network_infrastructure.yml +++ b/roles/azure_network_infrastructure/tasks/azure_network_infrastructure.yml @@ -79,3 +79,20 @@ Name: "{{ az_network_security_group }}" Creator: "{{ az_tag_creator }}" Organization: "{{ organization_name }}" + +- name: Create a private DNS zone + azure.azcollection.azure_rm_privatednszone: + resource_group: "{{ az_resource_group }}" + name: "{{ az_private_dns_zone }}" + tags: + Name: "{{ az_virtual_network }}" + Creator: "{{ az_tag_creator }}" + Organization: "{{ organization_name }}" + +- name: Create a virtual network link + azure.azcollection.azure_rm_privatednszonelink: + resource_group: "{{ az_resource_group }}" + name: "{{ az_private_network_link }}" + zone_name: "{{ az_private_dns_zone }}" + virtual_network: "{{ az_virtual_network }}" + state: present