Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-v1.30] Add PSPs for dex and policy recommendation #2762

Merged
merged 1 commit into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2022 Tigera, Inc. All rights reserved.
// Copyright (c) 2020-2023 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -101,6 +101,7 @@ func newReconciler(mgr manager.Manager, opts options.AddOptions, tierWatchReady
status: status.New(mgr.GetClient(), "authentication", opts.KubernetesVersion),
clusterDomain: opts.ClusterDomain,
tierWatchReady: tierWatchReady,
usePSP: opts.UsePSP,
}
r.status.Run(opts.ShutdownContext)
return r
Expand Down Expand Up @@ -156,6 +157,7 @@ type ReconcileAuthentication struct {
status status.StatusManager
clusterDomain string
tierWatchReady *utils.ReadyFlag
usePSP bool
}

// Reconcile the cluster state with the Authentication object that is found in the cluster.
Expand Down Expand Up @@ -330,6 +332,7 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci
DeleteDex: disableDex,
TLSKeyPair: tlsKeyPair,
TrustedBundle: trustedBundle,
UsePSP: r.usePSP,
}

// Render the desired objects from the CRD and create or update them.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2019-2022 Tigera, Inc. All rights reserved.
// Copyright (c) 2019-2023 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -163,7 +163,7 @@ var _ = Describe("authentication controller tests", func() {
},
}
Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred())
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag}
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, true}
_, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{
Name: "authentication",
Namespace: "",
Expand All @@ -188,7 +188,7 @@ var _ = Describe("authentication controller tests", func() {

Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred())

r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag}
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, true}
_, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{
Name: "authentication",
Namespace: "",
Expand Down Expand Up @@ -229,7 +229,7 @@ var _ = Describe("authentication controller tests", func() {
},
}
Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred())
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag}
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, true}
_, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{
Name: "authentication",
Namespace: "",
Expand Down Expand Up @@ -289,7 +289,7 @@ var _ = Describe("authentication controller tests", func() {
},
}
Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred())
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag}
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, true}
_, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{
Name: "authentication",
Namespace: "",
Expand Down Expand Up @@ -334,7 +334,7 @@ var _ = Describe("authentication controller tests", func() {
Expect(cli.Create(ctx, auth)).ToNot(HaveOccurred())

// Reconcile
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag}
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, true}
_, err := r.Reconcile(ctx, reconcile.Request{})
Expect(err).ShouldNot(HaveOccurred())
authentication, err := utils.GetAuthentication(ctx, cli)
Expand Down Expand Up @@ -492,7 +492,7 @@ var _ = Describe("authentication controller tests", func() {
}
Expect(cli.Create(ctx, idpSecret)).ToNot(HaveOccurred())
Expect(cli.Create(ctx, auth)).ToNot(HaveOccurred())
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag}
r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, true}
_, err := r.Reconcile(ctx, reconcile.Request{})
if expectReconcilePass {
Expect(err).ToNot(HaveOccurred())
Expand Down
61 changes: 43 additions & 18 deletions pkg/render/dex.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
Expand All @@ -35,18 +36,20 @@ import (
rmeta "github.com/tigera/operator/pkg/render/common/meta"
"github.com/tigera/operator/pkg/render/common/networkpolicy"
"github.com/tigera/operator/pkg/render/common/podaffinity"
"github.com/tigera/operator/pkg/render/common/podsecuritypolicy"
"github.com/tigera/operator/pkg/render/common/secret"
"github.com/tigera/operator/pkg/render/common/securitycontext"
"github.com/tigera/operator/pkg/tls/certificatemanagement"
)

const (
DexNamespace = "tigera-dex"
DexObjectName = "tigera-dex"
DexPort = 5556
DexTLSSecretName = "tigera-dex-tls"
DexClientId = "tigera-manager"
DexPolicyName = networkpolicy.TigeraComponentPolicyPrefix + "allow-tigera-dex"
DexNamespace = "tigera-dex"
DexObjectName = "tigera-dex"
DexPodSecurityPolicyName = "tigera-dex"
DexPort = 5556
DexTLSSecretName = "tigera-dex-tls"
DexClientId = "tigera-manager"
DexPolicyName = networkpolicy.TigeraComponentPolicyPrefix + "allow-tigera-dex"
)

var DexEntityRule = networkpolicy.CreateEntityRule(DexNamespace, DexObjectName, DexPort)
Expand All @@ -68,6 +71,9 @@ type DexComponentConfiguration struct {
DeleteDex bool
TLSKeyPair certificatemanagement.KeyPairInterface
TrustedBundle certificatemanagement.TrustedBundle

// Whether the cluster supports pod security policies.
UsePSP bool
}

type dexComponent struct {
Expand Down Expand Up @@ -132,6 +138,10 @@ func (c *dexComponent) Objects() ([]client.Object, []client.Object) {
objs = append(objs, certificatemanagement.CSRClusterRoleBinding(DexObjectName, DexNamespace))
}

if c.cfg.UsePSP {
objs = append(objs, c.podSecurityPolicy())
}

if c.cfg.DeleteDex {
return nil, objs
}
Expand All @@ -151,23 +161,34 @@ func (c *dexComponent) serviceAccount() *corev1.ServiceAccount {
}

func (c *dexComponent) clusterRole() client.Object {
rules := []rbacv1.PolicyRule{
{
APIGroups: []string{"dex.coreos.com"},
Resources: []string{"*"},
Verbs: []string{"*"},
},
{
APIGroups: []string{"apiextensions.k8s.io"},
Resources: []string{"customresourcedefinitions"},
Verbs: []string{"create"},
},
}

if c.cfg.UsePSP {
rules = append(rules, rbacv1.PolicyRule{
APIGroups: []string{"policy"},
Resources: []string{"podsecuritypolicies"},
Verbs: []string{"use"},
ResourceNames: []string{DexPodSecurityPolicyName},
})
}

return &rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1"},
ObjectMeta: metav1.ObjectMeta{
Name: DexObjectName,
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{"dex.coreos.com"},
Resources: []string{"*"},
Verbs: []string{"*"},
},
{
APIGroups: []string{"apiextensions.k8s.io"},
Resources: []string{"customresourcedefinitions"},
Verbs: []string{"create"},
},
},
Rules: rules,
}
}

Expand All @@ -192,6 +213,10 @@ func (c *dexComponent) clusterRoleBinding() client.Object {
}
}

func (c *dexComponent) podSecurityPolicy() *policyv1beta1.PodSecurityPolicy {
return podsecuritypolicy.NewBasePolicy(DexPodSecurityPolicyName)
}

func (c *dexComponent) deployment() client.Object {
var initContainers []corev1.Container
if c.cfg.TLSKeyPair.UseCertificateManagement() {
Expand Down
15 changes: 15 additions & 0 deletions pkg/render/dex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ var _ = Describe("dex rendering tests", func() {
ClusterDomain: clusterName,
TLSKeyPair: tlsKeyPair,
TrustedBundle: trustedCaBundle,
UsePSP: true,
}
})

Expand Down Expand Up @@ -207,6 +208,7 @@ var _ = Describe("dex rendering tests", func() {
{render.DexObjectName, render.DexNamespace, "", "v1", "Secret"},
{render.OIDCSecretName, render.DexNamespace, "", "v1", "Secret"},
{pullSecretName, render.DexNamespace, "", "v1", "Secret"},
{"tigera-dex", "", "policy", "v1beta1", "PodSecurityPolicy"},
}

for i, expectedRes := range expectedResources {
Expand Down Expand Up @@ -294,6 +296,7 @@ var _ = Describe("dex rendering tests", func() {
{render.OIDCSecretName, render.DexNamespace, "", "v1", "Secret"},
{pullSecretName, render.DexNamespace, "", "v1", "Secret"},
{"tigera-dex:csr-creator", "", "rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"},
{"tigera-dex", "", "policy", "v1beta1", "PodSecurityPolicy"},
}

for i, expectedRes := range expectedResources {
Expand All @@ -302,6 +305,18 @@ var _ = Describe("dex rendering tests", func() {
Expect(len(resources)).To(Equal(len(expectedResources)))
})

It("should render properly when PSP is not supported by the cluster", func() {
cfg.UsePSP = false
component := render.Dex(cfg)
Expect(component.ResolveImages(nil)).To(BeNil())
resources, _ := component.Objects()

// Should not contain any PodSecurityPolicies
for _, r := range resources {
Expect(r.GetObjectKind().GroupVersionKind().Kind).NotTo(Equal("PodSecurityPolicy"))
}
})

It("should not render PodAffinity when ControlPlaneReplicas is 1", func() {
var replicas int32 = 1
cfg.Installation.ControlPlaneReplicas = &replicas
Expand Down
26 changes: 23 additions & 3 deletions pkg/render/policyrecommendation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package render
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -28,6 +29,7 @@ import (
relasticsearch "github.com/tigera/operator/pkg/render/common/elasticsearch"
rmeta "github.com/tigera/operator/pkg/render/common/meta"
"github.com/tigera/operator/pkg/render/common/networkpolicy"
"github.com/tigera/operator/pkg/render/common/podsecuritypolicy"
"github.com/tigera/operator/pkg/render/common/secret"
"github.com/tigera/operator/pkg/render/common/securitycontext"
"github.com/tigera/operator/pkg/tls/certificatemanagement"
Expand All @@ -37,9 +39,10 @@ import (
const (
ElasticsearchPolicyRecommendationUserSecret = "tigera-ee-policy-recommendation-elasticsearch-access"

PolicyRecommendationName = "tigera-policy-recommendation"
PolicyRecommendationNamespace = PolicyRecommendationName
PolicyRecommendationPolicyName = networkpolicy.TigeraComponentPolicyPrefix + PolicyRecommendationName
PolicyRecommendationName = "tigera-policy-recommendation"
PolicyRecommendationNamespace = PolicyRecommendationName
PolicyRecommendationPodSecurityPolicyName = PolicyRecommendationName
PolicyRecommendationPolicyName = networkpolicy.TigeraComponentPolicyPrefix + PolicyRecommendationName

PolicyRecommendationTLSSecretName = "policy-recommendation-tls"
)
Expand Down Expand Up @@ -114,6 +117,10 @@ func (pr *policyRecommendationComponent) Objects() ([]client.Object, []client.Ob
pr.deployment(),
)

if pr.cfg.UsePSP {
objs = append(objs, pr.podSecurityPolicy())
}

return objs, nil
}

Expand Down Expand Up @@ -162,6 +169,15 @@ func (pr *policyRecommendationComponent) clusterRole() client.Object {
},
}

if pr.cfg.UsePSP {
rules = append(rules, rbacv1.PolicyRule{
APIGroups: []string{"policy"},
Resources: []string{"podsecuritypolicies"},
Verbs: []string{"use"},
ResourceNames: []string{PolicyRecommendationPodSecurityPolicyName},
})
}

return &rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1"},
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -195,6 +211,10 @@ func (pr *policyRecommendationComponent) clusterRoleBinding() client.Object {
}
}

func (pr *policyRecommendationComponent) podSecurityPolicy() *policyv1beta1.PodSecurityPolicy {
return podsecuritypolicy.NewBasePolicy(PolicyRecommendationPodSecurityPolicyName)
}

// deployment returns the policy recommendation deployments. It assumes that this is defined for
// management and standalone clusters only.
func (pr *policyRecommendationComponent) deployment() *appsv1.Deployment {
Expand Down
1 change: 1 addition & 0 deletions pkg/render/policyrecommendation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ var _ = Describe("Policy recommendation rendering tests", func() {
{name: "allow-tigera.default-deny", ns: "tigera-policy-recommendation", group: "projectcalico.org", version: "v3", kind: "NetworkPolicy"},
{name: "allow-tigera.tigera-policy-recommendation", ns: "tigera-policy-recommendation", group: "projectcalico.org", version: "v3", kind: "NetworkPolicy"},
{name: "tigera-policy-recommendation", ns: "tigera-policy-recommendation", group: "apps", version: "v1", kind: "Deployment"},
{name: "tigera-policy-recommendation", ns: "", group: "policy", version: "v1beta1", kind: "PodSecurityPolicy"},
}

Expect(len(resources)).To(Equal(len(expectedResources)))
Expand Down