github.com/docker/compose-on-kubernetes@v0.5.0/e2e/rbac_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/docker/compose-on-kubernetes/api/compose/latest"
     8  	"github.com/docker/compose-on-kubernetes/internal/e2e/cluster"
     9  	. "github.com/onsi/ginkgo" // Import ginkgo to simplify test code
    10  	. "github.com/onsi/gomega" // Import gomega to simplify test code
    11  	rbacv1 "k8s.io/api/rbac/v1"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	typedrbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
    14  	"k8s.io/client-go/rest"
    15  )
    16  
    17  var _ = Describe("Compose fry with permission", func() {
    18  
    19  	var (
    20  		originNS *cluster.Namespace
    21  		cleanup  func()
    22  	)
    23  
    24  	BeforeEach(func() {
    25  		originNS, cleanup = createNamespace()
    26  	})
    27  
    28  	AfterEach(func() {
    29  		cleanup()
    30  	})
    31  
    32  	It("Should allow user to create stack", func() {
    33  		ns, err := originNS.As(rest.ImpersonationConfig{
    34  			UserName: "employee",
    35  			Groups:   []string{"test-group"},
    36  			Extra: map[string][]string{
    37  				"test-extra": {"test-value"},
    38  			},
    39  		})
    40  		expectNoError(err)
    41  		rbac, err := typedrbacv1.NewForConfig(config)
    42  		expectNoError(err)
    43  		// allow employee stack and kube access on namespace
    44  		_, err = rbac.Roles(ns.Name()).Create(&rbacv1.Role{
    45  			ObjectMeta: metav1.ObjectMeta{
    46  				Name:      "office-role",
    47  				Namespace: ns.Name(),
    48  			},
    49  			Rules: []rbacv1.PolicyRule{{
    50  				APIGroups: []string{"", "extensions", "apps", "compose.docker.com"},
    51  				Resources: []string{"deployments", "replicasets", "pods", "stacks", "stacks/composefile"},
    52  				Verbs:     []string{"*"},
    53  			}},
    54  		})
    55  		expectNoError(err)
    56  
    57  		_, err = rbac.RoleBindings(ns.Name()).Create(&rbacv1.RoleBinding{
    58  			ObjectMeta: metav1.ObjectMeta{
    59  				Name:      "office-role-binding",
    60  				Namespace: ns.Name(),
    61  			},
    62  			RoleRef: rbacv1.RoleRef{
    63  				Kind: "Role",
    64  				Name: "office-role",
    65  			},
    66  			Subjects: []rbacv1.Subject{
    67  				{
    68  					Kind: "User",
    69  					Name: "employee",
    70  				},
    71  			},
    72  		})
    73  		expectNoError(err)
    74  
    75  		spec := `version: '3.2'
    76  services:
    77    back:
    78      image: nginx:1.12.1-alpine`
    79  
    80  		// rbac rules can take time to apply
    81  		waitUntil(func() (bool, error) {
    82  			_, err = ns.CreateStack(cluster.StackOperationV1beta2Compose, "app", spec)
    83  			if err != nil {
    84  				GinkgoWriter.Write([]byte(fmt.Sprintf("error occurred, waiting: %s\n", err)))
    85  			}
    86  			return err == nil, nil
    87  		})
    88  
    89  		waitUntil(ns.ContainsNPods(1))
    90  	})
    91  
    92  	It("Should deny user to create stack", func() {
    93  		ns, err := originNS.As(rest.ImpersonationConfig{
    94  			UserName: "employee",
    95  			Groups:   []string{"test-group"},
    96  			Extra: map[string][]string{
    97  				"test-extra": {"test-value"},
    98  			},
    99  		})
   100  		expectNoError(err)
   101  		rbac, err := typedrbacv1.NewForConfig(config)
   102  		expectNoError(err)
   103  		// allow employee stack access on denied namespace
   104  		_, err = rbac.Roles(ns.Name()).Create(&rbacv1.Role{
   105  			ObjectMeta: metav1.ObjectMeta{
   106  				Name:      "denied-role",
   107  				Namespace: ns.Name(),
   108  			},
   109  			Rules: []rbacv1.PolicyRule{{
   110  				APIGroups: []string{"compose.docker.com"},
   111  				Resources: []string{"stacks", "stacks/composefile"},
   112  				Verbs:     []string{"*"},
   113  			}},
   114  		})
   115  		expectNoError(err)
   116  
   117  		_, err = rbac.RoleBindings(ns.Name()).Create(&rbacv1.RoleBinding{
   118  			ObjectMeta: metav1.ObjectMeta{
   119  				Name:      "denied-role-binding",
   120  				Namespace: ns.Name(),
   121  			},
   122  			RoleRef: rbacv1.RoleRef{
   123  				Kind: "Role",
   124  				Name: "denied-role",
   125  			},
   126  			Subjects: []rbacv1.Subject{
   127  				{
   128  					Kind: "User",
   129  					Name: "employee",
   130  				},
   131  			},
   132  		})
   133  		expectNoError(err)
   134  
   135  		spec := `version: '3.2'
   136  services:
   137    back:
   138      image: nginx:1.12.1-alpine`
   139  		// rbac rules can take time to apply
   140  		waitUntil(func() (bool, error) {
   141  			_, err = ns.CreateStack(cluster.StackOperationV1beta2Compose, "app", spec)
   142  			if err != nil {
   143  				GinkgoWriter.Write([]byte(fmt.Sprintf("error occurred, waiting: %s\n", err)))
   144  			}
   145  			return err == nil, nil
   146  		})
   147  		waitUntil(func() (bool, error) {
   148  			stack, err := ns.GetStack("app")
   149  			if err != nil {
   150  				return false, err
   151  			}
   152  			if stack.Status == nil {
   153  				return false, nil
   154  			}
   155  			if stack.Status.Phase == latest.StackFailure {
   156  				return true, nil
   157  			}
   158  			if stack.Status.Phase == latest.StackAvailable {
   159  				return false, errors.New("Stack available when it should not")
   160  			}
   161  			return false, nil
   162  		})
   163  	})
   164  
   165  	It("Should respect view/edit/admin cluster roles", func() {
   166  		viewer, err := originNS.As(rest.ImpersonationConfig{
   167  			UserName: "viewer",
   168  		})
   169  		expectNoError(err)
   170  		editor, err := originNS.As(rest.ImpersonationConfig{
   171  			UserName: "editor",
   172  		})
   173  		expectNoError(err)
   174  		admin, err := originNS.As(rest.ImpersonationConfig{
   175  			UserName: "admin",
   176  		})
   177  		expectNoError(err)
   178  		rbac, err := typedrbacv1.NewForConfig(config)
   179  		expectNoError(err)
   180  		_, err = rbac.RoleBindings(originNS.Name()).Create(&rbacv1.RoleBinding{
   181  			ObjectMeta: metav1.ObjectMeta{
   182  				Name:      "viewer-role-binding",
   183  				Namespace: originNS.Name(),
   184  			},
   185  			RoleRef: rbacv1.RoleRef{
   186  				Kind: "ClusterRole",
   187  				Name: "view",
   188  			},
   189  			Subjects: []rbacv1.Subject{
   190  				{
   191  					Kind: "User",
   192  					Name: "viewer",
   193  				},
   194  			},
   195  		})
   196  		expectNoError(err)
   197  		_, err = rbac.RoleBindings(originNS.Name()).Create(&rbacv1.RoleBinding{
   198  			ObjectMeta: metav1.ObjectMeta{
   199  				Name:      "editor-role-binding",
   200  				Namespace: originNS.Name(),
   201  			},
   202  			RoleRef: rbacv1.RoleRef{
   203  				Kind: "ClusterRole",
   204  				Name: "edit",
   205  			},
   206  			Subjects: []rbacv1.Subject{
   207  				{
   208  					Kind: "User",
   209  					Name: "editor",
   210  				},
   211  			},
   212  		})
   213  		expectNoError(err)
   214  		_, err = rbac.RoleBindings(originNS.Name()).Create(&rbacv1.RoleBinding{
   215  			ObjectMeta: metav1.ObjectMeta{
   216  				Name:      "admin-role-binding",
   217  				Namespace: originNS.Name(),
   218  			},
   219  			RoleRef: rbacv1.RoleRef{
   220  				Kind: "ClusterRole",
   221  				Name: "admin",
   222  			},
   223  			Subjects: []rbacv1.Subject{
   224  				{
   225  					Kind: "User",
   226  					Name: "admin",
   227  				},
   228  			},
   229  		})
   230  		expectNoError(err)
   231  		_, err = originNS.CreateStack(cluster.StackOperationV1beta2Stack, "by-cluster-admin", `version: '3.2'
   232  services:
   233    back-cluster-admin:
   234      image: nginx:1.12.1-alpine`)
   235  		expectNoError(err)
   236  		_, err = editor.CreateStack(cluster.StackOperationV1beta2Stack, "by-editor", `version: '3.2'
   237  services:
   238    back-editor:
   239      image: nginx:1.12.1-alpine`)
   240  		expectNoError(err)
   241  		_, err = admin.CreateStack(cluster.StackOperationV1beta2Stack, "by-admin", `version: '3.2'
   242  services:
   243    back-admin:
   244      image: nginx:1.12.1-alpine`)
   245  		expectNoError(err)
   246  		_, err = viewer.CreateStack(cluster.StackOperationV1beta2Stack, "by-viewer", `version: '3.2'
   247  services:
   248    back-viewer:
   249      image: nginx:1.12.1-alpine`)
   250  		Expect(err).To(HaveOccurred())
   251  		stacks, err := viewer.ListStacks()
   252  		expectNoError(err)
   253  		Expect(stacks).To(HaveLen(3))
   254  		stacks, err = editor.ListStacks()
   255  		expectNoError(err)
   256  		Expect(stacks).To(HaveLen(3))
   257  		stacks, err = admin.ListStacks()
   258  		expectNoError(err)
   259  		Expect(stacks).To(HaveLen(3))
   260  		waitUntil(originNS.IsStackAvailable("by-cluster-admin"))
   261  		waitUntil(originNS.IsStackAvailable("by-editor"))
   262  		waitUntil(originNS.IsStackAvailable("by-admin"))
   263  	})
   264  })