Skip to content
This repository has been archived by the owner on Dec 14, 2023. It is now read-only.

Commit

Permalink
feat: use irsa name for sa name (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieuJacquot-voodoo authored Feb 23, 2021
1 parent 60b7b9a commit 1ea565b
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 42 deletions.
31 changes: 26 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ This project is built using the Kubernetes [operator SDK](https://sdk.operatorfr

## Example

This CRD will allow any pod using the `serviceAccount` named `s3put` to `Get` and `List` all objects in the s3 bucket with ARN `arn:aws:s3:::test-irsa-4gkut9fl`
This CRD will allow any pod using the `serviceAccount` named `s3-get-lister` to `Get` and `List` all objects in the s3 bucket with ARN `arn:aws:s3:::test-irsa-4gkut9fl`

```
apiVersion: irsa.voodoo.io/v1alpha1
kind: IamRoleServiceAccount
metadata:
name: iamroleserviceaccount-test-sample
name: s3-get-lister
spec:
serviceAccountName: s3put
policy:
statement:
- resource: "arn:aws:s3:::test-irsa-4gkut9fl"
Expand All @@ -33,8 +32,30 @@ What this operator does (from a user point of view) :
- create an IAM Role with this policy attached to it
- create a serviceAccount named as specified with the IAM Role capabilities

_NB :_
- the name of the resource (`metadata.name`) is mandatory (because of k8s) and has no particular utility for the end-user
you can use the serviceAccount created by the irsa-operator by simply setting its name in your pods `spec.serviceAccountName`

```
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: irsa-test
name: irsa-test
spec:
selector:
matchLabels:
app: irsa-test
template:
metadata:
labels:
app: irsa-test
spec:
serviceAccountName: s3-get-lister # <- HERE
containers:
- image: amazon/aws-cli
name: aws-cli
command: ["aws", "s3", "ls", "arn:aws:s3:::test-irsa-4gkut9fl"]
```

## (manual) installation of the operator

Expand Down
12 changes: 3 additions & 9 deletions api/v1alpha1/iamroleserviceaccount_types.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package v1alpha1

import (
"errors"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NewIamRoleServiceAccount is the IamRoleServiceAccount constructor
func NewIamRoleServiceAccount(name, ns, saName string, policyspec PolicySpec) *IamRoleServiceAccount {
func NewIamRoleServiceAccount(name, ns string, policyspec PolicySpec) *IamRoleServiceAccount {
return &IamRoleServiceAccount{
TypeMeta: metav1.TypeMeta{
APIVersion: "irsa.voodoo.io/v1alpha1",
Expand All @@ -19,8 +18,7 @@ func NewIamRoleServiceAccount(name, ns, saName string, policyspec PolicySpec) *I
Namespace: ns,
},
Spec: IamRoleServiceAccountSpec{
ServiceAccountName: saName,
Policy: policyspec,
Policy: policyspec,
},
}
}
Expand All @@ -37,16 +35,12 @@ func (irsa IamRoleServiceAccount) IsPendingDeletion() bool {

// Validate returns an error if the IamRoleServiceAccountSpec is not valid
func (irsa IamRoleServiceAccount) Validate() error {
if irsa.Spec.ServiceAccountName == "" {
return errors.New("empty serviceAccountName")
}
return irsa.Spec.Policy.Validate()
}

// IamRoleServiceAccountSpec defines the desired state of IamRoleServiceAccount
type IamRoleServiceAccountSpec struct {
ServiceAccountName string `json:"serviceAccountName"`
Policy PolicySpec `json:"policy"`
Policy PolicySpec `json:"policy"`
}

// IamRoleServiceAccountStatus defines the observed state of IamRoleServiceAccount
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/role_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

// NewRole constructs a Role, setting mandatory fields for us
func NewRole(name, ns, serviceAccountName string) *Role {
func NewRole(name, ns string) *Role {
return &Role{
TypeMeta: metav1.TypeMeta{
APIVersion: "irsa.voodoo.io/v1alpha1",
Expand All @@ -19,7 +19,7 @@ func NewRole(name, ns, serviceAccountName string) *Role {
Namespace: ns,
},
Spec: RoleSpec{
ServiceAccountName: serviceAccountName,
ServiceAccountName: name,
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion aws/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var _ = Describe("policy", func() {
})

var _ = Describe("role", func() {
role := api.NewRole("name", "testns", "serviceaccountname")
role := api.NewRole("name", "testns")
Context("given a valid role", func() {
It("doesn't exist yet", func() {
exists, err := awsmngr.RoleExists(role.AwsName(clusterName))
Expand Down
3 changes: 0 additions & 3 deletions config/crd/bases/irsa.voodoo.io_iamroleserviceaccounts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,8 @@ spec:
required:
- statement
type: object
serviceAccountName:
type: string
required:
- policy
- serviceAccountName
type: object
status:
description: IamRoleServiceAccountStatus defines the observed state of
Expand Down
3 changes: 0 additions & 3 deletions config/helm/irsa/templates/irsa-operator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,8 @@ spec:
required:
- statement
type: object
serviceAccountName:
type: string
required:
- policy
- serviceAccountName
type: object
status:
description: IamRoleServiceAccountStatus defines the observed state of IamRoleServiceAccount
Expand Down
9 changes: 4 additions & 5 deletions controllers/iamroleserviceaccount_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (r *IamRoleServiceAccountReconciler) admissionStep(ctx context.Context, irs
}

{ // we check the serviceAccountName doesn't conflict with an existing one
if r.saWithNameExistsInNs(ctx, irsa.Spec.ServiceAccountName, irsa.ObjectMeta.Namespace) {
if r.saWithNameExistsInNs(ctx, irsa.ObjectMeta.Name, irsa.ObjectMeta.Namespace) {
e := errors.New("service_account already exists")
r.log.Info(e.Error())

Expand Down Expand Up @@ -190,7 +190,7 @@ func (r *IamRoleServiceAccountReconciler) reconcilerRoutine(ctx context.Context,

{ // service_account creation
var ok completed
saAlreadyExists, ok = r.saAlreadyExists(ctx, irsa.Spec.ServiceAccountName, irsa.ObjectMeta.Namespace)
saAlreadyExists, ok = r.saAlreadyExists(ctx, irsa.ObjectMeta.Name, irsa.ObjectMeta.Namespace)
if !ok {
return ctrl.Result{Requeue: true}, nil
}
Expand Down Expand Up @@ -226,7 +226,7 @@ func (r *IamRoleServiceAccountReconciler) executeFinalizerIfPresent(ctx context.

{ // we delete the service account we created, we first need to ensure it is not owned by another operator (since it's a serviceaccount)
sa := &corev1.ServiceAccount{}
if err := r.Get(ctx, types.NamespacedName{Namespace: irsa.Namespace, Name: irsa.Spec.ServiceAccountName}, sa); err != nil {
if err := r.Get(ctx, types.NamespacedName{Namespace: irsa.ObjectMeta.Namespace, Name: irsa.ObjectMeta.Name}, sa); err != nil {
if !k8serrors.IsNotFound(err) {
r.log.Error(err, "get resource failed")
return false
Expand Down Expand Up @@ -376,7 +376,6 @@ func (r *IamRoleServiceAccountReconciler) createRole(ctx context.Context, irsa *
role := api.NewRole(
irsa.ObjectMeta.Name,
irsa.ObjectMeta.Namespace,
irsa.Spec.ServiceAccountName,
)

// set this irsa instance as the owner of this role
Expand Down Expand Up @@ -419,7 +418,7 @@ func (r *IamRoleServiceAccountReconciler) createServiceAccount(ctx context.Conte
Kind: "ServiceAccount",
},
ObjectMeta: metav1.ObjectMeta{
Name: irsa.Spec.ServiceAccountName,
Name: irsa.ObjectMeta.Name,
Namespace: irsa.ObjectMeta.Namespace,
Annotations: map[string]string{
"eks.amazonaws.com/role-arn": role.Spec.RoleARN,
Expand Down
13 changes: 2 additions & 11 deletions controllers/iamroleserviceaccount_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var _ = Describe("IamRoleServiceAccount validity check", func() {

It("fails at submission", func() {
Expect(
api.NewIamRoleServiceAccount(validName(), testns, randString(), invalidPolicySpec).Validate(),
api.NewIamRoleServiceAccount(validName(), testns, invalidPolicySpec).Validate(),
).ShouldNot(Succeed())
})
})
Expand All @@ -23,18 +23,9 @@ var _ = Describe("IamRoleServiceAccount validity check", func() {
{Resource: "arn:aws:s3:::my_corporate_bucket/exampleobject.png", Action: []string{"act1"}},
},
}
name := validName()

Context("if the spec.serviceAccountName is an empty string", func() {
invalidSaName := ""
It("doesnt pass validation", func() {
irsa := api.NewIamRoleServiceAccount(name, testns, invalidSaName, validPolicy)
Expect(irsa.Validate()).ShouldNot(Succeed())
})
})

Context("if everything else is also ok", func() {
irsa := api.NewIamRoleServiceAccount(name, testns, validName(), validPolicy)
irsa := api.NewIamRoleServiceAccount(validName(), testns, validPolicy)
It("it passes validation", func() {
Expect(irsa.Validate()).Should(Succeed())
})
Expand Down
5 changes: 2 additions & 3 deletions controllers/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,17 @@ func run(irsaName string, wg *sync.WaitGroup) {
}

{ // k8s
saName := validName()
{
// we submit the iamroleserviceaccount Spec to k8s
createResource(
api.NewIamRoleServiceAccount(irsaName, testns, saName, submittedPolicy),
api.NewIamRoleServiceAccount(irsaName, testns, submittedPolicy),
).Should(Succeed())
}
{ // every CR must eventually reach an OK status & serviceAccount has been created
foundPolicyInCondition(irsaName, testns, api.CrOK).Should(BeTrue())
foundRoleInCondition(irsaName, testns, api.CrOK).Should(BeTrue())
foundIrsaInCondition(irsaName, testns, api.IrsaOK).Should(BeTrue())
findSa(saName, testns).Should(BeTrue())
findSa(irsaName, testns).Should(BeTrue())
}
}

Expand Down

0 comments on commit 1ea565b

Please sign in to comment.