Skip to content

False positive on Network Policies .. Sometimes #311

@bpfoster

Description

@bpfoster




Describe the bug
Running popeye sometimes reports

  · foo/foo-75f84cd95b-9s62d...................................................😱
    😱 [POP-1204] Pod Ingress is not secured by a network policy.
    😱 [POP-1204] Pod Egress is not secured by a network policy.

Despite there being a Network Policy for it.

Expected behavior
No warning on missing Network Policy

Versions (please complete the following information):

  • OS: RHEL 8
  • Popeye: v0.21.3
  • K8s: v1.26.11

Additional context
I have created NetworkPolicies using the

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

resource type.

I notice the cluster also has Calico installed providing their NetworkPolicy CRD:

$ kubectl get crd | grep networkpolicies
globalnetworkpolicies.crd.projectcalico.org
networkpolicies.crd.projectcalico.org

Installed policies:

$ kubectl get networkpolicies.crd.projectcalico.org 
No resources found in foo namespace.

$ kubectl get networkpolicies.networking.k8s.io 
NAME                                     POD-SELECTOR
foo                 app.kubernetes.io/instance=foo,app.kubernetes.io/name=foo

When I debug popeye, I see that the GVR being queried in the DB for network policies is sometimes the calico one, and sometimes the k8s.io one.

txn, it := s.db.MustITForNS(internal.Glossary[internal.NP], pod.Namespace)

When it's the Calico one, the NetworkPolicy is not found.

My guess is there's some non-determinism in the order in which the CRDs are returned/loaded, and from what I can see, the popeye DB only supports 1 per type and is overwriting whichever comes first with the second one.

popeye/internal/alias.go

Lines 92 to 116 in d09ec25

func (a *Aliases) Realize() {
for gvr, res := range a.metas {
a.aliases[res.Name] = gvr
if res.SingularName != "" {
a.aliases[res.SingularName] = gvr
}
for _, n := range res.ShortNames {
a.aliases[n] = gvr
}
if kk, ok := customShortNames[R(res.Name)]; ok {
for _, k := range kk {
a.aliases[k] = gvr
}
}
if lgvr, ok := Glossary[R(res.SingularName)]; ok {
if greaterV(gvr.V(), lgvr.V()) {
Glossary[R(res.SingularName)] = gvr
}
} else if lgvr, ok := Glossary[R(res.Name)]; ok {
if greaterV(gvr.V(), lgvr.V()) {
Glossary[R(res.Name)] = gvr
}
}
}
}

Thinking about it... should popeye know the GVR for each resource type it cares about, and ignore others? In this case it knows it wants networkpolicies.networking.k8s.io and would discard the caclico type. If there was a calico NP (or some other random one), popeye would panic when it tries to assert to netv1.NetworkPolicy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions