Thought Leadership
May 21, 2026

Securing End-of-Life Software in Kubernetes: A Platform Team’s Playbook

A Platform Team's Playbook for When Upgrading Isn't an Immediate Option

Give me the TL;DR
Securing End-of-Life Software in Kubernetes: A Platform Team’s Playbook
For Qualys admins, NES for .NET directly resolves the EOL/Obsolete Software:   Microsoft .NET Version 6 Detected vulnerability, ensuring your systems remain secure and compliant. Fill out the form to get pricing details and learn more.

When Upgrading Isn’t an Immediate Option

Most organizations have workloads in production running End-of-Life (EOL) software. These workloads are often stable, critical to the business, and not in a position to be upgraded immediately. An EOL scanner flags vulnerabilities, but there are no immediate upstream fixes because support has ended.

Ingress NGINX is a useful example of why this matters in Kubernetes. The ingress controller sits at the edge of the cluster, routes external traffic to internal services, and often becomes the first component attackers interact with. For teams running affected or unsupported Ingress NGINX versions, vulnerabilities such as the recent “NGINX Rift” CVE-2026-42945 or CVE-2026-32282 can become more than a component-level finding. They can create risk at the boundary of the entire system.

Upgrading is still the recommended long-term solution, but real upgrade paths often include breaking changes, coordination across teams, and extensive testing. That is the operational challenge. How do you safely run EOL software that already exists in your Kubernetes cluster while working toward a long-term fix?

Throughout this playbook, Ingress NGINX is used as an example because it is a common Kubernetes component, it often sits at the edge of the cluster, and vulnerabilities in that layer can have platform-wide impact. The same containment model applies to other EOL workloads as well: runtimes, application frameworks, sidecars, agents, databases, and internal services.

TL;DR

  • EOL software in Kubernetes is not unusual, but it needs to be treated as managed risk.
  • Start by inventorying affected workloads, images, ingress paths, versions, and ownership.
  • Isolate EOL workloads with namespaces, node separation, NetworkPolicies, and stricter access paths.
  • Use edge controls such as rate limits, traffic filtering, and geographic restrictions where appropriate.
  • Enforce the pattern with admission policies, CI/CD guardrails, image scanning, and GitOps-based rollout controls.
  • When upstream support is gone, HeroDevs Never-Ending Support (NES) can provide patched, drop-in replacements that keep workloads secure and compliant while longer-term upgrades move forward.

What EOL Actually Means in a Kubernetes World

End-of-Life means:

  • No security patches
  • No upstream fixes
  • No CVE remediation

That is already a problem, but in a distributed system like Kubernetes, it becomes amplified. The runtime is baked into a container image, that image is replicated across pods and nodes, and the service is exposed through ingress. East-west communication within the cluster expands the surface area further, and the vulnerability is no longer isolated to a single instance. It exists everywhere that workload runs.

More importantly, compromises do not stop at the application layer. In Kubernetes, workloads are deeply integrated with the rest of the platform. Attackers that successfully exploit a vulnerability in a service are not there to take down your application. They are there to pivot and gain privileged access to whatever they can get their hands on. This means accessing Kubernetes secrets, service account tokens, or environment variables injected at runtime. In many cases, these credentials provide access to other services, APIs, cloud environments, databases, or even external systems.

Risk compounds in Kubernetes. A single vulnerability in a microservice can quickly escalate into an operational nightmare, a risk to customer data, and a compliance issue. That single vulnerability just became a pathway into the broader system. Kubernetes does not inherently create this risk, but it connects everything together, which amplifies the impact of any single vulnerability.

The Operational Reality

If it is running in your cluster, it’s your responsibility. It doesn’t matter if another team owns the application code, if an upgrade is already planned, or if the service is considered temporary. Once it is deployed, it is reachable, and therefore exploitable. At this point, ownership shifts to the platform to ensure the workload runs safely until a proper fix is in place.

In practice, most workloads have access to more than just their own process. They may have service accounts, network paths to other services, and credentials injected at runtime. That means a vulnerable service can become a pivot point into the systems and data it is allowed to reach.

The responsibility of securing the workload in Kubernetes typically falls on the Infrastructure or Platform Engineering team. Application teams own the code. Platform teams own the environment, network boundaries, and operational security around it. Their role is to minimize the attack surface, prevent lateral compromise, and enforce strong network security. This includes implementing least-privilege identity and access management, secure service-to-service communication, and ensuring sensitive data is properly handled with encryption. It also means maintaining robust logging and observability.

Strategy: Contain & Control

If you can’t immediately fix the vulnerability, the goal becomes reducing exposure, limiting blast radius, and preventing a vulnerable workload or ingress controller from becoming a broader platform compromise.

Start with inventory

Before you can contain EOL software, you need to know where it is running. Start by identifying workloads, images, ingress paths, annotations, versions, and ownership metadata. Even simple queries can help identify workloads and components that need review:

  • What registries are my workloads pulling from?
kubectl get deployments -A -o custom-columns='NAMESPACE:.metadata.namespace,DEPLOYMENT:.metadata.name,IMAGE:.spec.template.spec.containers[*].image'
  • What version of Ingress NGINX am I running?
kubectl get deploy -A -l app.kubernetes.io/name=ingress-nginx -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,IMAGE:.spec.template.spec.containers[*].image'
  • What ingress paths are available in my cluster?
kubectl get ingress -A -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,HOSTS:.spec.rules[*].host'
  • Once EOL workloads are identified, they should be labeled clearly so teams can apply stricter policies, reporting, and exception handling.
kubectl label deployment legacy-api risk.herodevs.com/eol=true -n legacy-apps

Isolate the workload

EOL workloads should not be treated the same as actively maintained services. They should be isolated accordingly. This starts with separating them into dedicated namespaces and applying strict network policies to control both ingress and egress traffic. East-west communication should be explicitly defined, justified, and documented. These workloads should also be isolated onto dedicated node groups where possible, using taints and tolerations to maintain separation from more sensitive workloads.

A simple NetworkPolicy can start by restricting traffic to known namespaces or components rather than allowing broad cluster-wide access.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-vulnerable-workload
  namespace: workload-a
spec:
  podSelector:
    matchLabels:
      risk.herodevs.com/eol: "true"
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: workload-b
    ports:
    - protocol: TCP
      port: 443

Pod specific controls matter as well. NetworkPolicies define how workloads communicate, but they don’t restrict what a pod can do on the node it runs on. Pod Security Standards (formerly Pod Security Policies) help reduce that risk by restricting privileged containers, host networking, host mount paths, and privileged escalation. For EOL workloads, enforcing at least the baseline or restricted profile helps reduce the likelihood that an application vulnerability would lead to a compromised host.

apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Lock down access paths

Most services are more exposed than they need to be. Over time, permissions expand beyond their original intent. Access paths that were once necessary remain in place long after they are no longer required. Revisiting access controls and network paths is an effective way to reduce risk. This means removing unnecessary ingress and egress routes, clearly defining and restricting service-to-service communication, and eliminating wildcard or overly permissive access policies. Tightening these boundaries reduces the number of ways a vulnerability can be exploited and minimizes the blast radius should something go wrong. A good practice is to start with a default deny for application namespaces and then layer in your allowed network paths.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: workload-a
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Put controls at the edge

The ingress layer is one of the most important control points in your system. Rate limiting, traffic filtering, and IP or geographic restrictions will not eliminate a vulnerability, but they can reduce exploitability and make automated abuse less effective.

This also makes the ingress layer itself a critical component to maintain. If your ingress controller is running an EOL or vulnerable version, it becomes a high-value target. Because it sits directly at the edge of your system, securing this layer is just as important as securing the workloads behind it. Ingress NGINX is a good example because vulnerabilities such as CVE-2026-32282 can turn a routing component into a broader platform risk.

For example, Ingress NGINX annotations can be used to limit request rates and concurrent connections while you work toward remediation.

nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-rpm: "300"
nginx.ingress.kubernetes.io/limit-connections: "10"

Geographic restrictions can also be considered when a workload only needs to serve users from known regions. These require controller-level configuration and a GeoIP database such as MaxMind GeoIP2. Again, these are risk-reduction controls, not a vulnerability fix.

if ($geo_blocked) {
  return 451;
}

This is where solutions like HeroDevs Never-Ending Support (NES) for Ingress NGINX come into play. Foundational components of your distributed system, like the ingress layer, should continue receiving security patches even after upstream support ends.

Enforce guardrails

Containing a vulnerable workload is one part of the problem. Architecting your platform with guardrails and preventative controls, so that future vulnerabilities or EOL workloads do not introduce additional risk, is another.

Platform guardrails:

  • RBAC: enforce least privilege so workloads can only access what they need
  • IRSA / Workload Identity: ensure workloads use scoped, temporary credentials
  • Network Policies: strictly define ingress/egress communication paths
  • Pod Security: to restrict running privileged containers
  • Image security controls: restrict allowed registries, use pull-through caches to control external image sources, and reference immutable image SHAs instead of mutable tags
  • Resource definitions: prevent abuse and exhaustion scenarios
  • etcd encryption: ensure sensitive data stored in the control plane is encrypted at rest

Least privilege should also include limiting access to the kube-apiserver. Many workloads run with the default pod service account which grants unnecessary privileges to the Kubernetes API. Most applications don’t actually need to interact with the API server at all, however Ingress NGINX is an exception here. An overly permissive service account is a common pivot point after an application is compromised. EOL workloads should use dedicated service accounts with minimal RBAC and no unnecessary API access.

Policy engines like Kyverno allow you to enforce these rules consistently with validating and mutating webhooks. You can block known vulnerable images, require explicit labeling for EOL workloads, and apply stricter controls to services that carry additional risk.

