mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-19 12:36:39 +00:00
fix: Enforce namespace metadata validation for capsule users only (#2042)
Signed-off-by: Tom Stockwell <tstockwell@redhat.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
|
||||
"github.com/projectcapsule/capsule/pkg/api"
|
||||
@@ -20,6 +21,8 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("creating a Namespace with user-specified labels and annotations", Ordered, Label("namespace", "metadata", "forbidden"), func() {
|
||||
originConfig := &capsulev1beta2.CapsuleConfiguration{}
|
||||
|
||||
tnt := &capsulev1beta2.Tenant{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-user-metadata-forbidden",
|
||||
@@ -62,7 +65,14 @@ var _ = Describe("creating a Namespace with user-specified labels and annotation
|
||||
},
|
||||
}
|
||||
|
||||
admin := rbac.UserSpec{
|
||||
Name: "admin",
|
||||
Kind: "User",
|
||||
}
|
||||
|
||||
JustBeforeEach(func() {
|
||||
Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: defaultConfigurationName}, originConfig)).To(Succeed())
|
||||
|
||||
EventuallyCreation(func() error {
|
||||
tnt.ResourceVersion = ""
|
||||
|
||||
@@ -70,13 +80,28 @@ var _ = Describe("creating a Namespace with user-specified labels and annotation
|
||||
}).Should(Succeed())
|
||||
|
||||
TenantReady(tnt, metav1.ConditionTrue, defaultTimeoutInterval)
|
||||
|
||||
ModifyCapsuleConfigurationOpts(func(configuration *capsulev1beta2.CapsuleConfiguration) {
|
||||
configuration.Spec.Administrators = []rbac.UserSpec{admin}
|
||||
})
|
||||
})
|
||||
|
||||
JustAfterEach(func() {
|
||||
EventuallyDeletion(tnt)
|
||||
|
||||
Eventually(func() error {
|
||||
c := &capsulev1beta2.CapsuleConfiguration{}
|
||||
if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: originConfig.Name}, c); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Spec = originConfig.Spec
|
||||
return k8sClient.Update(context.Background(), c)
|
||||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||||
})
|
||||
|
||||
It("should allow", func() {
|
||||
ctx := context.TODO()
|
||||
|
||||
By("specifying non-forbidden labels", func() {
|
||||
ns := NewNamespace("", map[string]string{
|
||||
"bim": "baz",
|
||||
@@ -114,6 +139,58 @@ var _ = Describe("creating a Namespace with user-specified labels and annotation
|
||||
g.Expect(ns.GetAnnotations()).To(HaveKeyWithValue("managed.projectcapsule.dev/source", "capsule"))
|
||||
}, defaultTimeoutInterval, time.Second).Should(Succeed())
|
||||
})
|
||||
|
||||
By("creating a Namespace with forbidden labels as an admin", func() {
|
||||
ns := NewNamespace("", map[string]string{
|
||||
"foo": "bar",
|
||||
"gatsby-custom": "value",
|
||||
meta.TenantLabel: tnt.GetName(),
|
||||
})
|
||||
|
||||
NamespaceCreation(ns, admin, defaultTimeoutInterval).Should(Succeed())
|
||||
NamespaceIsPartOfTenant(tnt, ns).Should(Succeed())
|
||||
})
|
||||
|
||||
By("creating a Namespace with forbidden annotations as an admin", func() {
|
||||
ns := NewNamespace("", map[string]string{
|
||||
meta.TenantLabel: tnt.GetName(),
|
||||
})
|
||||
ns.SetAnnotations(map[string]string{"foo": "bar", "gatsby-custom": "value"})
|
||||
|
||||
NamespaceCreation(ns, admin, defaultTimeoutInterval).Should(Succeed())
|
||||
NamespaceIsPartOfTenant(tnt, ns).Should(Succeed())
|
||||
})
|
||||
|
||||
By("updating a Namespace with a new forbidden label as an admin", func() {
|
||||
ns := NewNamespace("admin-update-labels", map[string]string{
|
||||
meta.TenantLabel: tnt.GetName(),
|
||||
})
|
||||
|
||||
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
||||
|
||||
original := ns.DeepCopy()
|
||||
ns.Labels["foo"] = "bar"
|
||||
ns.Labels["gatsby-custom"] = "value"
|
||||
|
||||
Eventually(func() error {
|
||||
return impersonationClient(admin.Name, nil).Patch(ctx, ns, client.MergeFrom(original))
|
||||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||||
})
|
||||
|
||||
By("updating a Namespace with a new forbidden annotation as an admin", func() {
|
||||
ns := NewNamespace("admin-update-annotations", map[string]string{
|
||||
meta.TenantLabel: tnt.GetName(),
|
||||
})
|
||||
|
||||
NamespaceCreation(ns, tnt.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
||||
|
||||
original := ns.DeepCopy()
|
||||
ns.SetAnnotations(map[string]string{"foo": "bar", "gatsby-custom": "value"})
|
||||
|
||||
Eventually(func() error {
|
||||
return impersonationClient(admin.Name, nil).Patch(ctx, ns, client.MergeFrom(original))
|
||||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
It("should fail when creating a Namespace", func() {
|
||||
|
||||
@@ -30,14 +30,14 @@ func UserMetadataHandler() handlers.TypedHandlerWithTenantUser[*corev1.Namespace
|
||||
func (h *userMetadataHandler) OnCreate(
|
||||
_ client.Client,
|
||||
_ client.Reader,
|
||||
_ users.AdmissionUser,
|
||||
user users.AdmissionUser,
|
||||
ns *corev1.Namespace,
|
||||
_ admission.Decoder,
|
||||
recorder events.EventRecorder,
|
||||
tnt *capsulev1beta2.Tenant,
|
||||
) handlers.Func {
|
||||
return func(ctx context.Context, req admission.Request) *admission.Response {
|
||||
if tnt.Spec.NamespaceOptions != nil {
|
||||
if tnt.Spec.NamespaceOptions != nil && user.IsCapsule() {
|
||||
labels, annotations, err := userMetadataForValidation(ns, nil, tnt)
|
||||
if err != nil {
|
||||
return ad.ErroredResponse(err)
|
||||
@@ -64,7 +64,7 @@ func (h *userMetadataHandler) OnCreate(
|
||||
func (h *userMetadataHandler) OnUpdate(
|
||||
_ client.Client,
|
||||
_ client.Reader,
|
||||
_ users.AdmissionUser,
|
||||
user users.AdmissionUser,
|
||||
newNs *corev1.Namespace,
|
||||
oldNs *corev1.Namespace,
|
||||
_ admission.Decoder,
|
||||
@@ -111,7 +111,7 @@ func (h *userMetadataHandler) OnUpdate(
|
||||
}
|
||||
}
|
||||
|
||||
if tnt.Spec.NamespaceOptions != nil {
|
||||
if tnt.Spec.NamespaceOptions != nil && user.IsCapsule() {
|
||||
labels, annotations, err := userMetadataForValidation(newNs, oldNs, tnt)
|
||||
if err != nil {
|
||||
return ad.ErroredResponse(err)
|
||||
|
||||
Reference in New Issue
Block a user