Skip to content

feat: add in-cluster HTTP (port 80) egress NetworkPolicy - #3626

Closed
rm3l wants to merge 3 commits into
redhat-developer:mainfrom
rm3l:feat/allow-http-egress-np
Closed

rm3l wants to merge 3 commits into
redhat-developer:mainfrom
rm3l:feat/allow-http-egress-np

Conversation

@rm3l

@rm3l rm3l commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Description

Adds an allow-http-egress NetworkPolicy to the operator's default NP config, allowing egress on port 80 only to cluster-internal destinations (namespaceSelector: {}).

This fixes OIDC discovery timeouts when Keycloak (or other in-cluster services) runs behind a plain HTTP route without TLS termination. The existing default-deny NPs only allow egress on ports 443, 53/5353, 5432, and 6379, which blocks port 80 traffic.

Which issue(s) does this PR fix or relate to

PR acceptance criteria

  • Tests — updated NP count assertions in networkpolicy_test.go (7→8 backend, 10→11 total, 8→9 flavour merge)
  • Documentation — NP is self-documenting via inline comments

How to test changes / Special notes to the reviewer

All existing NP tests pass with updated assertions. The new NP is added to:

  • config/profile/rhdh/default-config/networkpolicy.yaml (source of truth)
  • pkg/model/testdata/default-config/networkpolicy.yaml (test fixture)
  • pkg/model/testdata/testflavours/default-config/networkpolicy.yaml (flavour test fixture)

bin/default-config/ is auto-generated and not updated here.

Companion chart PR: redhat-developer/rhdh-chart#556

Keycloak and other in-cluster services may run behind plain HTTP
routes or services without TLS termination. The existing default-deny
NPs only allow egress on ports 443, 53/5353, 5432, and 6379, which
blocks port 80 traffic and causes OIDC discovery timeouts.

Add an allow-http-egress NP restricted to cluster-internal
destinations (namespaceSelector: {}) so that plugins can reach
in-cluster HTTP services without requiring users to create custom
additive NPs.

Assisted-by: Claude
@rhdh-qodo-merge

Copy link
Copy Markdown

PR Summary by Qodo

Allow cluster-internal HTTP egress in default NetworkPolicies

✨ Enhancement 🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Allows Backstage pods to reach cluster-internal HTTP services on TCP port 80.
• Prevents OIDC discovery timeouts for identity providers without TLS termination.
• Synchronizes model fixtures and NetworkPolicy counts with the new default.
Diagram

graph TD
  A["Default NP config"] -->|loaded by| B["Operator model"] -->|renders| C["HTTP egress policy"] -->|selects| D["Backstage pods"] -->|TCP 80| E["Cluster HTTP service"]
Loading
High-Level Assessment

The dedicated NetworkPolicy is the preferred approach because it preserves default-deny behavior while narrowly enabling HTTP access to namespace-backed, cluster-internal workloads. Unrestricted port 80 egress would be broader than necessary, while requiring user-authored additive policies would leave common in-cluster OIDC deployments broken by default.

Files changed (4) +59 / -4

Enhancement (1) +21 / -0
networkpolicy.yamlAdd cluster-internal HTTP egress policy +21/-0

Add cluster-internal HTTP egress policy

• Adds the source-of-truth 'allow-http-egress' NetworkPolicy for Backstage pods. It permits TCP port 80 only to destinations selected through Kubernetes namespaces, supporting in-cluster services without TLS termination.

config/profile/rhdh/default-config/networkpolicy.yaml

Tests (3) +38 / -4
networkpolicy_test.goUpdate expected default NetworkPolicy counts +4/-4

Update expected default NetworkPolicy counts

• Increases backend and total policy assertions to account for the new HTTP egress policy across default, local-database-disabled, and flavour-merge scenarios.

pkg/model/networkpolicy_test.go

networkpolicy.yamlAdd HTTP egress policy to default fixture +17/-0

Add HTTP egress policy to default fixture

• Mirrors the new 'allow-http-egress' policy in the model's default configuration fixture, including its namespace restriction and TCP port 80 rule.

pkg/model/testdata/default-config/networkpolicy.yaml

networkpolicy.yamlAdd HTTP egress policy to flavour fixture +17/-0

Add HTTP egress policy to flavour fixture

• Adds the cluster-internal TCP port 80 policy to the flavour-merge fixture so tests reflect the updated default NetworkPolicy set.

pkg/model/testdata/testflavours/default-config/networkpolicy.yaml

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Released installs omit port 80 access ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new allow-http-egress document was added to the source profile without regenerating the bundle
ConfigMap and consolidated installation manifest. Installations using either checked-in release
artifact therefore retain the previous default-deny configuration and never receive the new port 80
allowance.
Code

config/profile/rhdh/default-config/networkpolicy.yaml[R60-63]

+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-http-egress
Relevance

●●● Strong

Release artifacts must match source; historical reviews accepted synchronized generated bundle and
install manifests.

PR-#1484
PR-#2717

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The profile kustomization includes the changed source file, but the generated bundle ConfigMap still
places the Redis policy immediately after the HTTPS policy and contains no HTTP policy. The PR
validation workflow explicitly regenerates these artifacts and fails when they differ, while the
operator bundle mounts that generated ConfigMap as its runtime default configuration.

config/profile/rhdh/kustomization.yaml[39-51]
bundle/rhdh/manifests/rhdh-default-config_v1_configmap.yaml[416-438]
dist/rhdh/install.yaml[3240-3261]
.github/workflows/pr-bundle-diff-checks.yaml[34-48]
bundle/rhdh/manifests/backstage-operator.clusterserviceversion.yaml[396-415]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The source default configuration contains the new NetworkPolicy, but the generated bundle and distribution manifests consumed by released installations remain stale.

## Fix Focus Areas
- config/profile/rhdh/default-config/networkpolicy.yaml[56-75]
- bundle/rhdh/manifests/rhdh-default-config_v1_configmap.yaml[416-438]
- dist/rhdh/install.yaml[3240-3261]

## Recommended Fix
Run `make bundles build-installers`, commit the regenerated files under `bundle`, `config`, and `dist`, and verify that both generated installation manifests contain the complete `allow-http-egress` policy.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Admins cannot identify egress scope 📘 Rule violation ✧ Quality ⭐ New
Description
docs/configuration.md describes the port 80 policy but does not say that the operator creates it
in the Backstage custom resource's namespace. Because network policies are namespace-scoped, readers
managing instances across namespaces cannot tell which backend pods receive this egress permission.
Code

docs/configuration.md[232]

+    - The `allow-http-egress` policy allows egress on port 80 TCP to in-cluster destinations only (`namespaceSelector: {}`), for services behind plain HTTP routes or services (e.g., Keycloak without TLS termination)
Relevance

●●● Strong

Recent precedents accept clarifying that generated resources operate in the Backstage CR namespace.

PR-#1551
PR-#1046

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance rule 5 requires documentation to identify the creation namespace when namespaced-resource
behavior depends on it. The changed documentation identifies permitted destinations but omits that
model metadata places every generated network policy in the Backstage custom resource's namespace.

Rule 5: Document resource creation namespace when behaviorally relevant
docs/configuration.md[232-232]
pkg/model/networkpolicy.go[80-96]
pkg/model/runtime.go[227-231]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new port 80 network policy documentation omits that the operator creates the policy in the same namespace as the Backstage custom resource, leaving its effective scope ambiguous.

## Fix Focus Areas
- docs/configuration.md[232-232]

## Recommended Fix
Extend the policy description to state that it is created in the Backstage custom resource's namespace and applies to matching backend pods in that namespace. Clarify that `namespaceSelector: {}` selects destination namespaces and does not make the policy cluster-wide.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Plain HTTP routes remain unreachable ✓ Resolved 🐞 Bug ≡ Correctness
Description
The namespaceSelector: {} destination admits namespace-selected pods but does not cover an
OpenShift Route reached through its router endpoint. When an OIDC issuer is addressed by a plain
HTTP Route rather than its ClusterIP Service, the default-deny policy can still block discovery on
port 80.
Code

config/profile/rhdh/default-config/networkpolicy.yaml[R70-74]

+  egress:
+    - to:
+        - namespaceSelector: {}
+      ports:
+        - port: 80
Relevance

● Weak

PR explicitly limits port 80 to cluster-internal destinations; external router access is outside its
stated scope.

PR-#3477
PR-#3394

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added comment promises support for plain HTTP routes, but the rule restricts destinations to
namespace-selected pods. The repository's Intelligent Assistant flavor handles an external OpenShift
Route with a separate port 80 rule that deliberately has no to selector, while its comment
distinguishes that router path from an internal Service.

config/profile/rhdh/default-config/networkpolicy.yaml[56-75]
config/profile/rhdh/default-config/flavours/intelligent-assistant/networkpolicy.yaml[12-20]
config/profile/rhdh/default-config/route.yaml[1-14]
config/profile/rhdh/default-config/service.yaml[1-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new destination selector supports direct in-cluster Service backends but not the OpenShift router path explicitly named by the feature description.

## Fix Focus Areas
- config/profile/rhdh/default-config/networkpolicy.yaml[56-75]
- config/profile/rhdh/default-config/flavours/intelligent-assistant/networkpolicy.yaml[12-17]

## Recommended Fix
Add a router-compatible TCP port 80 egress rule following the existing Intelligent Assistant policy's route handling, propagate it to both fixtures, and add a semantic test that distinguishes direct Service access from Route access. If unrestricted port 80 is unacceptable, remove Route support from the stated behavior and require a separately configured router or CIDR policy.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
⚠️ Tickets: not configured — ticket URL found in PR but could not be fetched — check ticket provider credentials
✅ Compliance rules (platform): 18 rules
✅ Cross-repo context — repo relationships
  ⚠️ Failed to retrieve: redhat-developer/rhdh-chart
Review mode: ⚖️ Balanced: This is a localized NetworkPolicy permission change affecting runtime egress and security boundaries, so it warrants a careful single-pass review despite being replicated in generated manifests.

Grey Divider

Tip of the day
💡 Did you know, you can choose which labels appear on a finding, and whether they show icons or text

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit 673e63d ⚖️ Balanced

Results up to commit 0ea45e4 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Released installs omit port 80 access ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new allow-http-egress document was added to the source profile without regenerating the bundle
ConfigMap and consolidated installation manifest. Installations using either checked-in release
artifact therefore retain the previous default-deny configuration and never receive the new port 80
allowance.
Code

config/profile/rhdh/default-config/networkpolicy.yaml[R60-63]

+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-http-egress
Relevance

●●● Strong

Release artifacts must match source; historical reviews accepted synchronized generated bundle and
install manifests.

PR-#1484
PR-#2717

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The profile kustomization includes the changed source file, but the generated bundle ConfigMap still
places the Redis policy immediately after the HTTPS policy and contains no HTTP policy. The PR
validation workflow explicitly regenerates these artifacts and fails when they differ, while the
operator bundle mounts that generated ConfigMap as its runtime default configuration.

config/profile/rhdh/kustomization.yaml[39-51]
bundle/rhdh/manifests/rhdh-default-config_v1_configmap.yaml[416-438]
dist/rhdh/install.yaml[3240-3261]
.github/workflows/pr-bundle-diff-checks.yaml[34-48]
bundle/rhdh/manifests/backstage-operator.clusterserviceversion.yaml[396-415]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The source default configuration contains the new NetworkPolicy, but the generated bundle and distribution manifests consumed by released installations remain stale.

## Fix Focus Areas
- config/profile/rhdh/default-config/networkpolicy.yaml[56-75]
- bundle/rhdh/manifests/rhdh-default-config_v1_configmap.yaml[416-438]
- dist/rhdh/install.yaml[3240-3261]

## Recommended Fix
Run `make bundles build-installers`, commit the regenerated files under `bundle`, `config`, and `dist`, and verify that both generated installation manifests contain the complete `allow-http-egress` policy.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational
2. Plain HTTP routes remain unreachable ✓ Resolved 🐞 Bug ≡ Correctness
Description
The namespaceSelector: {} destination admits namespace-selected pods but does not cover an
OpenShift Route reached through its router endpoint. When an OIDC issuer is addressed by a plain
HTTP Route rather than its ClusterIP Service, the default-deny policy can still block discovery on
port 80.
Code

config/profile/rhdh/default-config/networkpolicy.yaml[R70-74]

+  egress:
+    - to:
+        - namespaceSelector: {}
+      ports:
+        - port: 80
Relevance

● Weak

PR explicitly limits port 80 to cluster-internal destinations; external router access is outside its
stated scope.

PR-#3477
PR-#3394

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added comment promises support for plain HTTP routes, but the rule restricts destinations to
namespace-selected pods. The repository's Intelligent Assistant flavor handles an external OpenShift
Route with a separate port 80 rule that deliberately has no to selector, while its comment
distinguishes that router path from an internal Service.

config/profile/rhdh/default-config/networkpolicy.yaml[56-75]
config/profile/rhdh/default-config/flavours/intelligent-assistant/networkpolicy.yaml[12-20]
config/profile/rhdh/default-config/route.yaml[1-14]
config/profile/rhdh/default-config/service.yaml[1-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new destination selector supports direct in-cluster Service backends but not the OpenShift router path explicitly named by the feature description.

## Fix Focus Areas
- config/profile/rhdh/default-config/networkpolicy.yaml[56-75]
- config/profile/rhdh/default-config/flavours/intelligent-assistant/networkpolicy.yaml[12-17]

## Recommended Fix
Add a router-compatible TCP port 80 egress rule following the existing Intelligent Assistant policy's route handling, propagate it to both fixtures, and add a semantic test that distinguishes direct Service access from Route access. If unrestricted port 80 is unacceptable, remove Route support from the stated behavior and require a separately configured router or CIDR policy.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread config/profile/rhdh/default-config/networkpolicy.yaml
@rhdh-qodo-merge rhdh-qodo-merge Bot added enhancement New feature or request Tests Bug fix labels Sep 24, 2026
@rhdh-qodo-merge

Copy link
Copy Markdown

Important

The /generate_labels command by Qodo is sunsetting on the 1st of October 2026 and will no longer be available. We recommend switching to the latest Qodo review capabilities. Learn more

@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.05%. Comparing base (6f75d0a) to head (673e63d).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3626      +/-   ##
==========================================
+ Coverage   60.00%   60.05%   +0.05%     
==========================================
  Files          51       51              
  Lines        3560     3560              
==========================================
+ Hits         2136     2138       +2     
+ Misses       1230     1229       -1     
+ Partials      194      193       -1     
Flag Coverage Δ
nightly ?
unittests 60.05% <ø> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown
Contributor

✅ PR images built and pushed successfully!

Images are available for testing (expires in 7 days):

Image Full tag PR tag
Operator quay.io/rhdh-community/operator:2.1.0-pr-3626-06eb140 quay.io/rhdh-community/operator:2.1.0-pr-3626
Bundle quay.io/rhdh-community/operator-bundle:2.1.0-pr-3626-06eb140 quay.io/rhdh-community/operator-bundle:2.1.0-pr-3626
Catalog quay.io/rhdh-community/operator-catalog:2.1.0-pr-3626-06eb140 quay.io/rhdh-community/operator-catalog:2.1.0-pr-3626

@sonarqubecloud

Copy link
Copy Markdown

@rm3l

rm3l commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 673e63d

@github-actions

Copy link
Copy Markdown
Contributor

✅ PR images built and pushed successfully!

Images are available for testing (expires in 7 days):

Image Full tag PR tag
Operator quay.io/rhdh-community/operator:2.1.0-pr-3626-673e63d quay.io/rhdh-community/operator:2.1.0-pr-3626
Bundle quay.io/rhdh-community/operator-bundle:2.1.0-pr-3626-673e63d quay.io/rhdh-community/operator-bundle:2.1.0-pr-3626
Catalog quay.io/rhdh-community/operator-catalog:2.1.0-pr-3626-673e63d quay.io/rhdh-community/operator-catalog:2.1.0-pr-3626

@rm3l

rm3l commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

May not be needed anymore

@rm3l rm3l closed this Sep 24, 2026
@rm3l
rm3l deleted the feat/allow-http-egress-np branch September 24, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix enhancement New feature or request Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant