Skip to content

Commit

Permalink
feat(kuma-cp): require kuma.io/origin: zone label when creating zon…
Browse files Browse the repository at this point in the history
…e-origination policies (#8873)

Signed-off-by: Ilya Lobkov <[email protected]>
  • Loading branch information
lobkovilya authored Jan 23, 2024
1 parent 88bf958 commit 17025b3
Show file tree
Hide file tree
Showing 17 changed files with 481 additions and 81 deletions.
20 changes: 17 additions & 3 deletions api/mesh/v1alpha1/dataplane_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,25 @@ const (

// ResourceOriginLabel is a standard label that has information about the origin of the resource.
// It can be either "global" or "zone".
ResourceOriginLabel = "kuma.io/origin"
ResourceOriginGlobal = "global"
ResourceOriginZone = "zone"
ResourceOriginLabel = "kuma.io/origin"
)

type ResourceOrigin string

const (
GlobalResourceOrigin ResourceOrigin = "global"
ZoneResourceOrigin ResourceOrigin = "zone"
)

func (o ResourceOrigin) IsValid() error {
switch o {
case GlobalResourceOrigin, ZoneResourceOrigin:
return nil
default:
return errors.Errorf("unknown resource origin %q", o)
}
}

type ProxyType string

const (
Expand Down
2 changes: 2 additions & 0 deletions docs/generated/raw/kuma-cp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,8 @@ multizone:
# Response backoff is a time Zone CP waits before sending ACK/NACK.
# This is a way to slow down Global CP from sending resources too often.
responseBackoff: 0s # ENV: KUMA_MULTIZONE_ZONE_KDS_RESPONSE_BACKOFF
# disableOriginLabelValidation disables validation of the origin label when applying resources on Zone CP
disableOriginLabelValidation: false # ENV: KUMA_MULTIZONE_ZONE_DISABLE_ORIGIN_LABEL_VALIDATION

# Diagnostics configuration
diagnostics:
Expand Down
41 changes: 28 additions & 13 deletions pkg/api-server/resource_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ const (
)

type resourceEndpoints struct {
mode config_core.CpMode
federatedZone bool
zoneName string
resManager manager.ResourceManager
descriptor model.ResourceTypeDescriptor
resourceAccess access.ResourceAccess
k8sMapper k8s.ResourceMapperFunc
filter func(request *restful.Request) (store.ListFilterFunc, error)
meshContextBuilder xds_context.MeshContextBuilder
mode config_core.CpMode
federatedZone bool
zoneName string
resManager manager.ResourceManager
descriptor model.ResourceTypeDescriptor
resourceAccess access.ResourceAccess
k8sMapper k8s.ResourceMapperFunc
filter func(request *restful.Request) (store.ListFilterFunc, error)
meshContextBuilder xds_context.MeshContextBuilder
disableOriginLabelValidation bool
}

func typeToLegacyOverviewPath(resourceType model.ResourceType) string {
Expand Down Expand Up @@ -442,7 +443,7 @@ func (r *resourceEndpoints) validateResourceRequest(request *restful.Request, re
err.AddViolation("mesh", "mesh from the URL has to be the same as in body")
}

err.AddError("labels", r.validateLabels(resourceMeta.Labels))
err.AddError("labels", r.validateLabels(resourceMeta))

if create {
err.AddError("", mesh.ValidateMeta(resourceMeta, r.descriptor.Scope))
Expand All @@ -456,13 +457,27 @@ func (r *resourceEndpoints) validateResourceRequest(request *restful.Request, re
return err.OrNil()
}

func (r *resourceEndpoints) validateLabels(labels map[string]string) validators.ValidationError {
func (r *resourceEndpoints) validateLabels(rm model.ResourceMeta) validators.ValidationError {
var err validators.ValidationError
for _, k := range maps.SortedKeys(labels) {

origin, ok := model.ResourceOrigin(rm)
if ok {
if oerr := origin.IsValid(); oerr != nil {
err.AddViolationAt(validators.Root().Key(mesh_proto.ResourceOriginLabel), oerr.Error())
}
}

if !r.disableOriginLabelValidation && r.federatedZone && r.descriptor.IsPluginOriginated {
if !ok || origin != mesh_proto.ZoneResourceOrigin {
err.AddViolationAt(validators.Root().Key(mesh_proto.ResourceOriginLabel), fmt.Sprintf("the origin label must be set to '%s'", mesh_proto.ZoneResourceOrigin))
}
}

for _, k := range maps.SortedKeys(rm.GetLabels()) {
for _, msg := range validation.IsQualifiedName(k) {
err.AddViolationAt(validators.Root().Key(k), msg)
}
for _, msg := range validation.IsValidLabelValue(labels[k]) {
for _, msg := range validation.IsValidLabelValue(rm.GetLabels()[k]) {
err.AddViolationAt(validators.Root().Key(k), msg)
}
}
Expand Down
17 changes: 9 additions & 8 deletions pkg/api-server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,14 +263,15 @@ func addResourcesEndpoints(
definition.ReadOnly = true
}
endpoints := resourceEndpoints{
k8sMapper: k8sMapper,
mode: cfg.Mode,
federatedZone: cfg.IsFederatedZoneCP(),
resManager: resManager,
descriptor: definition,
resourceAccess: resourceAccess,
filter: filters.Resource(definition),
meshContextBuilder: meshContextBuilder,
k8sMapper: k8sMapper,
mode: cfg.Mode,
federatedZone: cfg.IsFederatedZoneCP(),
resManager: resManager,
descriptor: definition,
resourceAccess: resourceAccess,
filter: filters.Resource(definition),
meshContextBuilder: meshContextBuilder,
disableOriginLabelValidation: cfg.Multizone.Zone.DisableOriginLabelValidation,
}
if cfg.Mode == config_core.Zone && cfg.Multizone != nil && cfg.Multizone.Zone != nil {
endpoints.zoneName = cfg.Multizone.Zone.Name
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/app/kuma-cp/kuma-cp.defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,8 @@ multizone:
# Response backoff is a time Zone CP waits before sending ACK/NACK.
# This is a way to slow down Global CP from sending resources too often.
responseBackoff: 0s # ENV: KUMA_MULTIZONE_ZONE_KDS_RESPONSE_BACKOFF
# disableOriginLabelValidation disables validation of the origin label when applying resources on Zone CP
disableOriginLabelValidation: false # ENV: KUMA_MULTIZONE_ZONE_DISABLE_ORIGIN_LABEL_VALIDATION

# Diagnostics configuration
diagnostics:
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ multizone:
nackBackoff: 21s
responseBackoff: 2s
tlsSkipVerify: true
disableOriginLabelValidation: true
dnsServer:
domain: test-domain
CIDR: 127.1.0.0/16
Expand Down Expand Up @@ -890,6 +891,7 @@ tracing:
"KUMA_MULTIZONE_ZONE_KDS_NACK_BACKOFF": "21s",
"KUMA_MULTIZONE_ZONE_KDS_RESPONSE_BACKOFF": "2s",
"KUMA_MULTIZONE_ZONE_KDS_TLS_SKIP_VERIFY": "true",
"KUMA_MULTIZONE_ZONE_DISABLE_ORIGIN_LABEL_VALIDATION": "true",
"KUMA_EXPERIMENTAL_KDS_DELTA_ENABLED": "true",
"KUMA_MULTIZONE_GLOBAL_KDS_ZONE_INSIGHT_FLUSH_INTERVAL": "5s",
"KUMA_DEFAULTS_SKIP_MESH_CREATION": "true",
Expand Down
3 changes: 3 additions & 0 deletions pkg/config/multizone/multicluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type ZoneConfig struct {
GlobalAddress string `json:"globalAddress,omitempty" envconfig:"kuma_multizone_zone_global_address"`
// KDS Configuration
KDS *KdsClientConfig `json:"kds,omitempty"`
// DisableOriginLabelValidation disables validation of the origin label when applying resources on Zone CP
DisableOriginLabelValidation bool `json:"disableOriginLabelValidation,omitempty" envconfig:"kuma_multizone_zone_disable_origin_label_validation"`
}

func (r *ZoneConfig) Sanitize() {
Expand Down Expand Up @@ -118,6 +120,7 @@ func DefaultZoneConfig() *ZoneConfig {
MsgSendTimeout: config_types.Duration{Duration: 60 * time.Second},
NackBackoff: config_types.Duration{Duration: 5 * time.Second},
},
DisableOriginLabelValidation: false,
}
}

Expand Down
15 changes: 11 additions & 4 deletions pkg/core/resources/model/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,11 +399,11 @@ func IsReferenced(refMeta ResourceMeta, refName string, resourceMeta ResourceMet
func IsLocallyOriginated(mode config_core.CpMode, r Resource) bool {
switch mode {
case config_core.Global:
origin, ok := r.GetMeta().GetLabels()[mesh_proto.ResourceOriginLabel]
return !ok || origin == mesh_proto.ResourceOriginGlobal
origin, ok := ResourceOrigin(r.GetMeta())
return !ok || origin == mesh_proto.GlobalResourceOrigin
case config_core.Zone:
origin, ok := r.GetMeta().GetLabels()[mesh_proto.ResourceOriginLabel]
return !ok || origin == mesh_proto.ResourceOriginZone
origin, ok := ResourceOrigin(r.GetMeta())
return !ok || origin == mesh_proto.ZoneResourceOrigin
default:
return true
}
Expand All @@ -419,6 +419,13 @@ func GetDisplayName(r Resource) string {
return r.GetMeta().GetName()
}

func ResourceOrigin(rm ResourceMeta) (mesh_proto.ResourceOrigin, bool) {
if labels := rm.GetLabels(); labels != nil && labels[mesh_proto.ResourceOriginLabel] != "" {
return mesh_proto.ResourceOrigin(labels[mesh_proto.ResourceOriginLabel]), true
}
return "", false
}

// ZoneOfResource returns zone from which the resource was synced to Global CP
// There is no information in the resource itself whether the resource is synced or created on the CP.
// Therefore, it's a caller responsibility to make use it only on synced resources.
Expand Down
4 changes: 2 additions & 2 deletions pkg/kds/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func DefaultContext(
}

globalMappers := []reconcile.ResourceMapper{
UpdateResourceMeta(util.WithLabel(mesh_proto.ResourceOriginLabel, mesh_proto.ResourceOriginGlobal)),
UpdateResourceMeta(util.WithLabel(mesh_proto.ResourceOriginLabel, string(mesh_proto.GlobalResourceOrigin))),
reconcile.If(
reconcile.And(
reconcile.TypeIs(system.GlobalSecretType),
Expand All @@ -83,7 +83,7 @@ func DefaultContext(

zoneMappers := []reconcile.ResourceMapper{
UpdateResourceMeta(
util.WithLabel(mesh_proto.ResourceOriginLabel, mesh_proto.ResourceOriginZone),
util.WithLabel(mesh_proto.ResourceOriginLabel, string(mesh_proto.ZoneResourceOrigin)),
util.WithLabel(mesh_proto.ZoneTag, cfg.Multizone.Zone.Name),
),
MapInsightResourcesZeroGeneration,
Expand Down
2 changes: 1 addition & 1 deletion pkg/kds/global/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func Callbacks(s sync_store.ResourceSyncer, k8sStore bool, kubeFactory resources
for _, r := range rs.GetItems() {
r.SetMeta(util.CloneResourceMeta(r.GetMeta(),
util.WithLabel(mesh_proto.ZoneTag, clusterName),
util.WithLabel(mesh_proto.ResourceOriginLabel, mesh_proto.ResourceOriginZone),
util.WithLabel(mesh_proto.ResourceOriginLabel, string(mesh_proto.ZoneResourceOrigin)),
))
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/kds/v2/client/zone_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ var _ = Describe("Zone Delta Sync", func() {

Expect(actual.Items[0].Spec).To(Equal(samples.Mesh1))
Expect(actual.Items[0].Meta.GetLabels()).To(Equal(map[string]string{
mesh_proto.ResourceOriginLabel: mesh_proto.ResourceOriginGlobal,
mesh_proto.ResourceOriginLabel: string(mesh_proto.GlobalResourceOrigin),
"foo": "bar",
}))
})
Expand All @@ -162,7 +162,7 @@ var _ = Describe("Zone Delta Sync", func() {

Expect(actual.Items[0].Spec).To(Equal(samples.Mesh1))
Expect(actual.Items[0].Meta.GetLabels()).To(Equal(map[string]string{
mesh_proto.ResourceOriginLabel: mesh_proto.ResourceOriginGlobal,
mesh_proto.ResourceOriginLabel: string(mesh_proto.GlobalResourceOrigin),
"foo": "bar",
}))

Expand All @@ -184,7 +184,7 @@ var _ = Describe("Zone Delta Sync", func() {
// then zone store should have updated mesh
g.Expect(actual.Items[0].GetSpec().(*mesh_proto.Mesh).Mtls).To(BeNil())
g.Expect(actual.Items[0].GetMeta().GetLabels()).To(Equal(map[string]string{
mesh_proto.ResourceOriginLabel: mesh_proto.ResourceOriginGlobal,
mesh_proto.ResourceOriginLabel: string(mesh_proto.GlobalResourceOrigin),
"foo": "barbar",
"newlabel": "newvalue",
}))
Expand Down Expand Up @@ -299,7 +299,7 @@ var _ = Describe("Zone Delta Sync", func() {
g.Expect(err).ToNot(HaveOccurred())
g.Expect(actual.Items).To(HaveLen(1))
g.Expect(actual.Items[0].GetMeta().GetLabels()).To(Equal(map[string]string{
mesh_proto.ResourceOriginLabel: mesh_proto.ResourceOriginGlobal,
mesh_proto.ResourceOriginLabel: string(mesh_proto.GlobalResourceOrigin),
}))
}, "5s", "100ms").Should(Succeed())
})
Expand Down
2 changes: 1 addition & 1 deletion pkg/kds/v2/store/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ func GlobalSyncCallback(
for _, r := range upstream.AddedResources.GetItems() {
r.SetMeta(util.CloneResourceMeta(r.GetMeta(),
util.WithLabel(mesh_proto.ZoneTag, upstream.ControlPlaneId),
util.WithLabel(mesh_proto.ResourceOriginLabel, mesh_proto.ResourceOriginZone),
util.WithLabel(mesh_proto.ResourceOriginLabel, string(mesh_proto.ZoneResourceOrigin)),
))
}

Expand Down
7 changes: 4 additions & 3 deletions pkg/plugins/policies/core/matchers/dataplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,11 @@ func (b ByTargetRef) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// If we assign numbers to origins like Global=-1, Zone=1, Unknown=0, then we can compare them as numbers
// and get the same result as in the table above.
func originToNumber(r core_model.Resource) int {
switch r.GetMeta().GetLabels()[mesh_proto.ResourceOriginLabel] {
case mesh_proto.ResourceOriginGlobal:
origin, _ := core_model.ResourceOrigin(r.GetMeta())
switch origin {
case mesh_proto.GlobalResourceOrigin:
return -1
case mesh_proto.ResourceOriginZone:
case mesh_proto.ZoneResourceOrigin:
return 1
default:
return 0
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugins/runtime/k8s/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func addValidators(mgr kube_ctrl.Manager, rt core_runtime.Runtime, converter k8s
}

allowedUsers := append(rt.Config().Runtime.Kubernetes.AllowedUsers, rt.Config().Runtime.Kubernetes.ServiceAccountName, "system:serviceaccount:kube-system:generic-garbage-collector")
handler := k8s_webhooks.NewValidatingWebhook(converter, core_registry.Global(), k8s_registry.Global(), rt.Config().Mode, rt.Config().IsFederatedZoneCP(), allowedUsers)
handler := k8s_webhooks.NewValidatingWebhook(converter, core_registry.Global(), k8s_registry.Global(), rt.Config().Mode, rt.Config().IsFederatedZoneCP(), allowedUsers, rt.Config().Multizone.Zone.DisableOriginLabelValidation)
composite.AddValidator(handler)

k8sMeshValidator := k8s_webhooks.NewMeshValidatorWebhook(rt.ResourceValidators().Mesh, converter, rt.Config().Store.UnsafeDelete)
Expand Down
Loading

0 comments on commit 17025b3

Please sign in to comment.