Skip to content

About

Kubernetes operator that generates NetworkPolicies for Kubernetes, Cilium or Calico from declarative allow/deny rules and built-in templates

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Network Policy Generator

Kubernetes operator that generates NetworkPolicies for Kubernetes, Cilium or Calico from declarative allow/deny rules and built-in templates, with an optional learning period before enforcement.

Top Language Version License Go Report Card Docker Pulls GitHub Release GitHub Stars

A Kubernetes controller that automatically generates and manages Kubernetes Network Policies based on user-defined rules and templates.

A NetworkPolicyGenerator in enforcing mode turns a short deny rule into a NetworkPolicy that admits only frontend, kube-system and port 80


Description

The Network Policy Generator is a Kubernetes operator that simplifies the creation and management of Network Policies by providing two main operational modes:

  • Learning Mode: Holds off enforcement for a specified duration, then switches to enforcing mode. Traffic collection is not implemented yet, so this mode records no traffic and produces no suggestions
  • Enforcing Mode: Automatically generates and applies Network Policies based on the configured rules

This tool helps security teams and cluster administrators implement network segmentation more effectively by:

  • Reducing manual Network Policy creation overhead
  • Supporting both permissive (allow-based) and restrictive (deny-based) policy approaches
  • Enabling gradual transition from learning to enforcement phases
  • Supporting multiple CNI backends via policyEngine field (kubernetes, cilium, calico)
  • Providing built-in policy templates for common workload types (web-app, database, monitoring, etc.)

Key Features

Pod Selector CIDR Rules Named Port Dry Run Policy Diff Kubernetes Cilium Calico Policy Templates Learning Mode Event Recording Prometheus Metrics Webhook Validation

  • Pod Label Selector — Target specific pods by label instead of entire namespaces
  • CIDR-based Rules — Define ingress/egress rules for external IP ranges (e.g., databases, external APIs)
  • Named Port Support — Use service port names (http, grpc) instead of numeric ports
  • Dry Run Mode — Preview generated policies in status without applying them to the cluster
  • Policy Diff/Audit — Track policy changes (Created/Updated/Unchanged, and Deleted for a policy the spec no longer needs) in status for audit trails
  • Owned cleanup — Every generated policy carries app.kubernetes.io/managed-by: network-policy-generator and a security.policy.io/generator-uid label, so policies left behind by an earlier spec (a dropped namespace, a different engine) are deleted, and editing or deleting a generated policy by hand is corrected right away
  • Event Recording — Emit Kubernetes Events on policy apply, delete, mode transition, and errors
  • Prometheus Metrics — Custom metrics for reconcile count, duration, active generators, and policy operations
  • Schema Validation — Core spec rules are enforced by the CRD itself (CEL x-kubernetes-validations), so they apply on every cluster with no extra setup
  • Webhook Validation — Optional admission webhook adding CIDR-format and cross-field checks (enable with --enable-webhooks flag, requires cert-manager)

Installation


Prerequisites

  • Kubernetes v1.25+ (the CRD ships CEL validation rules, which require x-kubernetes-validations)
  • kubectl v1.11.3+
  • For Cilium policies: Cilium CNI installed on the cluster
  • For Calico policies: Calico CNI installed on the cluster

Option 1: Helm (Recommended)

Recommended: OCI registry (Helm 3.8+)

# Single-command install — no helm repo add needed
helm install npg oci://ghcr.io/somaz94/charts/network-policy-generator \
  --version 0.5.0

The chart creates the namespace named by its namespace value (network-policy-generator-system unless you change it) and deploys the controller there, whatever --namespace says, so install it without --namespace and --create-namespace.

Alternative: classic Helm repo

# Add the Helm repository
helm repo add network-policy-generator https://somaz94.github.io/network-policy-generator/helm-repo
helm repo update

# Install with default values
helm install npg network-policy-generator/network-policy-generator

# Or install with custom values
helm install npg network-policy-generator/network-policy-generator \
  --set image.tag=v0.5.0 \
  --set crds.cleanup=false

For full Helm chart options, see Helm README.


Option 2: kubectl apply (Quick Install)

kubectl apply -f https://raw.githubusercontent.com/somaz94/network-policy-generator/main/dist/install.yaml

Option 3: Build from Source

# Clone the repository
git clone https://github.com/somaz94/network-policy-generator.git
cd network-policy-generator

# Install CRDs
make install

# Deploy the controller
make deploy IMG=somaz940/network-policy-generator:v0.5.0

Verify Installation

# Check the controller is running
kubectl get pods -n network-policy-generator-system

# Check CRDs are installed
kubectl get crd networkpolicygenerators.security.policy.io

Quick Start

After installation, create a NetworkPolicyGenerator resource:

# Apply a sample policy
kubectl apply -f config/samples/security_v1_networkpolicygenerator-deny.yaml

# Check the status
kubectl get networkpolicygenerator

# View generated NetworkPolicies
kubectl get networkpolicy -A

Available sample configurations:

  • security_v1_networkpolicygenerator-allow.yaml: Allow-based policy example
  • security_v1_networkpolicygenerator-deny.yaml: Deny-based policy example
  • security_v1_networkpolicygenerator.yaml: Combined deny-policy example (enforcing mode, global rules)
  • security_v1_networkpolicygenerator-pod-selector.yaml: Pod label selector example
  • security_v1_networkpolicygenerator-cidr-rules.yaml: CIDR-based egress/ingress rules
  • security_v1_networkpolicygenerator-named-port.yaml: Named port (http, grpc) example
  • security_v1_networkpolicygenerator-dry-run.yaml: Dry run mode (preview without applying)
  • security_v1_networkpolicygenerator-full-features.yaml: All features combined
  • security_v1_networkpolicygenerator-calico-deny.yaml: Calico deny policy
  • security_v1_networkpolicygenerator-calico-allow.yaml: Calico allow policy
  • security_v1_networkpolicygenerator-template-web-app.yaml: Web-app policy template
  • security_v1_networkpolicygenerator-template-database.yaml: Database policy template
  • security_v1_networkpolicygenerator-template-backend-api.yaml: Backend API policy template
  • security_v1_networkpolicygenerator-template-monitoring.yaml: Monitoring policy template
  • security_v1_networkpolicygenerator-cilium-deny.yaml: Cilium deny policy
  • security_v1_networkpolicygenerator-cilium-allow.yaml: Cilium allow policy
  • test-policy.yaml: Namespace-specific policy examples
  • test.yaml: Test pods and services for validation

Uninstall

# Helm
helm uninstall npg

# kubectl
kubectl delete -f https://raw.githubusercontent.com/somaz94/network-policy-generator/main/dist/install.yaml

# From source
make undeploy
make uninstall

Usage Examples


1. Allow-based Policy (Default Deny)

Creates a policy that denies all traffic by default, only allowing traffic from specified namespaces:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: test-policy-generator-allow
spec:
  mode: "enforcing"
  policy:
    type: "allow"     # Default deny, explicit allow
    deniedNamespaces: # Namespaces to deny access from
      - "test-ns1"
      - "test-ns2"
  globalRules:
    - type: "allow"
      port: 80
      protocol: TCP
      direction: "ingress"
    - type: "allow"
      port: 443
      protocol: TCP
      direction: "egress"

2. Deny-based Policy (Default Allow)

Creates a policy that allows all traffic by default, only denying traffic from specified namespaces:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: test-policy-generator-deny
spec:
  mode: "enforcing"
  policy:
    type: "deny"      # Default allow, explicit deny
    allowedNamespaces: # Only these namespaces are allowed
      - "test-ns1"
      - "test-ns2"
  globalRules:
    - type: "allow"
      port: 80
      protocol: TCP
      direction: "ingress"
    - type: "allow"
      port: 443
      protocol: TCP
      direction: "egress"

3. Learning Mode Example

Waits for a specified duration before enforcing policies:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: traffic-learner
spec:
  mode: "learning"
  duration: "1m"      # Learning period before enforcing (use longer durations in production)
  policy:
    type: "deny"
    allowedNamespaces:
      - "test-ns1"
      - "test-ns2"
    deniedNamespaces:
      - "test-ns3"
      - "test-ns4"

