Skip to content

WIP: SPIRE-220: Implementation for the Network Policy for the ZTWIM operands#55

Open
PillaiManish wants to merge 6 commits intoopenshift:mainfrom
PillaiManish:spire-220_network-policy
Open

WIP: SPIRE-220: Implementation for the Network Policy for the ZTWIM operands#55
PillaiManish wants to merge 6 commits intoopenshift:mainfrom
PillaiManish:spire-220_network-policy

Conversation

@PillaiManish
Copy link
Member

No description provided.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Oct 29, 2025
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 29, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 29, 2025

@PillaiManish: This pull request references SPIRE-220 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

Walkthrough

Adds 11 Kubernetes NetworkPolicy manifests as embedded assets; introduces decoding and labeling utilities; adds reconciler logic to create/apply these NetworkPolicies during reconcile; registers networking.k8s.io/v1 scheme and RBAC/watch support for NetworkPolicy resources.

Changes

Cohort / File(s) Summary
NetworkPolicy YAMLs
bindata/network-policy/default-deny-networkpolicy.yaml, bindata/network-policy/spire-agent/spire-agent-allow-egress-to-api-server-networkpolicy.yaml, bindata/network-policy/spire-agent/spire-agent-allow-egress-to-spire-server-networkpolicy.yaml, bindata/network-policy/spire-agent/spire-agent-allow-ingress-to-metrics-networkpolicy.yaml, bindata/network-policy/spire-oidc-discovery-provider/spire-oidc-allow-ingress-to-8443-networkpolicy.yaml, bindata/network-policy/spire-server/spire-server-allow-egress-ingress-to-federation-networkpolicy.yaml, bindata/network-policy/spire-server/spire-server-allow-egress-to-api-server-networkpolicy.yaml, bindata/network-policy/spire-server/spire-server-allow-egress-to-dns-networkpolicy.yaml, bindata/network-policy/spire-server/spire-server-allow-ingress-to-8081-networkpolicy.yaml, bindata/network-policy/spire-server/spire-server-allow-ingress-to-metrics-networkpolicy.yaml, bindata/network-policy/spire-server/spire-server-allow-ingress-to-webhook-networkpolicy.yaml
Adds 11 NetworkPolicy manifests in the zero-trust-workload-identity-manager namespace defining default-deny and specific ingress/egress allowances (ports, namespace/pod selectors as declared).
Embedded assets (go-bindata)
pkg/operator/assets/bindata.go
Adds embedded byte arrays, bytes accessors, asset constructors, public asset accessors, registers new assets in _bindata, and updates bintree entries for the new network-policy paths.
Static reconciler
pkg/controller/static-resource-controller/network-policy.go
New code to list static NetworkPolicy objects from embedded assets, decode them, apply standardized labels, and reconcile via createOrUpdate (CreateOrApplyNetworkPolicyResources and per-policy helper builders).
Controller flow / status
pkg/controller/static-resource-controller/controller.go
Adds exported NetworkPolicyResourcesGeneration constant, inserts CreateOrApplyNetworkPolicyResources step into reconcile with eventing and reconcileStatus updates on success/failure, and adds a watch for networking.k8s.io/v1 NetworkPolicy.
Asset name constants
pkg/controller/utils/constants.go
Adds exported constants for each NetworkPolicy asset name (e.g., DefaultDenyNetworkPolicyAssetName, SpireAgentAllowEgressToApiServerNetworkPolicyAssetName, etc.).
Utils / decoding
pkg/controller/utils/utils.go
Registers the networking.k8s.io/v1 scheme import and adds DecodeNetworkPolicyObjBytes(objBytes []byte) *networkingv1.NetworkPolicy to decode raw YAML bytes into NetworkPolicy objects.
RBAC & CSV
config/rbac/role.yaml, bundle/manifests/...clusterserviceversion.yaml
Adds RBAC rule granting create/get/list/update/watch on networkpolicies (networking.k8s.io) to the manager ClusterRole and adds corresponding clusterPermissions entry in the CSV manifest; bumps CSV createdAt timestamp.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Mixed declarative assets and new controller logic; moderate heterogeneity.
  • Areas needing extra attention:
    • NetworkPolicy selectors, namespace/pod label correctness and port/protocol definitions.
    • Label application helpers to ensure required labels are applied consistently.
    • Decoder and scheme registration for networking.k8s.io/v1.
    • Asset registration entries and bintree paths in pkg/operator/assets/bindata.go.
    • RBAC entries in config/rbac/role.yaml and CSV clusterPermissions alignment.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.85% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description Check ❓ Inconclusive No pull request description was provided by the author. The evaluation criteria state this is a lenient check, but the explicit pass condition requires the description to be "related in some way to the changeset." Since no description exists, it cannot satisfy this requirement of being related to the changes. While the absence of a description is not actively misleading or off-topic, the lack of any descriptive content makes it impossible to verify that the description meets the pass criteria specified in the check instructions. The author should provide a pull request description that explains the purpose, scope, and key details of the network policy implementation. Even though the PR title and code changes are clear, a description helps reviewers understand the motivation and any important context that isn't immediately obvious from the code alone. The description can be brief but should relate to the changeset in some way.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "WIP: SPIRE-220: Implementation for the Network Policy for the ZTWIM operands" accurately reflects the primary change in the pull request. The changeset consists of multiple new Kubernetes NetworkPolicy YAML manifests, supporting Go code to manage these policies, and RBAC updates to enable the operator to manage network policies. The title specifically identifies the core change as implementing network policies for ZTWIM (zero-trust-workload-identity-manager) operands, which directly matches the 11 new network policy files and their associated integration code. The title is clear, concise, and provides sufficient context for understanding the main intent without unnecessary noise.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link

