1

I'd like to write a Rego rule that checks Kubernetes deployment selectors against the labels declared in the template. The rule should pass if every key/value present in spec.selector.matchLabels is present in spec.template.metadata.labels.

If I were to write this in Javascript it would look something like this:

for(let key of input.spec.selector.matchLabels) {
  assert(input.spec.selector.matchLabels[key] === input.spec.template.metadata.labels[key], `${key} doesn't match`)
}

I'm not sure how to write the equivalent in Rego. I've come up with a way to check that keys are present but I don't know how to check the values. Here's what I have so far:

selector_match_labels {
    # keys in matchLabels are present in the template labels
    matchLabels := { label | input.spec.selector.matchLabels[label] }
    labels := { label | input.spec.template.metadata.labels[label] }
    count(matchLabels - labels) == 0
    # How to check the values of each key matches?
}
Will Beason
  • 3,417
  • 2
  • 28
  • 46
ahawkins
  • 1,164
  • 1
  • 10
  • 15

2 Answers2

2

You're almost there. Just create a set of key-value pairs instead of a set of keys.

matchLabels := { [label, value] | some label; value := input.spec.selector.matchLabels[label] }
labels := { [label, value] | some label; value := input.spec.template.metadata.labels[label] }
count(matchLabels - labels) == 0
tsandall
  • 1,544
  • 8
  • 8
  • Thanks. I see how comprehensions are working now. Your solution generates a set of `[ label, value ]` pairs then compares the sets. That was my initial approach since that's how I think about it in programming languages. I think my [answer](https://stackoverflow.com/a/63319080/1393668) is more in line with rego's approach. What do you think? – ahawkins Aug 08 '20 at 18:48
0

Here's another solution that finds any non-matching value.

deny[msg] {
    some label
    val := input.spec.selector.matchLabels[label]
    val != input.spec.template.metadata.labels[label]
    msg = sprintf("template label %s must match selector", [ label ])
}

This solution uses some to find any key that doesn't match. That's enough to create a deny rule. This is opposite of "allow if all key/values match" which works well enough for a deny rule.

ahawkins
  • 1,164
  • 1
  • 10
  • 15
  • It turns out my answer does not account work correctly if there is a missing key. It only works if keys are present in both objects with different values. Using [this answer](https://stackoverflow.com/a/63317694/1393668) handles all cases. – ahawkins Aug 08 '20 at 20:14