4. Namespace-specific Policy

Apply different policies to different namespaces:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: test-policy-generator-deny
  namespace: test-ns1
spec:
  mode: "enforcing"
  policy:
    type: "deny"
    allowedNamespaces:
      - "test-ns3"  # Only test-ns3 can access test-ns1
  globalRules:
    - type: "allow"
      port: 80
      protocol: TCP
      direction: "ingress"

5. Pod Label Selector

Target specific pods by label instead of applying to the entire namespace:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: pod-selector-example
spec:
  mode: "enforcing"
  policy:
    type: "deny"
    allowedNamespaces:
      - "kube-system"
    podSelector:
      app: nginx
      tier: frontend
  globalRules:
    - type: "allow"
      port: 80
      protocol: TCP
      direction: "ingress"

6. CIDR-based Rules

Define egress/ingress rules for external IP ranges:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: cidr-rules-example
spec:
  mode: "enforcing"
  policy:
    type: "deny"
    allowedNamespaces:
      - "kube-system"
  cidrRules:
    - cidr: "10.0.0.0/8"
      direction: "egress"
      protocol: TCP
      port: 5432
    - cidr: "192.168.1.0/24"
      except:
        - "192.168.1.100/32"
      direction: "ingress"
      protocol: TCP
      port: 443

7. Named Port Support

Use service port names instead of numeric ports:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: named-port-example
spec:
  mode: "enforcing"
  policy:
    type: "deny"
    allowedNamespaces:
      - "kube-system"
  globalRules:
    - type: "allow"
      namedPort: "http"
      protocol: TCP
      direction: "ingress"
    - type: "allow"
      namedPort: "grpc"
      protocol: TCP
      direction: "egress"

8. Dry Run Mode

Preview generated policies without applying them:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: dry-run-example
spec:
  mode: "enforcing"
  dryRun: true
  policy:
    type: "deny"
    allowedNamespaces:
      - "kube-system"
  globalRules:
    - type: "allow"
      port: 80
      protocol: TCP
      direction: "ingress"

Generated policies are stored in .status.generatedPolicies as JSON. No NetworkPolicy resources are created.


9. Calico NetworkPolicy

Generate Calico-native crd.projectcalico.org/v1 NetworkPolicy resources:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: calico-deny-example
spec:
  mode: "enforcing"
  policyEngine: "calico"
  policy:
    type: "deny"
    allowedNamespaces:
      - "kube-system"
    podSelector:
      app: web
  globalRules:
    - type: "allow"
      port: 80
      protocol: TCP
      direction: "ingress"

Calico policies use selector-based syntax (app == 'web'), namespace selectors via projectcalico.org/name, and include automatic DNS egress allow rules.


10. Policy Templates

Use built-in templates for common workload types instead of writing rules from scratch:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: template-web-app-example
spec:
  mode: "enforcing"
  templateName: "web-app"
  policy:
    type: "deny"
    allowedNamespaces:
      - "kube-system"

Available templates:

Template Description
zero-trust Deny all traffic, allow only DNS egress
web-app Allow HTTP/HTTPS ingress, DNS and HTTPS egress
backend-api Allow API ports (8080, 8443, 9090) ingress from allowedNamespaces, HTTPS egress
database Allow DB ports (3306, 5432, 6379, 27017) ingress from allowedNamespaces, DNS-only egress
monitoring Allow Prometheus scraping (9090, 9100) from allowedNamespaces, HTTPS egress

Templates are merged with user-defined globalRules (user rules take precedence over template rules). The web-app ingress rules stay open to anywhere; the other templates' ingress rules use from: allowedNamespaces, so a database port is not exposed to every pod and external client.

globalRules fields

Each rule sets type, port or namedPort, protocol and direction, plus an optional from:

