Skip to content

Commit 5619e9f

Browse files
authored
Add option to create service account for pod identities which defaults to false (#7784)
* only create service account if explicitly instructed to do so * only delete SAs if they were created by eksctl * fix lint
1 parent 2974871 commit 5619e9f

File tree

12 files changed

+69
-46
lines changed

12 files changed

+69
-46
lines changed

examples/39-pod-identity-association.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ iam:
2020
# roleARN is given, eksctl will only create the pod identity association
2121
- namespace: default
2222
serviceAccountName: s3-reader
23+
createServiceAccount: true # default is false
2324
roleARN: arn:aws:iam::111122223333:role/role-1
2425

2526
# roleARN is not given, eksctl will first create an IAM role with given roleName using:

pkg/actions/podidentityassociation/creator.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,20 @@ func (c *Creator) CreateTasks(ctx context.Context, podIdentityAssociations []api
6060
stackCreator: c.stackCreator,
6161
})
6262
}
63-
piaCreationTasks.Append(&tasks.GenericTask{
64-
Description: fmt.Sprintf("create service account %q, if it does not already exist", pia.NameString()),
65-
Doer: func() error {
66-
if err := kubernetes.MaybeCreateServiceAccountOrUpdateMetadata(c.clientSet, v1.ObjectMeta{
67-
Name: pia.ServiceAccountName,
68-
Namespace: pia.Namespace,
69-
}); err != nil {
70-
return fmt.Errorf("failed to create service account %q: %w", pia.NameString(), err)
71-
}
72-
return nil
73-
},
74-
})
63+
if pia.CreateServiceAccount {
64+
piaCreationTasks.Append(&tasks.GenericTask{
65+
Description: fmt.Sprintf("create service account %q, if it does not already exist", pia.NameString()),
66+
Doer: func() error {
67+
if err := kubernetes.MaybeCreateServiceAccountOrUpdateMetadata(c.clientSet, v1.ObjectMeta{
68+
Name: pia.ServiceAccountName,
69+
Namespace: pia.Namespace,
70+
}); err != nil {
71+
return fmt.Errorf("failed to create service account %q: %w", pia.NameString(), err)
72+
}
73+
return nil
74+
},
75+
})
76+
}
7577
piaCreationTasks.Append(&createPodIdentityAssociationTask{
7678
ctx: ctx,
7779
info: fmt.Sprintf("create pod identity association for service account %q", pia.NameString()),

pkg/actions/podidentityassociation/creator_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,10 @@ var _ = Describe("Create", func() {
9595
Entry("returns an error if creating the service account fails", createPodIdentityAssociationEntry{
9696
toBeCreated: []api.PodIdentityAssociation{
9797
{
98-
Namespace: namespace,
99-
ServiceAccountName: serviceAccountName1,
100-
RoleARN: roleARN,
98+
Namespace: namespace,
99+
ServiceAccountName: serviceAccountName1,
100+
RoleARN: roleARN,
101+
CreateServiceAccount: true,
101102
},
102103
},
103104
mockK8s: func(clientSet *kubeclientfakes.Clientset) {

pkg/actions/podidentityassociation/deleter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func (d *Deleter) DeleteTasks(ctx context.Context, podIDs []Identifier) (*tasks.
124124
}
125125
piaDeletionTasks.Append(d.makeDeleteTask(ctx, podID, roleStackNames))
126126
piaDeletionTasks.Append(&tasks.GenericTask{
127-
Description: fmt.Sprintf("delete service account %q", podID.IDString()),
127+
Description: fmt.Sprintf("delete service account %q, if it exists and is managed by eksctl", podID.IDString()),
128128
Doer: func() error {
129129
if err := kubernetes.MaybeDeleteServiceAccount(d.ClientSet, v1.ObjectMeta{
130130
Name: podID.ServiceAccountName,

pkg/actions/podidentityassociation/migrator_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,6 @@ var _ = Describe("Create", func() {
220220
validateCustomLoggerOutput: func(output string) {
221221
Expect(output).To(ContainSubstring("update trust policy for owned role \"test-role-1\""))
222222
Expect(output).To(ContainSubstring("update trust policy for unowned role \"test-role-2\""))
223-
Expect(output).To(ContainSubstring("create service account \"default/service-account-1\", if it does not already exist"))
224-
Expect(output).To(ContainSubstring("create service account \"default/service-account-2\", if it does not already exist"))
225223
Expect(output).To(ContainSubstring("create pod identity association for service account \"default/service-account-1\""))
226224
Expect(output).To(ContainSubstring("create pod identity association for service account \"default/service-account-2\""))
227225
},

pkg/apis/eksctl.io/v1alpha5/iam.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ type PodIdentityAssociation struct {
175175

176176
RoleARN string `json:"roleARN"`
177177

178+
// +optional
179+
CreateServiceAccount bool `json:"createServiceAccount,omitempty"`
180+
178181
// +optional
179182
RoleName string `json:"roleName,omitempty"`
180183

pkg/cfn/manager/create_tasks.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ import (
2222
"github.com/weaveworks/eksctl/pkg/vpc"
2323
)
2424

25-
const (
26-
managedByKubernetesLabelKey = "app.kubernetes.io/managed-by"
27-
managedByKubernetesLabelValue = "eksctl"
28-
)
29-
3025
// NewTasksToCreateCluster defines all tasks required to create a cluster along
3126
// with some nodegroups; see CreateAllNodeGroups for how onlyNodeGroupSubset works.
3227
func (c *StackCollection) NewTasksToCreateCluster(ctx context.Context, nodeGroups []*api.NodeGroup,
@@ -157,10 +152,6 @@ func (c *StackCollection) NewTasksToCreateIAMServiceAccounts(serviceAccounts []*
157152
}
158153
}
159154

160-
if sa.Labels == nil {
161-
sa.Labels = make(map[string]string)
162-
}
163-
sa.Labels[managedByKubernetesLabelKey] = managedByKubernetesLabelValue
164155
if !api.IsEnabled(sa.RoleOnly) {
165156
saTasks.Append(&kubernetesTask{
166157
info: fmt.Sprintf("create serviceaccount %q", sa.NameString()),

pkg/ctl/cmdutils/filter/iamserviceaccount_filter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (f *IAMServiceAccountFilter) SetExcludeExistingFilter(ctx context.Context,
6262
if api.IsEnabled(sa.RoleOnly) {
6363
return nil
6464
}
65-
exists, err := kubernetes.CheckServiceAccountExists(clientSet, sa.ClusterIAMMeta.AsObjectMeta())
65+
exists, _, err := kubernetes.CheckServiceAccountExists(clientSet, sa.ClusterIAMMeta.AsObjectMeta())
6666
if err != nil {
6767
return err
6868
}

pkg/ctl/create/pod_identity_association.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ func configureCreatePodIdentityAssociationCmd(cmd *cmdutils.Cmd, pia *api.PodIde
7272
fs.StringVar(&pia.RoleName, "role-name", "", "Set a custom name for the created role")
7373
fs.StringVar(&pia.PermissionsBoundaryARN, "permission-boundary-arn", "", "ARN of the policy that is used to set the permission boundary for the role")
7474

75+
fs.BoolVar(&pia.CreateServiceAccount, "create-service-account", false, "instructs eksctl to create the K8s service account")
76+
7577
fs.StringSliceVar(&pia.PermissionPolicyARNs, "permission-policy-arns", []string{}, "List of ARNs of the IAM permission policies to attach")
7678

7779
fs.VarP(&pia.WellKnownPolicies, "well-known-policies", "", "Used to attach common IAM policies")

pkg/kubernetes/serviceaccount.go

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import (
1010
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1111
)
1212

13+
const (
14+
managedByKubernetesLabelKey = "app.kubernetes.io/managed-by"
15+
managedByKubernetesLabelValue = "eksctl"
16+
)
17+
1318
// NewServiceAccount creates a corev1.ServiceAccount object using the provided meta.
1419
func NewServiceAccount(meta metav1.ObjectMeta) *corev1.ServiceAccount {
1520
return &corev1.ServiceAccount{
@@ -21,18 +26,25 @@ func NewServiceAccount(meta metav1.ObjectMeta) *corev1.ServiceAccount {
2126
}
2227
}
2328

24-
// CheckServiceAccountExists check if a serviceaccount with a given name already exists, and
25-
// returns boolean or an error
26-
func CheckServiceAccountExists(clientSet Interface, meta metav1.ObjectMeta) (bool, error) {
29+
// CheckServiceAccountExists check if a serviceaccount with a given name already exists,
30+
// and if it is managed by eksctl
31+
func CheckServiceAccountExists(clientSet Interface, meta metav1.ObjectMeta) (bool, bool, error) {
2732
name := meta.Namespace + "/" + meta.Name
28-
_, err := clientSet.CoreV1().ServiceAccounts(meta.Namespace).Get(context.TODO(), meta.Name, metav1.GetOptions{})
29-
if err == nil {
30-
return true, nil
33+
sa, err := clientSet.CoreV1().ServiceAccounts(meta.Namespace).Get(context.TODO(), meta.Name, metav1.GetOptions{})
34+
if err != nil {
35+
if !apierrors.IsNotFound(err) {
36+
return false, false, errors.Wrapf(err, "checking whether serviceaccount %q exists", name)
37+
}
38+
return false, false, nil
3139
}
32-
if !apierrors.IsNotFound(err) {
33-
return false, errors.Wrapf(err, "checking whether serviceaccount %q exists", name)
40+
41+
if sa.Labels != nil {
42+
if value, ok := sa.Labels[managedByKubernetesLabelKey]; ok && (value == managedByKubernetesLabelValue) {
43+
return true, true, nil
44+
}
3445
}
35-
return false, nil
46+
47+
return true, false, nil
3648
}
3749

3850
// MaybeCreateServiceAccountOrUpdateMetadata will only create serviceaccount with the given name if
@@ -41,11 +53,14 @@ func CheckServiceAccountExists(clientSet Interface, meta metav1.ObjectMeta) (boo
4153
// meta will be retained
4254
func MaybeCreateServiceAccountOrUpdateMetadata(clientSet Interface, meta metav1.ObjectMeta) error {
4355
name := meta.Namespace + "/" + meta.Name
44-
56+
if meta.Labels == nil {
57+
meta.Labels = make(map[string]string)
58+
}
59+
meta.Labels[managedByKubernetesLabelKey] = managedByKubernetesLabelValue
4560
if err := MaybeCreateNamespace(clientSet, meta.Namespace); err != nil {
4661
return err
4762
}
48-
exists, err := CheckServiceAccountExists(clientSet, meta)
63+
exists, _, err := CheckServiceAccountExists(clientSet, meta)
4964
if err != nil {
5065
return err
5166
}
@@ -100,14 +115,18 @@ func MaybeCreateServiceAccountOrUpdateMetadata(clientSet Interface, meta metav1.
100115
// MaybeDeleteServiceAccount will only delete the serviceaccount if it exists
101116
func MaybeDeleteServiceAccount(clientSet Interface, meta metav1.ObjectMeta) error {
102117
name := meta.Namespace + "/" + meta.Name
103-
exists, err := CheckServiceAccountExists(clientSet, meta)
118+
exists, isManagedByEksctl, err := CheckServiceAccountExists(clientSet, meta)
104119
if err != nil {
105120
return err
106121
}
107122
if !exists {
108123
logger.Info("serviceaccount %q was already deleted", name)
109124
return nil
110125
}
126+
if !isManagedByEksctl {
127+
logger.Info("serviceaccount %q was not created by eksctl; will not be deleted", name)
128+
return nil
129+
}
111130
err = clientSet.CoreV1().ServiceAccounts(meta.Namespace).Delete(context.TODO(), meta.Name, metav1.DeleteOptions{})
112131
if err != nil {
113132
return err

0 commit comments

Comments
 (0)