Update permission config in addontemplate (#285)

Signed-off-by: zhujian <jiazhu@redhat.com>
This commit is contained in:
Jian Zhu
2023-09-22 10:08:17 +08:00
committed by GitHub
parent 769272cbec
commit e6443b6523
11 changed files with 243 additions and 85 deletions

2
go.mod
View File

@@ -28,7 +28,7 @@ require (
k8s.io/kube-aggregator v0.27.2
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749
open-cluster-management.io/addon-framework v0.7.1-0.20230920005921-65bcbb446df8
open-cluster-management.io/api v0.11.1-0.20230919033310-0146ddfab71c
open-cluster-management.io/api v0.11.1-0.20230921010001-9cb6321fa748
sigs.k8s.io/controller-runtime v0.15.0
sigs.k8s.io/kube-storage-version-migrator v0.0.5
)

4
go.sum
View File

@@ -1158,8 +1158,8 @@ k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 h1:xMMXJlJbsU8w3V5N2FLDQ8YgU8s1E
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
open-cluster-management.io/addon-framework v0.7.1-0.20230920005921-65bcbb446df8 h1:cVyjsSeboWwgg2bkMU2s78hkUTK3LzVyQMWwEf+/gRw=
open-cluster-management.io/addon-framework v0.7.1-0.20230920005921-65bcbb446df8/go.mod h1:xdIh8sARZ7zoH/KvHp9ATYoousIdotI+Js0VZt0+qtc=
open-cluster-management.io/api v0.11.1-0.20230919033310-0146ddfab71c h1:p73vRGhWgBucvoYmMHKlVjABz5SWBT0rmfzKqXnF1I0=
open-cluster-management.io/api v0.11.1-0.20230919033310-0146ddfab71c/go.mod h1:/CZhelEH+30/pX7vXGSZOzLMX0zvjthYOkT/5ZTzVTQ=
open-cluster-management.io/api v0.11.1-0.20230921010001-9cb6321fa748 h1:OjemV/LWwBuKDZJLfEPw51w0Zbd9HKgpkxGtPclOjkQ=
open-cluster-management.io/api v0.11.1-0.20230921010001-9cb6321fa748/go.mod h1:/CZhelEH+30/pX7vXGSZOzLMX0zvjthYOkT/5ZTzVTQ=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -384,38 +384,59 @@ spec:
to bind the user provided ClusterRole/Role to the "system:open-cluster-management:cluster:<cluster-name>:addon:<addon-name>"
Group.
properties:
roleRef:
description: RoleRef is an reference to the permission
resource. it could be a role or a cluster role,
the user must make sure it exist on the hub cluster.
currentCluster:
description: CurrentCluster contains the configuration
of CurrentCluster type binding. It is required when
the type is CurrentCluster.
properties:
apiGroup:
description: APIGroup is the group for the resource
being referenced
type: string
kind:
description: Kind is the type of resource being
referenced
type: string
name:
description: Name is the name of resource being
referenced
clusterRoleName:
description: ClusterRoleName is the name of the
clusterrole the addon agent is bound. A rolebinding
will be created referring to this cluster role
in each cluster namespace. The user must make
sure the clusterrole exists on the hub cluster.
type: string
required:
- apiGroup
- kind
- name
- clusterRoleName
type: object
x-kubernetes-map-type: atomic
singleNamespace:
description: SingleNamespace contains the configuration
of SingleNamespace type binding. It is required
when the type is SingleNamespace
properties:
namespace:
description: Namespace is the namespace the addon
agent has permissions to bind to. A rolebinding
will be created in this namespace referring
to the RoleRef.
type: string
roleRef:
description: RoleRef is an reference to the permission
resource. it could be a role or a cluster role,
the user must make sure it exist on the hub
cluster.
properties:
apiGroup:
description: APIGroup is the group for the
resource being referenced
type: string
kind:
description: Kind is the type of resource
being referenced
type: string
name:
description: Name is the name of resource
being referenced
type: string
required:
- apiGroup
- kind
- name
type: object
x-kubernetes-map-type: atomic
required:
- namespace
- roleRef
type: object
type:
description: 'Type of the permissions setting. It
@@ -429,7 +450,6 @@ spec:
- SingleNamespace
type: string
required:
- roleRef
- type
type: object
type: array

View File

@@ -363,6 +363,10 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
for _, pc := range kcrc.HubPermissions {
switch pc.Type {
case addonapiv1alpha1.HubPermissionsBindingCurrentCluster:
if pc.CurrentCluster == nil {
return fmt.Errorf("current cluster is required when the HubPermission type is CurrentCluster")
}
a.logger.V(5).Info("Set hub permission for addon",
"addonNamespace", addon.Namespace,
"addonName", addon.Name,
@@ -377,19 +381,26 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
Name: addon.Name,
UID: addon.UID,
}
roleRef := rbacv1.RoleRef{
Kind: "ClusterRole",
APIGroup: rbacv1.GroupName,
Name: pc.CurrentCluster.ClusterRoleName,
}
err := a.createPermissionBinding(templateName,
cluster.Name, addon.Name, cluster.Name, pc.RoleRef, &owner)
cluster.Name, addon.Name, cluster.Name, roleRef, &owner)
if err != nil {
return err
}
case addonapiv1alpha1.HubPermissionsBindingSingleNamespace:
if pc.SingleNamespace == nil {
return fmt.Errorf("single namespace is nil")
return fmt.Errorf("single namespace is required when the HubPermission type is SingleNamespace")
}
// set owner reference nil since the rolebinding has different namespace with the ManagedClusterAddon
// TODO: cleanup the rolebinding when the addon is deleted
err := a.createPermissionBinding(templateName,
cluster.Name, addon.Name, pc.SingleNamespace.Namespace, pc.RoleRef, nil)
cluster.Name, addon.Name, pc.SingleNamespace.Namespace, pc.SingleNamespace.RoleRef, nil)
if err != nil {
return err
}
@@ -405,7 +416,7 @@ func (a *CRDTemplateAgentAddon) createPermissionBinding(templateName, clusterNam
subject := []rbacv1.Subject{}
for _, group := range groups {
subject = append(subject, rbacv1.Subject{
Kind: "Group", APIGroup: "rbac.authorization.k8s.io", Name: group,
Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: group,
})
}
binding := &rbacv1.RoleBinding{

View File

@@ -52,13 +52,13 @@ func TestTemplateCSRConfigurationsFunc(t *testing.T) {
HubPermissions: []addonapiv1alpha1.HubPermissionConfig{
{
Type: addonapiv1alpha1.HubPermissionsBindingSingleNamespace,
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "test",
},
SingleNamespace: &addonapiv1alpha1.SingleNamespaceBindingConfig{
Namespace: "test",
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.GroupName,
Kind: "ClusterRole",
Name: "test",
},
},
},
},
@@ -172,13 +172,13 @@ func TestTemplateCSRApproveCheckFunc(t *testing.T) {
HubPermissions: []addonapiv1alpha1.HubPermissionConfig{
{
Type: addonapiv1alpha1.HubPermissionsBindingSingleNamespace,
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "test",
},
SingleNamespace: &addonapiv1alpha1.SingleNamespaceBindingConfig{
Namespace: "test",
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.GroupName,
Kind: "ClusterRole",
Name: "test",
},
},
},
},
@@ -273,13 +273,13 @@ func TestTemplateCSRSignFunc(t *testing.T) {
HubPermissions: []addonapiv1alpha1.HubPermissionConfig{
{
Type: addonapiv1alpha1.HubPermissionsBindingSingleNamespace,
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "test",
},
SingleNamespace: &addonapiv1alpha1.SingleNamespaceBindingConfig{
Namespace: "test",
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.GroupName,
Kind: "ClusterRole",
Name: "test",
},
},
},
},
@@ -445,7 +445,7 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
validatePermissionFunc func(*testing.T, kubernetes.Interface)
}{
{
name: "kubeclient current cluster binding",
name: "kubeclient current cluster binding, rolebinding not exist",
agentName: "agent1",
cluster: NewFakeManagedCluster("cluster1"),
template: NewFakeAddonTemplate("template1", []addonapiv1alpha1.RegistrationSpec{
@@ -455,10 +455,57 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
HubPermissions: []addonapiv1alpha1.HubPermissionConfig{
{
Type: addonapiv1alpha1.HubPermissionsBindingCurrentCluster,
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: "test",
CurrentCluster: &addonapiv1alpha1.CurrentClusterBindingConfig{
ClusterRoleName: "test",
},
},
},
},
},
}),
addon: NewFakeTemplateManagedClusterAddon("addon1", "cluster1", "template1", "fakehash"),
expectedErr: nil,
validatePermissionFunc: func(t *testing.T, kubeClient kubernetes.Interface) {
rb, err := kubeClient.RbacV1().RoleBindings("cluster1").Get(context.TODO(),
fmt.Sprintf("open-cluster-management:%s:%s:agent", "addon1", strings.ToLower("ClusterRole")),
metav1.GetOptions{},
)
if err != nil {
t.Errorf("failed to get rolebinding: %v", err)
}
if rb.RoleRef.Name != "test" {
t.Errorf("expected rolebinding %s, got %s", "test", rb.RoleRef.Name)
}
if rb.RoleRef.Kind != "ClusterRole" {
t.Errorf("expected rolebinding kind %s, got %s", "ClusterRole", rb.RoleRef.Kind)
}
if len(rb.OwnerReferences) != 1 {
t.Errorf("expected rolebinding to have 1 owner reference, got %d", len(rb.OwnerReferences))
}
if rb.OwnerReferences[0].Kind != "ManagedClusterAddOn" {
t.Errorf("expected rolebinding owner reference kind to be ManagedClusterAddOn, got %s",
rb.OwnerReferences[0].Kind)
}
if rb.OwnerReferences[0].Name != "addon1" {
t.Errorf("expected rolebinding owner reference name to be addon1, got %s",
rb.OwnerReferences[0].Name)
}
},
},
{
name: "kubeclient current cluster binding, rolebinding exists",
agentName: "agent1",
cluster: NewFakeManagedCluster("cluster1"),
template: NewFakeAddonTemplate("template1", []addonapiv1alpha1.RegistrationSpec{
{
Type: addonapiv1alpha1.RegistrationTypeKubeClient,
KubeClient: &addonapiv1alpha1.KubeClientRegistrationConfig{
HubPermissions: []addonapiv1alpha1.HubPermissionConfig{
{
Type: addonapiv1alpha1.HubPermissionsBindingCurrentCluster,
CurrentCluster: &addonapiv1alpha1.CurrentClusterBindingConfig{
ClusterRoleName: "test",
},
},
},
@@ -473,7 +520,7 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
Name: "system:authenticated"},
}, rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Kind: "ClusterRole",
Name: "test",
},
metav1.OwnerReference{
@@ -485,7 +532,7 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
expectedErr: nil,
validatePermissionFunc: func(t *testing.T, kubeClient kubernetes.Interface) {
rb, err := kubeClient.RbacV1().RoleBindings("cluster1").Get(context.TODO(),
fmt.Sprintf("open-cluster-management:%s:%s:agent", "addon1", strings.ToLower("Role")),
fmt.Sprintf("open-cluster-management:%s:%s:agent", "addon1", strings.ToLower("ClusterRole")),
metav1.GetOptions{},
)
if err != nil {
@@ -495,6 +542,9 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
if rb.RoleRef.Name != "test" {
t.Errorf("expected rolebinding %s, got %s", "test", rb.RoleRef.Name)
}
if rb.RoleRef.Kind != "ClusterRole" {
t.Errorf("expected rolebinding kind %s, got %s", "ClusterRole", rb.RoleRef.Kind)
}
if len(rb.OwnerReferences) != 1 {
t.Errorf("expected rolebinding to have 1 owner reference, got %d", len(rb.OwnerReferences))
}
@@ -519,13 +569,13 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
HubPermissions: []addonapiv1alpha1.HubPermissionConfig{
{
Type: addonapiv1alpha1.HubPermissionsBindingSingleNamespace,
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "test",
},
SingleNamespace: &addonapiv1alpha1.SingleNamespaceBindingConfig{
Namespace: "test",
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.GroupName,
Kind: "ClusterRole",
Name: "test",
},
},
},
},

View File

@@ -95,10 +95,15 @@ spec:
kubeClient:
hubPermissions:
- type: CurrentCluster
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cm-admin
currentCluster:
clusterRoleName: cm-admin
- type: SingleNamespace
singleNamespace:
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cm-admin
- customSigner:
signerName: << CustomSignerName >>
signingCA:

2
vendor/modules.txt vendored
View File

@@ -1428,7 +1428,7 @@ open-cluster-management.io/addon-framework/pkg/index
open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration
open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner
open-cluster-management.io/addon-framework/pkg/utils
# open-cluster-management.io/api v0.11.1-0.20230919033310-0146ddfab71c
# open-cluster-management.io/api v0.11.1-0.20230921010001-9cb6321fa748
## explicit; go 1.19
open-cluster-management.io/api/addon/v1alpha1
open-cluster-management.io/api/client/addon/clientset/versioned

View File

@@ -384,38 +384,59 @@ spec:
to bind the user provided ClusterRole/Role to the "system:open-cluster-management:cluster:<cluster-name>:addon:<addon-name>"
Group.
properties:
roleRef:
description: RoleRef is an reference to the permission
resource. it could be a role or a cluster role,
the user must make sure it exist on the hub cluster.
currentCluster:
description: CurrentCluster contains the configuration
of CurrentCluster type binding. It is required when
the type is CurrentCluster.
properties:
apiGroup:
description: APIGroup is the group for the resource
being referenced
type: string
kind:
description: Kind is the type of resource being
referenced
type: string
name:
description: Name is the name of resource being
referenced
clusterRoleName:
description: ClusterRoleName is the name of the
clusterrole the addon agent is bound. A rolebinding
will be created referring to this cluster role
in each cluster namespace. The user must make
sure the clusterrole exists on the hub cluster.
type: string
required:
- apiGroup
- kind
- name
- clusterRoleName
type: object
x-kubernetes-map-type: atomic
singleNamespace:
description: SingleNamespace contains the configuration
of SingleNamespace type binding. It is required
when the type is SingleNamespace
properties:
namespace:
description: Namespace is the namespace the addon
agent has permissions to bind to. A rolebinding
will be created in this namespace referring
to the RoleRef.
type: string
roleRef:
description: RoleRef is an reference to the permission
resource. it could be a role or a cluster role,
the user must make sure it exist on the hub
cluster.
properties:
apiGroup:
description: APIGroup is the group for the
resource being referenced
type: string
kind:
description: Kind is the type of resource
being referenced
type: string
name:
description: Name is the name of resource
being referenced
type: string
required:
- apiGroup
- kind
- name
type: object
x-kubernetes-map-type: atomic
required:
- namespace
- roleRef
type: object
type:
description: 'Type of the permissions setting. It
@@ -429,7 +450,6 @@ spec:
- SingleNamespace
type: string
required:
- roleRef
- type
type: object
type: array

View File

@@ -123,19 +123,33 @@ type HubPermissionConfig struct {
// +kubebuilder:validation:Enum:=CurrentCluster;SingleNamespace
Type HubPermissionsBindingType `json:"type"`
// RoleRef is an reference to the permission resource. it could be a role or a cluster role,
// the user must make sure it exist on the hub cluster.
// +kubebuilder:validation:Required
RoleRef rbacv1.RoleRef `json:"roleRef"`
// CurrentCluster contains the configuration of CurrentCluster type binding.
// It is required when the type is CurrentCluster.
CurrentCluster *CurrentClusterBindingConfig `json:"currentCluster,omitempty"`
// SingleNamespace contains the configuration of SingleNamespace type binding.
// It is required when the type is SingleNamespace
SingleNamespace *SingleNamespaceBindingConfig `json:"singleNamespace,omitempty"`
}
type CurrentClusterBindingConfig struct {
// ClusterRoleName is the name of the clusterrole the addon agent is bound. A rolebinding
// will be created referring to this cluster role in each cluster namespace.
// The user must make sure the clusterrole exists on the hub cluster.
// +kubebuilder:validation:Required
ClusterRoleName string `json:"clusterRoleName"`
}
type SingleNamespaceBindingConfig struct {
// Namespace is the namespace the addon agent has permissions to bind to. A rolebinding
// will be created in this namespace referring to the RoleRef.
// +kubebuilder:validation:Required
Namespace string `json:"namespace"`
// RoleRef is an reference to the permission resource. it could be a role or a cluster role,
// the user must make sure it exist on the hub cluster.
// +kubebuilder:validation:Required
RoleRef rbacv1.RoleRef `json:"roleRef"`
}
type CustomSignerRegistrationConfig struct {

View File

@@ -453,6 +453,22 @@ func (in *ConfigSpecHash) DeepCopy() *ConfigSpecHash {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CurrentClusterBindingConfig) DeepCopyInto(out *CurrentClusterBindingConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CurrentClusterBindingConfig.
func (in *CurrentClusterBindingConfig) DeepCopy() *CurrentClusterBindingConfig {
if in == nil {
return nil
}
out := new(CurrentClusterBindingConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomSignerRegistrationConfig) DeepCopyInto(out *CustomSignerRegistrationConfig) {
*out = *in
@@ -532,7 +548,11 @@ func (in *HealthCheck) DeepCopy() *HealthCheck {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HubPermissionConfig) DeepCopyInto(out *HubPermissionConfig) {
*out = *in
out.RoleRef = in.RoleRef
if in.CurrentCluster != nil {
in, out := &in.CurrentCluster, &out.CurrentCluster
*out = new(CurrentClusterBindingConfig)
**out = **in
}
if in.SingleNamespace != nil {
in, out := &in.SingleNamespace, &out.SingleNamespace
*out = new(SingleNamespaceBindingConfig)
@@ -971,6 +991,7 @@ func (in *SigningCARef) DeepCopy() *SigningCARef {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SingleNamespaceBindingConfig) DeepCopyInto(out *SingleNamespaceBindingConfig) {
*out = *in
out.RoleRef = in.RoleRef
return
}

View File

@@ -113,6 +113,14 @@ func (AddOnTemplateSpec) SwaggerDoc() map[string]string {
return map_AddOnTemplateSpec
}
var map_CurrentClusterBindingConfig = map[string]string{
"clusterRoleName": "ClusterRoleName is the name of the clusterrole the addon agent is bound. A rolebinding will be created referring to this cluster role in each cluster namespace. The user must make sure the clusterrole exists on the hub cluster.",
}
func (CurrentClusterBindingConfig) SwaggerDoc() map[string]string {
return map_CurrentClusterBindingConfig
}
var map_CustomSignerRegistrationConfig = map[string]string{
"signerName": "signerName is the name of signer that addon agent will use to create csr.",
"subject": "Subject is the user subject of the addon agent to be registered to the hub. If it is not set, the addon agent will have the default subject \"subject\": {\n \"user\": \"system:open-cluster-management:cluster:{clusterName}:addon:{addonName}:agent:{agentName}\",\n \"groups: [\"system:open-cluster-management:cluster:{clusterName}:addon:{addonName}\",\n \"system:open-cluster-management:addon:{addonName}\", \"system:authenticated\"]\n}",
@@ -126,7 +134,7 @@ func (CustomSignerRegistrationConfig) SwaggerDoc() map[string]string {
var map_HubPermissionConfig = map[string]string{
"": "HubPermissionConfig configures the permission of the addon agent to access the hub cluster. Will create a RoleBinding in the same namespace as the managedClusterAddon to bind the user provided ClusterRole/Role to the \"system:open-cluster-management:cluster:<cluster-name>:addon:<addon-name>\" Group.",
"type": "Type of the permissions setting. It defines how to bind the roleRef on the hub cluster. It can be: - CurrentCluster: Bind the roleRef to the namespace with the same name as the managedCluster. - SingleNamespace: Bind the roleRef to the namespace specified by SingleNamespaceBindingConfig.",
"roleRef": "RoleRef is an reference to the permission resource. it could be a role or a cluster role, the user must make sure it exist on the hub cluster.",
"currentCluster": "CurrentCluster contains the configuration of CurrentCluster type binding. It is required when the type is CurrentCluster.",
"singleNamespace": "SingleNamespace contains the configuration of SingleNamespace type binding. It is required when the type is SingleNamespace",
}
@@ -162,6 +170,15 @@ func (SigningCARef) SwaggerDoc() map[string]string {
return map_SigningCARef
}
var map_SingleNamespaceBindingConfig = map[string]string{
"namespace": "Namespace is the namespace the addon agent has permissions to bind to. A rolebinding will be created in this namespace referring to the RoleRef.",
"roleRef": "RoleRef is an reference to the permission resource. it could be a role or a cluster role, the user must make sure it exist on the hub cluster.",
}
func (SingleNamespaceBindingConfig) SwaggerDoc() map[string]string {
return map_SingleNamespaceBindingConfig
}
var map_AddOnMeta = map[string]string{
"": "AddOnMeta represents a collection of metadata information for the add-on.",
"displayName": "displayName represents the name of add-on that will be displayed.",