Skip to content

Commit 8338dd7

Browse files
committed
azurerm_kubernetes_cluster - add policy property to network_profile.advanced_networking block
This change adds support for the `policy` property within the `network_profile.advanced_networking` block for Azure Kubernetes Service clusters. The property maps to the Azure SDK's `AdvancedNetworkingSecurity.AdvancedNetworkPolicies` field. Changes: - Add `policy` field with valid values `FQDN` and `L7` - Add validation to ensure `policy` can only be set when `security_enabled` is `true`, and that it cannot be combined with a service mesh profile in `Istio` mode - Expand/flatten maps the API's `None` value to/from the Terraform-idiomatic empty string so the field can be omitted to disable advanced network policies - Add tests for the new property and validation - Update documentation Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
1 parent d73352f commit 8338dd7

3 files changed

Lines changed: 299 additions & 3 deletions

File tree

internal/services/containers/kubernetes_cluster_network_resource_test.go

Lines changed: 264 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.policy` can only be set 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.policy` can only be set 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.policy` cannot be set 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{}
@@ -1549,6 +1607,212 @@ resource "azurerm_kubernetes_cluster" "test" {
15491607
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, networkPlugin)
15501608
}
15511609

1610+
func (KubernetesClusterResource) advancedNetworkingWithPolicies(data acceptance.TestData, advancedNetworkPolicies string) string {
1611+
return fmt.Sprintf(`
1612+
provider "azurerm" {
1613+
features {}
1614+
}
1615+
1616+
resource "azurerm_resource_group" "test" {
1617+
name = "acctestRG-aks-%[1]d"
1618+
location = "%[2]s"
1619+
}
1620+
1621+
resource "azurerm_virtual_network" "test" {
1622+
name = "acctestvirtnet%[1]d"
1623+
address_space = ["10.0.0.0/8"]
1624+
location = azurerm_resource_group.test.location
1625+
resource_group_name = azurerm_resource_group.test.name
1626+
}
1627+
1628+
resource "azurerm_subnet" "test" {
1629+
name = "acctestsubnet%[1]d"
1630+
resource_group_name = azurerm_resource_group.test.name
1631+
virtual_network_name = azurerm_virtual_network.test.name
1632+
address_prefixes = ["10.1.0.0/16"]
1633+
}
1634+
1635+
resource "azurerm_kubernetes_cluster" "test" {
1636+
name = "acctestaks%[1]d"
1637+
location = azurerm_resource_group.test.location
1638+
resource_group_name = azurerm_resource_group.test.name
1639+
dns_prefix = "acctestaks%[1]d"
1640+
1641+
linux_profile {
1642+
admin_username = "acctestuser%[1]d"
1643+
1644+
ssh_key {
1645+
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld"
1646+
}
1647+
}
1648+
1649+
default_node_pool {
1650+
name = "default"
1651+
node_count = 2
1652+
vm_size = "Standard_DS2_v2"
1653+
vnet_subnet_id = azurerm_subnet.test.id
1654+
upgrade_settings {
1655+
max_surge = "10%%"
1656+
}
1657+
}
1658+
1659+
identity {
1660+
type = "SystemAssigned"
1661+
}
1662+
1663+
network_profile {
1664+
network_plugin = "azure"
1665+
network_data_plane = "cilium"
1666+
1667+
advanced_networking {
1668+
observability_enabled = true
1669+
security_enabled = true
1670+
policy = "%[3]s"
1671+
}
1672+
}
1673+
}
1674+
`, data.RandomInteger, data.Locations.Primary, advancedNetworkPolicies)
1675+
}
1676+
1677+
func (KubernetesClusterResource) advancedNetworkingWithPoliciesSecurityDisabled(data acceptance.TestData, advancedNetworkPolicies string) string {
1678+
return fmt.Sprintf(`
1679+
provider "azurerm" {
1680+
features {}
1681+
}
1682+
1683+
resource "azurerm_resource_group" "test" {
1684+
name = "acctestRG-aks-%[1]d"
1685+
location = "%[2]s"
1686+
}
1687+
1688+
resource "azurerm_virtual_network" "test" {
1689+
name = "acctestvirtnet%[1]d"
1690+
address_space = ["10.0.0.0/8"]
1691+
location = azurerm_resource_group.test.location
1692+
resource_group_name = azurerm_resource_group.test.name
1693+
}
1694+
1695+
resource "azurerm_subnet" "test" {
1696+
name = "acctestsubnet%[1]d"
1697+
resource_group_name = azurerm_resource_group.test.name
1698+
virtual_network_name = azurerm_virtual_network.test.name
1699+
address_prefixes = ["10.1.0.0/16"]
1700+
}
1701+
1702+
resource "azurerm_kubernetes_cluster" "test" {
1703+
name = "acctestaks%[1]d"
1704+
location = azurerm_resource_group.test.location
1705+
resource_group_name = azurerm_resource_group.test.name
1706+
dns_prefix = "acctestaks%[1]d"
1707+
1708+
linux_profile {
1709+
admin_username = "acctestuser%[1]d"
1710+
1711+
ssh_key {
1712+
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld"
1713+
}
1714+
}
1715+
1716+
default_node_pool {
1717+
name = "default"
1718+
node_count = 2
1719+
vm_size = "Standard_DS2_v2"
1720+
vnet_subnet_id = azurerm_subnet.test.id
1721+
upgrade_settings {
1722+
max_surge = "10%%"
1723+
}
1724+
}
1725+
1726+
identity {
1727+
type = "SystemAssigned"
1728+
}
1729+
1730+
network_profile {
1731+
network_plugin = "azure"
1732+
network_data_plane = "cilium"
1733+
1734+
advanced_networking {
1735+
observability_enabled = true
1736+
security_enabled = false
1737+
policy = "%[3]s"
1738+
}
1739+
}
1740+
}
1741+
`, data.RandomInteger, data.Locations.Primary, advancedNetworkPolicies)
1742+
}
1743+
1744+
func (KubernetesClusterResource) advancedNetworkingWithPoliciesAndIstio(data acceptance.TestData, advancedNetworkPolicies string) string {
1745+
return fmt.Sprintf(`
1746+
provider "azurerm" {
1747+
features {}
1748+
}
1749+
1750+
resource "azurerm_resource_group" "test" {
1751+
name = "acctestRG-aks-%[1]d"
1752+
location = "%[2]s"
1753+
}
1754+
1755+
resource "azurerm_virtual_network" "test" {
1756+
name = "acctestvirtnet%[1]d"
1757+
address_space = ["10.0.0.0/8"]
1758+
location = azurerm_resource_group.test.location
1759+
resource_group_name = azurerm_resource_group.test.name
1760+
}
1761+
1762+
resource "azurerm_subnet" "test" {
1763+
name = "acctestsubnet%[1]d"
1764+
resource_group_name = azurerm_resource_group.test.name
1765+
virtual_network_name = azurerm_virtual_network.test.name
1766+
address_prefixes = ["10.1.0.0/16"]
1767+
}
1768+
1769+
resource "azurerm_kubernetes_cluster" "test" {
1770+
name = "acctestaks%[1]d"
1771+
location = azurerm_resource_group.test.location
1772+
resource_group_name = azurerm_resource_group.test.name
1773+
dns_prefix = "acctestaks%[1]d"
1774+
1775+
linux_profile {
1776+
admin_username = "acctestuser%[1]d"
1777+
1778+
ssh_key {
1779+
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld"
1780+
}
1781+
}
1782+
1783+
default_node_pool {
1784+
name = "default"
1785+
node_count = 2
1786+
vm_size = "Standard_DS2_v2"
1787+
vnet_subnet_id = azurerm_subnet.test.id
1788+
upgrade_settings {
1789+
max_surge = "10%%"
1790+
}
1791+
}
1792+
1793+
identity {
1794+
type = "SystemAssigned"
1795+
}
1796+
1797+
network_profile {
1798+
network_plugin = "azure"
1799+
network_data_plane = "cilium"
1800+
1801+
advanced_networking {
1802+
observability_enabled = true
1803+
security_enabled = true
1804+
policy = "%[3]s"
1805+
}
1806+
}
1807+
1808+
service_mesh_profile {
1809+
mode = "Istio"
1810+
revisions = ["asm-1-28"]
1811+
}
1812+
}
1813+
`, data.RandomInteger, data.Locations.Primary, advancedNetworkPolicies)
1814+
}
1815+
15521816
func (KubernetesClusterResource) serviceMeshProfile(data acceptance.TestData, internalIngressEnabled bool, externalIngressEnabled bool) string {
15531817
return fmt.Sprintf(`
15541818
provider "azurerm" {

internal/services/containers/kubernetes_cluster_resource.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,15 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
185185
return fmt.Errorf("when `network_profile.0.advanced_networking` has `security_enabled` set to `true`, `network_profile.0.network_plugin` must be set to `%s`", managedclusters.NetworkPluginAzure)
186186
}
187187
}
188+
advancedNetworkPolicies := d.Get("network_profile.0.advanced_networking.0.policy").(string)
189+
if !securityEnabled && advancedNetworkPolicies != "" {
190+
return fmt.Errorf("`network_profile.0.advanced_networking.0.policy` can only be set when `network_profile.0.advanced_networking.0.security_enabled` is set to `true`")
191+
}
192+
if advancedNetworkPolicies != "" {
193+
if mode := d.Get("service_mesh_profile.0.mode").(string); mode == string(managedclusters.ServiceMeshModeIstio) {
194+
return fmt.Errorf("`network_profile.0.advanced_networking.0.policy` cannot be set when `service_mesh_profile.0.mode` is set to `%s`", managedclusters.ServiceMeshModeIstio)
195+
}
196+
}
188197
}
189198
return nil
190199
},
@@ -1366,6 +1375,15 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
13661375
Default: false,
13671376
AtLeastOneOf: []string{"network_profile.0.advanced_networking.0.observability_enabled", "network_profile.0.advanced_networking.0.security_enabled"},
13681377
},
1378+
"policy": {
1379+
Type: pluginsdk.TypeString,
1380+
Optional: true,
1381+
ValidateFunc: validation.StringInSlice([]string{
1382+
string(managedclusters.AdvancedNetworkPoliciesFQDN),
1383+
string(managedclusters.AdvancedNetworkPoliciesLSeven),
1384+
// Note: Whilst the `None` value exists it's handled in the Create/Update and Read functions.
1385+
}, false),
1386+
},
13691387
},
13701388
},
13711389
},
@@ -3755,14 +3773,21 @@ func expandKubernetesClusterAdvancedNetworking(input []interface{}, d *pluginsdk
37553773
observabilityEnabled := config["observability_enabled"].(bool)
37563774
securityEnabled := config["security_enabled"].(bool)
37573775

3776+
advancedNetworkPolicies := managedclusters.AdvancedNetworkPoliciesNone
3777+
if v := config["policy"].(string); v != "" {
3778+
advancedNetworkPolicies = managedclusters.AdvancedNetworkPolicies(v)
3779+
}
3780+
security := &managedclusters.AdvancedNetworkingSecurity{
3781+
Enabled: pointer.To(securityEnabled),
3782+
AdvancedNetworkPolicies: pointer.To(advancedNetworkPolicies),
3783+
}
3784+
37583785
return &managedclusters.AdvancedNetworking{
37593786
Enabled: pointer.To(true),
37603787
Observability: &managedclusters.AdvancedNetworkingObservability{
37613788
Enabled: pointer.To(observabilityEnabled),
37623789
},
3763-
Security: &managedclusters.AdvancedNetworkingSecurity{
3764-
Enabled: pointer.To(securityEnabled),
3765-
},
3790+
Security: security,
37663791
}
37673792
}
37683793

@@ -3777,14 +3802,19 @@ func flattenKubernetesClusterAdvancedNetworking(advancedNetworking *managedclust
37773802
}
37783803

37793804
securityEnabled := false
3805+
advancedNetworkPolicies := ""
37803806
if advancedNetworking.Security != nil {
37813807
securityEnabled = pointer.From(advancedNetworking.Security.Enabled)
3808+
if v := advancedNetworking.Security.AdvancedNetworkPolicies; v != nil && *v != managedclusters.AdvancedNetworkPoliciesNone {
3809+
advancedNetworkPolicies = string(*v)
3810+
}
37823811
}
37833812

37843813
return []interface{}{
37853814
map[string]interface{}{
37863815
"observability_enabled": observabilityEnabled,
37873816
"security_enabled": securityEnabled,
3817+
"policy": advancedNetworkPolicies,
37883818
},
37893819
}
37903820
}

website/docs/r/kubernetes_cluster.html.markdown

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

737737
* `security_enabled` - (Optional) Is security enabled? Defaults to `false`. This can only be enabled (set to `true`) when `network_plugin` is set to `azure` and `network_data_plane` is set to `cilium`.
738738

739+
* `policy` - (Optional) Specifies the advanced network policy for the cluster. Possible values are `FQDN` and `L7`. This can only be set when `security_enabled` is set to `true` and `network_data_plane` is set to `cilium`. This cannot be set when `service_mesh_profile` `mode` is set to `Istio`. Omitting this field disables advanced network policy enforcement (equivalent to `None`).
740+
739741
---
740742

741743
A `load_balancer_profile` block supports the following:

0 commit comments

Comments
 (0)