For example, Kyverno can generate a restrictive NetworkPolicy when a Deployment is labeled as EOL. This gives platform teams a way to automatically apply containment controls without relying on every application team to create the policy manually. The exact namespaces, ports, and labels should be adapted to your own platform conventions.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: generate-default-deny-for-eol-workloads
spec:
  background: true
  rules:
  - name: generate-default-deny-networkpolicy
    match:
      any:
      - resources:
          kinds:
          - Deployment
          selector:
            matchLabels:
              risk.herodevs.com/eol: "true"
    generate:
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      name: isolate-eol-workload
      namespace: "{{request.object.metadata.namespace}}"
      synchronize: true
      data:
        spec:
          podSelector:
            matchLabels:
              risk.herodevs.com/eol: "true"
          policyTypes:
          - Ingress
          - Egress
          ingress:
          - from:
            - namespaceSelector:
                matchLabels:
                  kubernetes.io/metadata.name: ingress-nginx
            ports:
            - protocol: TCP
              port: 8080
          egress:
          - to:
            - namespaceSelector:
                matchLabels:
                  kubernetes.io/metadata.name: kube-system
              podSelector:
                matchLabels:
                  k8s-app: kube-dns
            ports:
            - protocol: UDP
              port: 53
            - protocol: TCP
              port: 53

Control how changes roll out

Mitigation efforts can introduce their own risk if done incorrectly, which is why changes should be deployed in a controlled and observable way. Shifting left is an important aspect in this process because you want to catch issues as early as possible in the development cycle. Pre-commit hooks are useful for enforcing linting, policy checks, and basic security validation before code reaches version control. From there, strong CI pipelines should include vulnerability scanning of container images with tools like Trivy, dependency scanning, and policies that block non-compliant builds from being promoted to production. The goal is to prevent vulnerable software from ever being deployed rather than trying to catch and mitigate it later in the process.

When you are confident in your CI process and have a release candidate for production, consider a GitOps CD solution like Flux CD or Argo CD. These tools ensure that your Kubernetes cluster state is continuously reconciled against your version control system. This provides a clear audit trail while enabling safer rollout strategies like canary or phased deployments. Combining GitOps with policy enforcement tools like Kyverno is a mature next step. Kyverno can help inject missing resource requests and limits, apply default network policies, or reject deployments that do not meet security standards. This means both your pipelines and your cluster are enforcing security controls and standards, instead of relying on someone to catch issues later.

Where HeroDevs NES Fits

Eventually, there comes a point where mitigation alone is no longer sufficient. You have isolated the service, restricted the network paths, and put security controls in place, yet vulnerability scanners continue to flag your software. This typically occurs when upstream support for a runtime, package, or dependency has ended. Teams are left responsible for managing production risk without a clear remediation path from upstream.

At this stage, your options are limited. The best long-term solution is to upgrade to a supported version, but this often requires significant time and effort. While you upgrade, your software remains running vulnerable in production. Building and maintaining internal patches is another option, but that requires ongoing operational overhead. Accepting the risk is rarely a viable alternative, especially in environments subject to regulatory, compliance, or security requirements.

HeroDevs Never-Ending Support (NES) provides a practical path forward. Rather than replacing the need to upgrade, NES becomes part of a broader strategy for managing EOL risk. It allows teams to continue operating safely while aligning remediation efforts with other engineering timelines.

NES provides patched versions of EOL software that are designed to function as drop-in replacements. This enables organizations to remediate vulnerabilities without forcing immediate changes to application code. In most cases, adopting NES is straightforward and allows teams to continue using the same frameworks, packages, and libraries they already rely on while continuing to receive ongoing security patches and support from the HeroDevs team.

For example, a team running Ingress NGINX through Helm could point the controller image to a maintained NES build while keeping the surrounding configuration unchanged.

imagePullSecrets:
- name: herodevs-registry-auth

controller:
  image:
    repository: registry.nes.herodevs.com/nes/ingress-nginx
    tag: v1.15.1-nes-1.15.3

By using NES, teams can remediate known EOL risk while planning upgrades on a realistic timeline. This helps avoid rushed migrations, unsupported internal forks, and long-lived exceptions that become difficult to defend during audits or security reviews. For platform teams, NES turns an unresolved EOL finding into a managed remediation path.

Taking Action on EOL Workloads in Your Cluster

EOL software in Kubernetes is not unusual. Most teams will encounter it at some point, often without realizing how much of it they already run. Assuming everything can be upgraded immediately does not reflect how real systems operate. Production environments require practical decisions and deliberate tradeoffs. 

When upstream support is genuinely gone, HeroDevs Never-Ending Support can help bridge the gap. NES gives teams access to patched, drop-in replacements so workloads can stay secure and compliant while upgrade plans execute on a realistic timeline.

To see what EOL components are running in your environment today, start with the free HeroDevs EOL scanner. To talk through coverage for Ingress NGINX, Node.js, .NET, Spring, or another EOL component already in your cluster, reach out to the HeroDevs team.

Table of Contents
Author
Justin Gorny
Sr. Infrastructure Engineer
Open Source Insights Delivered Monthly