diff --git a/api/hypershift/v1beta1/azure.go b/api/hypershift/v1beta1/azure.go index c99523ceedf..6ce044013e4 100644 --- a/api/hypershift/v1beta1/azure.go +++ b/api/hypershift/v1beta1/azure.go @@ -469,6 +469,15 @@ type AzurePlatformSpec struct { // +kubebuilder:validation:MaxLength=255 TenantID string `json:"tenantID"` + // azureContainerRegistryCredentials configures authentication for worker nodes pulling images + // from Azure Container Registry (ACR) using a user-assigned managed identity. + // When set, the identity is attached to worker VM scale sets and its resource ID is written + // into the worker cloud provider config so kubelet's ACR credential provider can authenticate + // without image pull secrets. + // + // +optional + AzureContainerRegistryCredentials AzureContainerRegistryCredentials `json:"azureContainerRegistryCredentials,omitzero"` + // topology specifies the network topology of the API server endpoint for the hosted cluster. // - Public: The API server is accessible only via a public endpoint. // - PublicAndPrivate: The API server is accessible via both public and private endpoints. @@ -546,6 +555,35 @@ type AzureResourceManagedIdentities struct { // +kubebuilder:validation:Pattern=`^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$` type AzureClientID string +// AzureManagedIdentityResourceID is an ARM resource ID for a user-assigned managed identity +// in the format /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{name}. +// +// +kubebuilder:validation:XValidation:rule="self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\\\.managedidentity/userassignedidentities/[^/]+$')",message="must be a user-assigned managed identity ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}" +// +kubebuilder:validation:MinLength=131 +// +kubebuilder:validation:MaxLength=345 +type AzureManagedIdentityResourceID string + +// UserAssignedManagedIdentity identifies a user-assigned managed identity by its ARM resource ID. +type UserAssignedManagedIdentity struct { + // resourceID is the ARM resource ID of the user-assigned managed identity. + // + // +required + ResourceID AzureManagedIdentityResourceID `json:"resourceID,omitempty"` +} + +// AzureContainerRegistryCredentials configures authentication for worker nodes +// pulling images from Azure Container Registry (ACR) using a user-assigned managed identity. +// The identity does not need to be in the same subscription or resource group as the +// HostedCluster, but it must be in the same Azure AD tenant. The management cluster's +// CAPZ identity must have Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action +// on the identity's scope to attach it to worker VM scale sets at creation time. +type AzureContainerRegistryCredentials struct { + // managedIdentity identifies the user-assigned managed identity used for ACR image pulls. + // + // +required + ManagedIdentity UserAssignedManagedIdentity `json:"managedIdentity,omitzero"` +} + // AzureWorkloadIdentities is a struct that contains the client IDs of all the managed identities in self-managed Azure // needing to authenticate with Azure's API. type AzureWorkloadIdentities struct { diff --git a/api/hypershift/v1beta1/zz_generated.deepcopy.go b/api/hypershift/v1beta1/zz_generated.deepcopy.go index d429305a30b..781c071db7a 100644 --- a/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -626,6 +626,22 @@ func (in *AzureAuthenticationConfiguration) DeepCopy() *AzureAuthenticationConfi return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureContainerRegistryCredentials) DeepCopyInto(out *AzureContainerRegistryCredentials) { + *out = *in + out.ManagedIdentity = in.ManagedIdentity +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureContainerRegistryCredentials. +func (in *AzureContainerRegistryCredentials) DeepCopy() *AzureContainerRegistryCredentials { + if in == nil { + return nil + } + out := new(AzureContainerRegistryCredentials) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureKMSKey) DeepCopyInto(out *AzureKMSKey) { *out = *in @@ -724,6 +740,7 @@ func (in *AzureNodePoolPlatform) DeepCopy() *AzureNodePoolPlatform { func (in *AzurePlatformSpec) DeepCopyInto(out *AzurePlatformSpec) { *out = *in in.AzureAuthenticationConfig.DeepCopyInto(&out.AzureAuthenticationConfig) + out.AzureContainerRegistryCredentials = in.AzureContainerRegistryCredentials in.Private.DeepCopyInto(&out.Private) } @@ -4587,6 +4604,21 @@ func (in *UnmanagedEtcdSpec) DeepCopy() *UnmanagedEtcdSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserAssignedManagedIdentity) DeepCopyInto(out *UserAssignedManagedIdentity) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserAssignedManagedIdentity. +func (in *UserAssignedManagedIdentity) DeepCopy() *UserAssignedManagedIdentity { + if in == nil { + return nil + } + out := new(UserAssignedManagedIdentity) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UserManagedDiagnostics) DeepCopyInto(out *UserManagedDiagnostics) { *out = *in diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml index 22b383a3c21..0cecf6b1f3e 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml @@ -5112,6 +5112,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml index f99005f1281..4356e6cf411 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -5103,6 +5103,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml index 1da5b5fa2d8..88941a0f2e4 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml @@ -5123,6 +5123,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml index 671a13070ef..709cb2e74ad 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml @@ -5435,6 +5435,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml index 41fdf2b00ea..e244a5ed4bc 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml @@ -5575,6 +5575,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml index 982e31ce12c..9048d463824 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml @@ -5566,6 +5566,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml index 9fea3f3cbf4..0480cf9aad0 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml @@ -5103,6 +5103,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml index 0c3039f547c..d3bb9eea2ea 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml @@ -5168,6 +5168,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml index adf8433228e..11f87bae948 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml @@ -5125,6 +5125,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml index ad4572617a6..5a0bbe9a5c9 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml @@ -5121,6 +5121,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml index 99ada505a92..05cbfe73e53 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml @@ -5179,6 +5179,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml index a6a9168091f..e98a13afb88 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml @@ -5103,6 +5103,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/TLSAdherence.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/TLSAdherence.yaml index 83b399282a0..8cb983b1332 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/TLSAdherence.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/TLSAdherence.yaml @@ -5143,6 +5143,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml index 873dd1d3b53..d3bfc773e1d 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml @@ -4992,6 +4992,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml index 81e5c722d2d..b62112ee3a9 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -4983,6 +4983,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml index 33eacd58b50..d35e1c65698 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml @@ -5003,6 +5003,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml index 44ad9d8ed2b..0190bd965d6 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml @@ -5315,6 +5315,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml index 968290ae2fa..1fa3bb1f0c5 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml @@ -5455,6 +5455,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml index 4b868e1a3ef..c446f456c50 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml @@ -5446,6 +5446,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml index 53291008cc1..4d36575b6d8 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml @@ -4983,6 +4983,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml index e4450913ffa..f5880ebcca4 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml @@ -5048,6 +5048,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml index 6fe328d94dd..c9c1be391e9 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml @@ -5005,6 +5005,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml index 8760da61721..f91758c70dd 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml @@ -5001,6 +5001,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml index e5d2caea650..2734bb62479 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml @@ -5059,6 +5059,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml index 22f92db2537..49e5f34f230 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml @@ -4983,6 +4983,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml index 30962b18779..2ba52d85c5d 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml @@ -5023,6 +5023,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/client/applyconfiguration/hypershift/v1beta1/azurecontainerregistrycredentials.go b/client/applyconfiguration/hypershift/v1beta1/azurecontainerregistrycredentials.go new file mode 100644 index 00000000000..4f90cd042eb --- /dev/null +++ b/client/applyconfiguration/hypershift/v1beta1/azurecontainerregistrycredentials.go @@ -0,0 +1,38 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +// AzureContainerRegistryCredentialsApplyConfiguration represents a declarative configuration of the AzureContainerRegistryCredentials type for use +// with apply. +type AzureContainerRegistryCredentialsApplyConfiguration struct { + ManagedIdentity *UserAssignedManagedIdentityApplyConfiguration `json:"managedIdentity,omitempty"` +} + +// AzureContainerRegistryCredentialsApplyConfiguration constructs a declarative configuration of the AzureContainerRegistryCredentials type for use with +// apply. +func AzureContainerRegistryCredentials() *AzureContainerRegistryCredentialsApplyConfiguration { + return &AzureContainerRegistryCredentialsApplyConfiguration{} +} + +// WithManagedIdentity sets the ManagedIdentity field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedIdentity field is set to the value of the last call. +func (b *AzureContainerRegistryCredentialsApplyConfiguration) WithManagedIdentity(value *UserAssignedManagedIdentityApplyConfiguration) *AzureContainerRegistryCredentialsApplyConfiguration { + b.ManagedIdentity = value + return b +} diff --git a/client/applyconfiguration/hypershift/v1beta1/azureplatformspec.go b/client/applyconfiguration/hypershift/v1beta1/azureplatformspec.go index 5eb798c50dc..77cfb859e5e 100644 --- a/client/applyconfiguration/hypershift/v1beta1/azureplatformspec.go +++ b/client/applyconfiguration/hypershift/v1beta1/azureplatformspec.go @@ -24,17 +24,18 @@ import ( // AzurePlatformSpecApplyConfiguration represents a declarative configuration of the AzurePlatformSpec type for use // with apply. type AzurePlatformSpecApplyConfiguration struct { - Cloud *string `json:"cloud,omitempty"` - Location *string `json:"location,omitempty"` - ResourceGroupName *string `json:"resourceGroup,omitempty"` - VnetID *string `json:"vnetID,omitempty"` - SubnetID *string `json:"subnetID,omitempty"` - SubscriptionID *string `json:"subscriptionID,omitempty"` - SecurityGroupID *string `json:"securityGroupID,omitempty"` - AzureAuthenticationConfig *AzureAuthenticationConfigurationApplyConfiguration `json:"azureAuthenticationConfig,omitempty"` - TenantID *string `json:"tenantID,omitempty"` - Topology *hypershiftv1beta1.AzureTopologyType `json:"topology,omitempty"` - Private *AzurePrivateSpecApplyConfiguration `json:"private,omitempty"` + Cloud *string `json:"cloud,omitempty"` + Location *string `json:"location,omitempty"` + ResourceGroupName *string `json:"resourceGroup,omitempty"` + VnetID *string `json:"vnetID,omitempty"` + SubnetID *string `json:"subnetID,omitempty"` + SubscriptionID *string `json:"subscriptionID,omitempty"` + SecurityGroupID *string `json:"securityGroupID,omitempty"` + AzureAuthenticationConfig *AzureAuthenticationConfigurationApplyConfiguration `json:"azureAuthenticationConfig,omitempty"` + TenantID *string `json:"tenantID,omitempty"` + AzureContainerRegistryCredentials *AzureContainerRegistryCredentialsApplyConfiguration `json:"azureContainerRegistryCredentials,omitempty"` + Topology *hypershiftv1beta1.AzureTopologyType `json:"topology,omitempty"` + Private *AzurePrivateSpecApplyConfiguration `json:"private,omitempty"` } // AzurePlatformSpecApplyConfiguration constructs a declarative configuration of the AzurePlatformSpec type for use with @@ -115,6 +116,14 @@ func (b *AzurePlatformSpecApplyConfiguration) WithTenantID(value string) *AzureP return b } +// WithAzureContainerRegistryCredentials sets the AzureContainerRegistryCredentials field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the AzureContainerRegistryCredentials field is set to the value of the last call. +func (b *AzurePlatformSpecApplyConfiguration) WithAzureContainerRegistryCredentials(value *AzureContainerRegistryCredentialsApplyConfiguration) *AzurePlatformSpecApplyConfiguration { + b.AzureContainerRegistryCredentials = value + return b +} + // WithTopology sets the Topology field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Topology field is set to the value of the last call. diff --git a/client/applyconfiguration/hypershift/v1beta1/userassignedmanagedidentity.go b/client/applyconfiguration/hypershift/v1beta1/userassignedmanagedidentity.go new file mode 100644 index 00000000000..cc7cd0c7438 --- /dev/null +++ b/client/applyconfiguration/hypershift/v1beta1/userassignedmanagedidentity.go @@ -0,0 +1,42 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + hypershiftv1beta1 "github.com/openshift/hypershift/api/hypershift/v1beta1" +) + +// UserAssignedManagedIdentityApplyConfiguration represents a declarative configuration of the UserAssignedManagedIdentity type for use +// with apply. +type UserAssignedManagedIdentityApplyConfiguration struct { + ResourceID *hypershiftv1beta1.AzureManagedIdentityResourceID `json:"resourceID,omitempty"` +} + +// UserAssignedManagedIdentityApplyConfiguration constructs a declarative configuration of the UserAssignedManagedIdentity type for use with +// apply. +func UserAssignedManagedIdentity() *UserAssignedManagedIdentityApplyConfiguration { + return &UserAssignedManagedIdentityApplyConfiguration{} +} + +// WithResourceID sets the ResourceID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceID field is set to the value of the last call. +func (b *UserAssignedManagedIdentityApplyConfiguration) WithResourceID(value hypershiftv1beta1.AzureManagedIdentityResourceID) *UserAssignedManagedIdentityApplyConfiguration { + b.ResourceID = &value + return b +} diff --git a/client/applyconfiguration/utils.go b/client/applyconfiguration/utils.go index 77e8b9c056b..244e085b282 100644 --- a/client/applyconfiguration/utils.go +++ b/client/applyconfiguration/utils.go @@ -109,6 +109,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &hypershiftv1beta1.AWSSharedVPCRolesRefApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("AzureAuthenticationConfiguration"): return &hypershiftv1beta1.AzureAuthenticationConfigurationApplyConfiguration{} + case v1beta1.SchemeGroupVersion.WithKind("AzureContainerRegistryCredentials"): + return &hypershiftv1beta1.AzureContainerRegistryCredentialsApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("AzureKMSKey"): return &hypershiftv1beta1.AzureKMSKeyApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("AzureKMSSpec"): @@ -405,6 +407,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &hypershiftv1beta1.TaintApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("UnmanagedEtcdSpec"): return &hypershiftv1beta1.UnmanagedEtcdSpecApplyConfiguration{} + case v1beta1.SchemeGroupVersion.WithKind("UserAssignedManagedIdentity"): + return &hypershiftv1beta1.UserAssignedManagedIdentityApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("UserManagedDiagnostics"): return &hypershiftv1beta1.UserManagedDiagnosticsApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("Volume"): diff --git a/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml b/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml index ed9896396e9..1f8bfb9ac2c 100644 --- a/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml +++ b/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml @@ -813,3 +813,638 @@ tests: type: Route route: {} expectedError: "workloadIdentities.controlPlaneOperator is required when Private Link is configured with WorkloadIdentities authentication" + + # --- ACR image pull managed identity validation --- + - name: When azureContainerRegistryCredentials has valid ARM resource ID it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureContainerRegistryCredentials: + managedIdentity: + resourceID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity" + + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + + - name: When azureContainerRegistryCredentials has lowercase ARM segments it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureContainerRegistryCredentials: + managedIdentity: + resourceID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourcegroups/test-rg/providers/microsoft.managedidentity/userassignedidentities/test-identity" + + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + + - name: When azureContainerRegistryCredentials has invalid resource ID format it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureContainerRegistryCredentials: + managedIdentity: + resourceID: "not-a-valid-resource-id" + + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "must be a user-assigned managed identity ARM resource ID in the format" + + - name: When azureContainerRegistryCredentials has wrong provider namespace it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureContainerRegistryCredentials: + managedIdentity: + resourceID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachines/test-vm" + + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "must be a user-assigned managed identity ARM resource ID in the format" + + - name: When azureContainerRegistryCredentials has trailing slash it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureContainerRegistryCredentials: + managedIdentity: + resourceID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity/" + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "must be a user-assigned managed identity ARM resource ID in the format" + + onUpdate: + - name: When azureContainerRegistryCredentials is removed after creation it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureContainerRegistryCredentials: + managedIdentity: + resourceID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity" + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + updated: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + azureAuthenticationConfig: + azureAuthenticationConfigType: ManagedIdentities + managedIdentities: + controlPlane: + managedIdentitiesKeyVault: + name: test-kv + tenantID: "87654321-4321-8765-2109-876543210987" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cloud-provider-secret + objectEncoding: utf-8 + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: node-pool-secret + objectEncoding: utf-8 + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: cpo-secret + objectEncoding: utf-8 + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: image-registry-secret + objectEncoding: utf-8 + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: ingress-secret + objectEncoding: utf-8 + network: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: network-secret + objectEncoding: utf-8 + disk: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: disk-secret + objectEncoding: utf-8 + file: + clientID: "12345678-1234-5678-9012-123456789012" + credentialsSecretName: file-secret + objectEncoding: utf-8 + dataPlane: + imageRegistryMSIClientID: "12345678-1234-5678-9012-123456789012" + diskMSIClientID: "12345678-1234-5678-9012-123456789012" + fileMSIClientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "" diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml index de809fbb3ce..95194c67d02 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml @@ -5954,6 +5954,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml index a31f9f8a02f..df55eedbda1 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml @@ -5604,6 +5604,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml index 3734ababc04..03e2c9ff999 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml @@ -5825,6 +5825,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml index b3be64d7b3b..2e6bba093b3 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml @@ -5834,6 +5834,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml index 6f530195fc0..103bf9ff42b 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml @@ -5484,6 +5484,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml index 26ee13c9605..2c8638f72bd 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml @@ -5705,6 +5705,34 @@ spec: is WorkloadIdentities, and forbidden otherwise rule: 'self.azureAuthenticationConfigType == ''WorkloadIdentities'' ? has(self.workloadIdentities) : !has(self.workloadIdentities)' + azureContainerRegistryCredentials: + description: |- + azureContainerRegistryCredentials configures authentication for worker nodes pulling images + from Azure Container Registry (ACR) using a user-assigned managed identity. + When set, the identity is attached to worker VM scale sets and its resource ID is written + into the worker cloud provider config so kubelet's ACR credential provider can authenticate + without image pull secrets. + properties: + managedIdentity: + description: managedIdentity identifies the user-assigned + managed identity used for ACR image pulls. + properties: + resourceID: + description: resourceID is the ARM resource ID of + the user-assigned managed identity. + maxLength: 345 + minLength: 131 + type: string + x-kubernetes-validations: + - message: must be a user-assigned managed identity + ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} + rule: self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\.managedidentity/userassignedidentities/[^/]+$') + required: + - resourceID + type: object + required: + - managedIdentity + type: object cloud: default: AzurePublicCloud description: 'cloud is the cloud environment identifier, valid diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go index 060fee3aeb2..1415bd3e505 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go @@ -28,6 +28,10 @@ func adaptConfig(cpContext component.WorkloadContext, cm *corev1.ConfigMap) erro return err } + if cpContext.HCP.Spec.Platform.Azure != nil && cpContext.HCP.Spec.Platform.Azure.AzureContainerRegistryCredentials.ManagedIdentity.ResourceID != "" { + cfg.UserAssignedIdentityID = string(cpContext.HCP.Spec.Platform.Azure.AzureContainerRegistryCredentials.ManagedIdentity.ResourceID) + } + serializedConfig, err := json.MarshalIndent(cfg, "", " ") if err != nil { return fmt.Errorf("failed to serialize cloudconfig: %w", err) @@ -199,4 +203,5 @@ type AzureConfig struct { ClusterServiceLoadBalancerHealthProbeMode string `json:"clusterServiceLoadBalancerHealthProbeMode"` ClusterServiceSharedLoadBalancerHealthProbePath string `json:"clusterServiceSharedLoadBalancerHealthProbePath,omitempty"` ClusterServiceSharedLoadBalancerHealthProbePort int32 `json:"clusterServiceSharedLoadBalancerHealthProbePort,omitempty"` + UserAssignedIdentityID string `json:"userAssignedIdentityID,omitempty"` } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config_test.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config_test.go index 54a59389e2a..e918b1b17ed 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config_test.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config_test.go @@ -77,6 +77,61 @@ func newTestHCP(annotations map[string]string) *hyperv1.HostedControlPlane { } } +func TestConfigWithAcrMI(t *testing.T) { + hcp := newTestHCP(nil) + hcp.Namespace = "HCP_NAMESPACE" + hcp.Spec.Platform.Azure.AzureContainerRegistryCredentials = hyperv1.AzureContainerRegistryCredentials{ + ManagedIdentity: hyperv1.UserAssignedManagedIdentity{ + ResourceID: "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-mi", + }, + } + + cm := &corev1.ConfigMap{} + _, _, err := assets.LoadManifestInto(ComponentName, "config.yaml", cm) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + cpContext := component.WorkloadContext{ + HCP: hcp, + } + err = adaptConfig(cpContext, cm) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + yaml, err := k8sutil.SerializeResource(cm, api.Scheme) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + testutil.CompareWithFixture(t, yaml) +} + +func TestConfigSecretDoesNotContainAcrMI(t *testing.T) { + hcp := newTestHCP(nil) + hcp.Namespace = "HCP_NAMESPACE" + hcp.Spec.Platform.Azure.AzureContainerRegistryCredentials = hyperv1.AzureContainerRegistryCredentials{ + ManagedIdentity: hyperv1.UserAssignedManagedIdentity{ + ResourceID: "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-mi", + }, + } + + secret := &corev1.Secret{ + Data: map[string][]byte{}, + } + cpContext := component.WorkloadContext{ + HCP: hcp, + } + err := adaptConfigSecret(cpContext, secret) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + cloudConf := string(secret.Data[ConfigKey]) + if strings.Contains(cloudConf, "userAssignedIdentityID") { + t.Fatalf("CP secret should NOT contain userAssignedIdentityID, got: %s", cloudConf) + } +} + func TestConfigErrorStates(t *testing.T) { tests := []struct { name string diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/testdata/zz_fixture_TestConfigWithAcrMI.yaml b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/testdata/zz_fixture_TestConfigWithAcrMI.yaml new file mode 100644 index 00000000000..2427db2e7f7 --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/testdata/zz_fixture_TestConfigWithAcrMI.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +data: + cloud.conf: |- + { + "cloud": "AzurePublicCloud", + "tenantId": "my-tenant-id", + "useManagedIdentityExtension": false, + "useFederatedWorkloadIdentityExtension": true, + "subscriptionId": "my-subscription-id", + "aadClientId": "my-client-id", + "aadClientSecret": "", + "aadClientCertPath": "", + "aadFederatedTokenFile": "/var/run/secrets/openshift/serviceaccount/token", + "aadMSIDataPlaneIdentityPath": "", + "resourceGroup": "my-resource-group", + "location": "eastus", + "vnetName": "my-vnet", + "vnetResourceGroup": "my-vnet-rg", + "subnetName": "my-subnet", + "securityGroupName": "my-security-group", + "securityGroupResourceGroup": "my-sg-rg", + "routeTableName": "", + "cloudProviderBackoff": true, + "cloudProviderBackoffDuration": 6, + "useInstanceMetadata": true, + "loadBalancerSku": "standard", + "disableOutboundSNAT": true, + "loadBalancerName": "my-infra-ID", + "clusterServiceLoadBalancerHealthProbeMode": "shared", + "userAssignedIdentityID": "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-mi" + } +kind: ConfigMap +metadata: + name: azure-cloud-config diff --git a/docs/content/reference/aggregated-docs.md b/docs/content/reference/aggregated-docs.md index e096fde8b08..7738119ca7a 100644 --- a/docs/content/reference/aggregated-docs.md +++ b/docs/content/reference/aggregated-docs.md @@ -35682,6 +35682,42 @@ This is only valid for self-managed Azure.

AzureClientID is a string that represents the client ID of a managed identity.

+###AzureContainerRegistryCredentials { #hypershift.openshift.io/v1beta1.AzureContainerRegistryCredentials } +

+(Appears on: +AzurePlatformSpec) +

+

+

AzureContainerRegistryCredentials configures authentication for worker nodes +pulling images from Azure Container Registry (ACR) using a user-assigned managed identity. +The identity does not need to be in the same subscription or resource group as the +HostedCluster, but it must be in the same Azure AD tenant. The management cluster’s +CAPZ identity must have Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action +on the identity’s scope to attach it to worker VM scale sets at creation time.

+

+ + + + + + + + + + + + + +
FieldDescription
+managedIdentity,omitzero
+ + +UserAssignedManagedIdentity + + +
+

managedIdentity identifies the user-assigned managed identity used for ACR image pulls.

+
###AzureDiagnosticsStorageAccountType { #hypershift.openshift.io/v1beta1.AzureDiagnosticsStorageAccountType }

(Appears on: @@ -35911,6 +35947,15 @@ and traffic must be routed through the private router (Swift).

+###AzureManagedIdentityResourceID { #hypershift.openshift.io/v1beta1.AzureManagedIdentityResourceID } +

+(Appears on: +UserAssignedManagedIdentity) +

+

+

AzureManagedIdentityResourceID is an ARM resource ID for a user-assigned managed identity +in the format /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{name}.

+

###AzureMarketplaceImage { #hypershift.openshift.io/v1beta1.AzureMarketplaceImage }

(Appears on: @@ -36379,6 +36424,24 @@ string +azureContainerRegistryCredentials,omitzero
+ + +AzureContainerRegistryCredentials + + + + +(Optional) +

azureContainerRegistryCredentials configures authentication for worker nodes pulling images +from Azure Container Registry (ACR) using a user-assigned managed identity. +When set, the identity is attached to worker VM scale sets and its resource ID is written +into the worker cloud provider config so kubelet’s ACR credential provider can authenticate +without image pull secrets.

+ + + + topology
@@ -48842,6 +48905,37 @@ capacity.

+###UserAssignedManagedIdentity { #hypershift.openshift.io/v1beta1.UserAssignedManagedIdentity } +

+(Appears on: +AzureContainerRegistryCredentials) +

+

+

UserAssignedManagedIdentity identifies a user-assigned managed identity by its ARM resource ID.

+

+ + + + + + + + + + + + + +
FieldDescription
+resourceID
+ + +AzureManagedIdentityResourceID + + +
+

resourceID is the ARM resource ID of the user-assigned managed identity.

+
###UserManagedDiagnostics { #hypershift.openshift.io/v1beta1.UserManagedDiagnostics }

(Appears on: diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md index 5de01ff9124..1d892f0b504 100644 --- a/docs/content/reference/api.md +++ b/docs/content/reference/api.md @@ -3244,6 +3244,42 @@ This is only valid for self-managed Azure.

AzureClientID is a string that represents the client ID of a managed identity.

+###AzureContainerRegistryCredentials { #hypershift.openshift.io/v1beta1.AzureContainerRegistryCredentials } +

+(Appears on: +AzurePlatformSpec) +

+

+

AzureContainerRegistryCredentials configures authentication for worker nodes +pulling images from Azure Container Registry (ACR) using a user-assigned managed identity. +The identity does not need to be in the same subscription or resource group as the +HostedCluster, but it must be in the same Azure AD tenant. The management cluster’s +CAPZ identity must have Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action +on the identity’s scope to attach it to worker VM scale sets at creation time.

+

+ + + + + + + + + + + + + +
FieldDescription
+managedIdentity,omitzero
+ + +UserAssignedManagedIdentity + + +
+

managedIdentity identifies the user-assigned managed identity used for ACR image pulls.

+
###AzureDiagnosticsStorageAccountType { #hypershift.openshift.io/v1beta1.AzureDiagnosticsStorageAccountType }

(Appears on: @@ -3473,6 +3509,15 @@ and traffic must be routed through the private router (Swift).

+###AzureManagedIdentityResourceID { #hypershift.openshift.io/v1beta1.AzureManagedIdentityResourceID } +

+(Appears on: +UserAssignedManagedIdentity) +

+

+

AzureManagedIdentityResourceID is an ARM resource ID for a user-assigned managed identity +in the format /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{name}.

+

###AzureMarketplaceImage { #hypershift.openshift.io/v1beta1.AzureMarketplaceImage }

(Appears on: @@ -3941,6 +3986,24 @@ string +azureContainerRegistryCredentials,omitzero
+ + +AzureContainerRegistryCredentials + + + + +(Optional) +

azureContainerRegistryCredentials configures authentication for worker nodes pulling images +from Azure Container Registry (ACR) using a user-assigned managed identity. +When set, the identity is attached to worker VM scale sets and its resource ID is written +into the worker cloud provider config so kubelet’s ACR credential provider can authenticate +without image pull secrets.

+ + + + topology
@@ -16404,6 +16467,37 @@ capacity.

+###UserAssignedManagedIdentity { #hypershift.openshift.io/v1beta1.UserAssignedManagedIdentity } +

+(Appears on: +AzureContainerRegistryCredentials) +

+

+

UserAssignedManagedIdentity identifies a user-assigned managed identity by its ARM resource ID.

+

+ + + + + + + + + + + + + +
FieldDescription
+resourceID
+ + +AzureManagedIdentityResourceID + + +
+

resourceID is the ARM resource ID of the user-assigned managed identity.

+
###UserManagedDiagnostics { #hypershift.openshift.io/v1beta1.UserManagedDiagnostics }

(Appears on: diff --git a/hypershift-operator/controllers/nodepool/azure.go b/hypershift-operator/controllers/nodepool/azure.go index 404b993d7eb..9bc82f96552 100644 --- a/hypershift-operator/controllers/nodepool/azure.go +++ b/hypershift-operator/controllers/nodepool/azure.go @@ -14,6 +14,7 @@ import ( "k8s.io/utils/ptr" capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + capzutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" "github.com/blang/semver" ) @@ -167,7 +168,7 @@ func getAzureMarketplaceMetadata(releaseImage *releaseinfo.ReleaseImage, arch st return result, nil } -func azureMachineTemplateSpec(nodePool *hyperv1.NodePool) (*capiazure.AzureMachineTemplateSpec, error) { +func azureMachineTemplateSpec(nodePool *hyperv1.NodePool, acrIdentityResourceID string) (*capiazure.AzureMachineTemplateSpec, error) { subnetName, err := azureutil.GetSubnetNameFromSubnetID(nodePool.Spec.Platform.Azure.SubnetID) if err != nil { return nil, fmt.Errorf("failed to determine subnet name for Azure machine: %w", err) @@ -244,6 +245,16 @@ func azureMachineTemplateSpec(nodePool *hyperv1.NodePool) (*capiazure.AzureMachi } } + if acrIdentityResourceID != "" { + azureMachineTemplate.Template.Spec.Identity = capiazure.VMIdentityUserAssigned + azureMachineTemplate.Template.Spec.UserAssignedIdentities = append( + azureMachineTemplate.Template.Spec.UserAssignedIdentities, + capiazure.UserAssignedIdentity{ + ProviderID: capzutil.ProviderIDPrefix + acrIdentityResourceID, + }, + ) + } + azureMachineTemplate.Template.Spec.SSHPublicKey = dummySSHKey return azureMachineTemplate, nil @@ -255,7 +266,12 @@ func (c *CAPI) azureMachineTemplate(_ context.Context, templateNameGenerator fun return nil, fmt.Errorf("failed to apply Azure image defaults: %w", err) } - spec, err := azureMachineTemplateSpec(c.nodePool) + var acrIdentityResourceID string + if c.hostedCluster != nil && c.hostedCluster.Spec.Platform.Azure != nil { + acrIdentityResourceID = string(c.hostedCluster.Spec.Platform.Azure.AzureContainerRegistryCredentials.ManagedIdentity.ResourceID) + } + + spec, err := azureMachineTemplateSpec(c.nodePool, acrIdentityResourceID) if err != nil { return nil, fmt.Errorf("failed to generate AzureMachineTemplateSpec: %w", err) } diff --git a/hypershift-operator/controllers/nodepool/azure_test.go b/hypershift-operator/controllers/nodepool/azure_test.go index 7b5e996ab8f..3c9746a7076 100644 --- a/hypershift-operator/controllers/nodepool/azure_test.go +++ b/hypershift-operator/controllers/nodepool/azure_test.go @@ -22,6 +22,7 @@ func TestAzureMachineTemplateSpec(t *testing.T) { testCases := []struct { name string nodePool *hyperv1.NodePool + acrIdentityResourceID string expectedAzureMachineTemplateSpec *capiazure.AzureMachineTemplateSpec expectedErr bool expectedErrMsg string @@ -507,12 +508,164 @@ func TestAzureMachineTemplateSpec(t *testing.T) { expectedErr: true, expectedErrMsg: "failed to determine subnet name for Azure machine: failed to parse subnet name from \"/subscriptions/testSubscriptionID/resourceGroups/testResourceGroupName/providers/Microsoft.Network/virtualNetworks/testVnetName/subnets/\"", }, + { + name: "When HostedCluster has AzureContainerRegistryCredentials set it should set UserAssigned identity", + nodePool: &hyperv1.NodePool{ + Spec: hyperv1.NodePoolSpec{ + Platform: hyperv1.NodePoolPlatform{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzureNodePoolPlatform{ + Image: hyperv1.AzureVMImage{ + Type: hyperv1.ImageID, + ImageID: ptr.To("testImageID"), + }, + SubnetID: "/subscriptions/testSubscriptionID/resourceGroups/testResourceGroupName/providers/Microsoft.Network/virtualNetworks/testVnetName/subnets/testSubnetName", + VMSize: "Standard_D2_v2", + OSDisk: hyperv1.AzureNodePoolOSDisk{ + SizeGiB: 30, + DiskStorageAccountType: "Standard_LRS", + }, + }, + }, + }, + }, + acrIdentityResourceID: "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-mi", + expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ + Template: capiazure.AzureMachineTemplateResource{ + ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + Spec: capiazure.AzureMachineSpec{ + ProviderID: nil, + VMSize: "Standard_D2_v2", + FailureDomain: nil, + Image: &capiazure.Image{ + ID: ptr.To("testImageID"), + SharedGallery: nil, + Marketplace: nil, + ComputeGallery: nil, + }, + Identity: capiazure.VMIdentityUserAssigned, + UserAssignedIdentities: []capiazure.UserAssignedIdentity{ + {ProviderID: "azure:///subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-mi"}, + }, + SystemAssignedIdentityRole: nil, + RoleAssignmentName: "", + OSDisk: capiazure.OSDisk{ + OSType: "", + DiskSizeGB: ptr.To[int32](30), + ManagedDisk: &capiazure.ManagedDiskParameters{ + StorageAccountType: "Standard_LRS", + DiskEncryptionSet: nil, + SecurityProfile: nil, + }, + DiffDiskSettings: nil, + CachingType: "", + }, + DataDisks: nil, + SSHPublicKey: dummySSHKey, + AdditionalTags: nil, + AdditionalCapabilities: nil, + AllocatePublicIP: false, + EnableIPForwarding: false, + AcceleratedNetworking: nil, + Diagnostics: nil, + SpotVMOptions: nil, + SecurityProfile: nil, + SubnetName: "", + DNSServers: nil, + VMExtensions: nil, + NetworkInterfaces: []capiazure.NetworkInterface{ + { + SubnetName: "testSubnetName", + PrivateIPConfigs: 0, + AcceleratedNetworking: nil, + }, + }, + CapacityReservationGroupID: nil, + }, + }, + }, + expectedErr: false, + }, + { + name: "When HostedCluster has no AzureContainerRegistryCredentials it should not set UserAssigned identity", + nodePool: &hyperv1.NodePool{ + Spec: hyperv1.NodePoolSpec{ + Platform: hyperv1.NodePoolPlatform{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzureNodePoolPlatform{ + Image: hyperv1.AzureVMImage{ + Type: hyperv1.ImageID, + ImageID: ptr.To("testImageID"), + }, + SubnetID: "/subscriptions/testSubscriptionID/resourceGroups/testResourceGroupName/providers/Microsoft.Network/virtualNetworks/testVnetName/subnets/testSubnetName", + VMSize: "Standard_D2_v2", + OSDisk: hyperv1.AzureNodePoolOSDisk{ + SizeGiB: 30, + DiskStorageAccountType: "Standard_LRS", + }, + }, + }, + }, + }, + expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ + Template: capiazure.AzureMachineTemplateResource{ + ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + Spec: capiazure.AzureMachineSpec{ + ProviderID: nil, + VMSize: "Standard_D2_v2", + FailureDomain: nil, + Image: &capiazure.Image{ + ID: ptr.To("testImageID"), + SharedGallery: nil, + Marketplace: nil, + ComputeGallery: nil, + }, + UserAssignedIdentities: nil, + SystemAssignedIdentityRole: nil, + RoleAssignmentName: "", + OSDisk: capiazure.OSDisk{ + OSType: "", + DiskSizeGB: ptr.To[int32](30), + ManagedDisk: &capiazure.ManagedDiskParameters{ + StorageAccountType: "Standard_LRS", + DiskEncryptionSet: nil, + SecurityProfile: nil, + }, + DiffDiskSettings: nil, + CachingType: "", + }, + DataDisks: nil, + SSHPublicKey: dummySSHKey, + AdditionalTags: nil, + AdditionalCapabilities: nil, + AllocatePublicIP: false, + EnableIPForwarding: false, + AcceleratedNetworking: nil, + Diagnostics: nil, + SpotVMOptions: nil, + SecurityProfile: nil, + SubnetName: "", + DNSServers: nil, + VMExtensions: nil, + NetworkInterfaces: []capiazure.NetworkInterface{ + { + SubnetName: "testSubnetName", + PrivateIPConfigs: 0, + AcceleratedNetworking: nil, + }, + }, + CapacityReservationGroupID: nil, + }, + }, + }, + expectedErr: false, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { g := NewGomegaWithT(t) - azureSpec, err := azureMachineTemplateSpec(tc.nodePool) + azureSpec, err := azureMachineTemplateSpec(tc.nodePool, tc.acrIdentityResourceID) if tc.expectedErr { g.Expect(err.Error()).To(ContainSubstring(tc.expectedErrMsg)) } else { diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go index c99523ceedf..6ce044013e4 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go @@ -469,6 +469,15 @@ type AzurePlatformSpec struct { // +kubebuilder:validation:MaxLength=255 TenantID string `json:"tenantID"` + // azureContainerRegistryCredentials configures authentication for worker nodes pulling images + // from Azure Container Registry (ACR) using a user-assigned managed identity. + // When set, the identity is attached to worker VM scale sets and its resource ID is written + // into the worker cloud provider config so kubelet's ACR credential provider can authenticate + // without image pull secrets. + // + // +optional + AzureContainerRegistryCredentials AzureContainerRegistryCredentials `json:"azureContainerRegistryCredentials,omitzero"` + // topology specifies the network topology of the API server endpoint for the hosted cluster. // - Public: The API server is accessible only via a public endpoint. // - PublicAndPrivate: The API server is accessible via both public and private endpoints. @@ -546,6 +555,35 @@ type AzureResourceManagedIdentities struct { // +kubebuilder:validation:Pattern=`^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$` type AzureClientID string +// AzureManagedIdentityResourceID is an ARM resource ID for a user-assigned managed identity +// in the format /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{name}. +// +// +kubebuilder:validation:XValidation:rule="self.lowerAscii().matches('^/subscriptions/[^/]+/resourcegroups/[^/]+/providers/microsoft\\\\.managedidentity/userassignedidentities/[^/]+$')",message="must be a user-assigned managed identity ARM resource ID in the format /subscriptions/{subscriptionID}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}" +// +kubebuilder:validation:MinLength=131 +// +kubebuilder:validation:MaxLength=345 +type AzureManagedIdentityResourceID string + +// UserAssignedManagedIdentity identifies a user-assigned managed identity by its ARM resource ID. +type UserAssignedManagedIdentity struct { + // resourceID is the ARM resource ID of the user-assigned managed identity. + // + // +required + ResourceID AzureManagedIdentityResourceID `json:"resourceID,omitempty"` +} + +// AzureContainerRegistryCredentials configures authentication for worker nodes +// pulling images from Azure Container Registry (ACR) using a user-assigned managed identity. +// The identity does not need to be in the same subscription or resource group as the +// HostedCluster, but it must be in the same Azure AD tenant. The management cluster's +// CAPZ identity must have Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action +// on the identity's scope to attach it to worker VM scale sets at creation time. +type AzureContainerRegistryCredentials struct { + // managedIdentity identifies the user-assigned managed identity used for ACR image pulls. + // + // +required + ManagedIdentity UserAssignedManagedIdentity `json:"managedIdentity,omitzero"` +} + // AzureWorkloadIdentities is a struct that contains the client IDs of all the managed identities in self-managed Azure // needing to authenticate with Azure's API. type AzureWorkloadIdentities struct { diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go index d429305a30b..781c071db7a 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -626,6 +626,22 @@ func (in *AzureAuthenticationConfiguration) DeepCopy() *AzureAuthenticationConfi return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureContainerRegistryCredentials) DeepCopyInto(out *AzureContainerRegistryCredentials) { + *out = *in + out.ManagedIdentity = in.ManagedIdentity +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureContainerRegistryCredentials. +func (in *AzureContainerRegistryCredentials) DeepCopy() *AzureContainerRegistryCredentials { + if in == nil { + return nil + } + out := new(AzureContainerRegistryCredentials) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureKMSKey) DeepCopyInto(out *AzureKMSKey) { *out = *in @@ -724,6 +740,7 @@ func (in *AzureNodePoolPlatform) DeepCopy() *AzureNodePoolPlatform { func (in *AzurePlatformSpec) DeepCopyInto(out *AzurePlatformSpec) { *out = *in in.AzureAuthenticationConfig.DeepCopyInto(&out.AzureAuthenticationConfig) + out.AzureContainerRegistryCredentials = in.AzureContainerRegistryCredentials in.Private.DeepCopyInto(&out.Private) } @@ -4587,6 +4604,21 @@ func (in *UnmanagedEtcdSpec) DeepCopy() *UnmanagedEtcdSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserAssignedManagedIdentity) DeepCopyInto(out *UserAssignedManagedIdentity) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserAssignedManagedIdentity. +func (in *UserAssignedManagedIdentity) DeepCopy() *UserAssignedManagedIdentity { + if in == nil { + return nil + } + out := new(UserAssignedManagedIdentity) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UserManagedDiagnostics) DeepCopyInto(out *UserManagedDiagnostics) { *out = *in