Skip to content

Commit fd5cafb

Browse files
authored
fix: load compliance report from file system (#3161)
Signed-off-by: chenk <[email protected]>
1 parent 6ab9380 commit fd5cafb

File tree

4 files changed

+73
-8
lines changed

4 files changed

+73
-8
lines changed

docs/docs/kubernetes/cli/compliance.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,52 @@ $ trivy k8s cluster --compliance=nsa --report summary --format json
6565
```
6666
$ trivy k8s cluster --compliance=nsa --report all --format json
6767
```
68+
69+
## Custom compliance report
70+
71+
The Trivy K8s CLI allows you to create a custom compliance specification and pass it to trivy for generating scan report .
72+
73+
The report is generated based on scanning result mapping between users define controls and trivy checks ID.
74+
The supported checks are from two types and can be found at [Aqua vulnerability DB](https://avd.aquasec.com/):
75+
- [misconfiguration](https://avd.aquasec.com/misconfig/)
76+
- [vulnerabilities](https://avd.aquasec.com/nvd)
77+
78+
79+
### Compliance spec format
80+
81+
The compliance spec file format should look as follow :
82+
83+
84+
```yaml
85+
---
86+
spec:
87+
id: "0001" # report unique identifier
88+
title: nsa # report title
89+
description: National Security Agency - Kubernetes Hardening Guidance # description of the report
90+
relatedResources :
91+
- https://www.nsa.gov/Press-Room/News-Highlights/Article/Article/2716980/nsa-cisa-release-kubernetes-hardening-guidance/ # reference is related to public or internal spec
92+
version: "1.0" # spec version
93+
controls:
94+
- name: Non-root containers # short control naming
95+
description: 'Check that container is not running as root' # long control description
96+
id: '1.0' # control identifier
97+
checks: # list of trivy checks which associated to control
98+
- id: AVD-KSV-0012 # check ID (midconfiguration ot vulnerability) must start with `AVD-` or `CVE-`
99+
severity: 'MEDIUM' # control severity
100+
- name: Immutable container file systems
101+
description: 'Check that container root file system is immutable'
102+
id: '1.1'
103+
checks:
104+
- id: AVD-KSV-0014
105+
severity: 'LOW'
106+
```
107+
108+
## Custom report CLI Commands
109+
110+
To generate the custom report, an custom spec file path should be passed to the `--compliance` flag with `@` prefix as follow:
111+
112+
113+
```
114+
$ trivy k8s cluster --compliance=@/spec/my_complaince.yaml --report summary
115+
```
116+

pkg/compliance/spec/compliance.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package spec
22

33
import (
4+
"fmt"
5+
"os"
46
"strings"
57

68
"golang.org/x/exp/maps"
79
"golang.org/x/xerrors"
810

11+
sp "github.com/aquasecurity/defsec/pkg/spec"
912
"github.com/aquasecurity/trivy/pkg/types"
1013
)
1114

@@ -96,3 +99,16 @@ func securityCheckByCheckID(checkID string) types.SecurityCheck {
9699
return types.SecurityCheckUnknown
97100
}
98101
}
102+
103+
// GetComlianceSpec accepct compliance flag name/path and return builtin or file system loaded spec
104+
func GetComplianceSpec(specNameOrPath string) ([]byte, error) {
105+
if strings.HasPrefix(specNameOrPath, "@") {
106+
buf, err := os.ReadFile(strings.TrimPrefix(specNameOrPath, "@"))
107+
if err != nil {
108+
return []byte{}, fmt.Errorf("error retrieving compliance spec from path: %w", err)
109+
}
110+
return buf, nil
111+
}
112+
return []byte(sp.NewSpecLoader().GetSpecByName(specNameOrPath)), nil
113+
114+
}

pkg/flag/report_flags.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,11 @@ func (f *ReportFlagGroup) ToOptions(out io.Writer) (ReportOptions, error) {
215215
}, nil
216216
}
217217

218-
func parseComplianceTypes(compliance interface{}) (string, error) {
219-
complianceString, ok := compliance.(string)
220-
if !ok || (len(complianceString) > 0 && !slices.Contains(types.Compliances, complianceString)) {
218+
func parseComplianceTypes(compliance string) (string, error) {
219+
if len(compliance) > 0 && !slices.Contains(types.Compliances, compliance) && !strings.HasPrefix(compliance, "@") {
221220
return "", xerrors.Errorf("unknown compliance : %v", compliance)
222221
}
223-
return complianceString, nil
222+
return compliance, nil
224223
}
225224

226225
func (f *ReportFlagGroup) forceListAllPkgs(format string, listAllPkgs, dependencyTree bool) bool {

pkg/k8s/commands/run.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"golang.org/x/xerrors"
99
"gopkg.in/yaml.v3"
1010

11-
sp "github.com/aquasecurity/defsec/pkg/spec"
1211
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
1312
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
1413
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
@@ -84,11 +83,13 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error
8483
var complianceSpec spec.ComplianceSpec
8584
// set scanners types by spec
8685
if r.flagOpts.ReportOptions.Compliance != "" {
87-
cs := sp.NewSpecLoader().GetSpecByName(r.flagOpts.ReportOptions.Compliance)
88-
if err = yaml.Unmarshal([]byte(cs), &complianceSpec); err != nil {
86+
cs, err := spec.GetComplianceSpec(r.flagOpts.ReportOptions.Compliance)
87+
if err != nil {
88+
return xerrors.Errorf("spec loading from file system error: %w", err)
89+
}
90+
if err = yaml.Unmarshal(cs, &complianceSpec); err != nil {
8991
return xerrors.Errorf("yaml unmarshal error: %w", err)
9092
}
91-
9293
securityChecks, err := complianceSpec.SecurityChecks()
9394
if err != nil {
9495
return xerrors.Errorf("security check error: %w", err)

0 commit comments

Comments
 (0)