Skip to content

Commit

Permalink
restrict RBAC for kube controller secrets to the required namespace only
Browse files Browse the repository at this point in the history
  • Loading branch information
vara2504 committed Nov 25, 2024
1 parent 917fdc4 commit ec9b169
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 75 deletions.
7 changes: 1 addition & 6 deletions pkg/render/kubecontrollers/kube-controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,6 @@ func NewCalicoKubeControllers(cfg *KubeControllersConfiguration) *kubeController
if cfg.Installation.Variant == operatorv1.TigeraSecureEnterprise {
kubeControllerRolePolicyRules = append(kubeControllerRolePolicyRules, kubeControllersRoleEnterpriseCommonRules(cfg)...)
kubeControllerRolePolicyRules = append(kubeControllerRolePolicyRules,
rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"secrets"},
Verbs: []string{"deletecollection"},
},
rbacv1.PolicyRule{
APIGroups: []string{"crd.projectcalico.org"},
Resources: []string{"remoteclusterconfigurations"},
Expand Down Expand Up @@ -426,7 +421,7 @@ func kubeControllersRoleEnterpriseCommonRules(cfg *KubeControllersConfiguration)
rules := []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"configmaps", "secrets"},
Resources: []string{"configmaps"},
Verbs: []string{"watch", "list", "get", "update", "create", "delete"},
},
{
Expand Down
6 changes: 3 additions & 3 deletions pkg/render/kubecontrollers/kube-controllers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ var _ = Describe("kube-controllers rendering tests", func() {
Expect(len(dp.Spec.Template.Spec.Volumes)).To(Equal(1))

clusterRole := rtest.GetResource(resources, kubecontrollers.KubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole)
Expect(clusterRole.Rules).To(HaveLen(20))
Expect(clusterRole.Rules).To(HaveLen(19))

ms := rtest.GetResource(resources, kubecontrollers.KubeControllerMetrics, common.CalicoNamespace, "", "v1", "Service").(*corev1.Service)
Expect(ms.Spec.ClusterIP).To(Equal("None"), "metrics service should be headless")
Expand Down Expand Up @@ -345,7 +345,7 @@ var _ = Describe("kube-controllers rendering tests", func() {
Expect(clusterRole.Rules).To(ContainElement(
rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"configmaps", "secrets"},
Resources: []string{"configmaps"},
Verbs: []string{"watch", "list", "get", "update", "create", "delete"},
}))
})
Expand Down Expand Up @@ -548,7 +548,7 @@ var _ = Describe("kube-controllers rendering tests", func() {
Expect(clusterRole.Rules).To(ContainElement(
rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"configmaps", "secrets"},
Resources: []string{"configmaps"},
Verbs: []string{"watch", "list", "get", "update", "create", "delete"},
}))
})
Expand Down
136 changes: 136 additions & 0 deletions pkg/render/logstorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ const (
EsManagerRole = "es-manager"
EsManagerRoleBinding = "es-manager"

CalicoKubeControllerSecret = "calico-kube-controller-secrets"

ElasticsearchTLSHashAnnotation = "hash.operator.tigera.io/es-secrets"
)

Expand Down Expand Up @@ -247,6 +249,14 @@ func (es *elasticsearchComponent) Objects() ([]client.Object, []client.Object) {
toCreate = append(toCreate, es.elasticsearchClusterRole(), es.elasticsearchClusterRoleBinding())
}

roles, bindings := es.elasticsearchRolesAndBindings()
for _, r := range roles {
toCreate = append(toCreate, r)
}
for _, b := range bindings {
toCreate = append(toCreate, b)
}

// Curator is no longer supported in ElasticSearch beyond version 8 so remove its resources here unconditionally so
// that on upgrade we clean up after ourselves. Eventually we can remove this cleanup code as well.
toDelete = append(toDelete, es.curatorDecommissionedResources()...)
Expand Down Expand Up @@ -997,6 +1007,79 @@ func (es *elasticsearchComponent) elasticsearchInternalAllowTigeraPolicy() *v3.N
}
}

func (es *elasticsearchComponent) elasticsearchRolesAndBindings() ([]*rbacv1.Role, []*rbacv1.RoleBinding) {

secretsRole := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: CalicoKubeControllerSecret,
Namespace: ElasticsearchNamespace,
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"secrets"},
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "update", "watch"},
},
},
}

operatorSecretsRole := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: CalicoKubeControllerSecret,
Namespace: common.OperatorNamespace(),
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"secrets"},
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "update", "watch"},
},
},
}

secretBinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: CalicoKubeControllerSecret,
Namespace: ElasticsearchNamespace,
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: CalicoKubeControllerSecret,
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: "calico-kube-controllers",
Namespace: common.CalicoNamespace,
},
},
}

// Bind the secrets permission to the operator namespace. This binding now adds permissions for kube controllers to manipulate
// secrets in the tigera-operator namespace
operatorSecretBinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: CalicoKubeControllerSecret,
Namespace: common.OperatorNamespace(),
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: CalicoKubeControllerSecret,
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: "calico-kube-controllers",
Namespace: common.CalicoNamespace,
},
},
}

return []*rbacv1.Role{secretsRole, operatorSecretsRole}, []*rbacv1.RoleBinding{secretBinding, operatorSecretBinding}
}

// overrideResourceRequirements replaces individual ResourceRequirements field's default value with user's value.
// - If user provided both Limits and Requests, use them.
// - If user provided just Limits, and Limits is <= default Requests, set Requests value as user's Limits value,
Expand Down Expand Up @@ -1099,6 +1182,7 @@ func (m *managedClusterLogStorage) Objects() (objsToCreate []client.Object, objs
m.elasticsearchExternalService(),
m.linseedExternalService(),
)

for _, r := range roles {
toCreate = append(toCreate, r)
}
Expand All @@ -1110,6 +1194,14 @@ func (m *managedClusterLogStorage) Objects() (objsToCreate []client.Object, objs
toCreate = append(toCreate, crb)
}

kcRoles, kcBindings := m.kubeControllerRolesAndBindings()
for _, role := range kcRoles {
toCreate = append(toCreate, role)
}
for _, binding := range kcBindings {
toCreate = append(toCreate, binding)
}

return toCreate, nil
}

Expand Down Expand Up @@ -1260,3 +1352,47 @@ func (m managedClusterLogStorage) linseedExternalRolesAndBindings() ([]*rbacv1.C

return []*rbacv1.ClusterRole{secretsRole, configMapsRole, namespacesRole}, []*rbacv1.RoleBinding{configMapBinding, secretBinding}, []*rbacv1.ClusterRoleBinding{namespacesBinding}
}

// In managed clusters we need to provision roles and bindings for kubecontrollers to provide permissions
// to manipulate secrets
func (m managedClusterLogStorage) kubeControllerRolesAndBindings() ([]*rbacv1.Role, []*rbacv1.RoleBinding) {

// Create Role and Binding to the operator namespace for kubecontroller to manipulate the needed secrets.
operatorSecretsRole := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: CalicoKubeControllerSecret,
Namespace: common.OperatorNamespace(),
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"secrets"},
Verbs: []string{"create", "delete", "deletecollection", "get", "list", "update", "watch"},
},
},
}

// Bind the secrets permission to the operator namespace. This binding now adds permissions for kube controllers to create
// its public cert secret in the tigera-operator namespace
operatorSecretBinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: CalicoKubeControllerSecret,
Namespace: common.OperatorNamespace(),
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: CalicoKubeControllerSecret,
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: "calico-kube-controllers",
Namespace: common.CalicoNamespace,
},
},
}

return []*rbacv1.Role{operatorSecretsRole}, []*rbacv1.RoleBinding{operatorSecretBinding}

}
Loading

0 comments on commit ec9b169

Please sign in to comment.