Repository navigation
Support generating Kubernetes NetworkPolicies - #138
tombentley wants to merge 25 commits into
Conversation
| To enforce this correctly some changes will also be needed to the loadBalancer `Service` the operator generates. | ||
| `Service.spec.loadBalancerSourceRanges` is a best-effort declaration of the source IPs which should be allowed through the load balance. | ||
| In practice enforcement is cloud-provider-dependent, and this can be igored. | ||
| We will also need to set `Service.spec.externalTrafficPolicy: Local` to preserve the client's source IP address, so that it can be enforced by the |
There was a problem hiding this comment.
That's already the subject of #134, so we need to watch for a conflict between the two proposals.
|
Thanks @tombentley - on first reading this looks reasonable. I will take a deeper look. |
| ``` | ||
|
|
||
|
|
||
| ### Operator-level opt-out |
There was a problem hiding this comment.
This KafkaProxyOperatorConfig looks like it wants to be its own thing rather than part of this proposal as it's a general mechanism for configuring the operator. Once it exists other features will want to hang their operator-level options off it too, so it feels like it deserves a proposal and a design discussion of its own rather than arriving as a side effect of NetworkPolicy generation.
Could it be split out, with a speculative reference kept here showing just the shape this proposal needs from it (the resourceGeneration toggle and the policyAttachment block) and a note that the exact schema is subject to that separate proposal?
There was a problem hiding this comment.
Yes, it is a general mechanism for configuring the proxy. A dedicated proposal would be a good idea. However, apart from this proposal, there's no immediate need to put anything in the spec. It seems odd to open a proposal for a CR with an empty spec.
|
|
||
| When no `KafkaProxyNetworkPolicy` targets a `KafkaProtocolFilter` we will generate a default `NetworkPolicy`, such as we saw above, which allows access to and from anywhere. | ||
| This default `NetworkPolicy` will have a name like `default-allow-filter-${kafka-filter-name}`. | ||
| **TODO** this would be, without policies lots of access, is that right/defensible? |
There was a problem hiding this comment.
On your TODO here ('this would be, without policies, lots of access, is that right/defensible ?'), I'd lean towards no for the filter case. The stated goal of the feature is auditability, and a default that silently allows a filter both ingress and egress to anywhere is the situation an audit is trying to catch. Defaulting a filter with no attached KafkaProxyNetworkPolicy to deny, or to requiring an explicit attachment to a well known policy via requiredAttachments would show the explicit decision to allow all and seems more in keeping with that goal than the automatic default-allow. The downside is that this stricter requirement could break existing filters if they need network access.
There was a problem hiding this comment.
I've (consciously) been trying to have my cake and eat it too: On the one hand we're being asked to make it deny-by-default, but on the other hand doing that without a new major version, or migration period, will break existing setups when they upgrade.
The upgrade is a real problem because (without taking special measures) you can't write the policy (a CR) without the CRD, which arrives at the same time as the new operator.
I think we could do something a little nicer: Use deny-by-default for new installs and allow-by-default for existing installs. This would have to be implemented in the operator itself (not the installation marchinery/manifests/OLM whatever).
| kind: NetworkPolicy | ||
| options: | ||
| generation: enabled|disabled | ||
| policyAttachment: |
There was a problem hiding this comment.
The requiredAttachments / permittedAttachments / prohibitedAttachments trio is quite a lot of machinery. Could we start with required and the default now, and let the other two follow if a user asks for them? or because this isn't a new feature as such, but is attempting to retro-fit over existing deployments that we'll need all the options the three give us to allow users the ability to correctly configure everything?
There was a problem hiding this comment.
If we're going to make the distinction between new installs vs existing installs when deciding whether to deny-/allow-by-default, then this becomes the place where the behaviour would be spelled out.
So for an existing install, we'd use:
policyAttachment:
policyTarget:
- group: kroxylicious.io
kind: KafkaProxyIngress
permittedAttachments: # the KafkaProxyIngressNetworkPolicy need not exist
- group: kroxylicious.io
kind: KafkaProxyIngressNetworkPolicy
whenAbsent: allow # when its missing we allow by defaultAnd for a new install we'd use:
policyAttachment:
policyTarget:
- group: kroxylicious.io
kind: KafkaProxyIngress
requiredAttachments: # a KafkaProxyIngressNetworkPolicy must exist
- group: kroxylicious.io
kind: KafkaProxyIngressNetworkPolicy But perhaps we can drop prohibitedAttachments for now, to try to reduce the complexity budget.
5f19b59 to
a5712c8
Compare
Signed-off-by: Tom Bentley <tbentley@redhat.com>
Signed-off-by: Tom Bentley <tbentley@redhat.com>
Corrects misspellings (opererator, reqirements, simplfy, propertry, igored, segration, korxyliciousio), inconsistent "targetting/targetted" vs "targeting/targeted", inconsistent organisation/organization spelling, and a couple of grammar slips. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
- Introduce both new CRDs (KafkaProxyNetworkPolicy, KafkaProxyOperatorConfig) up front in a summary table, instead of only naming one under a "New CRDs" heading and introducing the other much later. - Extract the inline aside about a future per-SNI-hostname IP-allowlist enhancement into its own "Future work" section, consistent with how "Rejected alternatives" is already broken out, leaving a forward pointer at its original location. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
- Add a "Typical owner" column to the New CRDs table, making explicit which role holds KafkaProxyNetworkPolicy (per-namespace/tenant) vs KafkaProxyOperatorConfig (cluster-admin/platform), tying back to the RBAC separation-of-concerns rationale already given in Motivation. - State explicitly that targetRef only resolves within the KafkaProxyNetworkPolicy's own namespace, so one tenant can never attach policy to another tenant's resources. - Note in Current situation that NetworkPolicy enforcement is CNI-dependent, since the proposal's audit/compliance motivation could otherwise read as implying guaranteed enforcement. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Replace the single KafkaProxyNetworkPolicy kind with KafkaProxyIngressNetworkPolicy (targets KafkaProxyIngress or KafkaProtocolFilter) and KafkaProxyEgressNetworkPolicy (targets KafkaService or KafkaProtocolFilter), following discussion of alternative designs for the policy-attachment kind. A single combined kind can only be granted via RBAC as a whole: a role trusted to declare one filter's own egress need would, by the same grant, also be able to declare sweeping ingress rules against the proxy's shared KafkaProxyIngress. Splitting by direction closes that gap and makes the two "may not target X" cross-validation rules impossible to express rather than something the operator has to reject at reconcile time. Splitting further, one kind per target CR, was considered and rejected as more CRDs/RBAC surface than needed; recorded as a rejected alternative alongside the single-kind case. Incidental fixes made while rewriting every example: spec.allow is now consistently an array (previously allowIngress/allowEgress examples inconsistently showed a single rule object in some places and an array in others), the generated NetworkPolicy ports field is consistently a list, and targetRef.group now matches the actual API group (kroxylicious.io, not io.kroxylicious). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Add a Status conditions table under New CRDs covering ResolvedRefs and Accepted (types, statuses, reasons, and meaning), grounded in the condition/reason vocabulary already implemented in the kroxy-np PoC (ReferencedResourcesNotFound, TransitivelyReferencedResourcesNotFound, Invalid, Disabled, ReferencedResourceNotReconciled), including the PoC's cascade behaviour where Accepted can never be True while ResolvedRefs is False, and where a Disabled NetworkPolicy generation config leaves ResolvedRefs untouched but forces Accepted: False. Previously the proposal only mentioned a bare "Accepted" condition. Also add a sentence making explicit that allowing multiple KafkaProxyIngressNetworkPolicy/KafkaProxyEgressNetworkPolicy to target the same resource (unioned, not replacing) is a deliberate divergence from the Gateway API's usual 1:1 direct policy attachment convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Replace the two TODOs about what internal DNS names Strimzi actually produces. Strimzi's bootstrap Service for a listener is named <cluster-name>-kafka-bootstrap (or <cluster-name>-kafka-<listener-name>-bootstrap for a named listener) and is stable across broker scaling/KafkaNodePool changes, since it's derived only from the Kafka resource's name. Its headless per-broker Service DNS names, by contrast, embed a broker-id that depends on node pool naming and can change as pools are scaled or renamed, so they're called out as unsuitable for bootstrapServers. Updated the internal-DNS bootstrapServers example to a realistic, correctly-formed Strimzi bootstrap Service DNS name (also fixing a "boostrap" typo), and fixed "entirely compose of" -> "entirely composed of" in both the internal- and external-DNS sections for consistency. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
A policy-attached NetworkPolicy is owned by the KafkaProxyIngressNetworkPolicy/ KafkaProxyEgressNetworkPolicy that produced it, so deleting the policy CR only removes its own NetworkPolicy rather than affecting others targeting the same resource. A default-allow NetworkPolicy (no policy CR exists) is owned by the target CR itself, since there's nothing else to own it. Previously this wasn't stated anywhere. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Validation of a KafkaProxyIngressNetworkPolicy/KafkaProxyEgressNetworkPolicy happens asynchronously on the reconciler's schedule, not at kubectl apply time, so a successful apply doesn't confirm the policy was accepted. Add a sentence recommending kubectl wait --for=condition=Accepted for pipelines that need that confirmation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Generated NetworkPolicy names are a prefix plus a source CR's name, so a sufficiently long source name could exceed Kubernetes' name length limit. State that the operator will handle this with the standard truncate-and-hash pattern already used elsewhere in Kubernetes (e.g. ReplicaSet/ControllerRevision names), without spelling out the algorithm here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
…g default Replace the open TODO about whether default-allow is defensible for KafkaProtocolFilter with a resolved design: a new KafkaProxyOperatorConfig.spec.resourceGeneration[].options.filterDefaultPolicy (allow|deny, schema default allow) governs what's generated when no KafkaProxyIngressNetworkPolicy/KafkaProxyEgressNetworkPolicy targets a filter. KafkaProxyIngress/KafkaService are unaffected since they always need some access to function. The schema default stays allow so upgrading an existing deployment never silently cuts off a filter's access. Separately, the operator applies a first-run heuristic: on startup, if no KafkaProxyOperatorConfig exists and no KafkaProxy/KafkaProtocolFilter resources exist either, it seeds one with filterDefaultPolicy: deny, giving fresh installs a secure default with no configuration required. This lives in the operator itself rather than in install tooling, because KafkaProxyOperatorConfig being a brand-new CRD means its absence looks identical on a fresh install and on an upgrade — no install mechanism (including OLM's ClusterServiceVersion, which OpenShift's embedded OperatorHub also uses) can tell those apart from that signal alone, unlike Helm's install-only hooks which only solve it for Helm specifically. Documents this in a new filterDefaultPolicy subsection, references it from Compatibility, and records the install-tooling-seeding approach as a rejected alternative with the reasoning above. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
…rgets Replace the standalone resourceGeneration.options.filterDefaultPolicy with policyAttachment.policyTarget[].permittedAttachments[].whenAbsent, restructuring policyTarget into per-target-kind entries (each with its own requiredAttachments/permittedAttachments/prohibitedAttachments) instead of flat global lists. This reuses the existing required/ permitted/prohibited machinery for "what happens when no policy is attached" rather than introducing a second, parallel configuration concept, and incidentally fixes the previously-unclear pairing between policyTarget kinds and attachment kinds. Extend the allow/deny default choice from KafkaProtocolFilter to KafkaProxyIngress and KafkaService as well, since the same reasoning applies to all three, and fold in two behavioural decisions: - When whenAbsent: deny applies, the target gets Accepted: False with a reason identifying the missing policy (not a silent failure), using the same treatment as a requiredAttachments violation, and propagates to dependents the same way existing ResolvedRefs/Accepted failures do. - Note the consequence for docs: a deny-by-default fresh install won't pass traffic until the right policy CRs exist, so quickstarts and example manifests need to be reviewed and updated accordingly. Update the KafkaProxyIngress/KafkaService/KafkaProtocolFilter sections and Compatibility to reference the new mechanism. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Previously the precise, auto-derivable egress rule for a strimziKafkaRef-based KafkaService still required an explicit (if empty) KafkaProxyEgressNetworkPolicy to be created, otherwise falling back to the generic allow/deny default like every other target. Since the operator already has everything it needs to compute the exact rule (the Kafka cluster's namespace and Strimzi's published broker pod labels), requiring a CR just to get the answer the system already knows is an avoidable papercut — and one that would bite every fresh, deny-by-default install proxying a same-cluster Strimzi target. Generate the precise rule unconditionally instead, with no CR required; policyAttachment's whenAbsent setting doesn't apply to this case, since there's no "allow vs deny" choice to make when a correct, minimal answer is already available. An explicit KafkaProxyEgressNetworkPolicy can still be attached on top for additional egress needs, additive with the auto-derived rule rather than replacing it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Resolves Keith's review comment flagging a potential conflict with proposal kroxylicious#134 ("Configuring the LoadBalancer Service from KafkaProxyIngress"), which has since been merged and implemented: each loadBalancer-type KafkaProxyIngress now gets its own dedicated Service (named after the ingress), rather than all loadBalancer ingresses on a proxy sharing one `<proxy>-sni` Service. This proposal's loadBalancer section was written against the old shared-Service model and is now out of date: - externalTrafficPolicy is already configurable via KafkaProxyIngress.spec.loadBalancer.service.externalTrafficPolicy (proposal kroxylicious#134); this proposal depends on it as a prerequisite rather than needing to introduce it, and should reject a KafkaProxyIngressNetworkPolicy with ipBlock rules against a loadBalancer ingress that doesn't have it set to Local, since otherwise the restriction would silently fail to match real client addresses. - The CIDR-union mechanism for sharing one Service across multiple KafkaProxyIngresses is no longer needed, since each ingress already has its own Service post-kroxylicious#134. The remaining, still-valid sharing concern is narrower: VirtualKafkaClusters that share one ingress (via SNI) still can't get per-cluster CIDR isolation from a Service-level restriction, which is what the Future work section's proxy-side IP-allowlist idea would address. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Signed-off-by: Tom Bentley <tbentley@redhat.com>
Centralize the podSelector, ownerReferences, and naming explanation for
generated NetworkPolicies into one section instead of repeating it per
target kind. The previous naming scheme (plain string concatenation)
could collide: the strimziKafkaRef auto-derived rule and an attached
KafkaProxyEgressNetworkPolicy both produced allow-egress-${name}, and
the -filter infix was textually indistinguishable from a hyphen inside
a user-chosen name. Replace it with a {token}.{name} scheme that's
collision-free by construction, using . as a reserved delimiter, and
move the allow/deny distinction to a label so it can't collide at all.
Signed-off-by: Tom Bentley <tbentley@redhat.com>
Splitting by direction only partially separated RBAC concerns: both resulting kinds still mixed a shared, proxy-wide target with per-filter ownership (KafkaProxyIngress/filter ingress, KafkaService/filter egress), so the two-kind split didn't justify its extra CRD/controller surface. A single kind now covers both directions, with spec.ingress/ spec.egress validity narrowed by CEL instead of by kind, and orgs needing finer-than-kind-level separation pointed at a policy engine (Kyverno/OPA/ValidatingAdmissionPolicy) layered on top. Signed-off-by: Tom Bentley <tbentley@redhat.com>
Move KafkaProxyOperatorConfig/policyAttachment earlier so it's defined before the per-target sections that depend on it, consolidate the allow/deny-when-absent explanation that was repeated near-verbatim across KafkaProxyIngress/KafkaService/KafkaProtocolFilter, and trim other repeated explanations (additive semantics, per-mechanism rejection reporting, RBAC rationale) down to one canonical statement plus cross-references. No technical content removed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
The full matchLabels block was repeated verbatim in every generated NetworkPolicy example; it's already fully defined once in "Common structure of generated NetworkPolicy resources", so later examples now just show podSelector: ... with a pointer back to it, matching the elision style already used for the KafkaProxyOperatorConfig outline example. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Resolves the open TODO about whether whenAbsent should default to deny for fresh installs. Decided: allow is the schema default for every install, fresh or upgraded, so the bar to a working proxy stays low. deny remains available, but only as an explicit administrator opt-in via KafkaProxyOperatorConfig — never something the operator decides on its own. The generated NetworkPolicy naming and kroxylicious.io/default-policy label are the audit trail an admin uses to find and tighten allow rules over time. Drops the first-run heuristic that auto-created a deny-default KafkaProxyOperatorConfig for installs with no existing KafkaProxy resources, and updates Compatibility and Rejected alternatives to match (folding the install-time-tooling-seeding alternative into a single rejected "deny-for-fresh-installs" entry, regardless of mechanism). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
Documents why clusterCIDRs can't get the same autodetection fallback clusterDomain has: no CNI-agnostic, low-privilege way to derive pod/service CIDRs, and reading Node.spec.podCIDRs cluster-wide would need a nodes RBAC grant disproportionate to the one check it enables today. Also makes explicit that leaving it unset skips the bootstrapServers internal-address check rather than enforcing it some other way. Notes proposal kroxylicious#148 (per-gateway source-address filtering in the proxy) as a plausible future second consumer of clusterCIDRs, so the field's value isn't pinned to a single narrow validation forever. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Tom Bentley <tbentley@redhat.com>
a5712c8 to
3fb8bd4
Compare
robobario
left a comment
There was a problem hiding this comment.
Thanks for the proposal @tombentley, getting my head around it slowly.
| egress: ... | ||
| ``` | ||
|
|
||
| * The `spec.targetRef` references another proxy CR — restricted (via an enum on the `kind` property at the CRD schema level) to `KafkaProxyIngress`, `KafkaService`, or `KafkaProtocolFilter`. |
There was a problem hiding this comment.
https://github.com/kroxylicious/design/blob/main/proposals/142-kube-api-routing.md has been accepted now, should we add KafkaProtocolRouter to the list? A user's router could also want to make network calls.
| policyTypes: | ||
| - Ingress | ||
| ingress: | ||
| - ports: # the ingress's own listening port, since spec.ingress[].ports was omitted |
There was a problem hiding this comment.
Would user supplied ports completely replace our generated ones? Taking the user's specifications is less surprising for audit, but more likely to leave them without connectivity if they don't allow ingress to the listen port. Since KPI port-allocation is an operator responsibility I don't think it would really be practical for a user to declare these, so I'm wondering, is there any case we can imagine where a user would want to add additional ports to the ingress policy beyond our listen ports and should we support that? I can't think of any, so maybe we could use CEL to block that combination early (referencing a KPI + ingress ports declared) and prevent misconfiguration?
I can imagine usages for ingress ports for the other types, like for Filters/Routers it would be possible for users to start up their own listening servers and want to configure ingress.
| We will add a new cluster-scoped CRD for expressing options for the operator. | ||
| The operator `Deployment` itself will support a `CONFIG_NAME` env var which allows to select the `KafkaProxyOperatorConfig` to be used by that operator instance. | ||
| The value will default to `default`. |
There was a problem hiding this comment.
I think we should state here that the new resource is optional and we don't try to explicitly install a default. It looks like there's rationale already in the rejected alternatives about it being painful to keep helm/OLM/manifests in sync if we tried to do this.
There was a problem hiding this comment.
(I later came upon the requirement in the goals to not manipulate existing NetworkPolicies, maybe that should be answered first, do we need to support this idea of different behaviour for new vs existing)
| * For new installations, generate `NetworkPolicy` resources by default, with the option to disable generation. | ||
| In the absence of ingress and egress policy resources, the generated `NetworkPolicy` will be allow-by-default. | ||
| * For existing installations, do **not** generate `NetworkPolicy` resources by default. Require the user to enable generation. |
There was a problem hiding this comment.
How are we planning to implement this. In the rejected alternatives it mentions we can't discriminate between new/existing since the optional resources could be absent.
The resourceGeneration section of the operator config is out of sync with this saying generation is enabled by default with no distinction between new/existing.
Does this goal need to be walked back? Or something added to describe how we can discriminate between new/existing?
(claude spotted)
|
|
||
| #### `podSelector` | ||
|
|
||
| The operator resolves `spec.targetRef` through to the `KafkaProxy` that ultimately owns the targeted resource, and copies that `KafkaProxy`'s own `Pod`-selector labels, unchanged, into every generated `NetworkPolicy`: |
There was a problem hiding this comment.
KafkaProtocolFilter and KafkaService can be shared by multiple KafkaProxy, should this sentence be updated to say we generate NetworkPolicies per targeted KafkaProxy plural?
(claude spotted)
| * `bootstrapServers` is a comma-separated list of the host addresses for some bootstrap servers of a Kafka cluster. | ||
|
|
||
|
|
||
| #### The `strimziKafkaRef` case |
There was a problem hiding this comment.
in the other bootstrapServers cases we nail down which are allowed to use namespace and pod selectors, vs ipBlock. Does the strimziKafkaRef have a similar restriction to selectors only because it's cluster local? We should add an equivalent statement about which types are allowed.
(claude spotted)
|
|
||
| Most of the remaining peer-type validation described in the sections below — e.g. `ipBlock` vs. selector, which depends on the *targeted* `KafkaProxyIngress`'s own `clusterIP`/`loadBalancer`/`openShiftRoute` mechanism — depends on the state of a different object, which a CRD-schema CEL rule cannot look up. That validation happens in the reconciler instead, and is reported via `Accepted: False` (see [Status conditions](#status-conditions)); each mechanism-specific section below therefore states only which peer type it requires, not how a violation gets reported. | ||
|
|
||
| `targetRef` only resolves within the same namespace as the `KafkaProxyNetworkPolicy` itself; there is no cross-namespace form (unlike, for example, the Gateway API's `ReferenceGrant`-mediated cross-namespace policy attachment). This keeps the ownership split described above confined to a single namespace: `KafkaProxyNetworkPolicy` can never grant or imply network access on behalf of a `KafkaProxyIngress`, `KafkaService`, or `KafkaProtocolFilter` owned by a different namespace/tenant. |
There was a problem hiding this comment.
this is fine for our proxy resources, but what about the pods/namespaces targeted by the ingress/egress rules?
should I, on the proxy team, be able to allow the proxy to egress to some other teams namespace without something like ReferenceGrant for the other team to allow access? Can I allow egress to kube-system namespace for example?
(claude discovered)
|
|
||
| The `KafkaService` CR supports two ways to express a target cluster: | ||
|
|
||
| * `strimziKafkaRef` is a reference to a Strimzi `Kafka` resource which exists in the same cluster as the `KafkaService` CR. |
There was a problem hiding this comment.
similar question about allowing egress to some other teams namespace containing Kafka. Is it okay to not have a ReferenceGrant type resource, which would give the Kafka team the ability to grant the policy
|
|
||
| ### Operator RBAC changes | ||
|
|
||
| The operator will need to be allowed to CRUD `NetworkPolicy` resources via its dependent resources `ClusterRole`. |
There was a problem hiding this comment.
Might be worth a callout that we've increased the Proxy blast radius. A kroxy operator watching all namespaces would be able to touch other tenants NetworkPolicy. This new access to the firewall type rules should be called out as a new risk.
(claude found)
| app.kubernetes.io/instance: my-proxy-cr | ||
| ``` | ||
|
|
||
| Because this `podSelector` is identical on every `NetworkPolicy` generated for a given `KafkaProxy` — regardless of which `KafkaProxyIngress`, `KafkaService`, or `KafkaProtocolFilter` drove its generation — they all select the same `Pods`, and `NetworkPolicy` rules are additive across policies selecting the same `Pod` (see [Current situation](#current-situation)). This means a broad rule generated for *any one* target on a proxy is unioned with every other target's rules for the same direction. For example, a `KafkaProxy` with one `KafkaService` using `strimziKafkaRef` (always getting the narrow, auto-derived `target-strimzi` rule) and a second `KafkaService` using `bootstrapServers` with no `KafkaProxyNetworkPolicy` attached (getting the allow-all `target-default` fallback) ends up, in practice, with unrestricted egress on that port from the proxy's `Pods`: the first `KafkaService`'s narrow rule is still generated correctly and still has naming/audit value, but it adds no enforcement once a sibling target's rule already allows everything. Restricting a proxy's effective ingress or egress for a given direction therefore means addressing *every* target attached to that proxy, not just the one under review. |
There was a problem hiding this comment.
One risk is that there's no visibility into whether your restrictions are widened. If I create a deny all egress rule for my filter, it can be flipped to an allow all by some other team/role setting up some other Filter with a wider policy, how do I know my policy has been weakened?
Maybe for visibility you could include it in the KafkaProxyNetworkPolicy, status, like list off all the associated KafkaProxyNetworkPolicies and whether their policy is redundant/widened?
This proposes allowing the operator to generate Kubernetes
NetworkPoliciesbased on theKafkaProxyIngresses,KafkaServicesandKafkaProtocolFilterswhich make up aKafkaProxy.