@@ -20,6 +20,7 @@ import (
2020 "github.com/hashicorp/go-azure-helpers/resourcemanager/identity"
2121 "github.com/hashicorp/go-azure-helpers/resourcemanager/location"
2222 "github.com/hashicorp/go-azure-helpers/resourcemanager/tags"
23+ "github.com/hashicorp/go-azure-sdk/resource-manager/containerregistry/2023-11-01-preview/registries"
2324 "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2025-05-01/agentpools"
2425 "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2025-05-01/maintenanceconfigurations"
2526 "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2025-05-01/managedclusters"
@@ -113,6 +114,16 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
113114 // Once it is GA, an additional logic is needed to handle the uninstallation of network policy.
114115 return old .(string ) != ""
115116 }),
117+ func (ctx context.Context , d * schema.ResourceDiff , meta interface {}) error {
118+ outboundType := d .Get ("network_profile.0.outbound_type" ).(string )
119+ artifactSource := d .Get ("bootstrap_profile.0.artifact_source" ).(string )
120+
121+ if outboundType == string (managedclusters .OutboundTypeNone ) && artifactSource != string (managedclusters .ArtifactSourceCache ) {
122+ return fmt .Errorf ("when `network_profile.0.outbound_type` is set to `none`, `bootstrap_profile.0.artifact_source` must be set to `Cache`" )
123+ }
124+
125+ return nil
126+ },
116127 ),
117128
118129 Timeouts : & pluginsdk.ResourceTimeout {
@@ -676,6 +687,30 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
676687 },
677688 },
678689
690+ "bootstrap_profile" : {
691+ Type : pluginsdk .TypeList ,
692+ Optional : true ,
693+ // Note: O+C because the API returns a default value for `bootstrapProfile` when it is omitted in the API request
694+ Computed : true ,
695+ MaxItems : 1 ,
696+ Elem : & pluginsdk.Resource {
697+ Schema : map [string ]* pluginsdk.Schema {
698+ "artifact_source" : {
699+ Type : pluginsdk .TypeString ,
700+ Optional : true ,
701+ ValidateFunc : validation .StringInSlice (managedclusters .PossibleValuesForArtifactSource (), false ),
702+ Default : managedclusters .ArtifactSourceDirect ,
703+ },
704+
705+ "container_registry_id" : {
706+ Type : pluginsdk .TypeString ,
707+ Optional : true ,
708+ ValidateFunc : registries .ValidateRegistryID ,
709+ },
710+ },
711+ },
712+ },
713+
679714 "local_account_disabled" : {
680715 Type : pluginsdk .TypeBool ,
681716 Optional : true ,
@@ -1115,6 +1150,7 @@ func resourceKubernetesCluster() *pluginsdk.Resource {
11151150 string (managedclusters .OutboundTypeUserDefinedRouting ),
11161151 string (managedclusters .OutboundTypeManagedNATGateway ),
11171152 string (managedclusters .OutboundTypeUserAssignedNATGateway ),
1153+ string (managedclusters .OutboundTypeNone ),
11181154 }, false ),
11191155 },
11201156
@@ -1700,6 +1736,9 @@ func resourceKubernetesClusterCreate(d *pluginsdk.ResourceData, meta interface{}
17001736 azureMonitorKubernetesMetricsRaw := d .Get ("monitor_metrics" ).([]interface {})
17011737 azureMonitorProfile := expandKubernetesClusterAzureMonitorProfile (azureMonitorKubernetesMetricsRaw )
17021738
1739+ bootstrapProfileRaw := d .Get ("bootstrap_profile" ).([]interface {})
1740+ bootstrapProfile := expandBootstrapProfile (bootstrapProfileRaw )
1741+
17031742 httpProxyConfigRaw := d .Get ("http_proxy_config" ).([]interface {})
17041743 httpProxyConfig := expandKubernetesClusterHttpProxyConfig (httpProxyConfigRaw )
17051744
@@ -1792,6 +1831,7 @@ func resourceKubernetesClusterCreate(d *pluginsdk.ResourceData, meta interface{}
17921831 DnsPrefix : pointer .To (dnsPrefix ),
17931832 EnableRBAC : pointer .To (d .Get ("role_based_access_control_enabled" ).(bool )),
17941833 KubernetesVersion : pointer .To (kubernetesVersion ),
1834+ BootstrapProfile : bootstrapProfile ,
17951835 LinuxProfile : linuxProfile ,
17961836 WindowsProfile : windowsProfile ,
17971837 MetricsProfile : metricsProfile ,
@@ -2370,6 +2410,21 @@ func resourceKubernetesClusterUpdate(d *pluginsdk.ResourceData, meta interface{}
23702410 }
23712411 }
23722412
2413+ if d .HasChange ("bootstrap_profile" ) {
2414+ bootstrapProfileRaw := d .Get ("bootstrap_profile" ).([]interface {})
2415+ profile := expandBootstrapProfile (bootstrapProfileRaw )
2416+
2417+ // If profile is removed in the config, we should set ArtifactSource to Direct as it's the default value in the service side.
2418+ if profile == nil {
2419+ profile = & managedclusters.ManagedClusterBootstrapProfile {
2420+ ArtifactSource : pointer .To (managedclusters .ArtifactSourceDirect ),
2421+ }
2422+ }
2423+
2424+ updateCluster = true
2425+ existing .Model .Properties .BootstrapProfile = profile
2426+ }
2427+
23732428 if d .HasChange ("upgrade_override" ) {
23742429 upgradeOverrideSettingRaw := d .Get ("upgrade_override" ).([]interface {})
23752430
@@ -2920,6 +2975,14 @@ func resourceKubernetesClusterRead(d *pluginsdk.ResourceData, meta interface{})
29202975 }
29212976
29222977 d .Set ("support_plan" , pointer .From (props .SupportPlan ))
2978+
2979+ bootstrapProfile , err := flattenBootstrapProfile (props .BootstrapProfile )
2980+ if err != nil {
2981+ return fmt .Errorf ("flattening `bootstrap_profile`: %+v" , err )
2982+ }
2983+ if err := d .Set ("bootstrap_profile" , bootstrapProfile ); err != nil {
2984+ return fmt .Errorf ("setting `bootstrap_profile`: %+v" , err )
2985+ }
29232986 }
29242987
29252988 identity , err := identity .FlattenSystemOrUserAssignedMap (model .Identity )
@@ -3171,6 +3234,44 @@ func flattenKubernetesClusterAPIAccessProfile(profile *managedclusters.ManagedCl
31713234 }
31723235}
31733236
3237+ func expandBootstrapProfile (rawBootstrapProfile []interface {}) * managedclusters.ManagedClusterBootstrapProfile {
3238+ if len (rawBootstrapProfile ) == 0 || rawBootstrapProfile [0 ] == nil {
3239+ return nil
3240+ }
3241+
3242+ config := rawBootstrapProfile [0 ].(map [string ]interface {})
3243+ var containerRegistryID * string
3244+ if v , exists := config ["container_registry_id" ]; exists && v != "" {
3245+ containerRegistryID = pointer .To (v .(string ))
3246+ }
3247+
3248+ return & managedclusters.ManagedClusterBootstrapProfile {
3249+ ArtifactSource : pointer.ToEnum [managedclusters.ArtifactSource ](config ["artifact_source" ].(string )),
3250+ ContainerRegistryId : containerRegistryID ,
3251+ }
3252+ }
3253+
3254+ func flattenBootstrapProfile (profile * managedclusters.ManagedClusterBootstrapProfile ) ([]interface {}, error ) {
3255+ if profile == nil || profile .ArtifactSource == nil {
3256+ return []interface {}{}, nil
3257+ }
3258+
3259+ var containerRegistryID string
3260+ if profile .ContainerRegistryId != nil {
3261+ id , err := registries .ParseRegistryID (* profile .ContainerRegistryId )
3262+ if err != nil {
3263+ return nil , err
3264+ }
3265+ containerRegistryID = id .ID ()
3266+ }
3267+ return []interface {}{
3268+ map [string ]interface {}{
3269+ "artifact_source" : profile .ArtifactSource ,
3270+ "container_registry_id" : containerRegistryID ,
3271+ },
3272+ }, nil
3273+ }
3274+
31743275func expandKubernetesClusterWorkloadAutoscalerProfile (input []interface {}, d * pluginsdk.ResourceData ) * managedclusters.ManagedClusterWorkloadAutoScalerProfile {
31753276 if len (input ) == 0 {
31763277 return nil
0 commit comments