Skip to content

Policies with names >=58 characters collapse to the same derived key #665

Description

@Pavani-Panakanti

Problem Description

The agent works out which NetworkPolicy or ClusterNetworkPolicy a PolicyEndpoint or ClusterPolicyEndpoint belongs to by chopping everything after the last hyphen off the endpoint's object name. That is only the inverse of what the API server did when the policy name is short. Once a policy name reaches 58 characters the API server truncates the generated name, the chop lands inside the policy's own name, and two different policies can produce the same derived key. Every consumer of that key then treats the two policies as one.

How the derivation works

The controller creates each endpoint with GenerateName: -. The API server's name generator truncates the base to MaxGeneratedNameLength = 63 - 5 = 58 and appends 5 random characters (k8s.io/apiserver/pkg/storage/names/generate.go).

The agent then recovers the policy name with pkg/utils/utils.go:252-254:

  func GetParentNPNameFromPEName(policyEndpointName string) string {
        return policyEndpointName[0:strings.LastIndex(policyEndpointName, "-")]
  }

When nothing was truncated the last hyphen is the separator the generator added, so the chop strips exactly the 5 random characters and returns the real policy name. The endpoint also carries the exact name in Spec.PolicyRef.Name, but the delete path cannot read it, the object is already gone so it derives from the name instead.

What happens

When the policy name is 58 characters or longer, the generator's trailing hyphen is truncated away along with part of the name. The last surviving hyphen belongs to the policy name itself, so the chop cuts inside it and deletes the part that distinguished the two policies.

    │  policy name         │  endpoint .Name             │  after chop      │  correct? │
    ├──────────────────────┼─────────────────────────────┼──────────────────┼───────────┤
    │ mypolicy-alpha       │ mypolicy-alpha-t7p5w        │ mypolicy-alpha   │ yes       │
    │ mypolicy-beta        │ mypolicy-beta-x9k4m         │ mypolicy-beta    │ yes       │
    ├──────────────────────┼─────────────────────────────┼──────────────────┼───────────┤
    │ ...-tier-alpha (62)  │ ...-tier-at7p5w             │ ...-tier         │ NO        │
    │ ...-tier-beta  (61)  │ ...-tier-bx9k4m             │ ...-tier         │ NO        │
    └──────────────────────┴─────────────────────────────┴──────────────────┴───────────┘

The endpoint names stay unique; only the derived key collides.

Two places consume that key, in both controllers:

  1. clusterNetworkPolicyToPodIdentifierMap / networkPolicyToPodIdentifierMap use it as a map key (clusterpolicyendpoints_controller.go:425,427, policyendpoints_controller.go:623,625,718). Two policies share one entry, and whichever reconciles last overwrites the other's pods, so the losing policy's pods can never be nominated as stale again.
  2. During a delete, rule derivation skips endpoints belonging to the same policy, because those slices are being removed too (clusterpolicyendpoints_controller.go:313-314, policyendpoints_controller.go:460-461). With a collided key an unrelated policy's endpoint is misidentified as a sibling, gets skipped, and its rules are dropped from the pod.

The same function also panics on a hyphenless name. A policy name of 58+ characters with no hyphen in its first 58 produces an endpoint name containing no hyphen at all, strings.LastIndex returns -1, and the slice expression fails with slice bounds out of range [:-1].

The panic is independent and worth guarding regardless:

func GetParentNPNameFromPEName(policyEndpointName string) string {
i := strings.LastIndex(policyEndpointName, "-")
if i < 0 {
return policyEndpointName
}
return policyEndpointName[:i]
}

Potential Fix:

Adding check on CRD (all our NP CRD's) to reject if name is too long - max len 57 chars

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions