Skip to content

Commit 7b4fe4f

Browse files
authored
Merge pull request #9351 from zalando-incubator/admission-e2e
Add e2e admission-controller role access tests
2 parents 780a647 + 9c9e8aa commit 7b4fe4f

File tree

3 files changed

+134
-46
lines changed

3 files changed

+134
-46
lines changed

cluster/cluster.yaml

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ Resources:
273273
AddonName: eks-pod-identity-agent
274274
ClusterName: !Ref EKSCluster
275275
{{ if eq .Cluster.Environment "e2e" }}
276-
E2EEKSIAMTestRoleUnprivileged:
276+
E2EEKSIAMTestRoleReadOnly:
277277
Properties:
278278
AssumeRolePolicyDocument:
279279
Statement:
@@ -285,26 +285,26 @@ Resources:
285285
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
286286
Version: 2012-10-17
287287
Path: /
288-
RoleName: "{{.Cluster.LocalID}}-e2e-eks-iam-test-unprivileged-role"
288+
RoleName: "{{.Cluster.LocalID}}-e2e-eks-iam-test-read-only-role"
289289
Type: 'AWS::IAM::Role'
290-
E2EEKSIAMTestAccessEntryUnprivileged:
290+
E2EEKSIAMTestAccessEntryReadOnly:
291291
Type: "AWS::EKS::AccessEntry"
292292
Properties:
293293
AccessPolicies:
294294
- AccessScope:
295295
Type: "cluster"
296296
PolicyArn: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
297297
ClusterName: !Ref EKSCluster
298-
PrincipalArn: !GetAtt E2EEKSIAMTestRoleUnprivileged.Arn
298+
PrincipalArn: !GetAtt E2EEKSIAMTestRoleReadOnly.Arn
299299
Username: !Join
300300
- ''
301301
- - !Sub 'arn:aws:sts::${AWS::AccountId}:assumed-role/'
302-
- !Ref E2EEKSIAMTestRoleUnprivileged
302+
- !Ref E2EEKSIAMTestRoleReadOnly
303303
- '/{{`{{SessionName}}`}}'
304304
KubernetesGroups:
305305
- zalando:readonly
306306
Type: "STANDARD"
307-
E2EEKSIAMTestRolePrivileged:
307+
E2EEKSIAMTestRoleAdministrator:
308308
Properties:
309309
AssumeRolePolicyDocument:
310310
Statement:
@@ -316,21 +316,21 @@ Resources:
316316
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
317317
Version: 2012-10-17
318318
Path: /
319-
RoleName: "{{.Cluster.LocalID}}-e2e-eks-iam-test-privileged-role"
319+
RoleName: "{{.Cluster.LocalID}}-e2e-eks-iam-test-administrator-role"
320320
Type: 'AWS::IAM::Role'
321-
E2EEKSIAMTestAccessEntryPrivileged:
321+
E2EEKSIAMTestAccessEntryAdministrator:
322322
Type: "AWS::EKS::AccessEntry"
323323
Properties:
324324
AccessPolicies:
325325
- AccessScope:
326326
Type: "cluster"
327327
PolicyArn: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
328328
ClusterName: !Ref EKSCluster
329-
PrincipalArn: !GetAtt E2EEKSIAMTestRolePrivileged.Arn
329+
PrincipalArn: !GetAtt E2EEKSIAMTestRoleAdministrator.Arn
330330
Username: !Join
331331
- ''
332332
- - !Sub 'arn:aws:sts::${AWS::AccountId}:assumed-role/'
333-
- !Ref E2EEKSIAMTestRolePrivileged
333+
- !Ref E2EEKSIAMTestRoleAdministrator
334334
- '/{{`{{SessionName}}`}}'
335335
KubernetesGroups:
336336
- zalando:administrator
@@ -366,6 +366,37 @@ Resources:
366366
KubernetesGroups:
367367
- zalando:collaborator
368368
Type: "STANDARD"
369+
E2EEKSIAMTestRoleEngineer:
370+
Properties:
371+
AssumeRolePolicyDocument:
372+
Statement:
373+
- Action:
374+
- 'sts:AssumeRole'
375+
- 'sts:SetSourceIdentity'
376+
Effect: Allow
377+
Principal:
378+
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
379+
Version: 2012-10-17
380+
Path: /
381+
RoleName: "{{.Cluster.LocalID}}-e2e-eks-iam-test-engineer-role"
382+
Type: 'AWS::IAM::Role'
383+
E2EEKSIAMTestAccessEntryEngineer:
384+
Type: "AWS::EKS::AccessEntry"
385+
Properties:
386+
AccessPolicies:
387+
- AccessScope:
388+
Type: "cluster"
389+
PolicyArn: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
390+
ClusterName: !Ref EKSCluster
391+
PrincipalArn: !GetAtt E2EEKSIAMTestRoleEngineer.Arn
392+
Username: !Join
393+
- ''
394+
- - !Sub 'arn:aws:sts::${AWS::AccountId}:assumed-role/'
395+
- !Ref E2EEKSIAMTestRoleEngineer
396+
- '/{{`{{SessionName}}`}}'
397+
KubernetesGroups:
398+
- zalando:engineer
399+
Type: "STANDARD"
369400
E2EEKSIAMTestRolePostgresAdministrator:
370401
Properties:
371402
AssumeRolePolicyDocument:

cluster/manifests/02-visibility/01-namespace.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ apiVersion: v1
22
kind: Namespace
33
metadata:
44
name: visibility
5+
labels:
6+
admission.zalando.org/infrastructure-component: "true" # This label flags the resource as protected

test/e2e/authorization.go

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -596,34 +596,41 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
596596
)
597597

598598
g.BeforeEach(func() {
599-
systemResource = examplePod("kube-system", nil)
600-
collaboratorResource = examplePod("visibility", nil)
601-
nonSystemResource = examplePod(f.Namespace.Name, nil)
599+
var err error
600+
601+
nonSystemResource, err = createPod(context.Background(), f.ClientSet, f.Namespace.Name, nil)
602+
framework.ExpectNoError(err)
603+
604+
collaboratorResource, err = createPod(context.Background(), f.ClientSet, "visibility", nil)
605+
framework.ExpectNoError(err)
606+
607+
systemResource, err = createPod(context.Background(), f.ClientSet, "kube-system", map[string]string{"admission.zalando.org/infrastructure-component": "true"})
608+
framework.ExpectNoError(err)
602609
})
603610

604-
g.Context("as privileged user", func() {
611+
g.Context("as admin user", func() {
605612
var client *kubernetes.Clientset
606613

607614
g.BeforeEach(func() {
608615
var err error
609616

610-
client, err = getPrivilegedClient(eksCluster, awsAccountID)
617+
client, err = getAdminClient(eksCluster, awsAccountID)
611618
framework.ExpectNoError(err)
612619
})
613620

614621
g.It("should allow write access in user namespace", func() {
615-
_, err := client.CoreV1().Pods(nonSystemResource.Namespace).Create(context.Background(), nonSystemResource, metav1.CreateOptions{DryRun: []string{"All"}})
616-
framework.ExpectNoError(err, "failed to create pod: %s in namespace: %s", nonSystemResource.Name, nonSystemResource.Namespace)
622+
err := client.CoreV1().Pods(nonSystemResource.Namespace).Delete(context.Background(), nonSystemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
623+
framework.ExpectNoError(err, "failed to delete pod: %s in namespace: %s", nonSystemResource.Name, nonSystemResource.Namespace)
617624
})
618625

619626
g.It("should allow write access in collaborator namespace", func() {
620-
_, err := client.CoreV1().Pods(collaboratorResource.Namespace).Create(context.Background(), collaboratorResource, metav1.CreateOptions{DryRun: []string{"All"}})
621-
framework.ExpectNoError(err, "failed to create pod: %s in namespace: %s", collaboratorResource.Name, collaboratorResource.Namespace)
627+
err := client.CoreV1().Pods(collaboratorResource.Namespace).Delete(context.Background(), collaboratorResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
628+
framework.ExpectNoError(err, "failed to delete pod: %s in namespace: %s", collaboratorResource.Name, collaboratorResource.Namespace)
622629
})
623630

624631
g.It("should allow write access in system namespace", func() {
625-
_, err := client.CoreV1().Pods(systemResource.Namespace).Create(context.Background(), systemResource, metav1.CreateOptions{DryRun: []string{"All"}})
626-
framework.ExpectNoError(err, "failed to create pod: %s in namespace: %s", systemResource.Name, systemResource.Namespace)
632+
err := client.CoreV1().Pods(systemResource.Namespace).Delete(context.Background(), systemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
633+
framework.ExpectNoError(err, "failed to delete pod: %s in namespace: %s", systemResource.Name, systemResource.Namespace)
627634
})
628635
})
629636

@@ -638,43 +645,43 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
638645
})
639646

640647
g.It("should allow write access in user namespace", func() {
641-
_, err := client.CoreV1().Pods(nonSystemResource.Namespace).Create(context.Background(), nonSystemResource, metav1.CreateOptions{DryRun: []string{"All"}})
642-
framework.ExpectNoError(err, "failed to create pod: %s in namespace: %s", nonSystemResource.Name, nonSystemResource.Namespace)
648+
err := client.CoreV1().Pods(nonSystemResource.Namespace).Delete(context.Background(), nonSystemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
649+
framework.ExpectNoError(err, "failed to delete pod: %s in namespace: %s", nonSystemResource.Name, nonSystemResource.Namespace)
643650
})
644651

645652
g.It("should allow write access in collaborator namespace", func() {
646-
_, err := client.CoreV1().Pods(collaboratorResource.Namespace).Create(context.Background(), collaboratorResource, metav1.CreateOptions{DryRun: []string{"All"}})
647-
framework.ExpectNoError(err, "failed to create pod: %s in namespace: %s", collaboratorResource.Name, collaboratorResource.Namespace)
653+
err := client.CoreV1().Pods(collaboratorResource.Namespace).Delete(context.Background(), collaboratorResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
654+
framework.ExpectNoError(err, "failed to delete pod: %s in namespace: %s", collaboratorResource.Name, collaboratorResource.Namespace)
648655
})
649656

650657
g.It("should deny write access in system namespace", func() {
651-
_, err := client.CoreV1().Pods(systemResource.Namespace).Create(context.Background(), systemResource, metav1.CreateOptions{DryRun: []string{"All"}})
658+
err := client.CoreV1().Pods(systemResource.Namespace).Delete(context.Background(), systemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
652659
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
653660
})
654661
})
655662

656-
g.Context("as unprivileged user", func() {
663+
g.Context("as engineer user", func() {
657664
var client *kubernetes.Clientset
658665

659666
g.BeforeEach(func() {
660667
var err error
661668

662-
client, err = getUnprivilegedClient(eksCluster, awsAccountID)
669+
client, err = getEngineerClient(eksCluster, awsAccountID)
663670
framework.ExpectNoError(err)
664671
})
665672

666673
g.It("should allow write access in user namespace", func() {
667-
_, err := client.CoreV1().Pods(nonSystemResource.Namespace).Create(context.Background(), nonSystemResource, metav1.CreateOptions{DryRun: []string{"All"}})
668-
framework.ExpectNoError(err, "failed to create pod: %s in namespace: %s", nonSystemResource.Name, nonSystemResource.Namespace)
674+
err := client.CoreV1().Pods(nonSystemResource.Namespace).Delete(context.Background(), nonSystemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
675+
framework.ExpectNoError(err, "failed to delete pod: %s in namespace: %s", nonSystemResource.Name, nonSystemResource.Namespace)
669676
})
670677

671678
g.It("should deny write access in collaborator namespace", func() {
672-
_, err := client.CoreV1().Pods(collaboratorResource.Namespace).Create(context.Background(), collaboratorResource, metav1.CreateOptions{DryRun: []string{"All"}})
679+
err := client.CoreV1().Pods(collaboratorResource.Namespace).Delete(context.Background(), collaboratorResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
673680
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
674681
})
675682

676683
g.It("should deny write access in system namespace", func() {
677-
_, err := client.CoreV1().Pods(systemResource.Namespace).Create(context.Background(), systemResource, metav1.CreateOptions{DryRun: []string{"All"}})
684+
err := client.CoreV1().Pods(systemResource.Namespace).Delete(context.Background(), systemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
678685
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
679686
})
680687
})
@@ -696,13 +703,13 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
696703
framework.ExpectNoError(err)
697704
})
698705

699-
g.Context("as privileged user", func() {
706+
g.Context("as admin user", func() {
700707
var client *kubernetes.Clientset
701708

702709
g.BeforeEach(func() {
703710
var err error
704711

705-
client, err = getPrivilegedClient(eksCluster, awsAccountID)
712+
client, err = getAdminClient(eksCluster, awsAccountID)
706713
framework.ExpectNoError(err)
707714
})
708715

@@ -717,13 +724,45 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
717724
})
718725
})
719726

720-
g.Context("as unprivileged user", func() {
727+
g.Context("as collaborator user", func() {
728+
var client *kubernetes.Clientset
729+
730+
g.BeforeEach(func() {
731+
var err error
732+
733+
client, err = getCollaboratorClient(eksCluster, awsAccountID)
734+
framework.ExpectNoError(err)
735+
})
736+
737+
g.It("should allow write access for non-system resources", func() {
738+
err := client.RbacV1().ClusterRoles().Delete(context.Background(), nonSystemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
739+
framework.ExpectNoError(err, "failed to delete cluster role: %s", nonSystemResource.Name)
740+
})
741+
742+
g.It("should deny write access for system resources", func() {
743+
err := client.RbacV1().ClusterRoles().Delete(context.Background(), systemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
744+
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
745+
})
746+
747+
// test specific namespaces
748+
g.It("should deny deletion of visibility namespace", func() {
749+
err := client.CoreV1().Namespaces().Delete(context.Background(), "visibility", metav1.DeleteOptions{DryRun: []string{"All"}})
750+
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
751+
})
752+
753+
g.It("should deny deletion of kube-system namespace", func() {
754+
err := client.CoreV1().Namespaces().Delete(context.Background(), "kube-system", metav1.DeleteOptions{DryRun: []string{"All"}})
755+
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("this namespace may not be deleted")))
756+
})
757+
})
758+
759+
g.Context("as engineer user", func() {
721760
var client *kubernetes.Clientset
722761

723762
g.BeforeEach(func() {
724763
var err error
725764

726-
client, err = getUnprivilegedClient(eksCluster, awsAccountID)
765+
client, err = getEngineerClient(eksCluster, awsAccountID)
727766
framework.ExpectNoError(err)
728767
})
729768

@@ -736,6 +775,17 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
736775
err := client.RbacV1().ClusterRoles().Delete(context.Background(), systemResource.Name, metav1.DeleteOptions{DryRun: []string{"All"}})
737776
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
738777
})
778+
779+
// test specific namespaces
780+
g.It("should deny deletion of visibility namespace", func() {
781+
err := client.CoreV1().Namespaces().Delete(context.Background(), "visibility", metav1.DeleteOptions{DryRun: []string{"All"}})
782+
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("write operations are forbidden")))
783+
})
784+
785+
g.It("should deny deletion of kube-system namespace", func() {
786+
err := client.CoreV1().Namespaces().Delete(context.Background(), "kube-system", metav1.DeleteOptions{DryRun: []string{"All"}})
787+
gomega.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("this namespace may not be deleted")))
788+
})
739789
})
740790
})
741791

@@ -785,13 +835,13 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
785835
})
786836
})
787837

788-
g.Context("as privileged user", func() {
838+
g.Context("as admin user", func() {
789839
var client *kubernetes.Clientset
790840

791841
g.BeforeEach(func() {
792842
var err error
793843

794-
client, err = getPrivilegedClient(eksCluster, awsAccountID)
844+
client, err = getAdminClient(eksCluster, awsAccountID)
795845
framework.ExpectNoError(err)
796846
})
797847

@@ -811,13 +861,13 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
811861
})
812862
})
813863

814-
g.Context("as unprivileged user", func() {
864+
g.Context("as read-only user", func() {
815865
var client *kubernetes.Clientset
816866

817867
g.BeforeEach(func() {
818868
var err error
819869

820-
client, err = getUnprivilegedClient(eksCluster, awsAccountID)
870+
client, err = getReadOnlyClient(eksCluster, awsAccountID)
821871
framework.ExpectNoError(err)
822872
})
823873

@@ -839,19 +889,24 @@ var _ = g.Describe("Authorization via admission-controller [RBAC] [Zalando]", fu
839889
})
840890
})
841891

842-
// getPrivilegedClient returns a client with the `zalando:administrator` group.
843-
func getPrivilegedClient(cluster *types.Cluster, awsAccountID string) (*kubernetes.Clientset, error) {
844-
return newClientWithRole(cluster, fmt.Sprintf("arn:aws:iam::%s:role/%s-e2e-eks-iam-test-privileged-role", awsAccountID, aws.ToString(cluster.Name)))
892+
// getAdminClient returns a client with the `zalando:administrator` group.
893+
func getAdminClient(cluster *types.Cluster, awsAccountID string) (*kubernetes.Clientset, error) {
894+
return newClientWithRole(cluster, fmt.Sprintf("arn:aws:iam::%s:role/%s-e2e-eks-iam-test-administrator-role", awsAccountID, aws.ToString(cluster.Name)))
845895
}
846896

847897
// getCollaboratorClient returns a client with the `zalando:collaborator` group.
848898
func getCollaboratorClient(cluster *types.Cluster, awsAccountID string) (*kubernetes.Clientset, error) {
849899
return newClientWithRole(cluster, fmt.Sprintf("arn:aws:iam::%s:role/%s-e2e-eks-iam-test-collaborator-role", awsAccountID, aws.ToString(cluster.Name)))
850900
}
851901

852-
// getUnprivilegedClient returns a client with the `zalando:readonly` group.
853-
func getUnprivilegedClient(cluster *types.Cluster, awsAccountID string) (*kubernetes.Clientset, error) {
854-
return newClientWithRole(cluster, fmt.Sprintf("arn:aws:iam::%s:role/%s-e2e-eks-iam-test-unprivileged-role", awsAccountID, aws.ToString(cluster.Name)))
902+
// getEngineerClient returns a client with the `zalando:engineer` group.
903+
func getEngineerClient(cluster *types.Cluster, awsAccountID string) (*kubernetes.Clientset, error) {
904+
return newClientWithRole(cluster, fmt.Sprintf("arn:aws:iam::%s:role/%s-e2e-eks-iam-test-engineer-role", awsAccountID, aws.ToString(cluster.Name)))
905+
}
906+
907+
// getReadOnlyClient returns a client with the `zalando:readonly` group.
908+
func getReadOnlyClient(cluster *types.Cluster, awsAccountID string) (*kubernetes.Clientset, error) {
909+
return newClientWithRole(cluster, fmt.Sprintf("arn:aws:iam::%s:role/%s-e2e-eks-iam-test-read-only-role", awsAccountID, aws.ToString(cluster.Name)))
855910
}
856911

857912
// getPostgresAdministratorClient returns a client with the `zalando:postgres-admin` group.

0 commit comments

Comments
 (0)