Skip to content

Commit

Permalink
Disable local accounts for aks aad clusters
Browse files Browse the repository at this point in the history
  • Loading branch information
LochanRn committed Oct 6, 2023
1 parent b9430aa commit 12f51a5
Show file tree
Hide file tree
Showing 15 changed files with 1,015 additions and 50 deletions.
3 changes: 3 additions & 0 deletions api/v1beta1/azuremanagedcontrolplane_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ type AzureManagedControlPlaneSpec struct {
// Immutable.
// +optional
DNSPrefix *string `json:"dnsPrefix,omitempty"`
// DisableLocalAccounts disables getting static credentials for this cluster when set. Expected to only be used for AAD clusters.
// +optional
DisableLocalAccounts *bool `json:"disableLocalAccounts,omitempty"`
}

// HTTPProxyConfig is the HTTP proxy configuration for the cluster.
Expand Down
38 changes: 38 additions & 0 deletions api/v1beta1/azuremanagedcontrolplane_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,35 @@ func (mw *azureManagedControlPlaneWebhook) ValidateUpdate(ctx context.Context, o
allErrs = append(allErrs, err)
}

if old.Spec.DisableLocalAccounts == nil &&
m.Spec.DisableLocalAccounts != nil &&
m.Spec.AADProfile == nil {
allErrs = append(allErrs,
field.Invalid(
field.NewPath("Spec", "DisableLocalAccounts"),
m.Spec.DisableLocalAccounts,
"DisableLocalAccounts can be set only for AAD enabled clusters"))
}

if old.Spec.DisableLocalAccounts != nil {
// Prevent DisableLocalAccounts modification if it was already set to some value
if m.Spec.DisableLocalAccounts == nil {
// unsetting the field is not allowed
allErrs = append(allErrs,
field.Invalid(
field.NewPath("Spec", "DisableLocalAccounts"),
m.Spec.DisableLocalAccounts,
"field is immutable, unsetting is not allowed"))
} else if *m.Spec.DisableLocalAccounts != *old.Spec.DisableLocalAccounts {
// changing the field is not allowed
allErrs = append(allErrs,
field.Invalid(
field.NewPath("Spec", "DisableLocalAccounts"),
*m.Spec.DisableLocalAccounts,
"field is immutable"))
}
}

// Consider removing this once moves out of preview
// Updating outboundType after cluster creation (PREVIEW)
// https://learn.microsoft.com/en-us/azure/aks/egress-outboundtype#updating-outboundtype-after-cluster-creation-preview
Expand Down Expand Up @@ -306,6 +335,7 @@ func (m *AzureManagedControlPlane) Validate(cli client.Client) error {
m.validateIdentity,
m.validateNetworkPluginMode,
m.validateDNSPrefix,
m.validateDisableLocalAccounts,
}

var errs []error
Expand Down Expand Up @@ -338,6 +368,14 @@ func (m *AzureManagedControlPlane) validateDNSPrefix(_ client.Client) error {
return kerrors.NewAggregate(allErrs.ToAggregate().Errors())
}

// validateVersion disabling local accounts for AAD based clusters.
func (m *AzureManagedControlPlane) validateDisableLocalAccounts(_ client.Client) error {
if m.Spec.DisableLocalAccounts != nil && m.Spec.AADProfile == nil {
return errors.New("DisableLocalAccounts should be set only for AAD enabled clusters")
}
return nil
}

