trivy
trivy copied to clipboard
distribute misconfiguration policies out of band
Currently Trivy's misconfiguration scanning/IaC scanning checks are embedded into the Trivy binary and shipped with it. This means that in order to update checks a user needs to update Trivy, which is not ideal. This issue is about separating the checks from the engine and distributing the checks package to existing clients, just like vulnerability scanning which downloads the Trivy vulnerability database automatically.
History and related work
Originally, Trivy's misconfiguration scanning relied on rego policies from appshield that were packaged into an OCI artifact stored in GHCR and distributed to the Trivy client automatically. When we started centralizing checks in defsec and merging with Terraform/CloudFormation checks which were written in Go, we deprecated this mechanism and started simply embedding all the checks.
Recently there was an attempt to extend the trivy DB to accommodate arbitrary data, in that case for the Kubernetes API compatibility feature. But this was later reverted in favor of embedding the data in defsec.
Discussion points:
- Air-gapped scanning
- Compatibility issues (e.g. policy -> engine)
- Schema changes + custom policies
- Include rego schemas in distribution?
- How to track required schema versions + version schemas
- Should we keep rules in the defsec repo but distribute a release artifact containing the policies? Coupling of defsec -> rules is fairly high, so there may be few advantages to creating a separate repo?
For the moment at the end of the last call we agreed as a first step:
- Package all rules up into an image and tag with the latest defsec version (separate
major
,major.minor
andmajor.minor.patch
tags) - Add a function to defsec that knows how to download the latest MAJOR image that matches it's version
- Call this function from trivy and add all rego from the image to the trivy cache directory to a subdirectory named
iac-rules
- Trivy should instruct defsec to look in this directory to find all rules, excluding builtin ones.
Same as this approach? https://github.com/aquasecurity/appshield/pkgs/container/appshield
Yep, we've come full circle :recycle:
To add to what @liamg said and to summarize my chat with him, I would like to propose the following:
- Bringing back the OCI artifact policy logic into Trivy, with necessary changes. I have a working PoC to demo that this could be done with very minimal logic changes needed. Later on if there's a need we could abstract it out.
- If we do so, we'd have at our disposal the following ways to specify rules:
- Use embedded policies (current, good for air-gapped solutions, or those who are fine with existing policies)
- Use published policies (fetches the defsec OCI artifact, could have the option to specify URL too later)
- Use custom local policies (air-gapped, custom policy use cases)
- Custom policy + embedded libraries
- Custom libraries + embedded policies (I doubt this would make sense for someone)
Trivy should instruct defsec to look in this directory to find all rules, excluding builtin ones.
I would agree with this. To start, we could make the above choices exclusive of each other. Which means you can only use one of the options and not a combination of them.
The combination of any of them will be a little more involved as there could be possible rego namespace collisions with variety of policies, for instance.
hi all,
I'd just like to share my update on this prior to my upcoming vacation just in case any of you wanted to pick it up while I was gone.
I’ve pushed my changes to Trivy on a branch here https://github.com/aquasecurity/trivy/compare/policy-fetcher?expand=1 feel free to push any changes to it if you pick it up.
Most of that is old logic we used to have in the past with appshield (minus the tests as it's still a WIP). It's been adapted to use defsec.
We would probably need to figure out what set of options we'd like to have. Currently we've deprecated --skip-policy-update
and in my branch I've added an option to --disable-embedded-policies
. I need to think a little more about it to see if that's the best choice but I welcome any suggestions.
Some more info, if you need to test locally how to setup and run you could do this:
- setup a local registry:
docker run -it --rm -p 5000:5000 registry
- bundle and push an artifact
rm -rf bundle bundle.tar.gz && rsync -avr --exclude=README.md --exclude="*_test.rego" --exclude="*.go" --exclude=test --exclude=advanced internal/rules/docker internal/rules/kubernetes bundle/ && cp internal/rules/.manifest bundle/ && sed -i -e "s/\[GITHUB_SHA\]/25bc95418f1181cc211121f678f4725c26112209325ccfbf389e1e3dd7f8cb46/" bundle/.manifest && tar -C bundle -czvf bundle.tar.gz . && oras push localhost:5000/defsec:1 --config /dev/null:application/vnd.cncf.openpolicyagent.config.v1+json bundle.tar.gz:application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip
- run trivy by removing any cached policies and metadata.json:
rm -rf /Users/simar/Library/Caches/trivy/policy/metadata.json /Users/simar/Library/Caches/trivy/policy/content/ && rm -rf ./trivy && make build && ./trivy --debug conf --skip-policy-update=true --disable-embedded-policies=true /Users/simar/repos/defsec/test/testdata/dockerfile/DS005
should scan and detect as usual.
PR is ready for review: https://github.com/aquasecurity/trivy/pull/3015