Gh18399 che SA cluster roles (#543)
Signed-off-by: Michal Vala <mvala@redhat.com> Co-authored-by: Anatolii Bazko <abazko@redhat.com>pull/562/head
parent
ec1b6ffafc
commit
cd239ce7a4
|
|
@ -60,3 +60,4 @@ rules:
|
|||
- list
|
||||
- create
|
||||
- watch
|
||||
- update
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ spec:
|
|||
# defaults to `che`. When set to `codeready`, CodeReady Workspaces is deployed
|
||||
# the difference is in images, labels, exec commands
|
||||
cheFlavor: ''
|
||||
# Comma-separated list of ClusterRoles that will be assigned
|
||||
# to che ServiceAccount. By default it is set to `che-namespace-editor`, which is used by Che
|
||||
# to label the namespaces. Set it empty to not grant any cluster-wide permissions to Che ServiceAccount.
|
||||
# Be aware that che-operator has to already have all permissions in these ClusterRoles to be able to grant them.
|
||||
cheClusterRoles: 'che-namespace-editor'
|
||||
# specifies a custom cluster role to user for the Che workspaces
|
||||
# Uses the default roles if left blank.
|
||||
cheWorkspaceClusterRole: ''
|
||||
|
|
|
|||
|
|
@ -310,6 +310,12 @@ spec:
|
|||
to configured true without OAuth configured. This property is
|
||||
also used by the OpenShift infra.
|
||||
type: boolean
|
||||
cheClusterRoles:
|
||||
description: Comma-separated list of ClusterRoles that will be assigned
|
||||
to che ServiceAccount. Be aware that che-operator has to already
|
||||
have all permissions in these ClusterRoles to be able to grant
|
||||
them.
|
||||
type: string
|
||||
cheDebug:
|
||||
description: Enables the debug mode for Che server. Defaults to
|
||||
`false`.
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ metadata:
|
|||
},
|
||||
"server": {
|
||||
"allowUserDefinedWorkspaceNamespaces": false,
|
||||
"cheClusterRoles": "che-namespace-editor",
|
||||
"cheFlavor": "",
|
||||
"cheImage": "",
|
||||
"cheImageTag": "",
|
||||
|
|
@ -272,6 +273,7 @@ spec:
|
|||
- list
|
||||
- create
|
||||
- watch
|
||||
- update
|
||||
serviceAccountName: che-operator
|
||||
- rules:
|
||||
- apiGroups:
|
||||
|
|
|
|||
|
|
@ -310,6 +310,12 @@ spec:
|
|||
to configured true without OAuth configured. This property is
|
||||
also used by the OpenShift infra.
|
||||
type: boolean
|
||||
cheClusterRoles:
|
||||
description: Comma-separated list of ClusterRoles that will be assigned
|
||||
to che ServiceAccount. Be aware that che-operator has to already
|
||||
have all permissions in these ClusterRoles to be able to grant
|
||||
them.
|
||||
type: string
|
||||
cheDebug:
|
||||
description: Enables the debug mode for Che server. Defaults to
|
||||
`false`.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ metadata:
|
|||
},
|
||||
"server": {
|
||||
"allowUserDefinedWorkspaceNamespaces": false,
|
||||
"cheClusterRoles": "che-namespace-editor",
|
||||
"cheFlavor": "",
|
||||
"cheImage": "",
|
||||
"cheImageTag": "",
|
||||
|
|
@ -288,6 +289,7 @@ spec:
|
|||
- list
|
||||
- create
|
||||
- watch
|
||||
- update
|
||||
serviceAccountName: che-operator
|
||||
- rules:
|
||||
- apiGroups:
|
||||
|
|
|
|||
|
|
@ -311,6 +311,12 @@ spec:
|
|||
to configured true without OAuth configured. This property is
|
||||
also used by the OpenShift infra.
|
||||
type: boolean
|
||||
cheClusterRoles:
|
||||
description: Comma-separated list of ClusterRoles that will be assigned
|
||||
to che ServiceAccount. Be aware that che-operator has to already
|
||||
have all permissions in these ClusterRoles to be able to grant
|
||||
them.
|
||||
type: string
|
||||
cheDebug:
|
||||
description: Enables the debug mode for Che server. Defaults to
|
||||
`false`.
|
||||
|
|
|
|||
|
|
@ -99,6 +99,10 @@ type CheClusterSpecServer struct {
|
|||
// Enables the debug mode for Che server. Defaults to `false`.
|
||||
// +optional
|
||||
CheDebug string `json:"cheDebug,omitempty"`
|
||||
// Comma-separated list of ClusterRoles that will be assigned to che ServiceAccount.
|
||||
// Be aware that che-operator has to already have all permissions in these ClusterRoles to be able to grant them.
|
||||
// +optional
|
||||
CheClusterRoles string `json:"cheClusterRoles,omitempty"`
|
||||
// Custom cluster role bound to the user for the Che workspaces.
|
||||
// The default roles are used if this is omitted or left blank.
|
||||
// +optional
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||
|
|
@ -593,6 +594,24 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
|
|||
}
|
||||
}
|
||||
|
||||
if len(instance.Spec.Server.CheClusterRoles) > 0 {
|
||||
cheClusterRoles := strings.Split(instance.Spec.Server.CheClusterRoles, ",")
|
||||
for _, cheClusterRole := range cheClusterRoles {
|
||||
cheClusterRole := strings.TrimSpace(cheClusterRole)
|
||||
cheClusterRoleBindingName := instance.Namespace + "-che-" + cheClusterRole
|
||||
cheClusterRoleBinding, err := deploy.SyncClusterRoleBindingToCluster(deployContext, cheClusterRoleBindingName, "che", cheClusterRole)
|
||||
if cheClusterRoleBinding == nil {
|
||||
logrus.Infof("Waiting on cluster role binding '%s' to be created", cheClusterRoleBindingName)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
if !tests {
|
||||
return reconcile.Result{RequeueAfter: time.Second}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cheWSExecRoleBinding, err := deploy.SyncRoleBindingToCluster(deployContext, "che-workspace-exec", "che-workspace", "exec", "Role")
|
||||
if cheWSExecRoleBinding == nil {
|
||||
logrus.Info("Waiting on role binding 'che-workspace-exec' to be created")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
//
|
||||
// Copyright (c) 2012-2019 Red Hat, Inc.
|
||||
// This program and the accompanying materials are made
|
||||
// available under the terms of the Eclipse Public License 2.0
|
||||
// which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0
|
||||
//
|
||||
// Contributors:
|
||||
// Red Hat, Inc. - initial API and implementation
|
||||
//
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/sirupsen/logrus"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var crbDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(rbac.ClusterRoleBinding{}, "TypeMeta", "ObjectMeta"),
|
||||
}
|
||||
|
||||
func SyncClusterRoleBindingToCluster(
|
||||
deployContext *DeployContext,
|
||||
name string,
|
||||
serviceAccountName string,
|
||||
clusterRoleName string) (*rbac.ClusterRoleBinding, error) {
|
||||
|
||||
specCRB, err := getSpecClusterRoleBinding(deployContext, name, serviceAccountName, clusterRoleName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clusterRB, err := getClusterRoleBiding(specCRB.Name, deployContext.ClusterAPI.Client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if clusterRB == nil {
|
||||
logrus.Infof("Creating a new object: %s, name %s", specCRB.Kind, specCRB.Name)
|
||||
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specCRB)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
diff := cmp.Diff(clusterRB, specCRB, crbDiffOpts)
|
||||
if len(diff) > 0 {
|
||||
logrus.Infof("Updating existed object: %s, name: %s", clusterRB.Kind, clusterRB.Name)
|
||||
fmt.Printf("Difference:\n%s", diff)
|
||||
clusterRB.Subjects = specCRB.Subjects
|
||||
clusterRB.RoleRef = specCRB.RoleRef
|
||||
err := deployContext.ClusterAPI.Client.Update(context.TODO(), clusterRB)
|
||||
return clusterRB, err
|
||||
}
|
||||
|
||||
return clusterRB, nil
|
||||
}
|
||||
|
||||
func getClusterRoleBiding(name string, client runtimeClient.Client) (*rbac.ClusterRoleBinding, error) {
|
||||
clusterRoleBinding := &rbac.ClusterRoleBinding{}
|
||||
crbName := types.NamespacedName{Name: name}
|
||||
err := client.Get(context.TODO(), crbName, clusterRoleBinding)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return clusterRoleBinding, nil
|
||||
}
|
||||
|
||||
func getSpecClusterRoleBinding(
|
||||
deployContext *DeployContext,
|
||||
name string,
|
||||
serviceAccountName string,
|
||||
roleName string) (*rbac.ClusterRoleBinding, error) {
|
||||
|
||||
labels := GetLabels(deployContext.CheCluster, DefaultCheFlavor(deployContext.CheCluster))
|
||||
clusterRoleBinding := &rbac.ClusterRoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ClusterRoleBinding",
|
||||
APIVersion: rbac.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
},
|
||||
Subjects: []rbac.Subject{
|
||||
{
|
||||
Kind: rbac.ServiceAccountKind,
|
||||
Name: serviceAccountName,
|
||||
Namespace: deployContext.CheCluster.Namespace,
|
||||
},
|
||||
},
|
||||
RoleRef: rbac.RoleRef{
|
||||
Name: roleName,
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
Kind: "ClusterRole",
|
||||
},
|
||||
}
|
||||
|
||||
return clusterRoleBinding, nil
|
||||
}
|
||||
|
|
@ -35,21 +35,21 @@ func SyncRoleBindingToCluster(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
clusterRB, err := getClusterRoleBiding(specRB.Name, specRB.Namespace, deployContext.ClusterAPI.Client)
|
||||
roleBinding, err := getRoleBiding(specRB.Name, specRB.Namespace, deployContext.ClusterAPI.Client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if clusterRB == nil {
|
||||
if roleBinding == nil {
|
||||
logrus.Infof("Creating a new object: %s, name %s", specRB.Kind, specRB.Name)
|
||||
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specRB)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clusterRB, nil
|
||||
return roleBinding, nil
|
||||
}
|
||||
|
||||
func getClusterRoleBiding(name string, namespace string, client runtimeClient.Client) (*rbac.RoleBinding, error) {
|
||||
func getRoleBiding(name string, namespace string, client runtimeClient.Client) (*rbac.RoleBinding, error) {
|
||||
roleBinding := &rbac.RoleBinding{}
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
|
|
|
|||
Loading…
Reference in New Issue