// validateVersion validates the Kubernetes version.
func (m *AzureManagedControlPlane) validateVersion(_ client.Client) error {
if !kubeSemver.MatchString(m.Spec.Version) {
Expand Down
133 changes: 133 additions & 0 deletions api/v1beta1/azuremanagedcontrolplane_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,30 @@ func TestAzureManagedControlPlane_ValidateCreate(t *testing.T) {
},
wantErr: false,
},
{
name: "DisableLocalAccounts cannot be set for non AAD clusters",
amcp: &AzureManagedControlPlane{
Spec: AzureManagedControlPlaneSpec{
Version: "v1.21.2",
DisableLocalAccounts: ptr.To[bool](true),
},
},
wantErr: true,
},
{
name: "DisableLocalAccounts can be set for AAD clusters",
amcp: &AzureManagedControlPlane{
Spec: AzureManagedControlPlaneSpec{
Version: "v1.21.2",
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
DisableLocalAccounts: ptr.To[bool](true),
},
},
wantErr: false,
},
}
client := mockClient{ReturnError: false}
for _, tc := range tests {
Expand Down Expand Up @@ -1715,6 +1739,94 @@ func TestAzureManagedControlPlane_ValidateUpdate(t *testing.T) {
},
wantErr: false,
},
{
name: "DisableLocalAccounts can be set only for AAD enabled clusters",
oldAMCP: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
},
},
amcp: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
DisableLocalAccounts: ptr.To[bool](true),
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
},
},
wantErr: false,
},
{
name: "DisableLocalAccounts cannot be disabled",
oldAMCP: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
DisableLocalAccounts: ptr.To[bool](true),
},
},
amcp: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
},
},
wantErr: true,
},
{
name: "DisableLocalAccounts cannot be disabled",
oldAMCP: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
DisableLocalAccounts: ptr.To[bool](true),
},
},
amcp: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
DisableLocalAccounts: ptr.To[bool](false),
AADProfile: &AADProfile{
Managed: true,
AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
},
},
},
wantErr: true,
},
{
name: "AzureManagedControlPlane DNSPrefix is immutable error nil -> capz-aks",
oldAMCP: &AzureManagedControlPlane{
Expand All @@ -1731,6 +1843,27 @@ func TestAzureManagedControlPlane_ValidateUpdate(t *testing.T) {
},
wantErr: true,
},
{
name: "DisableLocalAccounts cannot be set for non AAD clusters",
oldAMCP: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
},
},
amcp: &AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
},
Spec: AzureManagedControlPlaneSpec{
Version: "v1.18.0",
DisableLocalAccounts: ptr.To[bool](true),
},
},
wantErr: true,
},
{
name: "AzureManagedControlPlane DNSPrefix is immutable error nil -> empty",
oldAMCP: &AzureManagedControlPlane{
Expand Down
6 changes: 6 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 42 additions & 10 deletions azure/scope/managedcontrolplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ func NewManagedControlPlaneScope(ctx context.Context, params ManagedControlPlane

// ManagedControlPlaneScope defines the basic context for an actuator to operate upon.
type ManagedControlPlaneScope struct {
Client client.Client
patchHelper *patch.Helper
kubeConfigData []byte
cache *ManagedControlPlaneCache
Client client.Client
patchHelper *patch.Helper
adminKubeConfigData []byte
userKubeConfigData []byte
cache *ManagedControlPlaneCache

AzureClients
Cluster *clusterv1.Cluster
Expand Down Expand Up @@ -459,6 +460,24 @@ func (s *ManagedControlPlaneScope) ManagedClusterAnnotations() map[string]string
return s.ControlPlane.Annotations
}

// IsLocalAcountsDisabled checks if local accounts are disabled for aad enabled managed clusters.
func (s *ManagedControlPlaneScope) IsLocalAcountsDisabled() bool {
if s.IsAADEnabled() &&
s.ControlPlane.Spec.DisableLocalAccounts != nil &&
*s.ControlPlane.Spec.DisableLocalAccounts {
return true
}
return false
}

// IsAADEnabled checks if azure active directory is enabled for managed clusters.
func (s *ManagedControlPlaneScope) IsAADEnabled() bool {
if s.ControlPlane.Spec.AADProfile != nil && s.ControlPlane.Spec.AADProfile.Managed {
return true
}
return false
}

// ManagedClusterSpec returns the managed cluster spec.
func (s *ManagedControlPlaneScope) ManagedClusterSpec() azure.ResourceSpecGetter {
managedClusterSpec := managedclusters.ManagedClusterSpec{
Expand Down Expand Up @@ -513,6 +532,9 @@ func (s *ManagedControlPlaneScope) ManagedClusterSpec() azure.ResourceSpecGetter
EnableAzureRBAC: s.ControlPlane.Spec.AADProfile.Managed,
AdminGroupObjectIDs: s.ControlPlane.Spec.AADProfile.AdminGroupObjectIDs,
}
if s.ControlPlane.Spec.DisableLocalAccounts != nil {
managedClusterSpec.DisableLocalAccounts = s.ControlPlane.Spec.DisableLocalAccounts
}
}

if s.ControlPlane.Spec.AddonProfiles != nil {
Expand Down Expand Up @@ -640,14 +662,24 @@ func (s *ManagedControlPlaneScope) MakeEmptyKubeConfigSecret() corev1.Secret {
}
}

// GetKubeConfigData returns a []byte that contains kubeconfig.
func (s *ManagedControlPlaneScope) GetKubeConfigData() []byte {
return s.kubeConfigData
// GetAdminKubeconfigData returns admin kubeconfig.
func (s *ManagedControlPlaneScope) GetAdminKubeconfigData() []byte {
return s.adminKubeConfigData
}

// SetAdminKubeconfigData sets admin kubeconfig data.
func (s *ManagedControlPlaneScope) SetAdminKubeconfigData(kubeConfigData []byte) {
s.adminKubeConfigData = kubeConfigData
}

// GetUserKubeconfigData returns user kubeconfig, required when using AAD with AKS cluster.
func (s *ManagedControlPlaneScope) GetUserKubeconfigData() []byte {
return s.userKubeConfigData
}

// SetKubeConfigData sets kubeconfig data.
func (s *ManagedControlPlaneScope) SetKubeConfigData(kubeConfigData []byte) {
s.kubeConfigData = kubeConfigData
// SetUserKubeconfigData sets userKubeconfig data.
func (s *ManagedControlPlaneScope) SetUserKubeconfigData(kubeConfigData []byte) {
s.userKubeConfigData = kubeConfigData
}

// SetKubeletIdentity sets the ID of the user-assigned identity for kubelet if not already set.
Expand Down
Loading

0 comments on commit 12f51a5

Please sign in to comment.