Skip to content

Commit

Permalink
Merge pull request #3543 from radixo/applicationlayer-status-sidecarw…
Browse files Browse the repository at this point in the history
…ebhook

Introdoces SidecarWebhook status
  • Loading branch information
tmjd authored Oct 16, 2024
2 parents be04bc9 + aa45e99 commit 784c9a7
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 5 deletions.
8 changes: 8 additions & 0 deletions api/v1/applicationlayer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ type ApplicationLayerPolicyStatusType string
// +kubebuilder:validation:Enum=Enabled;Disabled
type SidecarStatusType string

// +kubebuilder:validation:Enum=Enabled;Disabled
type SidecarWebhookStateType string

const (
WAFDisabled WAFStatusType = "Disabled"
WAFEnabled WAFStatusType = "Enabled"
Expand All @@ -67,6 +70,8 @@ const (
ApplicationLayerPolicyDisabled ApplicationLayerPolicyStatusType = "Disabled"
SidecarEnabled SidecarStatusType = "Enabled"
SidecarDisabled SidecarStatusType = "Disabled"
SidecarWebhookStateEnabled SidecarWebhookStateType = "Enabled"
SidecarWebhookStateDisabled SidecarWebhookStateType = "Disabled"
)

type EnvoySettings struct {
Expand Down Expand Up @@ -110,6 +115,9 @@ type ApplicationLayerStatus struct {
// State provides user-readable status.
State string `json:"state,omitempty"`

// SidecarWebhook provides the state of sidecar injection mutatinwebhookconfiguration
SidecarWebhook *SidecarWebhookStateType `json:"sidecarWebhook,omitempty"`

// Conditions represents the latest observed set of conditions for the component. A component may be one or more of
// Ready, Progressing, Degraded or other customer types.
// +optional
Expand Down
5 changes: 5 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ const (
// references with any that already exist on the object rather than replace the owner references. Further
// the controller in the owner reference will not be set.
MultipleOwnersLabel = "operator.tigera.io/multipleOwners"

// Sidecar common names
SidecarMutatingWebhookConfigName = "tigera-sidecar-webhook-configuration"
)
26 changes: 26 additions & 0 deletions pkg/controller/applicationlayer/applicationlayer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ import (
"github.com/tigera/operator/pkg/render/applicationlayer/embed"
rmeta "github.com/tigera/operator/pkg/render/common/meta"

admregv1 "k8s.io/api/admissionregistration/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -122,6 +124,13 @@ func add(mgr manager.Manager, c ctrlruntime.Controller) error {
)
}

// Watch mutatingwebhookconfiguration responsible for sidecar injetion
err = c.WatchObject(&admregv1.MutatingWebhookConfiguration{ObjectMeta: metav1.ObjectMeta{Name: common.SidecarMutatingWebhookConfigName}},
&handler.EnqueueRequestForObject{})
if err != nil {
return fmt.Errorf("applicationlayer-controller failed to watch sidecar MutatingWebhookConfiguration resource: %w", err)
}

// Watch configmaps created for envoy and dikastes in calico-system namespace:
maps := []string{
applicationlayer.EnvoyConfigMapName,
Expand Down Expand Up @@ -305,6 +314,18 @@ func (r *ReconcileApplicationLayer) Reconcile(ctx context.Context, request recon
return reconcile.Result{RequeueAfter: utils.StandardRetry}, nil
}

err = r.client.Get(ctx, types.NamespacedName{Name: common.SidecarMutatingWebhookConfigName}, &admregv1.MutatingWebhookConfiguration{})
if err != nil {
sidecarWebhookDisabled := operatorv1.SidecarWebhookStateDisabled
instance.Status.SidecarWebhook = &sidecarWebhookDisabled
if !apierrors.IsNotFound(err) {
return reconcile.Result{}, err
}
} else {
sidecarWebhookEnabled := operatorv1.SidecarWebhookStateEnabled
instance.Status.SidecarWebhook = &sidecarWebhookEnabled
}

// Everything is available - update the CRD status.
instance.Status.State = operatorv1.TigeraStatusReady
if err = r.client.Status().Update(ctx, instance); err != nil {
Expand All @@ -323,6 +344,7 @@ func updateApplicationLayerWithDefaults(al *operatorv1.ApplicationLayer) {
defaultWebApplicationFirewallStatusType operatorv1.WAFStatusType = operatorv1.WAFDisabled
defaultApplicationLayerPolicyStatusType operatorv1.ApplicationLayerPolicyStatusType = operatorv1.ApplicationLayerPolicyDisabled
defaultSidecarStatusType operatorv1.SidecarStatusType = operatorv1.SidecarDisabled
defaultSidecarWebhookStateType operatorv1.SidecarWebhookStateType = operatorv1.SidecarWebhookStateDisabled
)

if al.Spec.LogCollection == nil {
Expand Down Expand Up @@ -360,6 +382,10 @@ func updateApplicationLayerWithDefaults(al *operatorv1.ApplicationLayer) {
if al.Spec.SidecarInjection == nil {
al.Spec.SidecarInjection = &defaultSidecarStatusType
}

if al.Status.SidecarWebhook == nil {
al.Status.SidecarWebhook = &defaultSidecarWebhookStateType
}
}

// validateApplicationLayer validates ApplicationLayer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
. "github.com/onsi/gomega"
"github.com/stretchr/testify/mock"

admregv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
rbacv1 "k8s.io/api/rbac/v1"
Expand Down Expand Up @@ -61,6 +62,7 @@ var _ = Describe("Application layer controller tests", func() {
Expect(rbacv1.SchemeBuilder.AddToScheme(scheme)).ShouldNot(HaveOccurred())
Expect(batchv1.SchemeBuilder.AddToScheme(scheme)).ShouldNot(HaveOccurred())
Expect(operatorv1.SchemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
Expect(admregv1.SchemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
// Create a client that will have a crud interface of k8s objects.
c = ctrlrfake.DefaultFakeClientBuilder(scheme).Build()
ctx = context.Background()
Expand Down Expand Up @@ -303,6 +305,66 @@ var _ = Describe("Application layer controller tests", func() {
Expect(test.GetResource(c, &fc)).To(BeNil())
Expect(*fc.Spec.TPROXYMode).To(Equal(crdv1.TPROXYModeOptionDisabled))
})

It("should render proper SidecarWebhook status", func() {
mockStatus.On("AddDaemonsets", mock.Anything).Return()
mockStatus.On("AddDeployments", mock.Anything).Return()
mockStatus.On("IsAvailable").Return(true)
mockStatus.On("AddStatefulSets", mock.Anything).Return()
mockStatus.On("AddCronJobs", mock.Anything)
mockStatus.On("OnCRNotFound").Return()
mockStatus.On("ClearDegraded")
mockStatus.On("SetDegraded", "Waiting for LicenseKeyAPI to be ready", "").Return().Maybe()
mockStatus.On("ReadyToMonitor")
mockStatus.On("SetMetaData", mock.Anything).Return()
Expect(c.Create(ctx, installation)).NotTo(HaveOccurred())

By("applying the ApplicationLayer CR to the fake cluster")
enabled := operatorv1.L7LogCollectionEnabled
Expect(c.Create(ctx, &operatorv1.ApplicationLayer{
ObjectMeta: metav1.ObjectMeta{Name: "tigera-secure"},
Spec: operatorv1.ApplicationLayerSpec{
LogCollection: &operatorv1.LogCollectionSpec{
CollectLogs: &enabled,
},
},
})).NotTo(HaveOccurred())

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

instance, err := getApplicationLayer(ctx, r.client)
Expect(err).ShouldNot(HaveOccurred())

Expect(*instance.Status.SidecarWebhook).To(Equal(operatorv1.SidecarWebhookStateDisabled))

By("creating sidecar mutatingwebhookconfiguration")
sidecarMutatingWebhook := &admregv1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: common.SidecarMutatingWebhookConfigName,
},
}
Expect(c.Create(ctx, sidecarMutatingWebhook)).NotTo(HaveOccurred())

_, err = r.Reconcile(ctx, reconcile.Request{})
Expect(err).ShouldNot(HaveOccurred())

instance, err = getApplicationLayer(ctx, r.client)
Expect(err).ShouldNot(HaveOccurred())

Expect(*instance.Status.SidecarWebhook).To(Equal(operatorv1.SidecarWebhookStateEnabled))

By("deleting sidecar mutatingwebhookconfiguration")
Expect(c.Delete(ctx, sidecarMutatingWebhook)).NotTo(HaveOccurred())

_, err = r.Reconcile(ctx, reconcile.Request{})
Expect(err).ShouldNot(HaveOccurred())

instance, err = getApplicationLayer(ctx, r.client)
Expect(err).ShouldNot(HaveOccurred())

Expect(*instance.Status.SidecarWebhook).To(Equal(operatorv1.SidecarWebhookStateDisabled))
})
Context("Reconcile for Condition status", func() {
generation := int64(2)
BeforeEach(func() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
annotations:
api-approved.kubernetes.io: https://github.com/kubernetes-sigs/network-policy-api/pull/30
policy.networking.k8s.io/bundle-version: v0.1.1
policy.networking.k8s.io/channel: standard
policy.networking.k8s.io/channel: experimental
creationTimestamp: null
name: adminnetworkpolicies.policy.networking.k8s.io
spec:
Expand Down Expand Up @@ -115,6 +115,16 @@ spec:
maxProperties: 1
minProperties: 1
properties:
namedPort:
description: |-
NamedPort selects a port on a pod(s) based on name.
Support: Extended
<network-policy-api:experimental>
type: string
portNumber:
description: |-
Port selects a port on a pod(s) based on number.
Expand Down Expand Up @@ -258,6 +268,97 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
networks:
description: |-
Networks defines a way to select peers via CIDR blocks.
This is intended for representing entities that live outside the cluster,
which can't be selected by pods, namespaces and nodes peers, but note
that cluster-internal traffic will be checked against the rule as
well. So if you Allow or Deny traffic to `"0.0.0.0/0"`, that will allow
or deny all IPv4 pod-to-pod traffic as well. If you don't want that,
add a rule that Passes all pod traffic before the Networks rule.
Each item in Networks should be provided in the CIDR format and should be
IPv4 or IPv6, for example "10.0.0.0/8" or "fd00::/8".
Networks can have upto 25 CIDRs specified.
Support: Extended
<network-policy-api:experimental>
items:
description: |-
CIDR is an IP address range in CIDR notation (for example, "10.0.0.0/8" or "fd00::/8").
This string must be validated by implementations using net.ParseCIDR
TODO: Introduce CEL CIDR validation regex isCIDR() in Kube 1.31 when it is available.
maxLength: 43
type: string
x-kubernetes-validations:
- message: CIDR must be either an IPv4 or IPv6 address.
IPv4 address embedded in IPv6 addresses are not
supported
rule: self.contains(':') != self.contains('.')
maxItems: 25
minItems: 1
type: array
x-kubernetes-list-type: set
nodes:
description: |-
Nodes defines a way to select a set of nodes in
the cluster. This field follows standard label selector
semantics; if present but empty, it selects all Nodes.
Support: Extended
<network-policy-api:experimental>
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
pods:
description: |-
Pods defines a way to select a set of pods in
Expand Down Expand Up @@ -373,6 +474,11 @@ spec:
- action
- to
type: object
x-kubernetes-validations:
- message: networks/nodes peer cannot be set with namedPorts since
there are no namedPorts for networks/nodes
rule: '!(self.to.exists(peer, has(peer.networks) || has(peer.nodes))
&& has(self.ports) && self.ports.exists(port, has(port.namedPort)))'
maxItems: 100
type: array
ingress:
Expand Down Expand Up @@ -617,6 +723,16 @@ spec:
maxProperties: 1
minProperties: 1
properties:
namedPort:
description: |-
NamedPort selects a port on a pod(s) based on name.
Support: Extended
<network-policy-api:experimental>
type: string
portNumber:
description: |-
Port selects a port on a pod(s) based on number.
Expand Down
7 changes: 7 additions & 0 deletions pkg/crds/operator/operator.tigera.io_applicationlayers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,13 @@ spec:
- type
type: object
type: array
sidecarWebhook:
description: SidecarWebhook provides the state of sidecar injection
mutatinwebhookconfiguration
enum:
- Enabled
- Disabled
type: string
state:
description: State provides user-readable status.
type: string
Expand Down
7 changes: 3 additions & 4 deletions pkg/render/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/tigera/api/pkg/lib/numorstring"

operatorv1 "github.com/tigera/operator/api/v1"
"github.com/tigera/operator/pkg/common"
"github.com/tigera/operator/pkg/components"
"github.com/tigera/operator/pkg/controller/k8sapi"
rcomp "github.com/tigera/operator/pkg/render/common/components"
Expand Down Expand Up @@ -69,8 +70,6 @@ const (
MultiTenantManagedClustersAccessClusterRoleName = "tigera-managed-cluster-access"
L7AdmissionControllerContainerName = "calico-l7-admission-controller"
L7AdmissionControllerPort = 6443

SidecarMutatingWebhookConfigName = "tigera-sidecar-webhook-configuration"
)

var TigeraAPIServerEntityRule = v3.EntityRule{
Expand Down Expand Up @@ -293,7 +292,7 @@ func (c *apiServerComponent) Objects() ([]client.Object, []client.Object) {
if c.cfg.IsSidecarInjectionEnabled() {
namespacedEnterpriseObjects = append(namespacedEnterpriseObjects, c.sidecarMutatingWebhookConfig())
} else {
objsToDelete = append(objsToDelete, &admregv1.MutatingWebhookConfiguration{ObjectMeta: metav1.ObjectMeta{Name: SidecarMutatingWebhookConfigName}})
objsToDelete = append(objsToDelete, &admregv1.MutatingWebhookConfiguration{ObjectMeta: metav1.ObjectMeta{Name: common.SidecarMutatingWebhookConfigName}})
}

podSecurityNamespaceLabel := PodSecurityStandard(PSSRestricted)
Expand Down Expand Up @@ -1104,7 +1103,7 @@ func (c *apiServerComponent) sidecarMutatingWebhookConfig() *admregv1.MutatingWe
Kind: "MutatingWebhookConfiguration",
APIVersion: "admissionregistration.k8s.io/v1",
},
ObjectMeta: metav1.ObjectMeta{Name: SidecarMutatingWebhookConfigName},
ObjectMeta: metav1.ObjectMeta{Name: common.SidecarMutatingWebhookConfigName},
Webhooks: []admregv1.MutatingWebhook{
{
AdmissionReviewVersions: []string{"v1"},
Expand Down

0 comments on commit 784c9a7

Please sign in to comment.