Part 3 of a series on implementing zero trust security in Red Hat OpenShift with the layered zero trust validated pattern.
Kubernetes NetworkPolicies are one of the most powerful—and most misunderstood—security primitives available to platform engineers. They declare intent: "This pod should only accept connections on port 8443 from the ingress namespace." But declaring intent is not the same as verifying that it works as intended.
In the 1st article in this series, we argued that network policies are your last line of defense when you can't patch fast enough. We showed how the Layered Zero Trust Validated Pattern (ZTVP) uses default-deny policies combined with per-pod allow rules to contain the blast radius of compromised workloads, following NIST SP 800-207 zero trust architecture principles. In the 2nd article, we demonstrated how Red Hat Advanced Cluster Security for Kubernetes acts as the active central brain to enforce those boundaries in real-time.
But writing a NetworkPolicy YAML file and applying it to a cluster is only half the story. The other half—the one that most teams skip—is verifying that your policies actually do what you think they do. This article covers the common mistakes, the tooling landscape, and a practical approach to closing the gap between network policy intent and verified reality.
The 7 mistakes everyone makes
After implementing strict network policies across multiple namespaces in the ZTVP—Vault, Keycloak, zero trust workload identity manager (SPIRE/SPIFFE), qtodo, and Red Hat Advanced Cluster Security—we've repeatedly seen the same patterns of failure. Here are the configuration mistakes that catch even the most experienced Kubernetes network and security architects.
1. The "I have policies, so I'm secure" illusion
Imagine a scenario in which you’ve deployed 2 per-pod NetworkPolicies: 1 for your app, 1 for your database. The database only accepts connections from workloads matching the app=myapp label. Looks solid.
But without a foundational default-deny policy, any pod that doesn't match an existing policy has unrestricted network access. A rogue pod with a generic label can resolve every service via DNS, reach Vault across namespaces, and exfiltrate data to the internet. Your per-pod policies are locked gates set in the middle of an open field.
We demonstrated this live in the ZTVP: a rogue pod deployed to the qtodo namespace could discover and reach Vault, Red Hat Advanced Cluster Security central, and the public internet, while only the database (which had its own ingress policy) was protected.
2. Forgetting egress
Most teams focus exclusively on the question of ingress—who can connect to my pod?. But egress is equally critical. Without strict egress restrictions, a compromised pod can:
- Resolve any service in any namespace via DNS (reconnaissance), which is well documented in the MITRE Attack techniques.
- Connect to the Kubernetes API server and enumerate cluster resources.
- Reach external command-and-control (C2) servers.
- Exfiltrate data to arbitrary external endpoints.
In the ZTVP, every pod has explicit egress rules. DNS is limited to the cluster's CoreDNS service. Kubernetes API access is granted only to pods that actually need it. Internet egress is fiercely denied unless explicitly justified by business logic.
3. Platform-specific gotchas
Kubernetes NetworkPolicies are a standard API, but their behavior depends entirely on the underlying Container Network Interface (CNI) plugin. For example, on OpenShift with OVN-Kubernetes by default:
- DNS uses port 5353, not 53. A policy allowing egress to port 53 does nothing; your pods won't be able to resolve hostnames.
- The Kubernetes API server endpoints are node IPs after DNAT. You cannot use a
namespaceSelectorto match them; you need a port-only rule on 6443. - The OpenShift router ingress behavior depends on the
endpointPublishingStrategy, which can be set toHostNetwork,NodePortService, orLoadBalancerService. When usingHostNetwork, the source IP is a node IP; for ingress from the router in this configuration, use thepolicy-group.network.openshift.io/ingressnamespace label. hostNetworkpods are exempt from NetworkPolicies entirely. If your DaemonSet useshostNetwork: true(like SPIRE agents), no NetworkPolicy applies to it. You must document this as a known security exception rather than pretending standard policies cover it.
We discovered every one of these gotchas the hard way during our ZTVP implementation.
4. Failure to test on a live cluster
A NetworkPolicy that renders correctly doesn't always function securely at runtime. The only way to know is to apply it to a running cluster and verify:
- Do all pods stay healthy?
- Do routes still respond?
- Do dependent services in other namespaces still work?
- If you restart a pod, does it recover? (e.g., SPIRE agents re-attest, Keycloak reconnects to PostgreSQL, Vault re-joins the cluster).
In the ZTVP, we mandate a dry run on a live cluster before committing any NetworkPolicy change (this is one of the best practices). We apply the policies via oc apply, verify all flows, force-restart critical pods, check logs for connection errors, and clean up. Only after the dry run passes do we commit the code to Git.
5. Argo CD template boolean traps
When creating NetworkPolicy templates gated by values (e.g., enabled: true), a subtle bug catches many teams. Helm overrides applied via extraValueFiles often pass booleans as strings ("true", not true). A template condition like:
{{- if .Values.networkPolicy.enabled }} fails silently when the value is a string. The policy doesn't render, no error is reported, and you operate under the illusion of network isolation.
Always use:
{{- if eq (.Values.networkPolicy.enabled | toString) "true" }}This is a particularly dangerous class of silent failure. Your CI pipeline passes, and your Helm template renders without errors, but the policy simply doesn't exist in the cluster. To mitigate these risks, you can use tools like Chart Testing to validate your Helm charts, checking that configurations are correct before they reach the cluster and avoiding such silent failures.
6. Ignoring additive policy semantics
When multiple NetworkPolicies select the same pod, their rules are additive—they combine, they do not override. There is no priority, no ordering, and no logic by which any one policy takes precedence over any other. The final effective policy is the mathematical union of all matching policies.
This means you cannot create a restrictive policy and expect it to narrow down a broader one. If Policy A allows port 8080 from everywhere, and Policy B allows port 8080 only from namespace X, a pod in which these policies have been applied accepts traffic on port 8080 from everywhere. This additive behavior makes troubleshooting extremely difficult in large clusters; when a connection is unexpectedly allowed, you must examine every policy that selects the affected pod.
7. Namespace-scoping blind spots and the AdminNetworkPolicy dilemma
Standard Kubernetes network policies are namespace-scoped. A cluster administrator cannot define a cluster-wide default NetworkPolicy using the standard Kubernetes API. To enforce default-deny across 20 namespaces, you need 20 identical policies. If one namespace is missed, it's completely unprotected.
To address this gap, the Kubernetes Network Policy API Working Group introduced AdminNetworkPolicies (ANPs). For specific insights on applying these policies within an OpenShift environment, refer to the Red Hat blog post “Using AdminNetworkPolicy API to secure OpenShift cluster networking.” It is vital to understand the difference between these 2 approaches:
- NetworkPolicy (NP): Developer-centric and namespace-scoped. Perfect for fine-grained, pod-to-pod microsegmentation within a specific application's boundary.
- AdminNetworkPolicy (ANP): Cluster-admin-centric and cluster-scoped. Designed to enforce broad, non-negotiable infrastructure guardrails (e.g., "tenant namespaces cannot communicate with each other" or "all pods must be able to reach cluster DNS").
Many teams assume ANPs are the silver bullet for enforcing a global deny-by-default posture. However, this is a dangerous misconception. ANPs do not cover per-namespace microsegmentation. If an administrator applies a strict global Deny rule via ANP, it executes with high priority and overrides developer-level network policies. If the admin denies everything, developers cannot punch the holes that are necessary for their applications to function.
While the relatively new BaselineAdminNetworkPolicy (BANP) allows for a baseline deny that developers can override, relying solely on global cluster policies to manage application-level microsegmentation is an antipattern. Global policies lack the granular context required for complex microservices and often break dynamic, operator-managed workloads or hidden cluster services.
Because of potential problems with using only AdminNetworkPolicy or a new BaselineAdminNetworkPolicy, in the ZTVP we leverage a layered approach with application-level microsegmentation. We use Helm chart templates with values-driven policies to enforce foundational namespace-scoped default-deny policies. This guarantees architectural consistency while empowering developers to build explicit, justified allow lists directly aligned with their application's logic.
The tooling gap
The limits of static analysis
Several tools exist to generate NetworkPolicies from Kubernetes manifests. They analyze your YAML files, discover services and selectors, and propose policies based on inferred connectivity. While useful as a starting point, such static analysis has fundamental limitations:
- No runtime visibility: A manifest declares what a pod could do, not what it actually does. A pod connecting to an external API at runtime won't declare that in its YAML definition.
- Platform ignorance: Static tools are unaware that OpenShift uses port 5353 for DNS, or that
hostNetworkpods bypass policies. - Dynamic operator constraints: Operators create pods, services, and policies dynamically. Static analysis of a Helm chart won't capture what the operator deploys after initialization.
Generated policies are proposals, not solutions. They must always be verified against a live cluster with real traffic. This approach is already covered in the Network Policy Architect skill explained in the next section.
Runtime network flow observation
Where security tooling truly adds value is in observing actual network flows. Red Hat Advanced Cluster Security provides runtime monitoring that tracks every connection between pods, namespaces, and external endpoints. This gives you:
- A real-time network topology map showing actual traffic patterns.
- Identification of unexpected connections (e.g., a pod reaching a service it shouldn't).
- Baseline flows that inform what your explicit allow rules should be.
- Continuous validation that your intent matches reality.
This is the capability that allows you to close the loop: You write policies based on architecture analysis, apply them, and then use runtime observation to confirm that the observed traffic matches your zero trust intent. When discrepancies appear, you iterate.
AI-assisted network policy design
To codify the lessons learned from the ZTVP implementation and streamline policy creation, we've developed the Network Policy Architect—an AI agent skill that guides you through the entire lifecycle.
The skill operates in two mandatory tiers:
- Tier 1: Architecture analysis: The agent analyzes your application's source code, Helm charts, and documentation to map all communication flows. It identifies special cases (e.g., DNAT,
hostNetwork) and drafts initial rules with justifications. - Tier 2: Live cluster verification: The agent connects to your running cluster, applies the proposed policies as a dry run, and records pass/fail results for every verification check. Only after the dry run passes does it produce the final plan.
The skill is designed for the critical security architect persona: every rule must trace back to an observed communication flow, and every exception must be explicitly acknowledged.
Seeing it in action: Analyzing an unsecured namespace
To demonstrate the Network Policy Architect in practice, we pointed it at a Keycloak namespace on a live OpenShift cluster—one that hadn't yet been hardened with custom network policies. This namespace runs 3 workloads: the Keycloak identity server (StatefulSet), a PostgreSQL database (Deployment), and the Red Hat build of Keycloak operator (Deployment). The Red Hat build of Keycloak operator had automatically created its own keycloak-network-policy covering ingress to the Keycloak server pods, but nothing beyond that. For the purposes of the demo, we use a CLI AI code agent where the skill can be invoked as follows:
/network-policy-architect Analyze the keycloak namespace on my OpenShift cluster. The namespace runs Keycloak (RHBK), PostgreSQL, and the RHBK operator.
Starting fresh Tier 1 analysis for the keycloak namespace. Cluster is live — let me gather the full inventory.Tier 1: Architecture analysis
The agent started by autonomously querying the cluster—running oc get pods, oc get svc, oc get routes, and examining pod labels, container ports, and existing network policies. It mapped every communication flow: Keycloak connecting to PostgreSQL on port 5432, JGroups clustering on ports 7800 and 57800, DNS resolution via CoreDNS on port 5353, and Kubernetes API access for JDBC_PING cluster discovery. It also recognized that the operator's keycloak-network-policy is managed via ownerReferences— meaning any modifications would be automatically reverted.
Once the analysis is completed, the full Tier 1 report is displayed to the end user, which includes architecture analysis, communication flow, security gaps and recommended network policies draft.
Tier 1: Architecture Analysis — keycloak Namespace
1. Pod Inventory
Pod Type 1: Keycloak (StatefulSet)
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Detail |
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Pod pattern | keycloak-N (currently keycloak-0, single replica) |
| Labels | app=keycloak, app.kubernetes.io/component=server, app.kubernetes.io/instance=keycloak, app.kubernetes.io/managed-by=keycloak-operator |
| Container | keycloak |
| Ports | 8443/TCP (HTTPS), 8080/TCP (HTTP), 9000/TCP (management) |
| hostNetwork | No |
| Service account | default (no special RBAC) |
| Volumes | keycloak-tls (Secret: keycloak-tls), projected SA token |
| Notes | Java/JVM application (glibc-based UBI). Uses JGroups with JDBC_PING discovery (peers found via PostgreSQL, not K8s API). JGroups mTLS encryption enabled. |
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
Pod Type 2: PostgreSQL (Deployment)
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Detail |
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Pod pattern | keycloak-N (currently keycloak-0, single replica) |
| Labels | app=keycloak, app.kubernetes.io/component=server, app.kubernetes.io/instance=keycloak, app.kubernetes.io/managed-by=keycloak-operator |
| Container | keycloak |
| Ports | 8443/TCP (HTTPS), 8080/TCP (HTTP), 9000/TCP (management) |
| hostNetwork | No |
| Service account | default (no special RBAC) |
| Volumes | keycloak-tls (Secret: keycloak-tls), projected SA token |
| Notes | Java/JVM application (glibc-based UBI). Uses JGroups with JDBC_PING discovery (peers found via PostgreSQL, not K8s API). JGroups mTLS encryption enabled. |
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
Pod Type 3: RHBK Operator (Deployment)
+-----------------+-----------------------------------------------------------------------------------------------------+
| Field | Detail |
+-----------------+-----------------------------------------------------------------------------------------------------+
| Pod pattern | keycloak-pgsql-* |
| Labels | app=keycloak-pgsql |
| Container | pgsql |
| Ports | 5432/TCP |
| hostNetwork | No |
| Service account | default (no special RBAC) |
| Volumes | Standard (PVC for data) |
| Notes | Upstream PostgreSQL container. Serves as primary datastore AND JGroups JDBC_PING discovery backend. |
+-----------------+-----------------------------------------------------------------------------------------------------+
Pod Type 4: Realm Import Job (Job sso)
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Detail |
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Pod pattern | rhbk-operator-* |
| Labels | name=rhbk-operator |
| Container | rhbk-operator |
| Ports | None declared in spec (Quarkus health on 8080 internally) |
| hostNetwork | No |
| Service account | rhbk-operator (OLM-managed, K8s API access for CRD management) |
| Notes | Java/Quarkus operator. Manages Keycloak CR, KeycloakRealmImport CR. Creates and owns the keycloak-network-policy NetworkPolicy, StatefulSet, Services, and Jobs. |
+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2. Service Inventory
+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Detail |
+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Pod pattern | sso-* |
| Labels | app=keycloak-realm-import, app.kubernetes.io/managed-by=keycloak-operator |
| Container | keycloak (same image as main Keycloak) |
| Ports | 8443, 8080, 9000 (declared but not used as server) |
| hostNetwork | No |
| Notes | Runs once during initial deployment (currently Completed). Imports realm config into database. Will re-run on future deployments if KeycloakRealmImport CR changes. |
+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Draft NetworkPolicy Rules
Policy 1: default-deny-in-namespace-keycloak
- Applies to: All pods (podSelector: {})
- Effect: Denies all ingress and egress not explicitly allowed
- NIST justification: Zero Trust baseline — no implicit trust
Policy 2: keycloak-egress (supplements operator-managed ingress policy)
- Applies to: app=keycloak, app.kubernetes.io/instance=keycloak, app.kubernetes.io/managed-by=keycloak-operator
- Egress rules:
- DNS: 5353/UDP+TCP → openshift-dns namespace
- PostgreSQL: 5432/TCP → pods with app=keycloak-pgsql
- JGroups: 7800, 57800/TCP → keycloak pods (self, same labels)
Policy 3: keycloak-pgsql
- Applies to: app=keycloak-pgsql
- Ingress rules:
- 5432/TCP from keycloak pods (app=keycloak, managed-by=keycloak-operator)
- 5432/TCP from realm import job (app=keycloak-realm-import)
- Egress rules:
- DNS: 5353/UDP+TCP → openshift-dns namespace
Policy 4: rhbk-operator
- Applies to: name=rhbk-operator
- Ingress rules: None (no inbound connections needed)
- Egress rules:
- DNS: 5353/UDP+TCP → openshift-dns namespace
- K8s API: 6443/TCP → any (port-only, DNAT prevents selector use)
- Keycloak management: 9000/TCP → keycloak pods
- Keycloak HTTPS: 8443/TCP → keycloak pods
Policy 5: keycloak-realm-import
- Applies to: app=keycloak-realm-import
- Ingress rules: None
- Egress rules:
- DNS: 5353/UDP+TCP → openshift-dns namespace
- PostgreSQL: 5432/TCP → pods with app=keycloak-pgsql
- Keycloak HTTPS: 8443/TCP → keycloak pods
- K8s API: 6443/TCP → any (port-only)In this example, the agent has identified 5 security gaps:
- No default-deny policy: Without a foundational deny-all rule, any pod not covered by an existing policy has unrestricted access. The PostgreSQL database—containing user credentials, realm configurations, and client secrets—was reachable from any pod in any namespace.
- No egress controls: All 3 pod types could freely resolve DNS across the cluster, connect to the Kubernetes API, and reach external endpoints—a direct exfiltration path.
- PostgreSQL had zero network policy: The most sensitive component in the namespace had no isolation whatsoever.
- The operator pod was unprotected: The Red Hat build of Keycloak operator, which has role-based access control permissions to manage resources across the namespace, had unrestricted network access.
- The operator-managed policy covered ingress only: Even the Keycloak server pods, which did have an ingress policy, had no egress restrictions.
Tier 2: Live cluster verification
The agent then applied all proposed policies directly to the running cluster as a dry run. It verified that all pods remained running and ready, that the Keycloak route still responded over HTTPS, and that no new connection errors appeared in the logs. Every verification step is reported to the end user.
Starting Tier 2 live cluster verification.
Steps 1–8 were covered during Tier 1 data gathering. Moving straight to generating the policy manifests and applying them.
Baseline healthy — all pods Running, route returns HTTP 200. Applying policies now.
All 5 policies applied. Running verification checks.
All pods still Running, route still returning HTTP 200. Let me run deeper checks — Keycloak login flow, operator reconciliation, DNS resolution, and log analysis.
Results are healthy:
*Realm info served correctly (confirms Keycloak → PostgreSQL working)
*Token endpoint returns 401 (not a timeout/500 — auth flow works, just dummy credentials)
*OCP OAuth reaches Keycloak (401 = processed the request, not network failure)
*Health endpoint on /health/ready via route is expected to fail — it's on management port 9000, not the HTTPS port 8443After recording all verification results as PASS, the agent cleaned up by removing the dry run policies.
Post-Apply Verification
+-----------------------------------+--------+----------------------------------------------------------------+
| Check | Result | Evidence |
+-----------------------------------+--------+----------------------------------------------------------------+
| All pods Running after NP applied | PASS | All 3 active pods Running/Ready, job Succeeded |
| Route responds (OIDC discovery) | PASS | HTTP 200 (0.608s) |
| Route responds (admin console) | PASS | HTTP 200 |
| Realm info served | PASS | Realm sso, public key present |
| Token endpoint functional | PASS | HTTP 401 (auth processed correctly, not timeout/5xx) |
| DNS resolution (PostgreSQL pod) | PASS | nslookup keycloak.keycloak.svc.cluster.local -> 172.231.70.175 |
| No new error logs (keycloak) | PASS | No errors in post-apply logs |
| No new error logs (operator) | PASS | No errors in post-apply logs |
| No new error logs (postgresql) | PASS | No errors in post-apply logs |
+-----------------------------------+--------+----------------------------------------------------------------+
This entire analysis—from initial namespace scan through gap detection, policy design, and live verification—was a single conversation with the AI agent. At the end, the user gets a final executive summary with ready-to-use, well- tested network policies.
Executive Summary
+----------------------------------+------------------------------------------------------------------------------------------------------------------+
| Field | Detail |
+----------------------------------+------------------------------------------------------------------------------------------------------------------+
| Namespace | keycloak |
| Pod types covered | 4 (Keycloak, PostgreSQL, RHBK Operator, Realm Import Job) |
| New NetworkPolicies proposed | 5 (default-deny + 4 per-pod) |
| Existing operator-managed policy | 1 (keycloak-network-policy — ingress only, not modified) |
| Known exceptions | OCP router uses port-only ingress rules (handled by operator policy); K8s API uses port-only egress rules (DNAT) |
| Dry-run result | ALL CHECKS PASSED |
+----------------------------------+------------------------------------------------------------------------------------------------------------------+The Network Policy Architect also shows the NIST SP 800-207 zero trust architecture alignment.
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Principle | Implementation |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Least privilege | Every egress/ingress rule maps to a specific, observed communication flow. No "allow all" rules. |
| Assume breach | Default-deny limits blast radius. A compromised PostgreSQL pod cannot reach the internet or other namespaces. A compromised keycloak pod can only reach PostgreSQL and DNS. |
| Microsegmentation | Per-pod policies (4 distinct policies), not a single namespace-wide allow rule. Each pod type has its own minimal allow set. |
| No implicit trust | Cross-namespace access explicitly denied. Internet egress explicitly denied. Even intra-namespace communication requires explicit rules. |
| Verify explicitly | Operator-managed policy provides ingress rules for keycloak; our policies supplement with egress. No overlap, no conflict. |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+The verification loop
The complete workflow for zero trust network isolation looks like this:
- Design: Analyze architecture, identify flows, and draft policies.
- Test: Apply to a live cluster, verify all flows, and force pod restarts.
- Deploy: Commit to Git, allowing Argo CD to sync the verified state to the cluster.
- Observe: Use Red Hat Advanced Cluster Security to monitor actual network flows against policy intent.
- Iterate: When new components are added, repeat from step 1.
Each step reinforces the others. Design without testing produces brittle policies. Testing without observation misses runtime drift. Observation without design has no secure baseline to compare against.
Getting started
The Layered Zero Trust Validated Pattern provides working, production-ready examples of this approach:
- Vault network policies: Per-pod rules for secrets infrastructure.
- Keycloak network policies: Operator-managed ingress with custom egress.
- Zero trust workload identity manager network policies: Handling
hostNetworkagents and federation endpoints. - qtodo network policies: Application-level default-deny demonstration.
Each implementation follows the same rigorous pattern: a default-deny foundation, justified per-pod rules, dry run verification, and strictly documented exceptions. The Network Policy Architect skill is also available in the Red Hat Agentic Collections for teams seeking AI-assisted guidance.
In a zero trust architecture, writing the policy is only the beginning. Verifying that it works—and continuously confirming that it still works—is what actually keeps your workloads safe.
Red Hat Product Security
About the author
Przemysław “Rogue” Roguski is a Security Architect at Red Hat who specializes in shift-left security initiatives focusing on embedding security best practices and attestation into the earliest stages of the SDLC. He contributes security analysis work on Red Hat OpenShift and other OpenShift-related products. He also designs security solutions and processes across Red Hat.
He contributes to the security ecosystem as a member of the CISA SBOM/VEX working groups, an OASIS OpenEoX Technical Committee member and a key contributor to the CWE program.
More like this
The Lightwell reality check
Accelerating post-quantum security migration with Red Hat Certificate System
Can Compliance Be A Piece Of Cake? | Compiler
Collaboration In Product Security | Compiler
Keep exploring
- Security approaches for hybrid cloud environments
Whitepaper - A layered approach to container and Kubernetes securityWhitepaper
Browse by channel
Automation
The latest on IT automation for tech, teams, and environments
Artificial intelligence
Updates on the platforms that free customers to run AI workloads anywhere
Open hybrid cloud
Explore how we build a more flexible future with hybrid cloud
Security
The latest on how we reduce risks across environments and technologies
Edge computing
Updates on the platforms that simplify operations at the edge
Infrastructure
The latest on the world’s leading enterprise Linux platform
Applications
Inside our solutions to the toughest application challenges
Virtualization
The future of enterprise virtualization for your workloads on-premise or across clouds