Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/azure-cli/azure/cli/command_modules/network/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -5576,6 +5576,11 @@
text: |
az network vpn-connection create --local-gateway2 MyLocalGateway --location westus2 --name MyConnection --resource-group MyResourceGroup --shared-key Abc123 --vnet-gateway1 MyVnetGateway
crafted: true
- name: Create a VPN connection with Certificate authentication using inline JSON.
text: |
az network vpn-connection create -g MyResourceGroup -n MyConnection \
--vnet-gateway1 MyVnetGateway --local-gateway2 MyLocalGateway \
--auth-type Certificate --cert-auth '{"outboundAuthCertificate":"https://customerKv.vault/Certificates/outBoundcert/Version","inboundAuthCertificateChain":["MIIC+TCCAeGgAwIBAgIQFOJUqDaxV5xJcKpTKO..","MIIC+TCCAeGgAwIBAgIQPJerInitNblK7yBgkqh.."],"inboundAuthCertificateSubjectName":"CN=rootCert.com"}'
"""

helps['network vpn-connection delete'] = """
Expand Down Expand Up @@ -5696,6 +5701,9 @@
text: |
az network vpn-connection update --name MyConnection --resource-group MyResourceGroup --use-policy-based-traffic-selectors true
crafted: true
- name: Update certificate authentication using JSON string
text: |
az network vpn-connection update -g MyResourceGroup -n MyConnection --certificate-authentication '{"outboundAuthCertificate":"https://{kv-name}.vault.azure.net/secrets/{secret-name}/{version}","inboundAuthCertificateChain":["MIIC+TCCAeG..."],"inboundAuthCertificateSubjectName":"CN=rootCert.com"}'
"""

helps['network vpn-connection show-device-config-script'] = """
Expand Down
6 changes: 6 additions & 0 deletions src/azure-cli/azure/cli/command_modules/network/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from azure.cli.command_modules.network._actions import (
TrustedClientCertificateCreate,
SslProfilesCreate, AddMappingRequest, WAFRulesCreate)
from azure.cli.core.util import shell_safe_json_parse


# pylint: disable=too-many-locals, too-many-branches, too-many-statements
Expand Down Expand Up @@ -781,6 +782,11 @@ def load_arguments(self, _):
for item in ['vnet_gateway2', 'local_gateway2', 'express_route_circuit2']:
c.argument(item, arg_group='Destination')

c.argument('auth_type', options_list=['--authentication-type', '--auth-type'], help='Authentication type for the VPN connection.', arg_type=get_enum_type(['Certificate', 'PSK']))
c.argument('cert_auth', options_list=['--certificate-authentication', '--cert-auth'],
help='Certificate-based authentication configuration. Provide as JSON string or file path with @ prefix, Expected keys (outboundAuthCertificate, inboundAuthCertificateChain, inboundAuthCertificateSubjectName).',
type=shell_safe_json_parse)

