Skip to content

Commit 84885ce

Browse files
author
Cecile Robert-Michon
committed
🐛 Make role assignment name deterministic
1 parent 121244f commit 84885ce

13 files changed

+149
-7
lines changed

api/v1alpha2/azuremachine_conversion.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func restoreAzureMachineSpec(restored, dst *infrav1alpha3.AzureMachineSpec) {
5353
if len(restored.UserAssignedIdentities) > 0 {
5454
dst.UserAssignedIdentities = restored.UserAssignedIdentities
5555
}
56+
dst.RoleAssignmentName = restored.RoleAssignmentName
5657
if restored.AcceleratedNetworking != nil {
5758
dst.AcceleratedNetworking = restored.AcceleratedNetworking
5859
}

api/v1alpha2/zz_generated.conversion.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha3/azuremachine_default.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha3
1818

1919
import (
2020
"encoding/base64"
21+
"k8s.io/apimachinery/pkg/util/uuid"
2122

2223
"golang.org/x/crypto/ssh"
2324

@@ -73,3 +74,12 @@ func (m *AzureMachine) SetDataDisksDefaults() {
7374
}
7475
}
7576
}
77+
78+
// SetIdentityDefaults sets the defaults for VM Identity.
79+
func (m *AzureMachine) SetIdentityDefaults() {
80+
if m.Spec.Identity == VMIdentitySystemAssigned {
81+
if m.Spec.RoleAssignmentName == "" {
82+
m.Spec.RoleAssignmentName = string(uuid.NewUUID())
83+
}
84+
}
85+
}

api/v1alpha3/azuremachine_default_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha3
1818

1919
import (
2020
"encoding/json"
21+
"github.com/google/uuid"
2122
"reflect"
2223
"testing"
2324

@@ -45,6 +46,38 @@ func TestAzureMachine_SetDefaultSSHPublicKey(t *testing.T) {
4546
g.Expect(publicKeyNotExistTest.machine.Spec.SSHPublicKey).To(Not(BeEmpty()))
4647
}
4748

49+
func TestAzureMachine_SetIdentityDefaults(t *testing.T) {
50+
g := NewWithT(t)
51+
52+
type test struct {
53+
machine *AzureMachine
54+
}
55+
56+
existingRoleAssignmentName := "42862306-e485-4319-9bf0-35dbc6f6fe9c"
57+
roleAssignmentExistTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
58+
Identity: VMIdentitySystemAssigned,
59+
RoleAssignmentName: existingRoleAssignmentName,
60+
}}}
61+
roleAssignmentEmptyTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
62+
Identity: VMIdentitySystemAssigned,
63+
RoleAssignmentName: "",
64+
}}}
65+
notSystemAssignedTest := test{machine: &AzureMachine{Spec: AzureMachineSpec{
66+
Identity: VMIdentityUserAssigned,
67+
}}}
68+
69+
roleAssignmentExistTest.machine.SetIdentityDefaults()
70+
g.Expect(roleAssignmentExistTest.machine.Spec.RoleAssignmentName).To(Equal(existingRoleAssignmentName))
71+
72+
roleAssignmentEmptyTest.machine.SetIdentityDefaults()
73+
g.Expect(roleAssignmentEmptyTest.machine.Spec.RoleAssignmentName).To(Not(BeEmpty()))
74+
_, err := uuid.Parse(roleAssignmentEmptyTest.machine.Spec.RoleAssignmentName)
75+
g.Expect(err).To(Not(HaveOccurred()))
76+
77+
notSystemAssignedTest.machine.SetIdentityDefaults()
78+
g.Expect(notSystemAssignedTest.machine.Spec.RoleAssignmentName).To(BeEmpty())
79+
}
80+
4881
func TestAzureMachine_SetDataDisksDefaults(t *testing.T) {
4982
cases := []struct {
5083
name string

api/v1alpha3/azuremachine_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ type AzureMachineSpec struct {
6666
// +optional
6767
UserAssignedIdentities []UserAssignedIdentity `json:"userAssignedIdentities,omitempty"`
6868

69+
// RoleAssignmentName is the name of the role assignment to create for a system assigned identity. It can be any valid GUID.
70+
// If not specified, a random GUID will be generated.
71+
// +optional
72+
RoleAssignmentName string `json:"roleAssignmentName,omitempty"`
73+
6974
// OSDisk specifies the parameters for the operating system disk of the machine
7075
OSDisk OSDisk `json:"osDisk"`
7176

api/v1alpha3/azuremachine_validation.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package v1alpha3
1919
import (
2020
"encoding/base64"
2121
"fmt"
22+
"github.com/google/uuid"
2223

2324
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
2425
"golang.org/x/crypto/ssh"
@@ -43,6 +44,24 @@ func ValidateSSHKey(sshKey string, fldPath *field.Path) field.ErrorList {
4344
return allErrs
4445
}
4546

47+
// ValidateUserAssignedIdentity validates the user-assigned identities list
48+
func ValidateSystemAssignedIdentity(identityType VMIdentity, old, new string, fldPath *field.Path) field.ErrorList {
49+
allErrs := field.ErrorList{}
50+
51+
if identityType == VMIdentitySystemAssigned {
52+
if _, err := uuid.Parse(new); err != nil {
53+
allErrs = append(allErrs, field.Invalid(fldPath, new, "Role assignment name must be a valid GUID. It is optional and will be auto-generated when not specified."))
54+
}
55+
if old != "" && old != new {
56+
allErrs = append(allErrs, field.Invalid(fldPath, new, "Role assignment name should not be modified after AzureMachine creation."))
57+
}
58+
} else if len(new) != 0 {
59+
allErrs = append(allErrs, field.Forbidden(fldPath, "Role assignment name should only be set when using system assigned identity."))
60+
}
61+
62+
return allErrs
63+
}
64+
4665
// ValidateUserAssignedIdentity validates the user-assigned identities list
4766
func ValidateUserAssignedIdentity(identityType VMIdentity, userAssignedIdenteties []UserAssignedIdentity, fldPath *field.Path) field.ErrorList {
4867
allErrs := field.ErrorList{}

api/v1alpha3/azuremachine_validation_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"crypto/rsa"
2222
"encoding/base64"
2323
"fmt"
24+
"github.com/google/uuid"
2425
"testing"
2526

2627
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
@@ -341,3 +342,58 @@ func TestAzureMachine_ValidateDataDisks(t *testing.T) {
341342
})
342343
}
343344
}
345+
346+
func TestAzureMachine_ValidateSystemAssignedIdentity(t *testing.T) {
347+
g := NewWithT(t)
348+
349+
tests := []struct {
350+
name string
351+
roleAssignmentName string
352+
old string
353+
Identity VMIdentity
354+
wantErr bool
355+
}{
356+
{
357+
name: "valid UUID",
358+
roleAssignmentName: uuid.New().String(),
359+
Identity: VMIdentitySystemAssigned,
360+
wantErr: false,
361+
},
362+
{
363+
name: "wrong Identity type",
364+
roleAssignmentName: uuid.New().String(),
365+
Identity: VMIdentityNone,
366+
wantErr: true,
367+
},
368+
{
369+
name: "not a valid UUID",
370+
roleAssignmentName: "notaguid",
371+
Identity: VMIdentitySystemAssigned,
372+
wantErr: true,
373+
},
374+
{
375+
name: "empty",
376+
roleAssignmentName: "",
377+
Identity: VMIdentitySystemAssigned,
378+
wantErr: true,
379+
},
380+
{
381+
name: "changed",
382+
roleAssignmentName: uuid.New().String(),
383+
old: uuid.New().String(),
384+
Identity: VMIdentitySystemAssigned,
385+
wantErr: true,
386+
},
387+
}
388+
389+
for _, tc := range tests {
390+
t.Run(tc.name, func(t *testing.T) {
391+
err := ValidateSystemAssignedIdentity(tc.Identity, tc.old, tc.roleAssignmentName, field.NewPath("sshPublicKey"))
392+
if tc.wantErr {
393+
g.Expect(err).ToNot(HaveLen(0))
394+
} else {
395+
g.Expect(err).To(HaveLen(0))
396+
}
397+
})
398+
}
399+
}

api/v1alpha3/azuremachine_webhook.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ func (m *AzureMachine) ValidateCreate() error {
5757
allErrs = append(allErrs, errs...)
5858
}
5959

60+
if errs := ValidateSystemAssignedIdentity(m.Spec.Identity, "", m.Spec.RoleAssignmentName, field.NewPath("roleAssignmentName")); len(errs) > 0 {
61+
allErrs = append(allErrs, errs...)
62+
}
63+
6064
if errs := ValidateUserAssignedIdentity(m.Spec.Identity, m.Spec.UserAssignedIdentities, field.NewPath("userAssignedIdentities")); len(errs) > 0 {
6165
allErrs = append(allErrs, errs...)
6266
}
@@ -75,6 +79,7 @@ func (m *AzureMachine) ValidateCreate() error {
7579
func (m *AzureMachine) ValidateUpdate(oldRaw runtime.Object) error {
7680
machinelog.Info("validate update", "name", m.Name)
7781
var allErrs field.ErrorList
82+
old := oldRaw.(*AzureMachine)
7883

7984
if errs := ValidateImage(m.Spec.Image, field.NewPath("image")); len(errs) > 0 {
8085
allErrs = append(allErrs, errs...)
@@ -88,6 +93,10 @@ func (m *AzureMachine) ValidateUpdate(oldRaw runtime.Object) error {
8893
allErrs = append(allErrs, errs...)
8994
}
9095

96+
if errs := ValidateSystemAssignedIdentity(m.Spec.Identity, old.Spec.RoleAssignmentName, m.Spec.RoleAssignmentName, field.NewPath("roleAssignmentName")); len(errs) > 0 {
97+
allErrs = append(allErrs, errs...)
98+
}
99+
91100
if errs := ValidateUserAssignedIdentity(m.Spec.Identity, m.Spec.UserAssignedIdentities, field.NewPath("userAssignedIdentities")); len(errs) > 0 {
92101
allErrs = append(allErrs, errs...)
93102
}
@@ -96,8 +105,6 @@ func (m *AzureMachine) ValidateUpdate(oldRaw runtime.Object) error {
96105
allErrs = append(allErrs, errs...)
97106
}
98107

99-
old := oldRaw.(*AzureMachine)
100-
101108
if errs := ValidateManagedDisk(old.Spec.OSDisk.ManagedDisk, m.Spec.OSDisk.ManagedDisk, field.NewPath("osDisk").Child("managedDisk")); len(errs) > 0 {
102109
allErrs = append(allErrs, errs...)
103110
}
@@ -134,4 +141,6 @@ func (m *AzureMachine) Default() {
134141
}
135142

136143
m.SetDataDisksDefaults()
144+
145+
m.SetIdentityDefaults()
137146
}

cloud/scope/machine.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@ import (
2020
"context"
2121
"encoding/base64"
2222
"encoding/json"
23-
2423
"github.com/Azure/go-autorest/autorest/to"
2524
"github.com/go-logr/logr"
2625
"github.com/pkg/errors"
2726
corev1 "k8s.io/api/core/v1"
2827
"k8s.io/apimachinery/pkg/types"
29-
"k8s.io/apimachinery/pkg/util/uuid"
3028
"k8s.io/klog/klogr"
3129
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3"
3230
azure "sigs.k8s.io/cluster-api-provider-azure/cloud"
@@ -226,7 +224,7 @@ func (m *MachineScope) RoleAssignmentSpecs() []azure.RoleAssignmentSpec {
226224
return []azure.RoleAssignmentSpec{
227225
{
228226
MachineName: m.Name(),
229-
UUID: string(uuid.NewUUID()),
227+
Name: m.AzureMachine.Spec.RoleAssignmentName,
230228
},
231229
}
232230
}

cloud/services/roleassignments/roleassignments.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (s *Service) Reconcile(ctx context.Context) error {
4343
PrincipalID: resultVM.Identity.PrincipalID,
4444
},
4545
}
46-
_, err = s.Client.Create(ctx, scope, roleSpec.UUID, params)
46+
_, err = s.Client.Create(ctx, scope, roleSpec.Name, params)
4747
if err != nil {
4848
return errors.Wrapf(err, "cannot assign role to VM system assigned identity")
4949
}

0 commit comments

Comments
 (0)