Skip to content

Commit

Permalink
Render DPI RBAC to access Linseed for multi-tenat management clusters
Browse files Browse the repository at this point in the history
  • Loading branch information
asincu committed Aug 24, 2024
1 parent a0208eb commit 6b4297a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 2 deletions.
14 changes: 12 additions & 2 deletions pkg/controller/intrusiondetection/intrusiondetection_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,6 @@ func (r *ReconcileIntrusionDetection) Reconcile(ctx context.Context, request rec
}

if !r.multiTenant {
// DPI is only supported in single-tenant / zero-tenant clusters.

// FIXME: core controller creates TyphaNodeTLSConfig, this controller should only get it.
// But changing the call from GetOrCreateTyphaNodeTLSConfig() to GetTyphaNodeTLSConfig()
// makes tests fail, this needs to be looked at.
Expand Down Expand Up @@ -559,6 +557,18 @@ func (r *ReconcileIntrusionDetection) Reconcile(ctx context.Context, request rec
},
TrustedBundle: typhaNodeTLS.TrustedBundle,
}))
} else {
dpiComponent := dpi.DPI(&dpi.DPIConfig{
IntrusionDetection: instance,
Installation: network,
PullSecrets: pullSecrets,
OpenShift: r.provider.IsOpenShift(),
ManagedCluster: isManagedCluster,
ManagementCluster: isManagementCluster,
ClusterDomain: r.clusterDomain,
Tenant: tenant,
})
components = append(components, dpiComponent)
}

for _, comp := range components {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -675,4 +675,66 @@ var _ = Describe("IntrusionDetection controller tests", func() {
Expect(*ids.Spec.ComponentResources[0].ResourceRequirements.Limits.Memory()).Should(Equal(resource.MustParse(dpi.DefaultMemoryLimit)))
})
})

Context("Multi-tenant mode", func() {
var tenantANamespace = "tenantANamespace"

BeforeEach(func() {
mockStatus = &status.MockStatus{}
mockStatus.On("OnCRFound").Return()
mockStatus.On("SetMetaData", mock.Anything).Return()

// Update the reconciler to run in external ES mode for these tests.
r.elasticExternal = true
r.multiTenant = true

// Create the Tenant resources for tenant-a
tenantA := &operatorv1.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Namespace: tenantANamespace,
},
Spec: operatorv1.TenantSpec{ID: "tenant-a"},
}
Expect(c.Create(ctx, tenantA)).NotTo(HaveOccurred())

err := c.Create(ctx, &operatorv1.IntrusionDetection{ObjectMeta: metav1.ObjectMeta{Name: "tigera-secure", Namespace: tenantANamespace}})
Expect(err).NotTo(HaveOccurred())

certificateManagerTenantA, err := certificatemanager.Create(c, nil, "", tenantANamespace, certificatemanager.AllowCACreation(), certificatemanager.WithTenant(tenantA))
Expect(err).NotTo(HaveOccurred())
Expect(c.Create(ctx, certificateManagerTenantA.KeyPair().Secret(tenantANamespace)))
tenantABundle, err := certificateManagerTenantA.CreateMultiTenantTrustedBundleWithSystemRootCertificates()
Expect(err).NotTo(HaveOccurred())
Expect(c.Create(ctx, tenantABundle.ConfigMap(tenantANamespace))).NotTo(HaveOccurred())

linseedTLSTenantA, err := certificateManagerTenantA.GetOrCreateKeyPair(c, render.TigeraLinseedSecret, tenantANamespace, []string{render.TigeraLinseedSecret})
Expect(err).NotTo(HaveOccurred())
Expect(c.Create(ctx, linseedTLSTenantA.Secret(tenantANamespace))).NotTo(HaveOccurred())

Expect(c.Delete(ctx, &v3.DeepPacketInspection{ObjectMeta: metav1.ObjectMeta{Name: "test-dpi", Namespace: "test-dpi-ns"}})).ShouldNot(HaveOccurred())
})