openshift-ci bot commented Oct 29, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: PillaiManish
Once this PR has been reviewed and has the lgtm label, please assign swghosh for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot requested a review from bharath-b-rh October 29, 2025 05:17
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
pkg/operator/assets/bindata.go (1)

148-164: Consider restricting egress destination to SPIRE server pods.

The spire-agent egress to port 8081 has no destination selector, allowing connections to any pod on that port, not just the SPIRE server.

Add a podSelector to the to field:

   egress:
     # Allow connection to SPIRE server
-    - ports:
+    - to:
+        - podSelector:
+            matchLabels:
+              app.kubernetes.io/name: spire-server
+      ports:
         - protocol: TCP
           port: 8081
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between d74a46d and 1f0d147.

📒 Files selected for processing (12)
  • bindata/network-policy/default-deny-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-agent/spire-agent-allow-egress-to-api-server-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-agent/spire-agent-allow-egress-to-spire-server-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-agent/spire-agent-allow-ingress-to-metrics-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-oidc-discovery-provider/spire-oidc-allow-ingress-to-8443-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-server/spire-server-allow-egress-ingress-to-federation-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-server/spire-server-allow-egress-to-api-server-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-server/spire-server-allow-egress-to-dns-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-server/spire-server-allow-ingress-to-8081-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-server/spire-server-allow-ingress-to-metrics-networkpolicy.yaml (1 hunks)
  • bindata/network-policy/spire-server/spire-server-allow-ingress-to-webhook-networkpolicy.yaml (1 hunks)
  • pkg/operator/assets/bindata.go (4 hunks)
🔇 Additional comments (9)
bindata/network-policy/spire-server/spire-server-allow-egress-to-dns-networkpolicy.yaml (1)

12-24: Well-scoped DNS egress policy with proper peer selectors.

This policy correctly restricts egress traffic to the openshift-dns namespace and specific DNS pods, following zero-trust principles. The configuration properly allows both TCP and UDP on port 5353.

bindata/network-policy/spire-agent/spire-agent-allow-ingress-to-metrics-networkpolicy.yaml (1)

12-19: Well-scoped metrics ingress policy with proper source selector.

This policy correctly restricts ingress traffic to the openshift-monitoring namespace. Note: the namespace selector uses the label key name rather than kubernetes.io/metadata.name (used in the DNS policy). Verify this label key is correct for the openshift-monitoring namespace, or consider standardizing to kubernetes.io/metadata.name for consistency across policies.

bindata/network-policy/spire-server/spire-server-allow-ingress-to-metrics-networkpolicy.yaml (1)

1-21: LGTM! Well-scoped metrics ingress policy.

This NetworkPolicy correctly restricts metrics ingress to the OpenShift monitoring namespace, with appropriate port specifications for both SPIRE server (9402) and controller manager (8082) metrics endpoints.

bindata/network-policy/default-deny-networkpolicy.yaml (2)

6-7: Verify the cert-manager ownership label.

The cert-manager.operator.openshift.io/owned-by: cert-manager label appears inconsistent with a default-deny NetworkPolicy for the ZTWIM namespace. This policy governs all SPIRE and related components, not just cert-manager resources.

Confirm whether this label is intentional or should reference the ZTWIM operator instead.


8-12: LGTM! Proper default-deny structure.

The empty podSelector with Ingress and Egress policy types (and no rules) correctly implements a default deny-all policy for the namespace.

pkg/operator/assets/bindata.go (4)

1-13: Note: This is a generated file.

As indicated by the header comment, this file is generated by go-bindata. Manual edits will be overwritten. Security issues identified in the embedded YAML policies should be addressed in the source YAML files, then regenerated.


116-131: Verify unrestricted egress to API server is acceptable.

The spire-agent egress policy allows TCP egress to port 6443 without destination restrictions. While this is typically the Kubernetes API server port, the policy doesn't restrict which endpoints can be reached.

For defense in depth, consider whether this should be restricted to specific API server endpoints (though this may be challenging in dynamic cluster environments).


288-303: Verify unrestricted egress to API server is acceptable.

Similar to the spire-agent policy, this allows egress to port 6443 without destination restrictions.

Consider whether API server egress should be more tightly scoped, though this may be operationally challenging.


217-233: ****

OIDC discovery endpoints are designed to be publicly accessible for federation purposes. The unrestricted ingress is required for external cloud providers and identity consumers (e.g., AWS, Vault, other OIDC clients) to discover and consume the SPIFFE issuance. Restricting access to specific namespaces or pods would prevent OIDC federation from functioning. Security is achieved at the application layer (serving only discovery and JWKS endpoints) and infrastructure layer (TLS, rate limiting, monitoring), not through NetworkPolicy ingress restrictions.

Likely an incorrect or invalid review comment.

Comment on lines +12 to +16
egress:
# Allow connection to SPIRE server
- ports:
- protocol: TCP
port: 8081
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing destination selector in egress rule—overly permissive for zero-trust environment.

The egress rule allows traffic to ANY destination on port 8081, not just SPIRE server pods. In a zero-trust namespace, this should be restricted to only spire-server pods.

Consider updating the egress rule to target spire-server pods explicitly:

  egress:
    # Allow connection to SPIRE server
-   - ports:
+   - to:
+       - podSelector:
+           matchLabels:
+             app.kubernetes.io/name: spire-server
+     ports:
        - protocol: TCP
          port: 8081
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
egress:
# Allow connection to SPIRE server
- ports:
- protocol: TCP
port: 8081
egress:
# Allow connection to SPIRE server
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: spire-server
ports:
- protocol: TCP
port: 8081
🤖 Prompt for AI Agents
In
bindata/network-policy/spire-agent/spire-agent-allow-egress-to-spire-server-networkpolicy.yaml
around lines 12 to 16, the egress rule is currently allowing port 8081 to any
destination; tighten it by adding a destination selector that limits egress to
the SPIRE server pods only—add a "to" block with a podSelector matching the
spire-server pod labels (and/or a namespaceSelector if the server runs in a
different namespace) so the rule only permits TCP:8081 traffic to those pods.

Comment on lines +13 to +21
ingress:
# Allow federation traffic
- ports:
- protocol: TCP
port: 8443
egress:
- ports:
- protocol: TCP
port: 8443
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Federation policy lacks both source and destination selectors—critically permissive for inter-cluster communication.

Federation traffic should be tightly controlled. Currently, this policy allows ingress from any source and egress to any destination on port 8443. For a zero-trust model, both rules must restrict to known federation peers (likely via namespace selectors for remote SPIRE servers).

