conftest
conftest copied to clipboard
Context sensitive exceptions
If I could go back in time I'd add to the discussion in #315, however..
We currently have a mechanism for suppressing named rules for an entire input file (or, as noted in that issue, the entire input when using --combine).
It would be nice to be able to add exceptions for specific matches on the input. Extending the deployment from the example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mydep
spec:
template:
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 8080
- name: host-agent
image: host-agent
Here the exception I want to be able to express is "mydep can run host-agent as root". I don't want to say "mydep can run any containers as root", nor do I want to say "any deployment that includes the host-agent can run any container as root". As far as I can tell, those are the two closest options that are currently supported.
I'm not sure how this could be implemented.
Perhaps it could pair nicely with structured errors, so given:
violation_noservice[{"msg": msg, "details":{"name":name}}] {
...
msg = sprintf("Found service %s but services are not allowed", [name])
}
we can somehow match against details->name
?
Or alternatively you could do a textual match against a violation's msg, and then you can ensure that whatever contextual information you need is included in the msg. A little fragile, but perhaps straightforward. That's essentially the workaround I'm adopting - don't use the built-in exceptions, instead output all violations to json and then filter out any with msgs matching a list of exceptions.
I can't think of a way to express it more directly, i.e. tell conftest to ignore the no_service rule for mydep's host-agent container. If there is though that would be ideal, as it avoids depending on the rule to output the data you need, instead you can just define it directly in terms of the input.
If I understand what you're trying to accomplish correctly, this should already be possible. When you create an exception, the body of that exception is what is matched on. e.g. for "mydep can run host-agent as root"
Full example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mydep
spec:
template:
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 8080
- name: host-agent
image: host-agent
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-mydep
spec:
template:
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 8080
- name: host-agent
image: host-agent
package main
deny_host_agent_root[msg] {
input.kind == "Deployment"
not input.spec.securityContext.runAsNonRoot
msg := "cannot run as root"
}
# Here the exception I want to be able to express is "mydep can run host-agent as root".
exception[rules] {
input.metadata.name == "mydep"
input.spec.template.spec.containers[_].name == "host-agent"
rules = ["host_agent_root"]
}
conftest test -p policy.rego dep.yaml
Thanks for the complete example, here's a version that shows what I meant.
package main
deny_root[msg] {
input.kind == "Deployment"
c = input.spec.template.spec.containers[_]
not c.securityContext.runAsNonRoot
msg := sprintf("container %s in deployment %s doesn't set runAsNonRoot", [c.name,input.metadata.name])
}
# Here the exception I want to be able to express is "mydep can run host-agent as root".
exception[rules] {
input.metadata.name == "mydep"
input.spec.template.spec.containers[_].name == "host-agent"
rules = ["root"]
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: mydep
spec:
template:
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 8080
securityContext:
runAsNonRoot: false
- name: host-agent
image: host-agent
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-mydep
spec:
template:
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 8080
securityContext:
runAsNonRoot: true
- name: host-agent
image: host-agent
securityContext:
runAsNonRoot: true
$ conftest test -p policy.rego dep.yaml
EXCP - dep.yaml - main - data.main.exception[_][_] == "root"
2 tests, 1 passed, 0 warnings, 0 failures, 1 exception
The issue shown here is that the exception intends to only allow mydep to run host-agent as root, but it actually allows my-dep to run any container as root - in the example it's running the web
container as root, as well as host-agent
.
I don't see a way in the current implementation that supports having a generic rule like "must specify runAsNonRoot=true" whilst having a targetted exception like this.
Awesome, thanks for the clarification. I see now. This feels like a duplicate of https://github.com/open-policy-agent/conftest/issues/453
Perhaps it is, I struggled to follow 453 tbh. Definitely in the same ballpark.
I've been having the same issue, specifically when trying to apply exceptions to specific resources in a terraform file.
I had a look at how we could extend conftest to support this use-case. I also put together a quick & dirty proof of concept to see what was possible.
This can set the stage for further discussion & refinement on the feature.
https://github.com/open-policy-agent/conftest/pull/584