Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule: multi-prefix-suffix-match #428

Open
anderseknert opened this issue Oct 27, 2023 · 0 comments
Open

Rule: multi-prefix-suffix-match #428

anderseknert opened this issue Oct 27, 2023 · 0 comments

Comments

@anderseknert
Copy link
Member

Few policies seem to make use of the new strings.any_prefix_match and strings.any_suffix_match functions.

These functions are extremely performant even when dealing with huge datasets. They have a benefit on smaller collections too though — their built-in "OR"-characteristic can often help simplify policy!

Example from the gatekeeper-library project:

Before

package k8sallowedrepos

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
  not any(satisfied)
  msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.initContainers[_]
  satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
  not any(satisfied)
  msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.ephemeralContainers[_]
  satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
  not any(satisfied)
  msg := sprintf("ephemeralContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
}

After

package k8sallowedrepos

violation[{"msg": msg}] {
    container_type := ["containers", "initContainers", "ephemeralContainers"][_]
    container := input.review.object.spec[container_type][_]
    not strings.any_prefix_match(container.image, input.parameters.repos)
    msg := sprintf(
        "%v <%v> has an invalid image repo <%v>, allowed repos are %v",
        [trim_right(container_type, "s"), container.name, container.image, input.parameters.repos],
    )
}

A rule that identifies calls to startswith and endswith using vars bound in iteration, and recommends considering the built-in functions created for that purpose, would be a great way to have more policy authors discover these functions, and possibly simplify some policies in the process.

The implementation might be a little tricky, as we'd need to consider not just if "loop vars" are used in these calls, but also if they are used elsewhere in the iteration. If that's the case, it's might not be worth replacing the built-in function call, but as it could be, so I imagine we could have a configuration option to toggle this for those willing to accept a few false positives. Those can always be dismissed using ignore directives.

A first iteration of this rule could identify the most simple case, i.e. startswith("foo", strings[_]) as that can always be replaced, and for the better. We can then expand to cover more advanced conditions in later updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: TODO
Development

No branches or pull requests

1 participant