It("should Reconcile with default values for DPI", func() {
clusterRole := rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: dpi.DeepPacketInspectionLinseedRBACName,
},
}
clusterRoleBinding := rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: dpi.DeepPacketInspectionLinseedRBACName,
},
}

_, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Namespace: tenantANamespace}})
Expect(err).ShouldNot(HaveOccurred())

err = test.GetResource(c, &clusterRole)
Expect(err).ShouldNot(HaveOccurred())

err = test.GetResource(c, &clusterRoleBinding)
Expect(err).ShouldNot(HaveOccurred())
})
})
})
13 changes: 13 additions & 0 deletions pkg/render/intrusiondetection/dpi/dpi.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type DPIConfig struct {
HasNoDPIResource bool
ClusterDomain string
DPICertSecret certificatemanagement.KeyPairInterface

Tenant *operatorv1.Tenant
}

func DPI(cfg *DPIConfig) render.Component {
Expand Down Expand Up @@ -89,6 +91,17 @@ func (d *dpiComponent) ResolveImages(is *operatorv1.ImageSet) error {

func (d *dpiComponent) Objects() (objsToCreate, objsToDelete []client.Object) {
var toCreate, toDelete []client.Object
if d.cfg.Tenant.MultiTenant() {
// We need to create the RBAC needed to allow managed cluster
// to push data via Linseed. Since DPI does not get deployed in the
// multi-tenant management cluster, Linseed token is created to match
// the canonical namespace. The ClusterRoleBinding will use the
// canonical service account.
toCreate = append(toCreate, d.dpiLinseedAccessClusterRole())
toCreate = append(toCreate, d.dpiLinseedAccessClusterRoleBinding())
return toCreate, toDelete
}

if d.cfg.HasNoLicense {
toDelete = append(toDelete, render.CreateNamespace(DeepPacketInspectionNamespace, d.cfg.Installation.KubernetesProvider, render.PSSPrivileged))
} else {
Expand Down
39 changes: 39 additions & 0 deletions pkg/render/intrusiondetection/dpi/dpi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,45 @@ var _ = Describe("DPI rendering tests", func() {
Entry("for managed, openshift-dns", testutils.AllowTigeraScenario{ManagedCluster: true, OpenShift: true}),
)
})

Context("multi-tenant", func() {
It("should render RBAC to allow Linseed access", func() {
cfg.Tenant = &operatorv1.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenantA",
Namespace: "tenantANamespace",
},
Spec: operatorv1.TenantSpec{
ID: "tenant-a-id",
},
}
dpiComponent := dpi.DPI(cfg)

resources, _ := dpiComponent.Objects()

cr := rtest.GetResource(resources, dpi.DeepPacketInspectionLinseedRBACName, "", rbacv1.GroupName, "v1", "ClusterRole").(*rbacv1.ClusterRole)
expectedRules := []rbacv1.PolicyRule{
{
APIGroups: []string{"linseed.tigera.io"},
Resources: []string{"events"},
Verbs: []string{
"create",
},
},
}
Expect(cr.Rules).To(ContainElements(expectedRules))
rb := rtest.GetResource(resources, dpi.DeepPacketInspectionLinseedRBACName, "", rbacv1.GroupName, "v1", "ClusterRoleBinding").(*rbacv1.ClusterRoleBinding)
Expect(rb.RoleRef.Kind).To(Equal("ClusterRole"))
Expect(rb.RoleRef.Name).To(Equal(dpi.DeepPacketInspectionLinseedRBACName))
Expect(rb.Subjects).To(ContainElements([]rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: dpi.DeepPacketInspectionName,
Namespace: dpi.DeepPacketInspectionNamespace,
},
}))
})
})
})

func validateDPIComponents(resources []client.Object, openshift bool) {
Expand Down

0 comments on commit 6b4297a

Please sign in to comment.