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 })