Add source and destination selectors to restrict federation traffic to known peers:

  ingress:
    # Allow federation traffic
-   - ports:
+   - from:
+       - namespaceSelector: {}  # Restrict to specific federation peer namespace(s)
+     ports:
        - protocol: TCP
          port: 8443
  egress:
-   - ports:
+   - to:
+       - namespaceSelector: {}  # Restrict to specific federation peer namespace(s)
+     ports:
        - protocol: TCP
          port: 8443
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ingress:
# Allow federation traffic
- ports:
- protocol: TCP
port: 8443
egress:
- ports:
- protocol: TCP
port: 8443
ingress:
# Allow federation traffic
- from:
- namespaceSelector: {} # Restrict to specific federation peer namespace(s)
ports:
- protocol: TCP
port: 8443
egress:
- to:
- namespaceSelector: {} # Restrict to specific federation peer namespace(s)
ports:
- protocol: TCP
port: 8443
🤖 Prompt for AI Agents
In
bindata/network-policy/spire-server/spire-server-allow-egress-ingress-to-federation-networkpolicy.yaml
around lines 13–21, the ingress and egress rules currently allow traffic on port
8443 from/to any endpoint; tighten them by adding explicit selectors: for
ingress add from: with namespaceSelector and/or podSelector that match your
known federation SPIRE server peers (e.g., namespaceSelector.matchLabels:
{federation: "true"} or podSelector.matchLabels for the peer pods) and for
egress add to: with the same selectors so traffic is only allowed to those
peers; keep the TCP port 8443 and ensure the selectors reflect your cluster’s
federation labels (or use ipBlock if you must restrict by CIDR).

Comment on lines +12 to +16
ingress:
# Allow SPIRE agents to connect
- ports:
- protocol: TCP
port: 8081
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Missing source restriction allows unrestricted access to SPIRE server API.

The ingress rule lacks a from selector, permitting ANY pod from ANY namespace to connect to the SPIRE server gRPC API on port 8081. This undermines the default-deny policy and violates zero-trust principles.

Restrict ingress to SPIRE agent pods only:

   ingress:
     # Allow SPIRE agents to connect
-    - ports:
+    - from:
+        - podSelector:
+            matchLabels:
+              app.kubernetes.io/name: spire-agent
+      ports:
         - protocol: TCP
           port: 8081
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ingress:
# Allow SPIRE agents to connect
- ports:
- protocol: TCP
port: 8081
ingress:
# Allow SPIRE agents to connect
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: spire-agent
ports:
- protocol: TCP
port: 8081
🤖 Prompt for AI Agents
In
bindata/network-policy/spire-server/spire-server-allow-ingress-to-8081-networkpolicy.yaml
around lines 12–16, the ingress rule currently has no `from` clause so it allows
any source to reach port 8081; restrict it to SPIRE agents by adding a `from`
selector that matches the SPIRE agent pods (or the agents' namespace). Update
the ingress entry to include a `from` with the correct podSelector labels used
by your spire-agent deployment (or a namespaceSelector + podSelector combination
if agents are isolated by namespace) so only agent pods can connect to TCP port
8081.

Comment on lines +250 to +271
var _networkPolicySpireServerSpireServerAllowEgressIngressToFederationNetworkpolicyYaml = []byte(`apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: spire-server-allow-egress-ingress-to-federation
namespace: zero-trust-workload-identity-manager
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: spire-server
policyTypes:
- Ingress
- Egress
ingress:
# Allow federation traffic
- ports:
- protocol: TCP
port: 8443
egress:
- ports:
- protocol: TCP
port: 8443
`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Federation policy allows unrestricted bidirectional traffic.

The federation NetworkPolicy allows both ingress and egress on port 8443 without source or destination restrictions. This permits any pod to connect to/from SPIRE server federation endpoints.

If federation is with specific external SPIRE servers, consider restricting based on known federation partners. At minimum, add comments documenting why unrestricted access is required.

🤖 Prompt for AI Agents
In pkg/operator/assets/bindata.go around lines 250 to 271 the embedded
NetworkPolicy for spire-server-allow-egress-ingress-to-federation currently
permits ingress and egress on TCP/8443 with no peer restrictions; tighten the
policy by adding appropriate from/to peer selectors or CIDR blocks (e.g.,
specific podSelector/namespaceSelector blocks for known federation partners or
external IPBlocks for external SPIRE servers) to restrict allowed sources and
destinations, and if truly required to remain open, add a clear comment above
the YAML explaining why unrestricted access is necessary and any compensating
controls.

Comment on lines +432 to +448
var _networkPolicySpireServerSpireServerAllowIngressToWebhookNetworkpolicyYaml = []byte(`apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: spire-server-allow-ingress-to-webhook
namespace: zero-trust-workload-identity-manager
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: spire-server
policyTypes:
- Ingress
ingress:
# Allow webhook traffic
- ports:
- protocol: TCP
port: 9443
`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Webhook endpoint has unrestricted ingress.

The webhook NetworkPolicy allows ingress from ANY source to port 9443. The Kubernetes API server needs to reach this webhook, but the policy doesn't restrict ingress to just the API server.

In OpenShift/Kubernetes, webhooks are called by the API server. However, restricting by source IP/podSelector can be complex. At minimum:

  1. Add a comment documenting why unrestricted access is necessary
  2. Consider if there are OpenShift-specific labels or network constructs to restrict this further

Alternatively, if the API server runs in a specific namespace with identifiable labels, add appropriate selectors.

🤖 Prompt for AI Agents
In pkg/operator/assets/bindata.go around lines 432 to 448, the NetworkPolicy for
the webhook currently allows unrestricted ingress to port 9443; update the
manifest to (1) add an explicit comment above the policy explaining why open
access is present if you determine it is required for API server reachability,
and (2) if possible restrict ingress instead of leaving it open by adding
appropriate selectors—e.g. a namespaceSelector or podSelector that targets the
API server namespace/pods (or OpenShift-specific labels) or any cluster network
construct you use—so only the API server (or known control-plane pods) can
connect; if you cannot restrict it, document that reason and the risk in the
comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pkg/controller/utils/utils.go (1)

113-119: Function follows established pattern but inherits panic behavior.

The implementation is consistent with other decode functions in this file. However, the function panics on decode errors or type assertion failures, which could cause runtime crashes if assets are malformed.

This is a pre-existing pattern across all decode functions in this file, so addressing it here would be inconsistent. Consider adding error handling to all decode functions in a future refactor.

pkg/controller/static-resource-controller/network-policy.go (1)

54-122: Consider refactoring to reduce code duplication.

All 11 helper methods follow an identical pattern: decode from asset, apply labels, and return. This could be consolidated into a single parameterized helper method.

For example:

func (r *StaticResourceReconciler) getNetworkPolicy(assetName string, labelFunc func(map[string]string) map[string]string) *v1.NetworkPolicy {
    policy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(assetName))
    policy.Labels = labelFunc(policy.Labels)
    return policy
}

Then each getter becomes:

func (r *StaticResourceReconciler) getSpireAgentAllowEgressToApiServerNetworkPolicy() *v1.NetworkPolicy {
    return r.getNetworkPolicy(utils.SpireAgentAllowEgressToApiServerNetworkPolicyAssetName, utils.SpireAgentLabels)
}

This would reduce maintenance burden and improve consistency across the codebase.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1f0d147 and 1871808.

📒 Files selected for processing (3)
  • pkg/controller/static-resource-controller/network-policy.go (1 hunks)
  • pkg/controller/utils/constants.go (1 hunks)
  • pkg/controller/utils/utils.go (3 hunks)
🔇 Additional comments (5)
pkg/controller/utils/utils.go (2)

16-16: LGTM!

The import is correctly placed and follows the established ordering pattern.


35-35: LGTM!

The scheme registration follows the established pattern and enables NetworkPolicy decoding.

pkg/controller/static-resource-controller/network-policy.go (2)

12-20: LGTM!

The method cleanly orchestrates NetworkPolicy creation/updates with appropriate error handling.


22-51: LGTM!

The method is well-organized with clear grouping and helpful comments. The default-deny policy is correctly placed first.

pkg/controller/utils/constants.go (1)

47-58: LGTM!

The constants are well-named, consistently structured, and follow the established naming convention. The logical grouping (default-deny, then by component) makes the code easy to navigate.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/controller/static-resource-controller/controller.go (1)

59-107: Missing RBAC for networking.k8s.io/NetworkPolicy will cause Forbidden errors

The new CreateOrApplyNetworkPolicyResources step needs permissions to manage NetworkPolicies. Add the kubebuilder RBAC marker so the operator ClusterRole includes them.

Apply this diff near the existing RBAC markers:

 // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
 // +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete
 // +kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=networking.k8s.io,resources=networkpolicies,verbs=get;list;watch;create;update;patch;delete
 // +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;watch;create;update;patch;delete
🧹 Nitpick comments (3)
pkg/controller/static-resource-controller/controller.go (3)

213-230: Pre-RBAC NetworkPolicy reconcile step added — confirm labeling and drift strategy

Good to run NetworkPolicy creation early. Please verify:

  • NetworkPolicies are labeled with utils.AppManagedByLabelKey/Value so predicates match.
  • Decide if you want reconcile-on-drift for NetworkPolicies; without a watch, external edits won’t enqueue. See suggested watch addition below.

334-345: Add watch for NetworkPolicies to reconcile on drift

Register a watch for networkingv1.NetworkPolicy so label-matched changes enqueue the “cluster” request, consistent with other managed resources.

Import and watch changes:

 import (
   "context"
@@
   storagev1 "k8s.io/api/storage/v1"
+  networkingv1 "k8s.io/api/networking/v1"
@@
   err := ctrl.NewControllerManagedBy(mgr).
@@
     Watches(&corev1.Service{}, handler.EnqueueRequestsFromMapFunc(mapFunc), controllerManagedResourcePredicates).
+    Watches(&networkingv1.NetworkPolicy{}, handler.EnqueueRequestsFromMapFunc(mapFunc), controllerManagedResourcePredicates).
     Watches(&rbacv1.RoleBinding{}, handler.EnqueueRequestsFromMapFunc(mapFunc), controllerManagedResourcePredicates).

Also ensure networkingv1 has been added to the scheme during manager setup (usually via client-go scheme registration).


216-229: Normalize event reason and success message (optional)

Use CamelCase reasons and “reconciled” wording for clarity/consistency.

- r.eventRecorder.Event(&config, corev1.EventTypeWarning, "failed to create network-policy resources",
-   err.Error())
+ r.eventRecorder.Event(&config, corev1.EventTypeWarning, "NetworkPolicyResourceCreateFailed", err.Error())

- Reason:  "NetworkPolicyResourceCreated",
- Message: "All NetworkPolicy resources for operands created",
+ Reason:  "NetworkPolicyResourcesReconciled",
+ Message: "All NetworkPolicy resources for operands are reconciled",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1871808 and 29d6ecb.

📒 Files selected for processing (1)
  • pkg/controller/static-resource-controller/controller.go (2 hunks)
🔇 Additional comments (1)
pkg/controller/static-resource-controller/controller.go (1)

36-36: Condition type addition looks good

New status key aligns with existing pattern and is scoped appropriately.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd18ef and 3300fa9.

📒 Files selected for processing (4)
  • bundle/manifests/zero-trust-workload-identity-manager.clusterserviceversion.yaml (2 hunks)
  • config/rbac/role.yaml (1 hunks)
  • pkg/controller/static-resource-controller/controller.go (5 hunks)
  • pkg/controller/static-resource-controller/network-policy.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/controller/static-resource-controller/controller.go
🔇 Additional comments (6)
bundle/manifests/zero-trust-workload-identity-manager.clusterserviceversion.yaml (2)

25-25: Metadata timestamp updated as expected.

Routine regeneration of ClusterServiceVersion manifest.


173-182: NetworkPolicy RBAC rule added in sync with config/rbac/role.yaml.

The new rule grants appropriate verbs for managing NetworkPolicy resources. Note that the delete verb is intentionally omitted—verify this is the intended design (e.g., to prevent accidental deletion of cluster-wide policies managed by the operator).

config/rbac/role.yaml (1)

85-94: NetworkPolicy RBAC rule correctly positioned and configured.

The rule is properly alphabetized among API groups and grants the necessary verbs (create, get, list, update, watch) for the operator to manage NetworkPolicy resources. This mirrors the ClusterServiceVersion changes and follows the existing RBAC pattern in the file.

pkg/controller/static-resource-controller/network-policy.go (3)

1-10: LGTM!

The package structure and imports are clean and appropriate for NetworkPolicy management.


12-20: LGTM!

The reconciliation loop is straightforward and handles errors correctly by returning early on failure.


25-26: Verify the timeline for enabling the default deny NetworkPolicy.

The default deny policy is currently commented out. In zero-trust architectures, a default-deny policy is typically a foundational security control that blocks all traffic unless explicitly allowed by other policies. Since this PR is marked WIP, confirm whether:

  • This is intentional for incremental rollout
  • When it will be enabled
  • What testing is planned before enabling it

Enabling default-deny without comprehensive allow policies can break workloads, so staged rollout may be appropriate.

Comment on lines +53 to +122
// Default deny network policy
func (r *StaticResourceReconciler) getDefaultDenyNetworkPolicy() *v1.NetworkPolicy {
defaultDenyNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.DefaultDenyNetworkPolicyAssetName))
// Apply standardized labels - this policy is general, so use basic managed-by label
defaultDenyNetworkPolicy.Labels = utils.SetLabel(defaultDenyNetworkPolicy.Labels, utils.AppManagedByLabelKey, utils.AppManagedByLabelValue)
return defaultDenyNetworkPolicy
}

// Spire Agent network policies
func (r *StaticResourceReconciler) getSpireAgentAllowEgressToApiServerNetworkPolicy() *v1.NetworkPolicy {
spireAgentNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireAgentAllowEgressToApiServerNetworkPolicyAssetName))
spireAgentNetworkPolicy.Labels = utils.SpireAgentLabels(spireAgentNetworkPolicy.Labels)
return spireAgentNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireAgentAllowEgressToSpireServerNetworkPolicy() *v1.NetworkPolicy {
spireAgentNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireAgentAllowEgressToSpireServerNetworkPolicyAssetName))
spireAgentNetworkPolicy.Labels = utils.SpireAgentLabels(spireAgentNetworkPolicy.Labels)
return spireAgentNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireAgentAllowIngressToMetricsNetworkPolicy() *v1.NetworkPolicy {
spireAgentNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireAgentAllowIngressToMetricsNetworkPolicyAssetName))
spireAgentNetworkPolicy.Labels = utils.SpireAgentLabels(spireAgentNetworkPolicy.Labels)
return spireAgentNetworkPolicy
}

// Spire OIDC Discovery Provider network policies
func (r *StaticResourceReconciler) getSpireOIDCDiscoveryProviderAllowIngressTo8443NetworkPolicy() *v1.NetworkPolicy {
spireOIDCNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireOIDCDiscoveryProviderAllowIngressTo8443NetworkPolicyAssetName))
spireOIDCNetworkPolicy.Labels = utils.SpireOIDCDiscoveryProviderLabels(spireOIDCNetworkPolicy.Labels)
return spireOIDCNetworkPolicy
}

// Spire Server network policies
func (r *StaticResourceReconciler) getSpireServerAllowEgressIngressToFederationNetworkPolicy() *v1.NetworkPolicy {
spireServerNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireServerAllowEgressIngressToFederationNetworkPolicyAssetName))
spireServerNetworkPolicy.Labels = utils.SpireServerLabels(spireServerNetworkPolicy.Labels)
return spireServerNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireServerAllowEgressToApiServerNetworkPolicy() *v1.NetworkPolicy {
spireServerNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireServerAllowEgressToApiServerNetworkPolicyAssetName))
spireServerNetworkPolicy.Labels = utils.SpireServerLabels(spireServerNetworkPolicy.Labels)
return spireServerNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireServerAllowEgressToDNSNetworkPolicy() *v1.NetworkPolicy {
spireServerNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireServerAllowEgressToDNSNetworkPolicyAssetName))
spireServerNetworkPolicy.Labels = utils.SpireServerLabels(spireServerNetworkPolicy.Labels)
return spireServerNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireServerAllowIngressTo8081NetworkPolicy() *v1.NetworkPolicy {
spireServerNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireServerAllowIngressTo8081NetworkPolicyAssetName))
spireServerNetworkPolicy.Labels = utils.SpireServerLabels(spireServerNetworkPolicy.Labels)
return spireServerNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireServerAllowIngressToMetricsNetworkPolicy() *v1.NetworkPolicy {
spireServerNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireServerAllowIngressToMetricsNetworkPolicyAssetName))
spireServerNetworkPolicy.Labels = utils.SpireServerLabels(spireServerNetworkPolicy.Labels)
return spireServerNetworkPolicy
}