from Ingress admits / egress reaches
anywhere (default) Every source or destination, in the cluster or outside it
allowedNamespaces Pods in spec.policy.allowedNamespaces, or only the policy's own namespace when that list is empty
sameNamespace Pods in the policy's own namespace

type: deny needs policyEngine: cilium or calico. Cilium writes it to ingressDeny/egressDeny, and Calico places it ahead of the allow rules; both apply it before any allow. A standard Kubernetes NetworkPolicy cannot deny, so the CRD rejects a deny rule on the kubernetes engine.


11. Learning Mode with Suggestions

The status has fields for namespace and rule suggestions, but they stay empty until traffic collection is implemented:

apiVersion: security.policy.io/v1
kind: NetworkPolicyGenerator
metadata:
  name: traffic-learner-improved
spec:
  mode: "learning"
  duration: "5m"
  policy:
    type: "deny"

After the learning period, check suggestions:

# View suggested namespaces
kubectl get networkpolicygenerator traffic-learner-improved -o jsonpath='{.status.suggestedNamespaces}'

# View suggested port/protocol rules
kubectl get networkpolicygenerator traffic-learner-improved -o jsonpath='{.status.suggestedRules}'

Monitoring the Generator Status

# View all NetworkPolicyGenerator resources
kubectl get networkpolicygenerator

# Get detailed information about a specific generator
kubectl describe networkpolicygenerator <name>

# Check the status
kubectl get networkpolicygenerator <name> -o yaml

Validation Rules

The CRD enforces the following rules at admission time. They are part of the CRD schema (CEL x-kubernetes-validations), so they apply even when the optional webhook is disabled — an invalid resource is rejected by kubectl apply rather than failing later during reconciliation.

Rule Message
spec.mode defaults to learning when omitted —
spec.duration must be positive when spec.mode is learning spec.duration is required and must be positive when mode is 'learning'
Each spec.globalRules[*] sets exactly one of port or namedPort exactly one of port or namedPort must be specified
A namespace may not appear in both allowedNamespaces and deniedNamespaces a namespace cannot be listed in both allowedNamespaces and deniedNamespaces
spec.globalRules[*].type: deny only with policyEngine cilium or calico globalRules of type deny need policyEngine cilium or calico; a Kubernetes NetworkPolicy can only allow
spec.globalRules[*].from defaults to anywhere when omitted —

A zero duration in learning mode is rejected because the generator would transition straight to enforcing on the next reconcile, applying policies with no learning period.

Enabling the webhook (--enable-webhooks) adds checks that the CRD schema cannot express, most notably CIDR-format validation for spec.cidrRules.


Testing

# Unit tests
make test

# Integration tests (auto-detects CNI and runs matching tests)
make test-integration                      # Auto-detect CNI
make test-integration ENGINE=kubernetes    # Kubernetes only
make test-integration ENGINE=cilium        # Cilium only
make test-integration ENGINE=calico        # Calico only
make test-integration ENGINE=all           # Force all engines

# Helm chart tests (lint, install, upgrade, policy tests, uninstall)
make test-helm                             # Auto-detect CNI
make test-helm ENGINE=kubernetes           # Kubernetes only
make test-helm ENGINE=cilium               # Cilium only
make test-helm ENGINE=calico               # Calico only
make test-helm ENGINE=all                  # Force all engines

For detailed manual test steps and sample descriptions, see Test Guide.


Documentation

Document Description
Helm Chart Helm chart installation, configuration, and values reference
Testing Guide Unit, integration, Helm, and manual test instructions
Troubleshooting Common issues and solutions
Version Bump Checklist for releasing a new version
Contributing How to contribute to this project

Contributing

Issues and pull requests are welcome.


Related projects

  • helios-lb: A bare-metal LoadBalancer for Kubernetes, a lightweight MetalLB alternative.
  • k8s-namespace-sync: An operator that syncs Secrets and ConfigMaps across namespaces.
  • kube-drift: An operator that runs the same manifest-vs-cluster comparison on a schedule, inside the cluster.

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

About

Kubernetes operator that generates NetworkPolicies for Kubernetes, Cilium or Calico from declarative allow/deny rules and built-in templates

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages