Skip to content

Commit c3bb2bc

Browse files
committed
azurerm_kubernetes_cluster - add advanced_network_policies property to advanced_networking block
This change adds support for the `advanced_network_policies` property within the `network_profile.advanced_networking` block for Azure Kubernetes Service clusters. Changes: - Add `advanced_network_policies` field with valid values: `FQDN`, `L7`, `None` - Add validation to ensure `advanced_network_policies` can only be set to `FQDN` or `L7` when `security_enabled` is `true` - Upgrade managedclusters SDK from 2025-07-01 to 2025-10-01 API version to support the new field - Add tests for the new property and validation - Update documentation to note Cilium cluster requirement Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
1 parent 5c0d5ed commit c3bb2bc

3 files changed

Lines changed: 297 additions & 5 deletions

File tree

internal/services/containers/kubernetes_cluster_network_resource_test.go

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,64 @@ func TestAccKubernetesCluster_advancedNetworkingNetworkDataplane(t *testing.T) {
101101
})
102102
}
103103

104+
func TestAccKubernetesCluster_advancedNetworkingPolicies(t *testing.T) {
105+
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
106+
r := KubernetesClusterResource{}
107+
108+
data.ResourceTest(t, r, []acceptance.TestStep{
109+
{
110+
Config: r.advancedNetworkingWithPolicies(data, "FQDN"),
111+
Check: acceptance.ComposeTestCheckFunc(
112+
check.That(data.ResourceName).ExistsInAzure(r),
113+
),
114+
},
115+
data.ImportStep(),
116+
{
117+
Config: r.advancedNetworkingWithPolicies(data, "L7"),
118+
Check: acceptance.ComposeTestCheckFunc(
119+
check.That(data.ResourceName).ExistsInAzure(r),
120+
),
121+
},
122+
data.ImportStep(),
123+
})
124+
}
125+
126+
func TestAccKubernetesCluster_advancedNetworkingPoliciesFQDNRequiresSecurity(t *testing.T) {
127+
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
128+
r := KubernetesClusterResource{}
129+
130+
data.ResourceTest(t, r, []acceptance.TestStep{
131+
{
132+
Config: r.advancedNetworkingWithPoliciesSecurityDisabled(data, "FQDN"),
133+
ExpectError: regexp.MustCompile("`network_profile.0.advanced_networking.0.advanced_network_policies` can only be set to `FQDN` or `L7` when `network_profile.0.advanced_networking.0.security_enabled` is set to `true`"),
134+
},
135+
})
136+
}
137+
138+
func TestAccKubernetesCluster_advancedNetworkingPoliciesL7RequiresSecurity(t *testing.T) {
139+
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
140+
r := KubernetesClusterResource{}
141+
142+
data.ResourceTest(t, r, []acceptance.TestStep{
143+
{
144+
Config: r.advancedNetworkingWithPoliciesSecurityDisabled(data, "L7"),
145+
ExpectError: regexp.MustCompile("`network_profile.0.advanced_networking.0.advanced_network_policies` can only be set to `FQDN` or `L7` when `network_profile.0.advanced_networking.0.security_enabled` is set to `true`"),
146+
},
147+
})
148+
}
149+
150+
func TestAccKubernetesCluster_advancedNetworkingPoliciesConflictsWithIstio(t *testing.T) {
151+
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
152+
r := KubernetesClusterResource{}
153+
154+
data.ResourceTest(t, r, []acceptance.TestStep{
155+
{
156+
Config: r.advancedNetworkingWithPoliciesAndIstio(data, "L7"),
157+
ExpectError: regexp.MustCompile("`network_profile.0.advanced_networking.0.advanced_network_policies` cannot be set to `FQDN` or `L7` when `service_mesh_profile.0.mode` is set to `Istio`"),
158+
},
159+
})
160+
}
161+
104162
func TestAccKubernetesCluster_serviceMeshProfile(t *testing.T) {
105163
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
106164
r := KubernetesClusterResource{}
@@ -1417,6 +1475,211 @@ resource "azurerm_kubernetes_cluster" "test" {
14171475
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, networkPlugin)
14181476
}
14191477

1478+
func (KubernetesClusterResource) advancedNetworkingWithPolicies(data acceptance.TestData, advancedNetworkPolicies string) string {
1479+
return fmt.Sprintf(`
1480+
provider "azurerm" {
1481+
features {}
1482+
}
1483+
1484+
resource "azurerm_resource_group" "test" {
1485+
name = "acctestRG-aks-%[1]d"
1486+
location = "%[2]s"
1487+
}
1488+
1489+
resource "azurerm_virtual_network" "test" {
1490+
name = "acctestvirtnet%[1]d"
1491+
address_space = ["10.0.0.0/8"]
1492+
location = azurerm_resource_group.test.location
1493+
resource_group_name = azurerm_resource_group.test.name
1494+
}
1495+
1496+
resource "azurerm_subnet" "test" {
1497+
name = "acctestsubnet%[1]d"
1498+
resource_group_name = azurerm_resource_group.test.name
1499+
virtual_network_name = azurerm_virtual_network.test.name
1500+
address_prefixes = ["10.1.0.0/16"]
1501+
}
1502+
1503+
resource "azurerm_kubernetes_cluster" "test" {
1504+
name = "acctestaks%[1]d"
1505+
location = azurerm_resource_group.test.location
1506+
resource_group_name = azurerm_resource_group.test.name
1507+
dns_prefix = "acctestaks%[1]d"
1508+
1509+
linux_profile {
1510+
admin_username = "acctestuser%[1]d"
1511+
1512+
ssh_key {
1513+
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld"
1514+
}
1515+
}
1516+
1517+
default_node_pool {
1518+
name = "default"
1519+
node_count = 2
1520+
vm_size = "Standard_DS2_v2"
1521+
vnet_subnet_id = azurerm_subnet.test.id
1522+
upgrade_settings {
1523+
max_surge = "10%%"
1524+
}
1525+
}
1526+
1527+
identity {
1528+
type = "SystemAssigned"
1529+
}
1530+
1531+
network_profile {
1532+
network_plugin = "azure"
1533+
network_data_plane = "cilium"
1534+
1535+
advanced_networking {
1536+
observability_enabled = true
1537+
security_enabled = true
1538+
advanced_network_policies = "%[3]s"
1539+
}
1540+
}
1541+
}
1542+
`, data.RandomInteger, data.Locations.Primary, advancedNetworkPolicies)
1543+
}
1544+
1545+
func (KubernetesClusterResource) advancedNetworkingWithPoliciesSecurityDisabled(data acceptance.TestData, advancedNetworkPolicies string) string {
1546+
return fmt.Sprintf(`
1547+
provider "azurerm" {
1548+
features {}
1549+
}
1550+
1551+
resource "azurerm_resource_group" "test" {
1552+
name = "acctestRG-aks-%[1]d"
1553+
location = "%[2]s"
1554+
}
1555+
1556+
resource "azurerm_virtual_network" "test" {
1557+
name = "acctestvirtnet%[1]d"
1558+
address_space = ["10.0.0.0/8"]
1559+
location = azurerm_resource_group.test.location
1560+
resource_group_name = azurerm_resource_group.test.name
1561+
}
1562+
1563+
resource "azurerm_subnet" "test" {
1564+
name = "acctestsubnet%[1]d"
1565+
resource_group_name = azurerm_resource_group.test.name
1566+
virtual_network_name = azurerm_virtual_network.test.name
1567+
address_prefixes = ["10.1.0.0/16"]
1568+
}
1569+
1570+
resource "azurerm_kubernetes_cluster" "test" {
1571+
name = "acctestaks%[1]d"
1572+
location = azurerm_resource_group.test.location
1573+
resource_group_name = azurerm_resource_group.test.name
1574+
dns_prefix = "acctestaks%[1]d"
1575+
1576+
linux_profile {
1577+
admin_username = "acctestuser%[1]d"
1578+
1579+
ssh_key {
1580+
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld"
1581+
}
1582+
}
1583+
1584+
default_node_pool {
1585+
name = "default"
1586+
node_count = 2
1587+
vm_size = "Standard_DS2_v2"
1588+
vnet_subnet_id = azurerm_subnet.test.id
1589+
upgrade_settings {
1590+
max_surge = "10%%"
1591+
}
1592+
}
1593+
1594+
identity {
1595+
type = "SystemAssigned"
1596+
}
1597+
1598+
network_profile {
1599+
network_plugin = "azure"
1600+
network_data_plane = "cilium"
1601+
1602+
advanced_networking {
1603+
observability_enabled = true
1604+
security_enabled = false
1605+
advanced_network_policies = "%[3]s"
1606+
}
1607+
}
1608+
}
1609+
`, data.RandomInteger, data.Locations.Primary, advancedNetworkPolicies)
1610+
}
1611+
1612+
func (KubernetesClusterResource) advancedNetworkingWithPoliciesAndIstio(data acceptance.TestData, advancedNetworkPolicies string) string {
1613+
return fmt.Sprintf(`
1614+
provider "azurerm" {
1615+
features {}
1616+
}
1617+
1618+
resource "azurerm_resource_group" "test" {
1619+
name = "acctestRG-aks-%[1]d"
1620+
location = "%[2]s"
1621+
}
1622+
1623+
resource "azurerm_virtual_network" "test" {
1624+
name = "acctestvirtnet%[1]d"
1625+
address_space = ["10.0.0.0/8"]
1626+
location = azurerm_resource_group.test.location
1627+
resource_group_name = azurerm_resource_group.test.name
1628+
}
1629+
1630+
resource "azurerm_subnet" "test" {
1631+
name = "acctestsubnet%[1]d"
1632+
resource_group_name = azurerm_resource_group.test.name
1633+
virtual_network_name = azurerm_virtual_network.test.name
1634+
address_prefixes = ["10.1.0.0/16"]
1635+
}
1636+
1637+
resource "azurerm_kubernetes_cluster" "test" {
1638+
name = "acctestaks%[1]d"
1639+
location = azurerm_resource_group.test.location
1640+
resource_group_name = azurerm_resource_group.test.name
1641+
dns_prefix = "acctestaks%[1]d"
1642+
1643+
linux_profile {
1644+
admin_username = "acctestuser%[1]d"
1645+
1646+
ssh_key {
1647+
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld"
1648+
}
1649+
}
1650+
1651+
default_node_pool {
1652+
name = "default"
1653+
node_count = 2
1654+
vm_size = "Standard_DS2_v2"
1655+
vnet_subnet_id = azurerm_subnet.test.id
1656+
upgrade_settings {
1657+
max_surge = "10%%"
1658+
}
1659+
}
1660+
1661+
identity {
1662+
type = "SystemAssigned"
1663+
}
1664+
1665+
network_profile {
1666+
network_plugin = "azure"
1667+
network_data_plane = "cilium"
1668+
1669+
advanced_networking {
1670+
observability_enabled = true
1671+
security_enabled = true
1672+
advanced_network_policies = "%[3]s"
1673+
}
1674+
}
1675+
1676+
service_mesh_profile {
1677+
mode = "Istio"
1678+
}
1679+
}
1680+
`, data.RandomInteger, data.Locations.Primary, advancedNetworkPolicies)
1681+
}
1682+
14201683
func (KubernetesClusterResource) serviceMeshProfile(data acceptance.TestData, internalIngressEnabled bool, externalIngressEnabled bool) string {
14211684
return fmt.Sprintf(`
14221685
provider "azurerm" {

internal/services/containers/kubernetes_cluster_resource.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,19 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
154154
if d.Get("network_profile.0.network_plugin").(string) != string(managedclusters.NetworkPluginAzure) {
155155
return fmt.Errorf("when `network_profile.0.advanced_networking` is set, `network_profile.0.network_plugin` must be set to `%s`", managedclusters.NetworkPluginAzure)
156156
}
157+
securityEnabled := d.Get("network_profile.0.advanced_networking.0.security_enabled").(bool)
158+
advancedNetworkPolicies := d.Get("network_profile.0.advanced_networking.0.advanced_network_policies").(string)
159+
if !securityEnabled && advancedNetworkPolicies != "" && advancedNetworkPolicies != string(managedclusters.AdvancedNetworkPoliciesNone) {
160+
return fmt.Errorf("`network_profile.0.advanced_networking.0.advanced_network_policies` can only be set to `%s` or `%s` when `network_profile.0.advanced_networking.0.security_enabled` is set to `true`", managedclusters.AdvancedNetworkPoliciesFQDN, managedclusters.AdvancedNetworkPoliciesLSeven)
161+
}
162+
if advancedNetworkPolicies != "" && advancedNetworkPolicies != string(managedclusters.AdvancedNetworkPoliciesNone) {
163+
if serviceMeshProfiles := d.Get("service_mesh_profile").([]interface{}); len(serviceMeshProfiles) > 0 {
164+
serviceMeshProfile := serviceMeshProfiles[0].(map[string]interface{})
165+
if serviceMeshProfile["mode"].(string) == string(managedclusters.ServiceMeshModeIstio) {
166+
return fmt.Errorf("`network_profile.0.advanced_networking.0.advanced_network_policies` cannot be set to `%s` or `%s` when `service_mesh_profile.0.mode` is set to `%s`", managedclusters.AdvancedNetworkPoliciesFQDN, managedclusters.AdvancedNetworkPoliciesLSeven, managedclusters.ServiceMeshModeIstio)
167+
}
168+
}
169+
}
157170
}
158171
return nil
159172
},
@@ -1339,6 +1352,11 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
13391352
Default: false,
13401353
AtLeastOneOf: []string{"network_profile.0.advanced_networking.0.observability_enabled", "network_profile.0.advanced_networking.0.security_enabled"},
13411354
},
1355+
"advanced_network_policies": {
1356+
Type: pluginsdk.TypeString,
1357+
Optional: true,
1358+
ValidateFunc: validation.StringInSlice(managedclusters.PossibleValuesForAdvancedNetworkPolicies(), false),
1359+
},
13421360
},
13431361
},
13441362
},
@@ -3680,14 +3698,20 @@ func expandKubernetesClusterAdvancedNetworking(input []interface{}, d *pluginsdk
36803698
observabilityEnabled := config["observability_enabled"].(bool)
36813699
securityEnabled := config["security_enabled"].(bool)
36823700

3701+
security := &managedclusters.AdvancedNetworkingSecurity{
3702+
Enabled: pointer.To(securityEnabled),
3703+
}
3704+
3705+
if v, ok := config["advanced_network_policies"].(string); ok && v != "" {
3706+
security.AdvancedNetworkPolicies = pointer.ToEnum[managedclusters.AdvancedNetworkPolicies](v)
3707+
}
3708+
36833709
return &managedclusters.AdvancedNetworking{
36843710
Enabled: pointer.To(true),
36853711
Observability: &managedclusters.AdvancedNetworkingObservability{
36863712
Enabled: pointer.To(observabilityEnabled),
36873713
},
3688-
Security: &managedclusters.AdvancedNetworkingSecurity{
3689-
Enabled: pointer.To(securityEnabled),
3690-
},
3714+
Security: security,
36913715
}
36923716
}
36933717

@@ -3702,14 +3726,17 @@ func flattenKubernetesClusterAdvancedNetworking(advancedNetworking *managedclust
37023726
}
37033727

37043728
securityEnabled := false
3729+
advancedNetworkPolicies := ""
37053730
if advancedNetworking.Security != nil {
37063731
securityEnabled = pointer.From(advancedNetworking.Security.Enabled)
3732+
advancedNetworkPolicies = string(pointer.From(advancedNetworking.Security.AdvancedNetworkPolicies))
37073733
}
37083734

37093735
return []interface{}{
37103736
map[string]interface{}{
3711-
"observability_enabled": observabilityEnabled,
3712-
"security_enabled": securityEnabled,
3737+
"observability_enabled": observabilityEnabled,
3738+
"security_enabled": securityEnabled,
3739+
"advanced_network_policies": advancedNetworkPolicies,
37133740
},
37143741
}
37153742
}

website/docs/r/kubernetes_cluster.html.markdown

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,8 @@ An `advanced_networking` block supports the following:
728728

729729
* `security_enabled` - (Optional) Is security enabled? Defaults to `false`.
730730

731+
* `advanced_network_policies` - (Optional) Specifies the advanced network policy for the cluster. Possible values are `FQDN`, `L7` and `None`. This can only be set to `FQDN` or `L7` when `security_enabled` is set to `true` and `network_data_plane` is set to `cilium`. This cannot be set to `FQDN` or `L7` when `service_mesh_profile` `mode` is set to `Istio`. Defaults to `FQDN` when `security_enabled` is set to `true`.
732+
731733
---
732734

733735
A `load_balancer_profile` block supports the following:

0 commit comments

Comments
 (0)