@@ -17,6 +17,7 @@ limitations under the License.
1717package azure
1818
1919import (
20+ "crypto/x509"
2021 "fmt"
2122 "net/http"
2223 "regexp"
@@ -27,6 +28,7 @@ import (
2728 "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
2829 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
2930 "github.com/Azure/azure-sdk-for-go/sdk/tracing/azotel"
31+ azureautorest "github.com/Azure/go-autorest/autorest/azure"
3032 "go.opentelemetry.io/otel"
3133
3234 "sigs.k8s.io/cluster-api-provider-azure/util/tele"
@@ -44,6 +46,8 @@ const (
4446 ChinaCloudName = "AzureChinaCloud"
4547 // USGovernmentCloudName is the name of the Azure US Government cloud.
4648 USGovernmentCloudName = "AzureUSGovernmentCloud"
49+ // AzSecretCloudName is the name of the Azure US Secret cloud.
50+ AzSecretCloudName = "AzureUSSecretCloud"
4751)
4852
4953const (
@@ -109,6 +113,27 @@ const (
109113 CustomHeaderPrefix = "infrastructure.cluster.x-k8s.io/custom-header-"
110114)
111115
116+ // Cloud service names
117+ const (
118+ MicrosoftGraphAPI = cloud .ServiceName ("MicrosoftGraphAPI" )
119+ GalleryURL = cloud .ServiceName ("GalleryURL" )
120+ AzureStorageURL = cloud .ServiceName ("AzureStorageURL" )
121+ )
122+
123+ // Remove AzureSecretConfig as it's now loaded dynamically
124+
125+ // AzSecretCertPool holds the certificate pool for custom Azure environments
126+ // This will be populated at runtime when custom certificates are detected
127+ var AzSecretCertPool * x509.CertPool
128+
129+ // AzSecretCertData holds the raw certificate data for custom Azure environments
130+ // This will be populated at runtime when custom certificates are detected
131+ var AzSecretCertData []byte
132+
133+ // GlobalHTTPClient holds the global HTTP client for custom Azure environments
134+ // This will be populated by the scope package to avoid import cycles
135+ var GlobalHTTPClient * http.Client
136+
112137var (
113138 // LinuxBootstrapExtensionCommand is the command the VM bootstrap extension will execute to verify Linux nodes bootstrap completes successfully.
114139 LinuxBootstrapExtensionCommand = fmt .Sprintf ("for i in $(seq 1 %d); do test -f %s && break; if [ $i -eq %d ]; then exit 1; else sleep %d; fi; done" , bootstrapExtensionRetries , bootstrapSentinelFile , bootstrapExtensionRetries , bootstrapExtensionSleep )
@@ -117,6 +142,11 @@ var (
117142 bootstrapExtensionRetries , bootstrapSentinelFile , bootstrapExtensionSleep )
118143)
119144
145+ // IsAzSecretCertConfigured returns true if the AzSecret certificate pool has been configured
146+ func IsAzSecretCertConfigured () bool {
147+ return AzSecretCertPool != nil
148+ }
149+
120150// GenerateBackendAddressPoolName generates a load balancer backend address pool name.
121151func GenerateBackendAddressPoolName (lbName string ) string {
122152 return fmt .Sprintf ("%s-%s" , lbName , "backendPool" )
@@ -360,6 +390,9 @@ func UserAgent() string {
360390}
361391
362392// ARMClientOptions returns default ARM client options for CAPZ SDK v2 requests.
393+ //
394+ // For custom cloud environments, it automatically converts dynamically loaded
395+ // environments to the new SDK v2 format.
363396func ARMClientOptions (azureEnvironment string , extraPolicies ... policy.Policy ) (* arm.ClientOptions , error ) {
364397 opts := & arm.ClientOptions {}
365398
@@ -373,8 +406,20 @@ func ARMClientOptions(azureEnvironment string, extraPolicies ...policy.Policy) (
373406 case "" :
374407 // No cloud name provided, so leave at defaults.
375408 default :
376- return nil , fmt .Errorf ("invalid cloud name %q" , azureEnvironment )
409+ // For custom environments, try to get the environment configuration
410+ // from the dynamically loaded environments
411+ cloudConfig , err := getCloudConfigurationFromEnvironment (azureEnvironment )
412+ if err != nil {
413+ return nil , fmt .Errorf ("invalid cloud name %q: %w" , azureEnvironment , err )
414+ }
415+ opts .Cloud = cloudConfig
416+ }
417+
418+ // Use centralized transport configuration
419+ if GlobalHTTPClient != nil {
420+ opts .ClientOptions .Transport = GlobalHTTPClient
377421 }
422+
378423 opts .PerCallPolicies = []policy.Policy {
379424 correlationIDPolicy {},
380425 userAgentPolicy {},
@@ -387,6 +432,39 @@ func ARMClientOptions(azureEnvironment string, extraPolicies ...policy.Policy) (
387432 return opts , nil
388433}
389434
435+ // getCloudConfigurationFromEnvironment converts a dynamically loaded environment
436+ // to the new Azure SDK v2 cloud configuration format
437+ // Must have this, since we are using the new SDK v2.
438+ func getCloudConfigurationFromEnvironment (environmentName string ) (cloud.Configuration , error ) {
439+ env , err := azureautorest .EnvironmentFromName (environmentName )
440+ if err != nil {
441+ return cloud.Configuration {}, fmt .Errorf ("environment %q not found: %w" , environmentName , err )
442+ }
443+
444+ // Convert from old SDK v1 format to new SDK v2 format
445+ return cloud.Configuration {
446+ ActiveDirectoryAuthorityHost : env .ActiveDirectoryEndpoint ,
447+ Services : map [cloud.ServiceName ]cloud.ServiceConfiguration {
448+ cloud .ResourceManager : {
449+ Endpoint : env .ResourceManagerEndpoint ,
450+ Audience : env .TokenAudience ,
451+ },
452+ MicrosoftGraphAPI : {
453+ Endpoint : env .GraphEndpoint ,
454+ Audience : env .GraphEndpoint ,
455+ },
456+ GalleryURL : {
457+ Endpoint : env .GalleryEndpoint ,
458+ Audience : env .GalleryEndpoint ,
459+ },
460+ AzureStorageURL : {
461+ Endpoint : fmt .Sprintf ("https://%s" , env .StorageEndpointSuffix ),
462+ Audience : fmt .Sprintf ("https://%s" , env .StorageEndpointSuffix ),
463+ },
464+ },
465+ }, nil
466+ }
467+
390468// correlationIDPolicy adds the "x-ms-correlation-request-id" header to requests.
391469// It implements the policy.Policy interface.
392470type correlationIDPolicy struct {}
@@ -437,3 +515,9 @@ func GetNormalizedKubernetesName(name string) string {
437515 name = strings .Trim (name , "-" )
438516 return name
439517}
518+
519+ // GetGlobalHTTPClient returns the global HTTP client for custom Azure environments
520+ // This is a wrapper to avoid import cycles by using a global variable approach
521+ func GetGlobalHTTPClient () * http.Client {
522+ return GlobalHTTPClient
523+ }
0 commit comments