func (r *StaticResourceReconciler) getSpireServerAllowIngressToWebhookNetworkPolicy() *v1.NetworkPolicy {
spireServerNetworkPolicy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(utils.SpireServerAllowIngressToWebhookNetworkPolicyAssetName))
spireServerNetworkPolicy.Labels = utils.SpireServerLabels(spireServerNetworkPolicy.Labels)
return spireServerNetworkPolicy
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle asset loading errors gracefully instead of panicking.

All getter functions use assets.MustAsset(), which panics if the asset is missing. This will crash the operator instead of allowing graceful error handling and recovery. While missing assets indicate a build/packaging issue, the operator should fail gracefully with a clear error message rather than panicking.

Consider one of these approaches:

  1. Use a non-panicking asset loader and return errors from getter functions
  2. Validate all required assets exist during controller initialization
  3. Wrap MustAsset calls with recover() and return appropriate errors

Additionally, these getter functions follow an identical pattern with only the asset name and label function varying. Consider refactoring to reduce duplication:

// Helper function to reduce duplication
func (r *StaticResourceReconciler) loadAndLabelNetworkPolicy(
    assetName string,
    labelFunc func(map[string]string) map[string]string,
) *v1.NetworkPolicy {
    policy := utils.DecodeNetworkPolicyObjBytes(assets.MustAsset(assetName))
    policy.Labels = labelFunc(policy.Labels)
    return policy
}

