diff --git a/docs/docs/misconfiguration/options/values.md b/docs/docs/misconfiguration/options/values.md new file mode 100644 index 000000000000..f5a39dc1de69 --- /dev/null +++ b/docs/docs/misconfiguration/options/values.md @@ -0,0 +1,48 @@ +# Value Overrides + +Value files can be passed for supported scannable config files. + +## Terraform value overrides +You can pass `tf-vars` files to Trivy to override default values found in the Terraform HCL code. + +```bash +trivy conf --tf-vars dev.terraform.tfvars ./infrastructure/tf +``` + +## Helm value overrides +There are a number of options for overriding values in Helm charts. When override values are passed to the Helm scanner, the values will be used during the Manifest rendering process and will become part of the scanned artifact. + +### Setting inline value overrides +Overrides can be set inline on the command line + +```bash +trivy conf --helm-set securityContext.runAsUser=0 ./charts/mySql +``` + +### Setting value file overrides +Overrides can be in a file that has the key=value set. + +```yaml +# Example override file (overrides.yaml) + +securityContext: + runAsUser: 0 +``` + +```bash +trivy conf --helm-values overrides.yaml ./charts/mySql +``` + +### Setting value as explicit string +the `--helm-set-string` is the same as `--helm-set` but explicitly retains the value as a string + +```bash +trivy config --helm-set-string name=false ./infrastructure/tf +``` + +### Setting sepecific values from files +Specific override values can come from specific files + +```bash +trivy conf --helm-set-file environment=dev.values.yaml ./charts/mySql +``` \ No newline at end of file diff --git a/go.mod b/go.mod index 61cbc9752518..3621bb867045 100644 --- a/go.mod +++ b/go.mod @@ -107,7 +107,7 @@ require ( github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect - github.com/aquasecurity/defsec v0.69.1 + github.com/aquasecurity/defsec v0.70.0 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect github.com/aws/aws-sdk-go v1.44.66 github.com/beorn7/perks v1.0.1 // indirect @@ -174,7 +174,7 @@ require ( github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/hcl/v2 v2.12.0 // indirect + github.com/hashicorp/hcl/v2 v2.13.0 // indirect github.com/hhatto/gorst v0.0.0-20181029133204-ca9f730cac5b // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.13 // indirect diff --git a/go.sum b/go.sum index e1bd3d6b69f0..374e48f748ae 100644 --- a/go.sum +++ b/go.sum @@ -172,7 +172,6 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= @@ -200,14 +199,13 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM= github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8= -github.com/aquasecurity/defsec v0.69.1 h1:K1Ir7iq8LHY+O2S1iXKl8beyclBGpXZ078S80wXSwPE= -github.com/aquasecurity/defsec v0.69.1/go.mod h1:ePeucB2upo/aOqvsks1ML6xflQRxokf4Qol16u0+IQs= +github.com/aquasecurity/defsec v0.70.0 h1:tzmKrnR/OssRC/0RwnmmPwnoWOCOY7rPc+3ZaqLumg0= +github.com/aquasecurity/defsec v0.70.0/go.mod h1:ZMuvHCXmvdL6EM3ckt/qY/qIJ6WEr5GNeGhNDFgVrcw= github.com/aquasecurity/go-dep-parser v0.0.0-20220626060741-179d0b167e5f h1:ObiLf3DY/Mr3hfqWHNgQ4vjVo/fFni216otahWzQXIE= github.com/aquasecurity/go-dep-parser v0.0.0-20220626060741-179d0b167e5f/go.mod h1:MDQj3aeTQHSRbM1ZOGQVFziHvJtwf7moK+f9gYlUdeE= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM= @@ -674,7 +672,6 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= @@ -901,8 +898,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl/v2 v2.12.0 h1:PsYxySWpMD4KPaoJLnsHwtK5Qptvj/4Q6s0t4sUxZf4= -github.com/hashicorp/hcl/v2 v2.12.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= +github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc= +github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= @@ -1109,7 +1106,6 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= @@ -1360,7 +1356,6 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE= github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= @@ -1417,7 +1412,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1524,11 +1518,8 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPS github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= -github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0= github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -1616,7 +1607,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1811,7 +1801,6 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/integration/fs_test.go b/integration/fs_test.go index 06f086e8a326..7eb389441240 100644 --- a/integration/fs_test.go +++ b/integration/fs_test.go @@ -24,6 +24,8 @@ func TestFilesystem(t *testing.T) { input string secretConfig string filePatterns []string + helmSet []string + helmValuesFile []string } tests := []struct { name string @@ -134,6 +136,24 @@ func TestFilesystem(t *testing.T) { }, golden: "testdata/helm_testchart.json.golden", }, + { + name: "helm chart directory scanning with value overrides using set", + args: args{ + securityChecks: "config", + input: "testdata/fixtures/fs/helm_testchart", + helmSet: []string{"securityContext.runAsUser=0"}, + }, + golden: "testdata/helm_testchart.overridden.json.golden", + }, + { + name: "helm chart directory scanning with value overrides using value file", + args: args{ + securityChecks: "config", + input: "testdata/fixtures/fs/helm_testchart", + helmValuesFile: []string{"testdata/fixtures/fs/helm_values/values.yaml"}, + }, + golden: "testdata/helm_testchart.overridden.json.golden", + }, { name: "helm chart directory scanning with builtin policies and non string Chart name", args: args{ @@ -195,6 +215,18 @@ func TestFilesystem(t *testing.T) { } } + if len(tt.args.helmSet) != 0 { + for _, helmSet := range tt.args.helmSet { + osArgs = append(osArgs, "--helm-set", helmSet) + } + } + + if len(tt.args.helmValuesFile) != 0 { + for _, helmValuesFile := range tt.args.helmValuesFile { + osArgs = append(osArgs, "--helm-values", helmValuesFile) + } + } + // Setup the output file outputFile := filepath.Join(t.TempDir(), "output.json") if *update { diff --git a/integration/testdata/fixtures/fs/helm_values/values.yaml b/integration/testdata/fixtures/fs/helm_values/values.yaml new file mode 100644 index 000000000000..041169482cbd --- /dev/null +++ b/integration/testdata/fixtures/fs/helm_values/values.yaml @@ -0,0 +1,2 @@ +securityContext: + runAsUser: 0 \ No newline at end of file diff --git a/integration/testdata/helm_testchart.overridden.json.golden b/integration/testdata/helm_testchart.overridden.json.golden new file mode 100644 index 000000000000..24b1b5ff8928 --- /dev/null +++ b/integration/testdata/helm_testchart.overridden.json.golden @@ -0,0 +1,496 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/fs/helm_testchart", + "ArtifactType": "filesystem", + "Metadata": { + "ImageConfig": { + "architecture": "", + "created": "0001-01-01T00:00:00Z", + "os": "", + "rootfs": { + "type": "", + "diff_ids": null + }, + "config": {} + } + }, + "Results": [ + { + "Target": "templates/deployment.yaml", + "Class": "config", + "Type": "helm", + "MisconfSummary": { + "Successes": 74, + "Failures": 4, + "Exceptions": 0 + }, + "Misconfigurations": [ + { + "Type": "Helm Security Check", + "ID": "KSV001", + "Title": "Process can elevate its own privileges", + "Description": "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.", + "Message": "Container 'testchart' of Deployment 'testchart' should set 'securityContext.allowPrivilegeEscalation' to false", + "Namespace": "builtin.kubernetes.KSV001", + "Query": "data.builtin.kubernetes.KSV001.deny", + "Resolution": "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.", + "Severity": "MEDIUM", + "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv001", + "References": [ + "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", + "https://avd.aquasec.com/misconfig/ksv001" + ], + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Provider": "Kubernetes", + "Service": "general", + "StartLine": 28, + "EndLine": 57, + "Code": { + "Lines": [ + { + "Number": 28, + "Content": " - name: testchart", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": true, + "LastCause": false + }, + { + "Number": 29, + "Content": " securityContext:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 30, + "Content": " capabilities:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 31, + "Content": " drop:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 32, + "Content": " - ALL", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 33, + "Content": " readOnlyRootFilesystem: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 34, + "Content": " runAsGroup: 10001", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 35, + "Content": " runAsNonRoot: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 36, + "Content": " runAsUser: 0", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": true + }, + { + "Number": 37, + "Content": "", + "IsCause": false, + "Annotation": "", + "Truncated": true, + "FirstCause": false, + "LastCause": false + } + ] + } + } + }, + { + "Type": "Helm Security Check", + "ID": "KSV020", + "Title": "Runs with low user ID", + "Description": "Force the container to run with user ID \u003e 10000 to avoid conflicts with the host’s user table.", + "Message": "Container 'testchart' of Deployment 'testchart' should set 'securityContext.runAsUser' \u003e 10000", + "Namespace": "builtin.kubernetes.KSV020", + "Query": "data.builtin.kubernetes.KSV020.deny", + "Resolution": "Set 'containers[].securityContext.runAsUser' to an integer \u003e 10000.", + "Severity": "LOW", + "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv020", + "References": [ + "https://kubesec.io/basics/containers-securitycontext-runasuser/", + "https://avd.aquasec.com/misconfig/ksv020" + ], + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Provider": "Kubernetes", + "Service": "general", + "StartLine": 28, + "EndLine": 57, + "Code": { + "Lines": [ + { + "Number": 28, + "Content": " - name: testchart", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": true, + "LastCause": false + }, + { + "Number": 29, + "Content": " securityContext:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 30, + "Content": " capabilities:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 31, + "Content": " drop:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 32, + "Content": " - ALL", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 33, + "Content": " readOnlyRootFilesystem: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 34, + "Content": " runAsGroup: 10001", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 35, + "Content": " runAsNonRoot: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 36, + "Content": " runAsUser: 0", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": true + }, + { + "Number": 37, + "Content": "", + "IsCause": false, + "Annotation": "", + "Truncated": true, + "FirstCause": false, + "LastCause": false + } + ] + } + } + }, + { + "Type": "Helm Security Check", + "ID": "KSV030", + "Title": "Default Seccomp profile not set", + "Description": "The RuntimeDefault/Localhost seccomp profile must be required, or allow specific additional profiles.", + "Message": "Either Pod or Container should set 'securityContext.seccompProfile.type' to 'RuntimeDefault'", + "Namespace": "builtin.kubernetes.KSV030", + "Query": "data.builtin.kubernetes.KSV030.deny", + "Resolution": "Set 'spec.securityContext.seccompProfile.type', 'spec.containers[*].securityContext.seccompProfile' and 'spec.initContainers[*].securityContext.seccompProfile' to 'RuntimeDefault' or undefined.", + "Severity": "LOW", + "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv030", + "References": [ + "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", + "https://avd.aquasec.com/misconfig/ksv030" + ], + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Provider": "Kubernetes", + "Service": "general", + "StartLine": 28, + "EndLine": 57, + "Code": { + "Lines": [ + { + "Number": 28, + "Content": " - name: testchart", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": true, + "LastCause": false + }, + { + "Number": 29, + "Content": " securityContext:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 30, + "Content": " capabilities:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 31, + "Content": " drop:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 32, + "Content": " - ALL", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 33, + "Content": " readOnlyRootFilesystem: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 34, + "Content": " runAsGroup: 10001", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 35, + "Content": " runAsNonRoot: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 36, + "Content": " runAsUser: 0", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": true + }, + { + "Number": 37, + "Content": "", + "IsCause": false, + "Annotation": "", + "Truncated": true, + "FirstCause": false, + "LastCause": false + } + ] + } + } + }, + { + "Type": "Helm Security Check", + "ID": "KSV105", + "Title": "Containers must not set runAsUser to 0", + "Description": "Containers should be forbidden from running with a root UID.", + "Message": "securityContext.runAsUser should be set to a value greater than 0", + "Namespace": "builtin.kubernetes.KSV105", + "Query": "data.builtin.kubernetes.KSV105.deny", + "Resolution": "Set 'securityContext.runAsUser' to a non-zero integer or leave undefined.", + "Severity": "LOW", + "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv105", + "References": [ + "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", + "https://avd.aquasec.com/misconfig/ksv105" + ], + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Provider": "Kubernetes", + "Service": "general", + "StartLine": 30, + "EndLine": 36, + "Code": { + "Lines": [ + { + "Number": 30, + "Content": " capabilities:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": true, + "LastCause": false + }, + { + "Number": 31, + "Content": " drop:", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 32, + "Content": " - ALL", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 33, + "Content": " readOnlyRootFilesystem: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 34, + "Content": " runAsGroup: 10001", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 35, + "Content": " runAsNonRoot: true", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": false + }, + { + "Number": 36, + "Content": " runAsUser: 0", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": false, + "LastCause": true + } + ] + } + } + } + ] + }, + { + "Target": "templates/service.yaml", + "Class": "config", + "Type": "helm", + "MisconfSummary": { + "Successes": 78, + "Failures": 0, + "Exceptions": 0 + } + }, + { + "Target": "templates/serviceaccount.yaml", + "Class": "config", + "Type": "helm", + "MisconfSummary": { + "Successes": 78, + "Failures": 0, + "Exceptions": 0 + } + } + ] +} diff --git a/mkdocs.yml b/mkdocs.yml index 38c41bb7be96..3138d18ed7e7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,6 +52,7 @@ nav: - Policy: docs/misconfiguration/options/policy.md - Filtering: docs/misconfiguration/options/filter.md - Report Formats: docs/misconfiguration/options/report.md + - Value Overrides: docs/misconfiguration/options/values.md - Others: docs/misconfiguration/options/others.md - Comparison: - vs Conftest: docs/misconfiguration/comparison/conftest.md diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index e490ee34dcde..f73c4ef9ccab 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -456,11 +456,16 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi if slices.Contains(opts.SecurityChecks, types.SecurityCheckConfig) { log.Logger.Info("Misconfiguration scanning is enabled") configScannerOptions = config.ScannerOption{ - Trace: opts.Trace, - Namespaces: append(opts.PolicyNamespaces, defaultPolicyNamespaces...), - PolicyPaths: opts.PolicyPaths, - DataPaths: opts.DataPaths, - FilePatterns: opts.FilePatterns, + Trace: opts.Trace, + Namespaces: append(opts.PolicyNamespaces, defaultPolicyNamespaces...), + PolicyPaths: opts.PolicyPaths, + DataPaths: opts.DataPaths, + FilePatterns: opts.FilePatterns, + HelmValues: opts.HelmValues, + HelmValueFiles: opts.HelmValueFiles, + HelmFileValues: opts.HelmFileValues, + HelmStringValues: opts.HelmStringValues, + TerraformTFVars: opts.TerraformTFVars, } } diff --git a/pkg/fanal/analyzer/config/config.go b/pkg/fanal/analyzer/config/config.go index c8d4b833b767..d32bcd653d9c 100644 --- a/pkg/fanal/analyzer/config/config.go +++ b/pkg/fanal/analyzer/config/config.go @@ -27,6 +27,12 @@ type ScannerOption struct { PolicyPaths []string DataPaths []string DisableEmbeddedPolicies bool + + HelmValues []string + HelmValueFiles []string + HelmFileValues []string + HelmStringValues []string + TerraformTFVars []string } func (o *ScannerOption) Sort() { diff --git a/pkg/fanal/handler/misconf/misconf.go b/pkg/fanal/handler/misconf/misconf.go index 513cf11c9572..2b84f6f47994 100644 --- a/pkg/fanal/handler/misconf/misconf.go +++ b/pkg/fanal/handler/misconf/misconf.go @@ -25,7 +25,9 @@ import ( "github.com/aquasecurity/defsec/pkg/scanners/options" "github.com/aquasecurity/defsec/pkg/scanners/rbac" tfscanner "github.com/aquasecurity/defsec/pkg/scanners/terraform" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" "github.com/aquasecurity/trivy/pkg/fanal/artifact" "github.com/aquasecurity/trivy/pkg/fanal/handler" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -177,19 +179,50 @@ func newMisconfPostHandler(artifactOpt artifact.Option) (handler.PostHandler, er opts = append(opts, options.ScannerWithPolicyNamespaces(opt.Namespaces...)) } + helmOpts := addHelmOpts(opts, artifactOpt.MisconfScannerOption) + tfOpts := addTFOpts(opts, artifactOpt.MisconfScannerOption) + return misconfPostHandler{ filePatterns: artifactOpt.MisconfScannerOption.FilePatterns, scanners: map[string]scanners.FSScanner{ - types.Terraform: tfscanner.New(opts...), + types.Terraform: tfscanner.New(tfOpts...), types.CloudFormation: cfscanner.New(opts...), types.Dockerfile: dfscanner.NewScanner(opts...), types.Kubernetes: k8sscanner.NewScanner(opts...), - types.Helm: helm.New(opts...), + types.Helm: helm.New(helmOpts...), types.Rbac: rbac.NewScanner(opts...), }, }, nil } +func addTFOpts(opts []options.ScannerOption, scannerOption config.ScannerOption) []options.ScannerOption { + if len(scannerOption.TerraformTFVars) > 0 { + opts = append(opts, tfscanner.ScannerWithTFVarsPaths(scannerOption.TerraformTFVars...)) + } + + return opts +} + +func addHelmOpts(opts []options.ScannerOption, scannerOption config.ScannerOption) []options.ScannerOption { + if len(scannerOption.HelmValueFiles) > 0 { + opts = append(opts, helm.ScannerWithValuesFile(scannerOption.HelmValueFiles...)) + } + + if len(scannerOption.HelmValues) > 0 { + opts = append(opts, helm.ScannerWithValues(scannerOption.HelmValues...)) + } + + if len(scannerOption.HelmFileValues) > 0 { + opts = append(opts, helm.ScannerWithFileValues(scannerOption.HelmFileValues...)) + } + + if len(scannerOption.HelmStringValues) > 0 { + opts = append(opts, helm.ScannerWithStringValues(scannerOption.HelmStringValues...)) + } + + return opts +} + var enabledDefsecTypes = map[detection.FileType]string{ detection.FileTypeCloudFormation: types.CloudFormation, detection.FileTypeTerraform: types.Terraform, diff --git a/pkg/flag/misconf_flags.go b/pkg/flag/misconf_flags.go index 897fa2b4715a..3854ccbe1187 100644 --- a/pkg/flag/misconf_flags.go +++ b/pkg/flag/misconf_flags.go @@ -53,6 +53,36 @@ var ( Value: []string{}, Usage: "Rego namespaces", } + HelmValuesFileFlag = Flag{ + Name: "helm-values", + ConfigName: "misconfiguration.helm-values", + Value: []string{}, + Usage: "specify paths to override the Helm values.yaml files", + } + HelmSetFlag = Flag{ + Name: "helm-set", + ConfigName: "misconfiguration.helm-set", + Value: []string{}, + Usage: "specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)", + } + HelmSetFileFlag = Flag{ + Name: "helm-set-file", + ConfigName: "misconfiguration.helm-set-file", + Value: []string{}, + Usage: "specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)", + } + HelmSetStringFlag = Flag{ + Name: "helm-set-string", + ConfigName: "misconfiguration.helm-set-string", + Value: []string{}, + Usage: "specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)", + } + TfVarsFlag = Flag{ + Name: "tf-vars", + ConfigName: "misconfiguration.tf-vars", + Value: []string{}, + Usage: "specify paths to override the Terraform tfvars files", + } ) // MisconfFlagGroup composes common printer flag structs used for commands providing misconfinguration scanning. @@ -66,6 +96,13 @@ type MisconfFlagGroup struct { PolicyPaths *Flag DataPaths *Flag PolicyNamespaces *Flag + + // Values Files + HelmValues *Flag + HelmValueFiles *Flag + HelmFileValues *Flag + HelmStringValues *Flag + TerraformTFVars *Flag } type MisconfOptions struct { @@ -78,6 +115,13 @@ type MisconfOptions struct { PolicyPaths []string DataPaths []string PolicyNamespaces []string + + // Values Files + HelmValues []string + HelmValueFiles []string + HelmFileValues []string + HelmStringValues []string + TerraformTFVars []string } func NewMisconfFlagGroup() *MisconfFlagGroup { @@ -89,6 +133,11 @@ func NewMisconfFlagGroup() *MisconfFlagGroup { PolicyPaths: &ConfigPolicyFlag, DataPaths: &ConfigDataFlag, PolicyNamespaces: &PolicyNamespaceFlag, + HelmValues: &HelmSetFlag, + HelmFileValues: &HelmSetFileFlag, + HelmStringValues: &HelmSetStringFlag, + HelmValueFiles: &HelmValuesFileFlag, + TerraformTFVars: &TfVarsFlag, } } @@ -97,7 +146,20 @@ func (f *MisconfFlagGroup) Name() string { } func (f *MisconfFlagGroup) Flags() []*Flag { - return []*Flag{f.FilePatterns, f.IncludeNonFailures, f.SkipPolicyUpdate, f.Trace, f.PolicyPaths, f.DataPaths, f.PolicyNamespaces} + return []*Flag{ + f.FilePatterns, + f.IncludeNonFailures, + f.SkipPolicyUpdate, + f.Trace, + f.PolicyPaths, + f.DataPaths, + f.PolicyNamespaces, + f.HelmValues, + f.HelmValueFiles, + f.HelmFileValues, + f.HelmStringValues, + f.TerraformTFVars, + } } func (f *MisconfFlagGroup) ToOptions() (MisconfOptions, error) { @@ -113,5 +175,11 @@ func (f *MisconfFlagGroup) ToOptions() (MisconfOptions, error) { PolicyPaths: getStringSlice(f.PolicyPaths), DataPaths: getStringSlice(f.DataPaths), PolicyNamespaces: getStringSlice(f.PolicyNamespaces), + + HelmValues: getStringSlice(f.HelmValues), + HelmValueFiles: getStringSlice(f.HelmValueFiles), + HelmFileValues: getStringSlice(f.HelmFileValues), + HelmStringValues: getStringSlice(f.HelmStringValues), + TerraformTFVars: getStringSlice(f.TerraformTFVars), }, nil }