with self.argument_context('network routeserver') as c:
c.argument('virtual_hub_name', options_list=['--name', '-n'], id_part='name',
help='Name of the route server.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ def build_vnet_resource(_, name, location, tags, vnet_prefix=None, subnet=None,

def build_vpn_connection_resource(cmd, name, location, tags, gateway1, gateway2, vpn_type, authorization_key,
enable_bgp, routing_weight, shared_key, use_policy_based_traffic_selectors,
express_route_gateway_bypass, ingress_nat_rule, egress_nat_rule):
express_route_gateway_bypass, ingress_nat_rule, egress_nat_rule,
auth_type, cert_auth):
vpn_properties = {
'virtualNetworkGateway1': {'id': gateway1},
'enableBgp': enable_bgp,
Expand Down Expand Up @@ -500,12 +501,18 @@ def build_vpn_connection_resource(cmd, name, location, tags, gateway1, gateway2,
if egress_nat_rule:
vpn_properties['egressNatRules'] = [{'id': rule} for rule in egress_nat_rule]

if auth_type:
vpn_properties['authenticationType'] = auth_type

if cert_auth:
vpn_properties['certificateAuthentication'] = cert_auth

vpn_connection = {
'type': 'Microsoft.Network/connections',
'name': name,
'location': location,
'tags': tags,
'apiVersion': '2015-06-15',
'apiVersion': '2025-01-01',
'dependsOn': [],
'properties': vpn_properties if vpn_type != 'VpnClient' else {}
}
Expand Down
19 changes: 19 additions & 0 deletions src/azure-cli/azure/cli/command_modules/network/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,13 @@ def process_vpn_connection_create_namespace(cmd, namespace):
raise ValueError('usage error: --vnet-gateway2 NAME_OR_ID | --local-gateway2 NAME_OR_ID '
'| --express-route-circuit2 NAME_OR_ID')

def _normalize_shared_key_fields(n):
# Turn "" into None so the sdk layer won’t serialize them
if getattr(n, 'shared_key', None) == '':
n.shared_key = None
if getattr(n, 'shared_key_keyvault_id', None) == '':
n.shared_key_keyvault_id = None

def _validate_name_or_id(value, resource_type):
if not is_valid_resource_id(value):
subscription = getattr(namespace, 'subscription', get_subscription_id(cmd.cli_ctx))
Expand All @@ -657,6 +664,10 @@ def _validate_name_or_id(value, resource_type):
name=value)
return value

auth = (getattr(namespace, 'auth_type', '') or '').strip().lower()

_normalize_shared_key_fields(namespace)

if (namespace.local_gateway2 or namespace.vnet_gateway2) and not namespace.shared_key:
raise CLIError('--shared-key is required for VNET-to-VNET or Site-to-Site connections.')

Expand All @@ -680,6 +691,14 @@ def _validate_name_or_id(value, resource_type):
_validate_name_or_id(namespace.vnet_gateway2, 'virtualNetworkGateways')
namespace.connection_type = 'Vnet2Vnet'

if auth == 'certificate':
# SharedKey/SharedKeyKeyvaultId should be empty when AuthenticationType is Certificate.
# Follow the link for more details : https://go.microsoft.com/fwlink/?linkid=2208263
if getattr(namespace, 'shared_key', None):
namespace.shared_key = None
if getattr(namespace, 'shared_key_keyvault_id', None):
namespace.shared_key_keyvault_id = None


def load_cert_file(param_name):
def load_cert_validator(namespace):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ class Create(AAZCommand):
"""

_aaz_info = {
"version": "2024-07-01",
"version": "2025-01-01",
"resources": [
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/virtualnetworkgateways/{}", "2024-07-01"],
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/virtualnetworkgateways/{}", "2025-01-01"],
]
}

Expand Down Expand Up @@ -228,6 +228,8 @@ def _build_arguments_schema(cls, *args, **kwargs):

# define Arg Group "BgpSettings"

# define Arg Group "CustomRoutes"

# define Arg Group "Identity"

_args_schema = cls._args_schema
Expand Down Expand Up @@ -423,6 +425,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
def _build_args_address_space_create(cls, _schema):
if cls._args_address_space_create is not None:
_schema.address_prefixes = cls._args_address_space_create.address_prefixes
_schema.ipam_pool_prefix_allocations = cls._args_address_space_create.ipam_pool_prefix_allocations
return

cls._args_address_space_create = AAZObjectArg()
Expand All @@ -432,11 +435,29 @@ def _build_args_address_space_create(cls, _schema):
options=["address-prefixes"],
help="A list of address blocks reserved for this virtual network in CIDR notation.",
)
address_space_create.ipam_pool_prefix_allocations = AAZListArg(
options=["ipam-pool-prefix-allocations"],
help="A list of IPAM Pools allocating IP address prefixes.",
)

address_prefixes = cls._args_address_space_create.address_prefixes
address_prefixes.Element = AAZStrArg()

ipam_pool_prefix_allocations = cls._args_address_space_create.ipam_pool_prefix_allocations
ipam_pool_prefix_allocations.Element = AAZObjectArg()

_element = cls._args_address_space_create.ipam_pool_prefix_allocations.Element
_element.number_of_ip_addresses = AAZStrArg(
options=["number-of-ip-addresses"],
help="Number of IP addresses to allocate.",
)
_element.id = AAZResourceIdArg(
options=["id"],
help="Resource id of the associated Azure IpamPool resource.",
)

_schema.address_prefixes = cls._args_address_space_create.address_prefixes
_schema.ipam_pool_prefix_allocations = cls._args_address_space_create.ipam_pool_prefix_allocations

_args_sub_resource_create = None

Expand Down Expand Up @@ -537,7 +558,7 @@ def url_parameters(self):
def query_parameters(self):
parameters = {
**self.serialize_query_param(
"api-version", "2024-07-01",
"api-version", "2025-01-01",
required=True,
),
}
Expand Down Expand Up @@ -706,7 +727,7 @@ def content(self):
vpn_client_configuration.set_prop("aadIssuer", AAZStrType, ".aad_issuer")
vpn_client_configuration.set_prop("aadTenant", AAZStrType, ".aad_tenant")
vpn_client_configuration.set_prop("radiusServerAddress", AAZStrType, ".radius_server")
vpn_client_configuration.set_prop("radiusServerSecret", AAZStrType, ".radius_secret")
vpn_client_configuration.set_prop("radiusServerSecret", AAZStrType, ".radius_secret", typ_kwargs={"flags": {"secret": True}})
vpn_client_configuration.set_prop("vpnAuthenticationTypes", AAZListType, ".vpn_auth_type")
vpn_client_configuration.set_prop("vpnClientAddressPool", AAZObjectType)
vpn_client_configuration.set_prop("vpnClientProtocols", AAZListType, ".client_protocol")
Expand Down Expand Up @@ -1104,6 +1125,7 @@ def _build_schema_on_200_201(cls):
)
vpn_client_configuration.radius_server_secret = AAZStrType(
serialized_name="radiusServerSecret",
flags={"secret": True},
)
vpn_client_configuration.radius_servers = AAZListType(
serialized_name="radiusServers",
Expand Down Expand Up @@ -1144,6 +1166,7 @@ def _build_schema_on_200_201(cls):
)
_element.radius_server_secret = AAZStrType(
serialized_name="radiusServerSecret",
flags={"secret": True},
)

vng_client_connection_configurations = cls._schema_on_200_201.properties.vpn_client_configuration.vng_client_connection_configurations
Expand Down Expand Up @@ -1278,11 +1301,25 @@ def _build_schema_address_space_create(cls, _builder):
if _builder is None:
return
_builder.set_prop("addressPrefixes", AAZListType, ".address_prefixes")
_builder.set_prop("ipamPoolPrefixAllocations", AAZListType, ".ipam_pool_prefix_allocations")

address_prefixes = _builder.get(".addressPrefixes")
if address_prefixes is not None:
address_prefixes.set_elements(AAZStrType, ".")

ipam_pool_prefix_allocations = _builder.get(".ipamPoolPrefixAllocations")
if ipam_pool_prefix_allocations is not None:
ipam_pool_prefix_allocations.set_elements(AAZObjectType, ".")

_elements = _builder.get(".ipamPoolPrefixAllocations[]")
if _elements is not None:
_elements.set_prop("numberOfIpAddresses", AAZStrType, ".number_of_ip_addresses")
_elements.set_prop("pool", AAZObjectType, typ_kwargs={"flags": {"client_flatten": True}})

pool = _builder.get(".ipamPoolPrefixAllocations[].pool")
if pool is not None:
pool.set_prop("id", AAZStrType, ".id")

@classmethod
def _build_schema_sub_resource_create(cls, _builder):
if _builder is None:
Expand All @@ -1295,6 +1332,7 @@ def _build_schema_sub_resource_create(cls, _builder):
def _build_schema_address_space_read(cls, _schema):
if cls._schema_address_space_read is not None:
_schema.address_prefixes = cls._schema_address_space_read.address_prefixes
_schema.ipam_pool_prefix_allocations = cls._schema_address_space_read.ipam_pool_prefix_allocations
return

cls._schema_address_space_read = _schema_address_space_read = AAZObjectType()
Expand All @@ -1303,11 +1341,36 @@ def _build_schema_address_space_read(cls, _schema):
address_space_read.address_prefixes = AAZListType(
serialized_name="addressPrefixes",
)
address_space_read.ipam_pool_prefix_allocations = AAZListType(
serialized_name="ipamPoolPrefixAllocations",
)

address_prefixes = _schema_address_space_read.address_prefixes
address_prefixes.Element = AAZStrType()

ipam_pool_prefix_allocations = _schema_address_space_read.ipam_pool_prefix_allocations
ipam_pool_prefix_allocations.Element = AAZObjectType()

_element = _schema_address_space_read.ipam_pool_prefix_allocations.Element
_element.allocated_address_prefixes = AAZListType(
serialized_name="allocatedAddressPrefixes",
flags={"read_only": True},
)
_element.number_of_ip_addresses = AAZStrType(
serialized_name="numberOfIpAddresses",
)
_element.pool = AAZObjectType(
flags={"client_flatten": True},
)

allocated_address_prefixes = _schema_address_space_read.ipam_pool_prefix_allocations.Element.allocated_address_prefixes
allocated_address_prefixes.Element = AAZStrType()

pool = _schema_address_space_read.ipam_pool_prefix_allocations.Element.pool
pool.id = AAZStrType()

_schema.address_prefixes = cls._schema_address_space_read.address_prefixes
_schema.ipam_pool_prefix_allocations = cls._schema_address_space_read.ipam_pool_prefix_allocations

_schema_sub_resource_read = None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class Delete(AAZCommand):
"""

_aaz_info = {
"version": "2024-07-01",
"version": "2025-01-01",
"resources": [
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/virtualnetworkgateways/{}", "2024-07-01"],
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/virtualnetworkgateways/{}", "2025-01-01"],
]
}

Expand Down Expand Up @@ -144,7 +144,7 @@ def url_parameters(self):
def query_parameters(self):
parameters = {
**self.serialize_query_param(
"api-version", "2024-07-01",
"api-version", "2025-01-01",
required=True,
),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ class List(AAZCommand):
"""

_aaz_info = {
"version": "2024-07-01",
"version": "2025-01-01",
"resources": [
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/virtualnetworkgateways", "2024-07-01"],
["mgmt-plane", "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/virtualnetworkgateways", "2025-01-01"],
]
}

Expand Down Expand Up @@ -112,7 +112,7 @@ def url_parameters(self):
def query_parameters(self):
parameters = {
**self.serialize_query_param(
"api-version", "2024-07-01",
"api-version", "2025-01-01",
required=True,
),
}
Expand Down Expand Up @@ -494,6 +494,7 @@ def _build_schema_on_200(cls):
)
vpn_client_configuration.radius_server_secret = AAZStrType(
serialized_name="radiusServerSecret",
flags={"secret": True},
)
vpn_client_configuration.radius_servers = AAZListType(
serialized_name="radiusServers",
Expand Down Expand Up @@ -534,6 +535,7 @@ def _build_schema_on_200(cls):
)
_element.radius_server_secret = AAZStrType(
serialized_name="radiusServerSecret",
flags={"secret": True},
)

vng_client_connection_configurations = cls._schema_on_200.value.Element.properties.vpn_client_configuration.vng_client_connection_configurations
Expand Down Expand Up @@ -669,6 +671,7 @@ class _ListHelper:
def _build_schema_address_space_read(cls, _schema):
if cls._schema_address_space_read is not None:
_schema.address_prefixes = cls._schema_address_space_read.address_prefixes
_schema.ipam_pool_prefix_allocations = cls._schema_address_space_read.ipam_pool_prefix_allocations
return

cls._schema_address_space_read = _schema_address_space_read = AAZObjectType()
Expand All @@ -677,11 +680,36 @@ def _build_schema_address_space_read(cls, _schema):
address_space_read.address_prefixes = AAZListType(
serialized_name="addressPrefixes",
)
address_space_read.ipam_pool_prefix_allocations = AAZListType(
serialized_name="ipamPoolPrefixAllocations",
)

address_prefixes = _schema_address_space_read.address_prefixes
address_prefixes.Element = AAZStrType()

ipam_pool_prefix_allocations = _schema_address_space_read.ipam_pool_prefix_allocations
ipam_pool_prefix_allocations.Element = AAZObjectType()

_element = _schema_address_space_read.ipam_pool_prefix_allocations.Element
_element.allocated_address_prefixes = AAZListType(
serialized_name="allocatedAddressPrefixes",
flags={"read_only": True},
)
_element.number_of_ip_addresses = AAZStrType(
serialized_name="numberOfIpAddresses",
)
_element.pool = AAZObjectType(
flags={"client_flatten": True},
)

allocated_address_prefixes = _schema_address_space_read.ipam_pool_prefix_allocations.Element.allocated_address_prefixes
allocated_address_prefixes.Element = AAZStrType()

pool = _schema_address_space_read.ipam_pool_prefix_allocations.Element.pool
pool.id = AAZStrType()

_schema.address_prefixes = cls._schema_address_space_read.address_prefixes
_schema.ipam_pool_prefix_allocations = cls._schema_address_space_read.ipam_pool_prefix_allocations

_schema_sub_resource_read = None

Expand Down
Loading
Loading