// Example usage
func (r *StaticResourceReconciler) getSpireAgentAllowEgressToApiServerNetworkPolicy() *v1.NetworkPolicy {
    return r.loadAndLabelNetworkPolicy(
        utils.SpireAgentAllowEgressToApiServerNetworkPolicyAssetName,
        utils.SpireAgentLabels,
    )
}

This consolidates the repeated pattern and makes the code more maintainable.

🤖 Prompt for AI Agents
In pkg/controller/static-resource-controller/network-policy.go (lines 53-122):
the current getters call assets.MustAsset(...) which panics on missing assets
and duplicate the same load-and-label pattern; change them to use a
non-panicking loader (or check asset existence) and return errors so callers can
handle failures gracefully, or validate all assets up-front during controller
initialization; also refactor the repeated code into a single helper method that
accepts the asset name and a label function, loads the asset (with error
propagation), decodes it, applies labels, and returns the *v1.NetworkPolicy and
error, then update each getter to call that helper and propagate/handle errors.

@openshift-ci
Copy link

openshift-ci bot commented Oct 29, 2025

@PillaiManish: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-bot
Copy link

Issues go stale after 90d of inactivity.

Mark the issue as fresh by commenting /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
Exclude this issue from closing by commenting /lifecycle frozen.

If this issue is safe to close now please do so with /close.

/lifecycle stale

@openshift-ci openshift-ci bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Jan 27, 2026
@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 27, 2026
@openshift-merge-robot
Copy link

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-bot
Copy link

Stale issues rot after 30d of inactivity.

Mark the issue as fresh by commenting /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.
Exclude this issue from closing by commenting /lifecycle frozen.

If this issue is safe to close now please do so with /close.

/lifecycle rotten
/remove-lifecycle stale

@openshift-ci openshift-ci bot added lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. and removed lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. labels Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants