BREAKING(aws): Deprecate trivy aws as subcmd in favour of a plugin (#6819)

This commit is contained in:
simar7
2024-06-20 13:56:46 -06:00
committed by GitHub
parent 6469d37cce
commit b58d42dc97
27 changed files with 47 additions and 4337 deletions

View File

@@ -43,7 +43,6 @@ trivy [global flags] command [flags] target
### SEE ALSO
* [trivy aws](trivy_aws.md) - [EXPERIMENTAL] Scan AWS account
* [trivy config](trivy_config.md) - Scan config files for misconfigurations
* [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format
* [trivy filesystem](trivy_filesystem.md) - Scan local filesystem

View File

@@ -1,127 +0,0 @@
## trivy aws
[EXPERIMENTAL] Scan AWS account
### Synopsis
Scan an AWS account for misconfigurations. Trivy uses the same authentication methods as the AWS CLI. See https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
The following services are supported:
- accessanalyzer
- api-gateway
- athena
- cloudfront
- cloudtrail
- cloudwatch
- codebuild
- documentdb
- dynamodb
- ec2
- ecr
- ecs
- efs
- eks
- elasticache
- elasticsearch
- elb
- emr
- iam
- kinesis
- kms
- lambda
- mq
- msk
- neptune
- rds
- redshift
- s3
- sns
- sqs
- ssm
- workspaces
```
trivy aws [flags]
```
### Examples
```
# basic scanning
$ trivy aws --region us-east-1
# limit scan to a single service:
$ trivy aws --region us-east-1 --service s3
# limit scan to multiple services:
$ trivy aws --region us-east-1 --service s3 --service ec2
# force refresh of cache for fresh results
$ trivy aws --region us-east-1 --update-cache
```
### Options
```
--account string The AWS account to scan. It's useful to specify this when reviewing cached results for multiple accounts.
--arn string The AWS ARN to show results for. Useful to filter results once a scan is cached.
--cf-params strings specify paths to override the CloudFormation parameters files
--check-namespaces strings Rego namespaces
--checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0")
--compliance string compliance report to generate (aws-cis-1.2,aws-cis-1.4)
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages
--endpoint string AWS Endpoint override
--exit-code int specify exit code when any security issues are found
-f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table")
--helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment)
--helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command.
--helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--helm-values strings specify paths to override the Helm values.yaml files
-h, --help help for aws
--ignore-policy string specify the Rego file path to evaluate each vulnerability
--ignorefile string specify .trivyignore file (default ".trivyignore")
--include-deprecated-checks include deprecated checks
--include-non-failures include successes and exceptions, available with '--scanners misconfig'
--list-all-pkgs output all packages in the JSON report regardless of vulnerability
--max-cache-age duration The maximum age of the cloud cache. Cached data will be required from the cloud provider if it is older than this. (default 24h0m0s)
--misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot])
-o, --output string output file name
--output-plugin-arg string [EXPERIMENTAL] output plugin arguments
--region string AWS Region to scan
--report string specify a report format for the output (all,summary) (default "all")
--reset-checks-bundle remove checks bundle
--service strings Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc.
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
--skip-check-update skip fetching rego check updates
--skip-service strings Skip selected AWS Service(s) specified with this flag. Can specify multiple services using --skip-service A --skip-service B etc.
-t, --template string output template
--tf-exclude-downloaded-modules exclude misconfigurations for downloaded terraform modules
--tf-vars strings specify paths to override the Terraform tfvars files
--trace enable more verbose trace output for custom queries
--update-cache Update the cache for the applicable cloud provider instead of using cached results.
```
### Options inherited from parent commands
```
--cache-dir string cache directory (default "/path/to/cache")
-c, --config string config path (default "trivy.yaml")
-d, --debug debug mode
--generate-default-config write the default config to trivy-default.yaml
--insecure allow insecure server connections
-q, --quiet suppress progress bar and log output
--timeout duration timeout (default 5m0s)
-v, --version show version
```
### SEE ALSO
* [trivy](trivy.md) - Unified security scanner

63
go.mod
View File

@@ -22,23 +22,21 @@ require (
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d
github.com/aquasecurity/loading v0.0.5
github.com/aquasecurity/table v1.8.0
github.com/aquasecurity/testdocker v0.0.0-20240613070307-2c3868d658ac
github.com/aquasecurity/tml v0.6.1
github.com/aquasecurity/trivy-aws v0.9.1-0.20240607040622-8a7f09cd891f
github.com/aquasecurity/trivy-checks v0.11.0
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240516051533-4c5a4aad13b7
github.com/aws/aws-sdk-go-v2 v1.27.2
github.com/aws/aws-sdk-go-v2/config v1.27.18
github.com/aws/aws-sdk-go-v2/credentials v1.17.18
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.24
github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.1
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12
github.com/aws/aws-sdk-go-v2/config v1.27.15
github.com/aws/aws-sdk-go-v2/credentials v1.17.15
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.2
github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9 // indirect
github.com/aws/smithy-go v1.20.2
github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c
github.com/bmatcuk/doublestar/v4 v4.6.1
@@ -176,46 +174,14 @@ require (
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9 // indirect
github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.26.7 // indirect
github.com/aws/aws-sdk-go-v2/service/apigateway v1.21.6 // indirect
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.18.6 // indirect
github.com/aws/aws-sdk-go-v2/service/athena v1.37.3 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.36.4 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.35.6 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.32.2 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/service/codebuild v1.26.5 // indirect
github.com/aws/aws-sdk-go-v2/service/docdb v1.34.4 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.8 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ecs v1.35.6 // indirect
github.com/aws/aws-sdk-go-v2/service/efs v1.28.1 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.41.0 // indirect
github.com/aws/aws-sdk-go-v2/service/elasticache v1.34.6 // indirect
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.6 // indirect
github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.25.0 // indirect
github.com/aws/aws-sdk-go-v2/service/emr v1.36.0 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.28.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9 // indirect
github.com/aws/aws-sdk-go-v2/service/kafka v1.28.5 // indirect
github.com/aws/aws-sdk-go-v2/service/kinesis v1.24.6 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 // indirect
github.com/aws/aws-sdk-go-v2/service/lambda v1.49.6 // indirect
github.com/aws/aws-sdk-go-v2/service/mq v1.20.6 // indirect
github.com/aws/aws-sdk-go-v2/service/neptune v1.28.1 // indirect
github.com/aws/aws-sdk-go-v2/service/rds v1.66.1 // indirect
github.com/aws/aws-sdk-go-v2/service/redshift v1.39.7 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sns v1.26.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect
github.com/aws/aws-sdk-go-v2/service/workspaces v1.38.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/briandowns/spinner v1.23.0 // indirect
@@ -287,6 +253,7 @@ require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gosuri/uitable v0.0.4 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
@@ -383,10 +350,10 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.27.0 // indirect
go.opentelemetry.io/otel/sdk v1.27.0 // indirect
go.opentelemetry.io/otel/trace v1.27.0 // indirect
go.opentelemetry.io/proto/otlp v1.2.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect

123
go.sum
View File

@@ -755,8 +755,6 @@ github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s=
github.com/aquasecurity/go-mock-aws v0.0.0-20240523055201-a4152219967f h1:NRq3oUfkheKgoYPjNUApUtClKaBRcc6KzdcBHqZPrAM=
github.com/aquasecurity/go-mock-aws v0.0.0-20240523055201-a4152219967f/go.mod h1:95xczqqItx1yPSrYG2SQM2gi2lqoYG9i3pLsYKSTpgI=
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 h1:eveqE9ivrt30CJ7dOajOfBavhZ4zPqHcZe/4tKp0alc=
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798/go.mod h1:hxbJZtKlO4P8sZ9nztizR6XLoE33O+BkPmuYQ4ACyz0=
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 h1:vmXNl+HDfqqXgr0uY1UgK1GAhps8nbAAtqHNBcgyf+4=
@@ -765,16 +763,12 @@ github.com/aquasecurity/go-version v0.0.0-20201107203531-5e48ac5d022a/go.mod h1:
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d h1:4zour5Sh9chOg+IqIinIcJ3qtr3cIf8FdFY6aArlXBw=
github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d/go.mod h1:1cPOp4BaQZ1G2F5fnw4dFz6pkOyXJI9KTuak8ghIl3U=
github.com/aquasecurity/loading v0.0.5 h1:2iq02sPSSMU+ULFPmk0v0lXnK/eZ2e0dRAj/Dl5TvuM=
github.com/aquasecurity/loading v0.0.5/go.mod h1:NSHeeq1JTDTFuXAe87q4yQ2DX57pXiaQMqq8Zm9HCJA=
github.com/aquasecurity/table v1.8.0 h1:9ntpSwrUfjrM6/YviArlx/ZBGd6ix8W+MtojQcM7tv0=
github.com/aquasecurity/table v1.8.0/go.mod h1:eqOmvjjB7AhXFgFqpJUEE/ietg7RrMSJZXyTN8E/wZw=
github.com/aquasecurity/testdocker v0.0.0-20240613070307-2c3868d658ac h1:dy7xjLOAAeCNycqJ3kws4vDFGm8WdeCovkHXf2um5uA=
github.com/aquasecurity/testdocker v0.0.0-20240613070307-2c3868d658ac/go.mod h1:nyavBQqxtIkQh99lQE1ssup3i2uIq1+giL7tOSHapYk=
github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo=
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
github.com/aquasecurity/trivy-aws v0.9.1-0.20240607040622-8a7f09cd891f h1:LS8Xb8Lb0mosGay+hk7hkt8jVc+L8msTdjJCU+ICcS8=
github.com/aquasecurity/trivy-aws v0.9.1-0.20240607040622-8a7f09cd891f/go.mod h1:pfwElhU8kilUmgib1xBw91ZBPJya6EZ1unwvqC0ijh4=
github.com/aquasecurity/trivy-checks v0.11.0 h1:hS5gSQyuyIITrY/kCY2AWQMUSwXLpdtbHDPaCs6eSaI=
github.com/aquasecurity/trivy-checks v0.11.0/go.mod h1:IAK3eHcKNxIHo/ckxKoHsXmEpUG45/38grW5bBjL9lw=
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d h1:fjI9mkoTUAkbGqpzt9nJsO24RAdfG+ZSiLFj0G2jO8c=
@@ -799,108 +793,44 @@ github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v
github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk=
github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c=
github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c=
github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc=
github.com/aws/aws-sdk-go-v2/config v1.27.15 h1:uNnGLZ+DutuNEkuPh6fwqK7LpEiPmzb7MIMA1mNWEUc=
github.com/aws/aws-sdk-go-v2/config v1.27.15/go.mod h1:7j7Kxx9/7kTmL7z4LlhwQe63MYEE5vkVV6nWg4ZAI8M=
github.com/aws/aws-sdk-go-v2/credentials v1.17.15 h1:YDexlvDRCA8ems2T5IP1xkMtOZ1uLJOCJdTr0igs5zo=
github.com/aws/aws-sdk-go-v2/credentials v1.17.15/go.mod h1:vxHggqW6hFNaeNC0WyXS3VdyjcV0a4KMUY4dKJ96buU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.24 h1:FzNwpVTZDCvm597Ty6mGYvxTolyC1oup0waaKntZI4E=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.24/go.mod h1:wM9NElT/Wn6n3CT1eyVcXtfCy8lSVjjQXfdawQbSShc=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20 h1:NCM9wYaJCmlIWZSO/JwUEveKf0NCvsSgo9V9BwOAolo=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20/go.mod h1:dmxIx3qriuepxqZgFeFMitFuftWPB94+MZv/6Btpth4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9 h1:vHyZxoLVOgrI8GqX7OMHLXp4YYoxeEsrjweXKpye+ds=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.9/go.mod h1:z9VXZsWA2BvZNH1dT0ToUYwMu/CR9Skkj/TBX+mceZw=
github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.26.7 h1:rLdKcienXrk+JFX1+DZg160ebG8lIF2nFvnEZL7dnII=
github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.26.7/go.mod h1:cwqaWBOZXu8pqEE1ZC4Sw2ycZLjwKrRP5tOAJFgCbYc=
github.com/aws/aws-sdk-go-v2/service/apigateway v1.21.6 h1:ePPaOVn92r5n8Neecdpy93hDmR0PBH6H6b7VQCE5vKE=
github.com/aws/aws-sdk-go-v2/service/apigateway v1.21.6/go.mod h1:P/zwE9uiC6eK/kL3CS60lxTTVC2zAvaS4iW31io41V4=
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.18.6 h1:bCdxKjM8DpkNJXnOLVx+Hnav0eM4yJK8kof56VvIjMc=
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.18.6/go.mod h1:zQ6tOYz7oGI7MbLRDBXfo63puDoTroVcVNXWfmRDA1E=
github.com/aws/aws-sdk-go-v2/service/athena v1.37.3 h1:qNLkDi/rOaauOuh33a4MNZjyfxvwIgC5qsDiHPvjDk0=
github.com/aws/aws-sdk-go-v2/service/athena v1.37.3/go.mod h1:MlpC6swcjh1Il80u6XoeY2BTHIZRZWvoXOfaq3rfh8I=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.36.4 h1:8qjQzwztUVdFJi/wrhPXxRgSbyAKDsnJuduHaw+yP30=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.36.4/go.mod h1:lHdM6itntBCcjvqxEHDoHkXRicwgY9aoPRptXuMdbgk=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.35.6 h1:Yc+avPLGARzp4A9Oi9VRxvlcGqI+0MYIg4tPSupKv2U=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.35.6/go.mod h1:zrqdG1b+4AGoTwTMVFzvzY7ARB3GPo4gKRuK8WPEo8w=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.32.2 h1:vQfCIHSDouEvbE4EuDrlCGKcrtABEqF3cMt61nGEV4g=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.32.2/go.mod h1:3ToKMEhVj+Q+HzZ8Hqin6LdAKtsi3zVXVNUPpQMd+Xk=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.30.1 h1:ZMgx58Tqyr8kTSR9zLzX+W933ujDYleOtFedvn0xHg8=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.30.1/go.mod h1:4Oeb7n2r/ApBIHphQkprve380p/RpPWBotumd44EDGg=
github.com/aws/aws-sdk-go-v2/service/codebuild v1.26.5 h1:EPnlDd4V2EXywlOPAw/pMUW4PHUgSulKm4zXFU6bixE=
github.com/aws/aws-sdk-go-v2/service/codebuild v1.26.5/go.mod h1:G2JUWf01sbb5/A8qGcM4dqy4nbl4y4IGWmaCDWAvA2Y=
github.com/aws/aws-sdk-go-v2/service/docdb v1.34.4 h1:0hvzmeEwiNthBmi2mpTnZgqFCKUxKoLWaQYzulEnqk4=
github.com/aws/aws-sdk-go-v2/service/docdb v1.34.4/go.mod h1:KSNSbXXGchzkLYCDwq9H9ZfPs2zn0SIVgs7LXsfPlRQ=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.8 h1:XKO0BswTDeZMLDBd/b5pCEZGttNXrzRUVtFvp2Ak/Vo=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.8/go.mod h1:N5tqZcYMM0N1PN7UQYJNWuGyO886OfnMhf/3MAbqMcI=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 h1:/FUtT3xsoHO3cfh+I/kCbcMCN98QZRsiFet/V8QkWSs=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7/go.mod h1:MaCAgWpGooQoCWZnMur97rGn5dp350w2+CeiV5406wE=
github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM=
github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.1 h1:0RiDkJO1veM6/FQ+GJcGiIhZgPwXlscX29B0zFE4Ulo=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.1/go.mod h1:gYk1NtyvkH1SxPcndDtfro3lwbiE5t0tW4eRki5YnOQ=
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.5 h1:dvvTFXpWSv9+8lTNPl1EPNZL6BCUV6MgVckEMvXaOgk=
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.5/go.mod h1:Ogt6AOZ/sPBlJZpVFJgOK+jGGREuo8DMjNg+O/7gpjI=
github.com/aws/aws-sdk-go-v2/service/ecs v1.35.6 h1:Sc2mLjyA1R8z2l705AN7Wr7QOlnUxVnGPJeDIVyUSrs=
github.com/aws/aws-sdk-go-v2/service/ecs v1.35.6/go.mod h1:LzHcyOEvaLjbc5e+fP/KmPWBr+h/Ef+EHvnf1Pzo368=
github.com/aws/aws-sdk-go-v2/service/efs v1.28.1 h1:dKtJBzCIew4/VDsYgrx6v140cIpQVoe93kCNniYATtE=
github.com/aws/aws-sdk-go-v2/service/efs v1.28.1/go.mod h1:ha+/WvylFi6dkfF2xfPekJWCNLGuD5PWIFrRRMz3psc=
github.com/aws/aws-sdk-go-v2/service/eks v1.41.0 h1:/bitqsA6wgIS2vgjtHJi1JG3SOTbobs1mCdeJBLOacY=
github.com/aws/aws-sdk-go-v2/service/eks v1.41.0/go.mod h1:GFqWNwDLyuSevADun69Dg5aurANpv8KNrz2vxYPEqmw=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.34.6 h1:Y/5eE9Sc+OBID9pZ4EVFzyQviv1d1RbqB17HRur9ySg=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.34.6/go.mod h1:iPx2i26hgUULkNh1Jk4QzYzzQKd2nXl/rD9Fm5hQ2uk=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.6 h1:twI2uRmpbm0KBog3Ay61IqOtNp6+QxKfSA78zftME/o=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.6/go.mod h1:Tpt4kC8x1HfYuh2rG/6yXZrxjABETERrUl9IdA/IS98=
github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.25.0 h1:LPEsYRsC6r3edPHO8KlZJNW0xxyfLHMXJ466MdHuBbQ=
github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.25.0/go.mod h1:CAXUsQvYQVzsXO36npqK3aUlxx2xMSM1Dun3O9jnaEE=
github.com/aws/aws-sdk-go-v2/service/emr v1.36.0 h1:FdeZ7AYOvyL09KH250Ncz4LF4SB1Vo9l7KZzn/LIrgQ=
github.com/aws/aws-sdk-go-v2/service/emr v1.36.0/go.mod h1:Drh6y2qLaw/wnDKTIcdqM2m358MIRXsZ2Bj2tjhVLq0=
github.com/aws/aws-sdk-go-v2/service/iam v1.28.7 h1:FKPRDYZOO0Eur19vWUL1B40Op0j89KQj3kARjrszMK8=
github.com/aws/aws-sdk-go-v2/service/iam v1.28.7/go.mod h1:YzMYyQ7S4twfYzLjwP24G1RAxypozVZeNaG1r2jxRms=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3 h1:l0mvKOGm25yo/Fy+Y/08Cm4aTA4XmnIuq4ppy+shfMI=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3/go.mod h1:iJ2sQeUTkjNp3nL7kE/Bav0xXYhtiRCRP5ZXk4jFhCQ=
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.2 h1:xUpMnRZonKfrHaNLC77IMpWZSUMRRXIi6IU5EhAPsrM=
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.2/go.mod h1:X52zjAVRaXklEU1TE/wO8kyyJSr9cJx9ZsqliWbyRys=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11 h1:4vt9Sspk59EZyHCAEMaktHKiq0C09noRTQorXD/qV+s=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.11/go.mod h1:5jHR79Tv+Ccq6rwYh+W7Nptmw++WiFafMfR42XhwNl8=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11 h1:e9AVb17H4x5FTE5KWIP5M1Du+9M86pS+Hw0lBUdN8EY=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11/go.mod h1:B90ZQJa36xo0ph9HsoteI1+r8owgQH/U1QNfqZQkj1Q=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9 h1:TE2i0A9ErH1YfRSvXfCr2SQwfnqsoJT9nPQ9kj0lkxM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.9/go.mod h1:9TzXX3MehQNGPwCZ3ka4CpwQsoAMWSF48/b+De9rfVM=
github.com/aws/aws-sdk-go-v2/service/kafka v1.28.5 h1:yCkyZDGahaCaAkdpVx8Te05t6eW2FarBLunVC8S23nU=
github.com/aws/aws-sdk-go-v2/service/kafka v1.28.5/go.mod h1:/KmX+vXMPJGAB56reo95tnsXa6QPNx6qli4L1AmYb7E=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.24.6 h1:FO/aIHk86VePDUh/3Q/A5pnvu45miO1GZB8rIq2BUlA=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.24.6/go.mod h1:Sj7qc+P/GOGOPMDn8+B7Cs+WPq1Gk+R6CXRXVhZtWcA=
github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 h1:FARrQLRQXpCFYylIUVF1dRij6YbPCmtwudq9NBk4kFc=
github.com/aws/aws-sdk-go-v2/service/kms v1.32.1/go.mod h1:8lETO9lelSG2B6KMXFh2OwPPqGV6WQM3RqLAEjP1xaU=
github.com/aws/aws-sdk-go-v2/service/lambda v1.49.6 h1:w8lI9zlVwRTL9f4KB9fRThddhRivv+EQQzv2nU8JDQo=
github.com/aws/aws-sdk-go-v2/service/lambda v1.49.6/go.mod h1:0V5z1X/8NA9eQ5cZSz5ZaHU8xA/hId2ZAlsHeO7Jrdk=
github.com/aws/aws-sdk-go-v2/service/mq v1.20.6 h1:n86T5yw0kS6a5nbpkEpDzLPCBXXb35lx3iDkmQWlizA=
github.com/aws/aws-sdk-go-v2/service/mq v1.20.6/go.mod h1:phfKOOpMQhlBv2KE8gF17P82zLcSedA9b7fMSGTLBdQ=
github.com/aws/aws-sdk-go-v2/service/neptune v1.28.1 h1:e+DGEARs5GfHuzDwztENiomdLa0sjs55ub27juoFdt0=
github.com/aws/aws-sdk-go-v2/service/neptune v1.28.1/go.mod h1:jHUFaho5cVpplTDO6bctuLbvnm8F+Xd27RGIJvVTlYI=
github.com/aws/aws-sdk-go-v2/service/rds v1.66.1 h1:TafjIpDW/+l7s+f3EIONaFsNvNfwVH21NkWYrE0hbEE=
github.com/aws/aws-sdk-go-v2/service/rds v1.66.1/go.mod h1:MYzRMSdY70kcS8AFg0aHmk/xj6VAe0UfaCCoLrBWPow=
github.com/aws/aws-sdk-go-v2/service/redshift v1.39.7 h1:k4WaqQ7LHSGrSftCRXTRLv7WaozXu+fZ1jdisQSR2eU=
github.com/aws/aws-sdk-go-v2/service/redshift v1.39.7/go.mod h1:8hU0Ax6q6QA+jrMcWTE0A4YH594MQoWP3EzGO3GH5Dw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 h1:UAxBuh0/8sFJk1qOkvOKewP5sWeWaTPDknbQz0ZkDm0=
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1/go.mod h1:hWjsYGjVuqCgfoveVcVFPXIWgz0aByzwaxKlN1StKcM=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0 h1:dPCRgAL4WD9tSMaDglRNGOiAtSTjkwNiUW5GDpWFfHA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0/go.mod h1:4Ae1NCLK6ghmjzd45Tc33GgCKhUWD2ORAlULtMO1Cbs=
github.com/aws/aws-sdk-go-v2/service/sns v1.26.6 h1:w2YwF8889ardGU3Y0qZbJ4Zzh+Q/QqKZ4kwkK7JFvnI=
github.com/aws/aws-sdk-go-v2/service/sns v1.26.6/go.mod h1:IrcbquqMupzndZ20BXxDxjM7XenTRhbwBOetk4+Z5oc=
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.6 h1:UdbDTllc7cmusTTMy1dcTrYKRl4utDEsmKh9ZjvhJCc=
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.6/go.mod h1:mCUv04gd/7g+/HNzDB4X6dzJuygji0ckvB3Lg/TdG5Y=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk=
github.com/aws/aws-sdk-go-v2/service/workspaces v1.38.1 h1:pqxn3fcZDgWmo8GMUjlxVBdakcGo0AeUb7mjX33pJIQ=
github.com/aws/aws-sdk-go-v2/service/workspaces v1.38.1/go.mod h1:kP5rUlnqfno/obflnKX4KMBWkoVHLDI8oCka9U0opRo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 h1:UXqEWQI0n+q0QixzU0yUUQBZXRd5037qdInTIHFTl98=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9/go.mod h1:xP6Gq6fzGZT8w/ZN+XvGMZ2RU1LeEs7b2yUP5DN8NY4=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7 h1:uO5XR6QGBcmPyo2gxofYJLFkcVQ4izOoGDNenlZhTEk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7/go.mod h1:feeeAYfAcwTReM6vbwjEyDmiGho+YgBhaFULuXDW8kc=
github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2 h1:gYSJhNiOF6J9xaYxu2NFNstoiNELwt0T9w29FxSfN+Y=
github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2/go.mod h1:739CllldowZiPPsDFcJHNF4FXrVxaSGVnZ9Ez9Iz9hc=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8 h1:Kv1hwNG6jHC/sxMTe5saMjH6t6ZLkgfvVxyEjfWL1ks=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8/go.mod h1:c1qtZUWtygI6ZdvKppzCSXsDOq5I4luJPZ0Ud3juFCA=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2 h1:nWBZ1xHCF+A7vv9sDzJOq4NWIdzFYm0kH7Pr4OjHYsQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2/go.mod h1:9lmoVDVLz/yUZwLaQ676TK02fhCu4+PgRSmMaKR1ozk=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9 h1:Qp6Boy0cGDloOE3zI6XhNLNZgjNS8YmiFQFHe71SaW0=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9/go.mod h1:0Aqn1MnEuitqfsCNyKsdKLhDUOr4txD/g19EfiUqgws=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -1521,7 +1451,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=

View File

@@ -1,78 +0,0 @@
//go:build integration
package integration
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/internal/testutil"
awscommands "github.com/aquasecurity/trivy/pkg/cloud/aws/commands"
"github.com/aquasecurity/trivy/pkg/flag"
)
func TestAwsCommandRun(t *testing.T) {
tests := []struct {
name string
options flag.Options
envs map[string]string
wantErr string
}{
{
name: "fail without region",
options: flag.Options{
RegoOptions: flag.RegoOptions{SkipCheckUpdate: true},
},
envs: map[string]string{
"AWS_ACCESS_KEY_ID": "test",
"AWS_SECRET_ACCESS_KEY": "test",
},
wantErr: "aws region is required",
},
{
name: "fail without creds",
envs: map[string]string{
"AWS_PROFILE": "non-existent-profile",
},
options: flag.Options{
RegoOptions: flag.RegoOptions{SkipCheckUpdate: true},
AWSOptions: flag.AWSOptions{
Region: "us-east-1",
},
},
wantErr: "non-existent-profile",
},
}
ctx := context.Background()
localstackC, addr, err := testutil.SetupLocalStack(ctx, "2.2.0")
require.NoError(t, err)
defer localstackC.Terminate(ctx)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.options.AWSOptions.Endpoint = addr
tt.options.GlobalOptions.Timeout = time.Minute
for k, v := range tt.envs {
t.Setenv(k, v)
}
err := awscommands.Run(context.Background(), tt.options)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
return
}
require.NoError(t, err)
})
}
}

View File

@@ -152,7 +152,6 @@ nav:
- Configuration:
- CLI:
- Overview: docs/references/configuration/cli/trivy.md
- AWS: docs/references/configuration/cli/trivy_aws.md
- Config: docs/references/configuration/cli/trivy_config.md
- Convert: docs/references/configuration/cli/trivy_convert.md
- Filesystem: docs/references/configuration/cli/trivy_filesystem.md

View File

@@ -1,132 +0,0 @@
package cache
import (
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/aquasecurity/trivy/pkg/iac/state"
)
type Cache struct {
path string
accountID string
region string
maxAge time.Duration
}
const SchemaVersion = 2
type CacheData struct {
SchemaVersion int `json:"schema_version"`
State *state.State `json:"state"`
Services map[string]ServiceMetadata `json:"service_metadata"`
Updated time.Time `json:"updated"`
}
type ServiceMetadata struct {
Name string `json:"name"`
Updated time.Time `json:"updated"`
}
var ErrCacheNotFound = fmt.Errorf("cache record not found")
var ErrCacheIncompatible = fmt.Errorf("cache record used incomatible schema")
var ErrCacheExpired = fmt.Errorf("cache record expired")
func New(cacheDir string, maxCacheAge time.Duration, accountID, region string) *Cache {
return &Cache{
path: path.Join(cacheDir, "cloud", "aws", accountID, strings.ToLower(region), "data.json"),
accountID: accountID,
region: region,
maxAge: maxCacheAge,
}
}
func (c *Cache) load() (*CacheData, error) {
m, err := os.Open(c.path)
if err != nil {
return nil, ErrCacheNotFound
}
defer func() { _ = m.Close() }()
var data CacheData
if err := json.NewDecoder(m).Decode(&data); err != nil {
return nil, err
}
if data.SchemaVersion != SchemaVersion {
return nil, ErrCacheIncompatible
}
if time.Since(data.Updated) > c.maxAge {
return nil, ErrCacheExpired
}
return &data, nil
}
func (c *Cache) ListServices(required []string) (included, missing []string) {
data, err := c.load()
if err != nil {
return nil, required
}
for _, service := range required {
metadata, ok := data.Services[service]
if !ok {
missing = append(missing, service)
continue
}
if time.Since(metadata.Updated) > c.maxAge {
missing = append(missing, service)
continue
}
included = append(included, service)
}
return included, missing
}
func (c *Cache) LoadState() (*state.State, error) {
data, err := c.load()
if err != nil {
return nil, err
}
return data.State, nil
}
func (c *Cache) AddServices(s *state.State, includedServices []string) error {
data := &CacheData{
SchemaVersion: SchemaVersion,
State: s,
Services: make(map[string]ServiceMetadata),
Updated: time.Now(),
}
if previous, err := c.load(); err == nil {
data.Services = previous.Services
}
for _, service := range includedServices {
data.Services[service] = ServiceMetadata{
Name: service,
Updated: time.Now(),
}
}
if err := os.MkdirAll(filepath.Dir(c.path), 0700); err != nil {
return err
}
f, err := os.Create(c.path)
if err != nil {
return err
}
defer func() { _ = f.Close() }()
return json.NewEncoder(f).Encode(data)
}

View File

@@ -1,183 +0,0 @@
package commands
import (
"context"
"errors"
"fmt"
"slices"
"sort"
"strings"
"github.com/aws/aws-sdk-go-v2/service/sts"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-aws/pkg/errs"
awsScanner "github.com/aquasecurity/trivy-aws/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/cloud"
"github.com/aquasecurity/trivy/pkg/cloud/aws/config"
"github.com/aquasecurity/trivy/pkg/cloud/aws/scanner"
"github.com/aquasecurity/trivy/pkg/cloud/report"
"github.com/aquasecurity/trivy/pkg/commands/operation"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/version/doc"
)
var allSupportedServicesFunc = awsScanner.AllSupportedServices
func getAccountIDAndRegion(ctx context.Context, region, endpoint string) (string, string, error) {
log.DebugContext(ctx, "Looking for AWS credentials provider...")
cfg, err := config.LoadDefaultAWSConfig(ctx, region, endpoint)
if err != nil {
return "", "", err
}
svc := sts.NewFromConfig(cfg)
log.DebugContext(ctx, "Looking up AWS caller identity...")
result, err := svc.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
if err != nil {
return "", "", xerrors.Errorf("failed to discover AWS caller identity: %w", err)
}
if result.Account == nil {
return "", "", xerrors.Errorf("missing account id for aws account")
}
log.DebugContext(ctx, "Verified AWS credentials for account!", log.String("account", *result.Account))
return *result.Account, cfg.Region, nil
}
func validateServicesInput(services, skipServices []string) error {
for _, s := range services {
for _, ss := range skipServices {
if s == ss {
return xerrors.Errorf("service: %s specified to both skip and include", s)
}
}
}
return nil
}
func processOptions(ctx context.Context, opt *flag.Options) error {
if err := validateServicesInput(opt.Services, opt.SkipServices); err != nil {
return err
}
// support comma separated services too
var splitServices []string
for _, service := range opt.Services {
splitServices = append(splitServices, strings.Split(service, ",")...)
}
opt.Services = splitServices
var splitSkipServices []string
for _, skipService := range opt.SkipServices {
splitSkipServices = append(splitSkipServices, strings.Split(skipService, ",")...)
}
opt.SkipServices = splitSkipServices
if len(opt.Services) != 1 && opt.ARN != "" {
return xerrors.Errorf("you must specify the single --service which the --arn relates to")
}
if opt.Account == "" || opt.Region == "" {
var err error
opt.Account, opt.Region, err = getAccountIDAndRegion(ctx, opt.Region, opt.Endpoint)
if err != nil {
return err
}
}
err := filterServices(ctx, opt)
if err != nil {
return err
}
log.DebugContext(ctx, "Scanning services", log.Any("services", opt.Services))
return nil
}
func filterServices(ctx context.Context, opt *flag.Options) error {
switch {
case len(opt.Services) == 0 && len(opt.SkipServices) == 0:
log.DebugContext(ctx, "No service(s) specified, scanning all services...")
opt.Services = allSupportedServicesFunc()
case len(opt.SkipServices) > 0:
log.DebugContext(ctx, "Excluding services", log.Any("services", opt.SkipServices))
for _, s := range allSupportedServicesFunc() {
if slices.Contains(opt.SkipServices, s) {
continue
}
if !slices.Contains(opt.Services, s) {
opt.Services = append(opt.Services, s)
}
}
case len(opt.Services) > 0:
log.DebugContext(ctx, "Specific services were requested...",
log.String("services", strings.Join(opt.Services, ", ")))
for _, service := range opt.Services {
var found bool
supported := allSupportedServicesFunc()
for _, allowed := range supported {
if allowed == service {
found = true
break
}
}
if !found {
return xerrors.Errorf("service '%s' is not currently supported - supported services are: %s", service, strings.Join(supported, ", "))
}
}
}
return nil
}
func Run(ctx context.Context, opt flag.Options) error {
ctx, cancel := context.WithTimeout(ctx, opt.GlobalOptions.Timeout)
defer cancel()
ctx = log.WithContextPrefix(ctx, "aws")
var err error
defer func() {
if errors.Is(err, context.DeadlineExceeded) {
// e.g. https://aquasecurity.github.io/trivy/latest/docs/configuration/
log.WarnContext(ctx, fmt.Sprintf("Provide a higher timeout value, see %s", doc.URL("/docs/configuration/", "")))
}
}()
if err := processOptions(ctx, &opt); err != nil {
return err
}
results, cached, err := scanner.NewScanner().Scan(ctx, opt)
if err != nil {
var aerr errs.AdapterError
if errors.As(err, &aerr) {
for _, e := range aerr.Errors() {
log.WarnContext(ctx, "Adapter error", log.Err(e))
}
} else {
return xerrors.Errorf("aws scan error: %w", err)
}
}
log.DebugContext(ctx, "Writing report to output...")
sort.Slice(results, func(i, j int) bool {
return results[i].Rule().AVDID < results[j].Rule().AVDID
})
res := results.GetFailed()
if opt.MisconfOptions.IncludeNonFailures {
res = results
}
r := report.New(cloud.ProviderAWS, opt.Account, opt.Region, res, opt.Services)
if err := report.Write(ctx, r, opt, cached); err != nil {
return xerrors.Errorf("unable to write results: %w", err)
}
return operation.Exit(opt, r.Failed(), types.Metadata{})
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
AVD-AWS-0086
AVD-AWS-0087
AVD-AWS-0088
AVD-AWS-0090
AVD-AWS-0132
AVD-AWS-0091
AVD-AWS-0092
AVD-AWS-0093

View File

@@ -1,13 +0,0 @@
spec:
id: "0001"
title: my-custom-spec
description: My fancy spec
version: "1.2"
controls:
- id: "1.1"
name: Unencrypted S3 bucket
description: |-
S3 Buckets should be encrypted to protect the data that is stored within them if access is compromised.
checks:
- id: AVD-AWS-0088
severity: HIGH

View File

@@ -1,420 +0,0 @@
{
"schema_version": 2,
"state": {
"AWS": {
"S3": {
"Buckets": [{
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Name": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": "examplebucket"
},
"PublicAccessBlock": null,
"BucketPolicies": null,
"Encryption": {
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Enabled": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
},
"Algorithm": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": ""
},
"KMSKeyId": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": ""
}
},
"Versioning": {
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Enabled": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
},
"MFADelete": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
}
},
"Logging": {
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Enabled": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
},
"TargetBucket": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": ""
}
},
"ACL": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": "private"
}
}]
},
"CloudTrail": {
"Trails": [{
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"Name": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": "management-events"
},
"EnableLogFileValidation": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": false
},
"IsMultiRegion": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": true
},
"KMSKeyID": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": ""
},
"CloudWatchLogsLogGroupArn": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": ""
},
"IsLogging": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": true
},
"BucketName": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:cloudtrail:us-east-1:12345678:trail/management-events",
"unresolvable": false
},
"value": "aws-cloudtrail-logs-12345678-d0a47f2f"
},
"EventSelectors": null
}]
}
}
},
"service_metadata": {
"s3": {
"name": "s3",
"updated": "2022-10-04T14:08:36.659817426+01:00"
},
"cloudtrail": {
"name": "cloudtrail",
"updated": "2022-10-04T14:08:36.659817426+01:00"
}
},
"updated": "2022-10-04T14:08:36.659817426+01:00"
}

View File

@@ -1,261 +0,0 @@
{
"schema_version": 2,
"state": {
"AWS": {
"S3": {
"Buckets": [{
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Name": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": "examplebucket"
},
"PublicAccessBlock": null,
"BucketPolicies": null,
"Encryption": {
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Enabled": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
},
"Algorithm": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": ""
},
"KMSKeyId": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": ""
}
},
"Versioning": {
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Enabled": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
},
"MFADelete": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
}
},
"Logging": {
"Metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"Enabled": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": false
},
"TargetBucket": {
"metadata": {
"default": true,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": ""
}
},
"ACL": {
"metadata": {
"default": false,
"explicit": false,
"managed": true,
"parent": null,
"range": {
"endLine": 0,
"filename": "arn:aws:s3:::examplebucket",
"fsKey": "",
"isLogicalSource": false,
"sourcePrefix": "remote",
"startLine": 0
},
"ref": "arn:aws:s3:::examplebucket",
"unresolvable": false
},
"value": "private"
}
}]
}
}
},
"service_metadata": {
"s3": {
"name": "s3",
"updated": "2022-10-04T14:08:36.659817426+01:00"
}
},
"updated": "2022-10-04T14:08:36.659817426+01:00"
}

View File

@@ -9,14 +9,14 @@ import (
)
func EndpointResolver(endpoint string) aws.EndpointResolverWithOptionsFunc {
return aws.EndpointResolverWithOptionsFunc(func(_, reg string, options ...any) (aws.Endpoint, error) {
return func(_, reg string, options ...any) (aws.Endpoint, error) {
return aws.Endpoint{
PartitionID: "aws",
URL: endpoint,
SigningRegion: reg,
Source: aws.EndpointSourceCustom,
}, nil
})
}
}
func MakeAWSOptions(region, endpoint string) []func(*awsconfig.LoadOptions) error {

View File

@@ -1,83 +0,0 @@
package scanner
import (
"fmt"
"io"
"os"
"github.com/aquasecurity/loading/pkg/bar"
)
type progressTracker struct {
serviceBar *bar.Bar
serviceTotal int
serviceCurrent int
isTTY bool
debugWriter io.Writer
}
func newProgressTracker(w io.Writer) *progressTracker {
var isTTY bool
if stat, err := os.Stdout.Stat(); err == nil {
isTTY = stat.Mode()&os.ModeCharDevice == os.ModeCharDevice
}
return &progressTracker{
isTTY: isTTY,
debugWriter: w,
}
}
func (m *progressTracker) Finish() {
if !m.isTTY || m.serviceBar == nil {
return
}
m.serviceBar.Finish()
}
func (m *progressTracker) IncrementResource() {
if !m.isTTY {
return
}
m.serviceBar.Increment()
}
func (m *progressTracker) SetTotalResources(i int) {
if !m.isTTY {
return
}
m.serviceBar.SetTotal(i)
}
func (m *progressTracker) SetTotalServices(i int) {
m.serviceTotal = i
}
func (m *progressTracker) SetServiceLabel(label string) {
if !m.isTTY {
return
}
m.serviceBar.SetLabel("└╴" + label)
m.serviceBar.SetCurrent(0)
}
func (m *progressTracker) FinishService() {
if !m.isTTY {
return
}
m.serviceCurrent++
m.serviceBar.Finish()
}
func (m *progressTracker) StartService(name string) {
if !m.isTTY {
return
}
fmt.Fprintf(m.debugWriter, "[%d/%d] Scanning %s...\n", m.serviceCurrent+1, m.serviceTotal, name)
m.serviceBar = bar.New(
bar.OptionHideOnFinish(true),
bar.OptionWithAutoComplete(false),
bar.OptionWithRenderFunc(bar.RenderColoured(0xff, 0x66, 0x00)),
)
m.SetServiceLabel("Initializing...")
}

View File

@@ -1,176 +0,0 @@
package scanner
import (
"context"
"fmt"
"io/fs"
"golang.org/x/xerrors"
aws "github.com/aquasecurity/trivy-aws/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/cloud/aws/cache"
"github.com/aquasecurity/trivy/pkg/commands/operation"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/iac/framework"
"github.com/aquasecurity/trivy/pkg/iac/scan"
"github.com/aquasecurity/trivy/pkg/iac/scanners/options"
"github.com/aquasecurity/trivy/pkg/iac/state"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/misconf"
)
type AWSScanner struct {
logger *log.Logger
}
func NewScanner() *AWSScanner {
return &AWSScanner{
logger: log.WithPrefix("aws"),
}
}
func (s *AWSScanner) Scan(ctx context.Context, option flag.Options) (scan.Results, bool, error) {
awsCache := cache.New(option.CacheDir, option.MaxCacheAge, option.Account, option.Region)
included, missing := awsCache.ListServices(option.Services)
prefixedLogger := log.NewWriteLogger(log.WithPrefix("aws"))
var scannerOpts []options.ScannerOption
if !option.NoProgress {
tracker := newProgressTracker(prefixedLogger)
defer tracker.Finish()
scannerOpts = append(scannerOpts, aws.ScannerWithProgressTracker(tracker))
}
if len(missing) > 0 {
scannerOpts = append(scannerOpts, aws.ScannerWithAWSServices(missing...))
}
if option.Debug {
scannerOpts = append(scannerOpts, options.ScannerWithDebug(prefixedLogger))
}
if option.Trace {
scannerOpts = append(scannerOpts, options.ScannerWithTrace(prefixedLogger))
}
if option.Region != "" {
scannerOpts = append(
scannerOpts,
aws.ScannerWithAWSRegion(option.Region),
)
}
if option.Endpoint != "" {
scannerOpts = append(
scannerOpts,
aws.ScannerWithAWSEndpoint(option.Endpoint),
)
}
var policyPaths []string
var downloadedPolicyPaths []string
var err error
downloadedPolicyPaths, err = operation.InitBuiltinPolicies(context.Background(), option.CacheDir, option.Quiet, option.SkipCheckUpdate, option.MisconfOptions.ChecksBundleRepository, option.RegistryOpts())
if err != nil {
if !option.SkipCheckUpdate {
s.logger.Error("Falling back to embedded checks", log.Err(err))
}
} else {
s.logger.Debug("Checks successfully loaded from disk")
policyPaths = append(policyPaths, downloadedPolicyPaths...)
scannerOpts = append(scannerOpts,
options.ScannerWithEmbeddedPolicies(false),
options.ScannerWithEmbeddedLibraries(false))
}
var policyFS fs.FS
policyFS, policyPaths, err = misconf.CreatePolicyFS(append(policyPaths, option.RegoOptions.CheckPaths...))
if err != nil {
return nil, false, xerrors.Errorf("unable to create policyfs: %w", err)
}
scannerOpts = append(scannerOpts,
options.ScannerWithPolicyFilesystem(policyFS),
options.ScannerWithPolicyDirs(policyPaths...),
)
dataFS, dataPaths, err := misconf.CreateDataFS(option.RegoOptions.DataPaths)
if err != nil {
s.logger.Error("Could not load config data", log.Err(err))
}
scannerOpts = append(scannerOpts,
options.ScannerWithDataDirs(dataPaths...),
options.ScannerWithDataFilesystem(dataFS),
)
scannerOpts = addPolicyNamespaces(option.RegoOptions.CheckNamespaces, scannerOpts)
if option.Compliance.Spec.ID != "" {
scannerOpts = append(scannerOpts, options.ScannerWithSpec(option.Compliance.Spec.ID))
} else {
scannerOpts = append(scannerOpts, options.ScannerWithFrameworks(
framework.Default,
framework.CIS_AWS_1_2))
}
scanner := aws.New(scannerOpts...)
var freshState *state.State
if len(missing) > 0 || option.CloudOptions.UpdateCache {
var err error
freshState, err = scanner.CreateState(ctx)
if err != nil {
return nil, false, err
}
}
fullState, err := createState(freshState, awsCache)
if err != nil {
return nil, false, err
}
if fullState == nil {
return nil, false, fmt.Errorf("no resultant state found")
}
if err := awsCache.AddServices(fullState, missing); err != nil {
return nil, false, err
}
defsecResults, err := scanner.Scan(ctx, fullState)
if err != nil {
return nil, false, err
}
return defsecResults, len(included) > 0, nil
}
func createState(freshState *state.State, awsCache *cache.Cache) (*state.State, error) {
var fullState *state.State
if previousState, err := awsCache.LoadState(); err == nil {
if freshState != nil {
fullState, err = previousState.Merge(freshState)
if err != nil {
return nil, err
}
} else {
fullState = previousState
}
} else {
fullState = freshState
}
return fullState, nil
}
func addPolicyNamespaces(namespaces []string, scannerOpts []options.ScannerOption) []options.ScannerOption {
if len(namespaces) > 0 {
scannerOpts = append(
scannerOpts,
options.ScannerWithPolicyNamespaces(namespaces...),
)
}
return scannerOpts
}

View File

@@ -1,5 +0,0 @@
package cloud
const (
ProviderAWS = "AWS"
)

View File

@@ -1,107 +0,0 @@
package report
import (
"fmt"
"strings"
"time"
"github.com/aws/aws-sdk-go-v2/aws/arn"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/iac/rego"
"github.com/aquasecurity/trivy/pkg/iac/scan"
"github.com/aquasecurity/trivy/pkg/types"
)
func ConvertResults(results scan.Results, provider string, scoped []string) map[string]ResultsAtTime {
convertedResults := make(map[string]ResultsAtTime)
resultsByServiceAndARN := make(map[string]map[string]scan.Results)
for _, result := range results {
service := result.Rule().Service
resource := result.Flatten().Resource
if service == "" || service == "general" {
if parsed, err := arn.Parse(resource); err == nil {
service = parsed.Service
}
}
existingService, ok := resultsByServiceAndARN[service]
if !ok {
existingService = make(map[string]scan.Results)
}
existingService[resource] = append(existingService[resource], result)
resultsByServiceAndARN[service] = existingService
}
// ensure we have entries for all scoped services, even if there are no results
for _, service := range scoped {
if _, ok := resultsByServiceAndARN[service]; !ok {
resultsByServiceAndARN[service] = nil
}
}
for service, arnResults := range resultsByServiceAndARN {
var convertedArnResults []types.Result
for arn, serviceResults := range arnResults {
arnResult := types.Result{
Target: arn,
Class: types.ClassConfig,
Type: ftypes.Cloud,
}
for _, result := range serviceResults {
var primaryURL string
// empty namespace implies a go rule from defsec, "builtin" refers to a built-in rego rule
// this ensures we don't generate bad links for custom policies
if result.RegoNamespace() == "" || rego.IsBuiltinNamespace(result.RegoNamespace()) {
primaryURL = fmt.Sprintf("https://avd.aquasec.com/misconfig/%s", strings.ToLower(result.Rule().AVDID))
}
status := types.MisconfStatusFailure
switch result.Status() {
case scan.StatusPassed:
status = types.MisconfStatusPassed
case scan.StatusIgnored:
status = types.MisconfStatusException
}
flat := result.Flatten()
arnResult.Misconfigurations = append(arnResult.Misconfigurations, types.DetectedMisconfiguration{
Type: provider,
ID: result.Rule().AVDID,
AVDID: result.Rule().AVDID,
Title: result.Rule().Summary,
Description: strings.TrimSpace(result.Rule().Explanation),
Message: strings.TrimSpace(result.Description()),
Namespace: result.RegoNamespace(),
Query: result.RegoRule(),
Resolution: result.Rule().Resolution,
Severity: string(result.Severity()),
PrimaryURL: primaryURL,
References: []string{primaryURL},
Status: status,
CauseMetadata: ftypes.CauseMetadata{
Resource: flat.Resource,
Provider: string(flat.RuleProvider),
Service: service,
StartLine: flat.Location.StartLine,
EndLine: flat.Location.EndLine,
},
})
}
convertedArnResults = append(convertedArnResults, arnResult)
}
convertedResults[service] = ResultsAtTime{
Results: convertedArnResults,
CreationTime: time.Now(),
}
}
return convertedResults
}

View File

@@ -1,242 +0,0 @@
package report
import (
"sort"
"testing"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/stretchr/testify/assert"
fanaltypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/iac/scan"
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
"github.com/aquasecurity/trivy/pkg/types"
)
func Test_ResultConversion(t *testing.T) {
tests := []struct {
name string
results scan.Results
provider string
scoped []string
expected map[string]ResultsAtTime
}{
{
name: "no results",
results: scan.Results{},
provider: "AWS",
expected: make(map[string]ResultsAtTime),
},
{
name: "no results, multiple scoped services",
results: scan.Results{},
provider: "AWS",
scoped: []string{"s3", "ec2"},
expected: map[string]ResultsAtTime{
"s3": {},
"ec2": {},
},
},
{
name: "multiple results",
results: func() scan.Results {
baseRule := scan.Rule{
AVDID: "AVD-AWS-9999",
Aliases: []string{"AWS999"},
ShortCode: "no-bad-stuff",
Summary: "Do not use bad stuff",
Explanation: "Bad stuff is... bad",
Impact: "Bad things",
Resolution: "Remove bad stuff",
Provider: "AWS",
Severity: "HIGH",
}
var s3Results scan.Results
s3Results.Add(
"something failed",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket1",
}).String()),
)
s3Results.Add(
"something else failed",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket2",
}).String()),
)
s3Results.Add(
"something else failed again",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket2",
}).String()),
)
baseRule.Service = "s3"
s3Results.SetRule(baseRule)
var ec2Results scan.Results
ec2Results.Add(
"instance is bad",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "ec2",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "instance1",
}).String()),
)
baseRule.Service = "ec2"
ec2Results.SetRule(baseRule)
return append(s3Results, ec2Results...)
}(),
provider: "AWS",
expected: map[string]ResultsAtTime{
"s3": {
Results: types.Results{
{
Target: "arn:aws:s3:us-east-1:1234567890:bucket1",
Class: "config",
Type: "cloud",
Misconfigurations: []types.DetectedMisconfiguration{
{
Type: "AWS",
ID: "AVD-AWS-9999",
AVDID: "AVD-AWS-9999",
Title: "Do not use bad stuff",
Description: "Bad stuff is... bad",
Message: "something failed",
Resolution: "Remove bad stuff",
Severity: "HIGH",
PrimaryURL: "https://avd.aquasec.com/misconfig/avd-aws-9999",
References: []string{
"https://avd.aquasec.com/misconfig/avd-aws-9999",
},
Status: "FAIL",
CauseMetadata: fanaltypes.CauseMetadata{
Resource: "arn:aws:s3:us-east-1:1234567890:bucket1",
Provider: "AWS",
Service: "s3",
StartLine: 0,
EndLine: 0,
Code: fanaltypes.Code{},
},
},
},
},
{
Target: "arn:aws:s3:us-east-1:1234567890:bucket2",
Class: "config",
Type: "cloud",
Misconfigurations: []types.DetectedMisconfiguration{
{
Type: "AWS",
ID: "AVD-AWS-9999",
AVDID: "AVD-AWS-9999",
Title: "Do not use bad stuff",
Description: "Bad stuff is... bad",
Message: "something else failed",
Resolution: "Remove bad stuff",
Severity: "HIGH",
PrimaryURL: "https://avd.aquasec.com/misconfig/avd-aws-9999",
References: []string{
"https://avd.aquasec.com/misconfig/avd-aws-9999",
},
Status: "FAIL",
CauseMetadata: fanaltypes.CauseMetadata{
Resource: "arn:aws:s3:us-east-1:1234567890:bucket2",
Provider: "AWS",
Service: "s3",
},
},
{
Type: "AWS",
ID: "AVD-AWS-9999",
AVDID: "AVD-AWS-9999",
Title: "Do not use bad stuff",
Description: "Bad stuff is... bad",
Message: "something else failed again",
Resolution: "Remove bad stuff",
Severity: "HIGH",
PrimaryURL: "https://avd.aquasec.com/misconfig/avd-aws-9999",
References: []string{
"https://avd.aquasec.com/misconfig/avd-aws-9999",
},
Status: "FAIL",
CauseMetadata: fanaltypes.CauseMetadata{
Resource: "arn:aws:s3:us-east-1:1234567890:bucket2",
Provider: "AWS",
Service: "s3",
},
},
},
},
},
},
"ec2": {
Results: types.Results{
{
Target: "arn:aws:ec2:us-east-1:1234567890:instance1",
Class: "config",
Type: "cloud",
Misconfigurations: []types.DetectedMisconfiguration{
{
Type: "AWS",
ID: "AVD-AWS-9999",
AVDID: "AVD-AWS-9999",
Title: "Do not use bad stuff",
Description: "Bad stuff is... bad",
Message: "instance is bad",
Resolution: "Remove bad stuff",
Severity: "HIGH",
PrimaryURL: "https://avd.aquasec.com/misconfig/avd-aws-9999",
References: []string{
"https://avd.aquasec.com/misconfig/avd-aws-9999",
},
Status: "FAIL",
CauseMetadata: fanaltypes.CauseMetadata{
Resource: "arn:aws:ec2:us-east-1:1234567890:instance1",
Provider: "AWS",
Service: "ec2",
},
},
},
},
},
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
converted := ConvertResults(test.results, test.provider, test.scoped)
assertConvertedResultsMatch(t, test.expected, converted)
})
}
}
func assertConvertedResultsMatch(t *testing.T, expected, actual map[string]ResultsAtTime) {
assert.Equal(t, len(expected), len(actual))
for service, resultsAtTime := range expected {
_, ok := actual[service]
assert.True(t, ok)
sort.Slice(actual[service].Results, func(i, j int) bool {
return actual[service].Results[i].Target < actual[service].Results[j].Target
})
assert.ElementsMatch(t, resultsAtTime.Results, actual[service].Results)
}
}

View File

@@ -1,160 +0,0 @@
package report
import (
"context"
"io"
"os"
"sort"
"time"
"golang.org/x/xerrors"
"github.com/aquasecurity/tml"
"github.com/aquasecurity/trivy/pkg/clock"
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/iac/scan"
pkgReport "github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/result"
"github.com/aquasecurity/trivy/pkg/types"
)
const (
tableFormat = "table"
)
// Report represents an AWS scan report
type Report struct {
Provider string
AccountID string
Region string
Results map[string]ResultsAtTime
ServicesInScope []string
}
type ResultsAtTime struct {
Results types.Results
CreationTime time.Time
}
func New(provider, accountID, region string, defsecResults scan.Results, scopedServices []string) *Report {
return &Report{
Provider: provider,
AccountID: accountID,
Results: ConvertResults(defsecResults, provider, scopedServices),
ServicesInScope: scopedServices,
Region: region,
}
}
// Failed returns whether the aws report includes any "failed" results
func (r *Report) Failed() bool {
for _, set := range r.Results {
if set.Results.Failed() {
return true
}
}
return false
}
// Write writes the results in the give format
func Write(ctx context.Context, rep *Report, opt flag.Options, fromCache bool) error {
output, cleanup, err := opt.OutputWriter(ctx)
if err != nil {
return xerrors.Errorf("failed to create output file: %w", err)
}
defer cleanup()
if opt.Compliance.Spec.ID != "" {
return writeCompliance(ctx, rep, opt, output)
}
ignoreConf, err := result.ParseIgnoreFile(ctx, opt.IgnoreFile)
if err != nil {
return xerrors.Errorf("%s error: %w", opt.IgnoreFile, err)
}
var filtered []types.Result
// filter results
for _, resultsAtTime := range rep.Results {
for _, res := range resultsAtTime.Results {
resCopy := res
if err := result.FilterResult(ctx, &resCopy, ignoreConf, opt.FilterOpts()); err != nil {
return err
}
sort.Slice(resCopy.Misconfigurations, func(i, j int) bool {
return resCopy.Misconfigurations[i].CauseMetadata.Resource < resCopy.Misconfigurations[j].CauseMetadata.Resource
})
filtered = append(filtered, resCopy)
}
}
sort.Slice(filtered, func(i, j int) bool {
return filtered[i].Target < filtered[j].Target
})
base := types.Report{
CreatedAt: clock.Now(ctx),
ArtifactName: rep.AccountID,
ArtifactType: artifact.TypeAWSAccount,
Results: filtered,
}
switch opt.Format {
case tableFormat:
// ensure color/formatting is disabled for pipes/non-pty
var useANSI bool
if output == os.Stdout {
if o, err := os.Stdout.Stat(); err == nil {
useANSI = (o.Mode() & os.ModeCharDevice) == os.ModeCharDevice
}
}
if !useANSI {
tml.DisableFormatting()
}
switch {
case len(opt.Services) == 1 && opt.ARN == "":
if err := writeResourceTable(rep, filtered, output, opt.Services[0]); err != nil {
return err
}
case len(opt.Services) == 1 && opt.ARN != "":
if err := writeResultsForARN(rep, filtered, output, opt.Services[0], opt.ARN, opt.Severities); err != nil {
return err
}
default:
if err := writeServiceTable(rep, filtered, output); err != nil {
return err
}
}
// render cache info
if fromCache {
_ = tml.Fprintf(output, "\n<blue>This scan report was loaded from cached results. If you'd like to run a fresh scan, use --update-cache.</blue>\n")
}
return nil
default:
return pkgReport.Write(ctx, base, opt)
}
}
func writeCompliance(ctx context.Context, rep *Report, opt flag.Options, output io.Writer) error {
var crr []types.Results
for _, r := range rep.Results {
crr = append(crr, r.Results)
}
complianceReport, err := cr.BuildComplianceReport(crr, opt.Compliance)
if err != nil {
return xerrors.Errorf("compliance report build error: %w", err)
}
return cr.Write(ctx, complianceReport, cr.Option{
Format: opt.Format,
Report: opt.ReportFormat,
Output: output,
})
}

View File

@@ -1,88 +0,0 @@
package report
import (
"fmt"
"io"
"sort"
"strconv"
"golang.org/x/term"
"github.com/aquasecurity/table"
"github.com/aquasecurity/tml"
pkgReport "github.com/aquasecurity/trivy/pkg/report/table"
"github.com/aquasecurity/trivy/pkg/types"
)
type sortableRow struct {
name string
counts map[string]int
}
func writeResourceTable(report *Report, results types.Results, output io.Writer, service string) error {
termWidth, _, err := term.GetSize(0)
if err != nil {
termWidth = 80
}
maxWidth := termWidth - 48
if maxWidth < 20 {
maxWidth = 20
}
t := table.New(output)
t.SetColumnMaxWidth(maxWidth)
t.SetHeaders("Resource", "Misconfigurations")
t.AddHeaders("Resource", "Critical", "High", "Medium", "Low", "Unknown")
t.SetHeaderVerticalAlignment(table.AlignBottom)
t.SetHeaderAlignment(table.AlignLeft, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignCenter)
t.SetAlignment(table.AlignLeft, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight)
t.SetRowLines(false)
t.SetAutoMergeHeaders(true)
t.SetHeaderColSpans(0, 1, 5)
// map resource -> severity -> count
grouped := make(map[string]map[string]int)
for _, result := range results {
for _, misconfiguration := range result.Misconfigurations {
if misconfiguration.CauseMetadata.Service != service {
continue
}
if _, ok := grouped[misconfiguration.CauseMetadata.Resource]; !ok {
grouped[misconfiguration.CauseMetadata.Resource] = make(map[string]int)
}
grouped[misconfiguration.CauseMetadata.Resource][misconfiguration.Severity]++
}
}
var sortable []sortableRow
for resource, severityCounts := range grouped {
sortable = append(sortable, sortableRow{
name: resource,
counts: severityCounts,
})
}
sort.Slice(sortable, func(i, j int) bool { return sortable[i].name < sortable[j].name })
for _, row := range sortable {
t.AddRow(
row.name,
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["CRITICAL"]), "CRITICAL"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["HIGH"]), "HIGH"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["MEDIUM"]), "MEDIUM"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["LOW"]), "LOW"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["UNKNOWN"]), "UNKNOWN"),
)
}
// render scan title
_ = tml.Fprintf(output, "\n<bold>Resource Summary for Service '%s' (%s Account %s)</bold>\n", service, report.Provider, report.AccountID)
// render table
if len(sortable) > 0 {
t.Render()
} else {
_, _ = fmt.Fprint(output, "\nNo problems detected.\n")
}
return nil
}

View File

@@ -1,124 +0,0 @@
package report
import (
"bytes"
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/flag"
)
func Test_ResourceReport(t *testing.T) {
tests := []struct {
name string
options flag.Options
fromCache bool
expected string
}{
{
name: "simple table output",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
AWSOptions: flag.AWSOptions{
Services: []string{"s3"},
},
},
fromCache: false,
expected: `
Resource Summary for Service 's3' (AWS Account )
┌─────────────────────────────────────────┬──────────────────────────────────────────┐
│ │ Misconfigurations │
│ ├──────────┬──────┬────────┬─────┬─────────┤
│ Resource │ Critical │ High │ Medium │ Low │ Unknown │
├─────────────────────────────────────────┼──────────┼──────┼────────┼─────┼─────────┤
│ arn:aws:s3:us-east-1:1234567890:bucket1 │ 0 │ 1 │ 0 │ 0 │ 0 │
│ arn:aws:s3:us-east-1:1234567890:bucket2 │ 0 │ 2 │ 0 │ 0 │ 0 │
└─────────────────────────────────────────┴──────────┴──────┴────────┴─────┴─────────┘
`,
},
{
name: "results from cache",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
AWSOptions: flag.AWSOptions{
Services: []string{"s3"},
},
},
fromCache: true,
expected: `
Resource Summary for Service 's3' (AWS Account )
┌─────────────────────────────────────────┬──────────────────────────────────────────┐
│ │ Misconfigurations │
│ ├──────────┬──────┬────────┬─────┬─────────┤
│ Resource │ Critical │ High │ Medium │ Low │ Unknown │
├─────────────────────────────────────────┼──────────┼──────┼────────┼─────┼─────────┤
│ arn:aws:s3:us-east-1:1234567890:bucket1 │ 0 │ 1 │ 0 │ 0 │ 0 │
│ arn:aws:s3:us-east-1:1234567890:bucket2 │ 0 │ 2 │ 0 │ 0 │ 0 │
└─────────────────────────────────────────┴──────────┴──────┴────────┴─────┴─────────┘
This scan report was loaded from cached results. If you'd like to run a fresh scan, use --update-cache.
`,
},
{
name: "no problems",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
},
},
AWSOptions: flag.AWSOptions{
Services: []string{"s3"},
},
},
fromCache: false,
expected: `
Resource Summary for Service 's3' (AWS Account )
No problems detected.
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
report := New(
"AWS",
tt.options.AWSOptions.Account,
tt.options.AWSOptions.Region,
createTestResults(),
tt.options.AWSOptions.Services,
)
output := bytes.NewBuffer(nil)
tt.options.SetOutputWriter(output)
require.NoError(t, Write(context.Background(), report, tt.options, tt.fromCache))
assert.Equal(t, "AWS", report.Provider)
assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID)
assert.Equal(t, tt.options.AWSOptions.Region, report.Region)
assert.ElementsMatch(t, tt.options.AWSOptions.Services, report.ServicesInScope)
assert.Equal(t, tt.expected, output.String())
})
}
}

View File

@@ -1,35 +0,0 @@
package report
import (
"fmt"
"io"
"github.com/aquasecurity/tml"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
renderer "github.com/aquasecurity/trivy/pkg/report/table"
"github.com/aquasecurity/trivy/pkg/types"
)
func writeResultsForARN(report *Report, results types.Results, output io.Writer, service, arn string, severities []dbTypes.Severity) error {
// render scan title
_ = tml.Fprintf(output, "\n<bold>Results for '%s' (%s Account %s)</bold>\n\n", arn, report.Provider, report.AccountID)
for _, result := range results {
var filtered []types.DetectedMisconfiguration
for _, misconfiguration := range result.Misconfigurations {
if arn != "" && misconfiguration.CauseMetadata.Resource != arn {
continue
}
if service != "" && misconfiguration.CauseMetadata.Service != service {
continue
}
filtered = append(filtered, misconfiguration)
}
if len(filtered) > 0 {
_, _ = fmt.Fprint(output, renderer.NewMisconfigRenderer(result, severities, false, false, true).Render())
}
}
return nil
}

View File

@@ -1,83 +0,0 @@
package report
import (
"bytes"
"context"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/flag"
)
func Test_ARNReport(t *testing.T) {
tests := []struct {
name string
options flag.Options
fromCache bool
expected string
}{
{
name: "simple output",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
AWSOptions: flag.AWSOptions{
Services: []string{"s3"},
ARN: "arn:aws:s3:us-east-1:1234567890:bucket1",
Account: "1234567890",
},
},
fromCache: false,
expected: `
Results for 'arn:aws:s3:us-east-1:1234567890:bucket1' (AWS Account 1234567890)
arn:aws:s3:us-east-1:1234567890:bucket1 (cloud)
Tests: 1 (SUCCESSES: 0, FAILURES: 1, EXCEPTIONS: 0)
Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
HIGH: something failed
════════════════════════════════════════
Bad stuff is... bad
See https://avd.aquasec.com/misconfig/avd-aws-9999
────────────────────────────────────────
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
report := New(
"AWS",
tt.options.AWSOptions.Account,
tt.options.AWSOptions.Region,
createTestResults(),
tt.options.AWSOptions.Services,
)
output := bytes.NewBuffer(nil)
tt.options.SetOutputWriter(output)
require.NoError(t, Write(context.Background(), report, tt.options, tt.fromCache))
assert.Equal(t, "AWS", report.Provider)
assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID)
assert.Equal(t, tt.options.AWSOptions.Region, report.Region)
assert.ElementsMatch(t, tt.options.AWSOptions.Services, report.ServicesInScope)
assert.Equal(t, tt.expected, strings.ReplaceAll(output.String(), "\r\n", "\n"))
})
}
}

View File

@@ -1,85 +0,0 @@
package report
import (
"fmt"
"io"
"sort"
"strconv"
"time"
"github.com/aquasecurity/table"
"github.com/aquasecurity/tml"
pkgReport "github.com/aquasecurity/trivy/pkg/report/table"
"github.com/aquasecurity/trivy/pkg/types"
)
func writeServiceTable(report *Report, results types.Results, output io.Writer) error {
t := table.New(output)
t.SetHeaders("Service", "Misconfigurations", "Last Scanned")
t.AddHeaders("Service", "Critical", "High", "Medium", "Low", "Unknown", "Last Scanned")
t.SetRowLines(false)
t.SetHeaderVerticalAlignment(table.AlignBottom)
t.SetHeaderAlignment(table.AlignLeft, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignLeft)
t.SetAlignment(table.AlignLeft, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignLeft)
t.SetAutoMergeHeaders(true)
t.SetHeaderColSpans(0, 1, 5, 1)
// map service -> severity -> count
grouped := make(map[string]map[string]int)
// set zero counts for all services
for _, service := range report.ServicesInScope {
grouped[service] = make(map[string]int)
}
for _, result := range results {
for _, misconfiguration := range result.Misconfigurations {
service := misconfiguration.CauseMetadata.Service
if _, ok := grouped[service]; !ok {
grouped[service] = make(map[string]int)
}
grouped[service][misconfiguration.Severity]++
}
}
var sortable []sortableRow
for service, severityCounts := range grouped {
sortable = append(sortable, sortableRow{
name: service,
counts: severityCounts,
})
}
sort.Slice(sortable, func(i, j int) bool { return sortable[i].name < sortable[j].name })
for _, row := range sortable {
var lastScanned string
scanAgo := time.Since(report.Results[row.name].CreationTime).Truncate(time.Minute)
switch {
case scanAgo.Hours() >= 48:
lastScanned = fmt.Sprintf("%d days ago", int(scanAgo.Hours()/24))
case scanAgo.Hours() > 1:
lastScanned = fmt.Sprintf("%d hours ago", int(scanAgo.Hours()))
case scanAgo.Minutes() > 1:
lastScanned = fmt.Sprintf("%d minutes ago", int(scanAgo.Minutes()))
default:
lastScanned = "just now"
}
t.AddRow(
row.name,
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["CRITICAL"]), "CRITICAL"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["HIGH"]), "HIGH"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["MEDIUM"]), "MEDIUM"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["LOW"]), "LOW"),
pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["UNKNOWN"]), "UNKNOWN"),
lastScanned,
)
}
// render scan title
_ = tml.Fprintf(output, "\n<bold>Scan Overview for %s Account %s</bold>\n", report.Provider, report.AccountID)
// render table
t.Render()
return nil
}

View File

@@ -1,420 +0,0 @@
package report
import (
"bytes"
"context"
"testing"
"time"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/iac/scan"
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
)
func Test_ServiceReport(t *testing.T) {
tests := []struct {
name string
options flag.Options
fromCache bool
expected string
}{
{
name: "simple table output",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
},
fromCache: false,
expected: `
Scan Overview for AWS Account
┌─────────┬──────────────────────────────────────────────────┬──────────────┐
│ │ Misconfigurations │ │
│ ├──────────┬──────────────┬────────┬─────┬─────────┤ │
│ Service │ Critical │ High │ Medium │ Low │ Unknown │ Last Scanned │
├─────────┼──────────┼──────────────┼────────┼─────┼─────────┼──────────────┤
│ ec2 │ 0 │ 1 │ 0 │ 0 │ 0 │ just now │
│ s3 │ 0 │ 3 │ 0 │ 0 │ 0 │ just now │
└─────────┴──────────┴──────────────┴────────┴─────┴─────────┴──────────────┘
`,
},
{
name: "results from cache",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
},
fromCache: true,
expected: `
Scan Overview for AWS Account
┌─────────┬──────────────────────────────────────────────────┬──────────────┐
│ │ Misconfigurations │ │
│ ├──────────┬──────────────┬────────┬─────┬─────────┤ │
│ Service │ Critical │ High │ Medium │ Low │ Unknown │ Last Scanned │
├─────────┼──────────┼──────────────┼────────┼─────┼─────────┼──────────────┤
│ ec2 │ 0 │ 1 │ 0 │ 0 │ 0 │ just now │
│ s3 │ 0 │ 3 │ 0 │ 0 │ 0 │ just now │
└─────────┴──────────┴──────────────┴────────┴─────┴─────────┴──────────────┘
This scan report was loaded from cached results. If you'd like to run a fresh scan, use --update-cache.
`,
},
{
name: "filter severities",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityMedium,
},
},
AWSOptions: flag.AWSOptions{
Services: []string{
"s3",
"ec2",
},
},
},
fromCache: false,
expected: `
Scan Overview for AWS Account
┌─────────┬──────────────────────────────────────────────────┬──────────────┐
│ │ Misconfigurations │ │
│ ├──────────┬──────────────┬────────┬─────┬─────────┤ │
│ Service │ Critical │ High │ Medium │ Low │ Unknown │ Last Scanned │
├─────────┼──────────┼──────────────┼────────┼─────┼─────────┼──────────────┤
│ ec2 │ 0 │ 0 │ 0 │ 0 │ 0 │ just now │
│ s3 │ 0 │ 0 │ 0 │ 0 │ 0 │ just now │
└─────────┴──────────┴──────────────┴────────┴─────┴─────────┴──────────────┘
`,
},
{
name: "scoped services without results",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: tableFormat,
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
AWSOptions: flag.AWSOptions{
Services: []string{
"ec2",
"s3",
"iam",
},
},
},
fromCache: false,
expected: `
Scan Overview for AWS Account
┌─────────┬──────────────────────────────────────────────────┬──────────────┐
│ │ Misconfigurations │ │
│ ├──────────┬──────────────┬────────┬─────┬─────────┤ │
│ Service │ Critical │ High │ Medium │ Low │ Unknown │ Last Scanned │
├─────────┼──────────┼──────────────┼────────┼─────┼─────────┼──────────────┤
│ ec2 │ 0 │ 1 │ 0 │ 0 │ 0 │ just now │
│ iam │ 0 │ 0 │ 0 │ 0 │ 0 │ just now │
│ s3 │ 0 │ 3 │ 0 │ 0 │ 0 │ just now │
└─────────┴──────────┴──────────────┴────────┴─────┴─────────┴──────────────┘
`,
},
{
name: "json output",
options: flag.Options{
ReportOptions: flag.ReportOptions{
Format: "json",
Severities: []types.Severity{
types.SeverityLow,
types.SeverityMedium,
types.SeverityHigh,
types.SeverityCritical,
},
},
},
fromCache: false,
expected: `{
"CreatedAt": "2021-08-25T12:20:30.000000005Z",
"ArtifactType": "aws_account",
"Metadata": {
"ImageConfig": {
"architecture": "",
"created": "0001-01-01T00:00:00Z",
"os": "",
"rootfs": {
"type": "",
"diff_ids": null
},
"config": {}
}
},
"Results": [
{
"Target": "arn:aws:ec2:us-east-1:1234567890:instance1",
"Class": "config",
"Type": "cloud",
"MisconfSummary": {
"Successes": 0,
"Failures": 1,
"Exceptions": 0
},
"Misconfigurations": [
{
"Type": "AWS",
"ID": "AVD-AWS-9999",
"AVDID": "AVD-AWS-9999",
"Title": "Do not use bad stuff",
"Description": "Bad stuff is... bad",
"Message": "instance is bad",
"Resolution": "Remove bad stuff",
"Severity": "HIGH",
"PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-9999",
"References": [
"https://avd.aquasec.com/misconfig/avd-aws-9999"
],
"Status": "FAIL",
"Layer": {},
"CauseMetadata": {
"Resource": "arn:aws:ec2:us-east-1:1234567890:instance1",
"Provider": "AWS",
"Service": "ec2",
"Code": {
"Lines": null
}
}
}
]
},
{
"Target": "arn:aws:s3:us-east-1:1234567890:bucket1",
"Class": "config",
"Type": "cloud",
"MisconfSummary": {
"Successes": 0,
"Failures": 1,
"Exceptions": 0
},
"Misconfigurations": [
{
"Type": "AWS",
"ID": "AVD-AWS-9999",
"AVDID": "AVD-AWS-9999",
"Title": "Do not use bad stuff",
"Description": "Bad stuff is... bad",
"Message": "something failed",
"Resolution": "Remove bad stuff",
"Severity": "HIGH",
"PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-9999",
"References": [
"https://avd.aquasec.com/misconfig/avd-aws-9999"
],
"Status": "FAIL",
"Layer": {},
"CauseMetadata": {
"Resource": "arn:aws:s3:us-east-1:1234567890:bucket1",
"Provider": "AWS",
"Service": "s3",
"Code": {
"Lines": null
}
}
}
]
},
{
"Target": "arn:aws:s3:us-east-1:1234567890:bucket2",
"Class": "config",
"Type": "cloud",
"MisconfSummary": {
"Successes": 0,
"Failures": 2,
"Exceptions": 0
},
"Misconfigurations": [
{
"Type": "AWS",
"ID": "AVD-AWS-9999",
"AVDID": "AVD-AWS-9999",
"Title": "Do not use bad stuff",
"Description": "Bad stuff is... bad",
"Message": "something else failed",
"Resolution": "Remove bad stuff",
"Severity": "HIGH",
"PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-9999",
"References": [
"https://avd.aquasec.com/misconfig/avd-aws-9999"
],
"Status": "FAIL",
"Layer": {},
"CauseMetadata": {
"Resource": "arn:aws:s3:us-east-1:1234567890:bucket2",
"Provider": "AWS",
"Service": "s3",
"Code": {
"Lines": null
}
}
},
{
"Type": "AWS",
"ID": "AVD-AWS-9999",
"AVDID": "AVD-AWS-9999",
"Title": "Do not use bad stuff",
"Description": "Bad stuff is... bad",
"Message": "something else failed again",
"Resolution": "Remove bad stuff",
"Severity": "HIGH",
"PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-9999",
"References": [
"https://avd.aquasec.com/misconfig/avd-aws-9999"
],
"Status": "FAIL",
"Layer": {},
"CauseMetadata": {
"Resource": "arn:aws:s3:us-east-1:1234567890:bucket2",
"Provider": "AWS",
"Service": "s3",
"Code": {
"Lines": null
}
}
}
]
},
{
"Target": "arn:aws:s3:us-east-1:1234567890:bucket3",
"Class": "config",
"Type": "cloud",
"MisconfSummary": {
"Successes": 1,
"Failures": 0,
"Exceptions": 0
}
}
]
}`,
},
}
ctx := clock.With(context.Background(), time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
report := New(
"AWS",
tt.options.AWSOptions.Account,
tt.options.AWSOptions.Region,
createTestResults(),
tt.options.AWSOptions.Services,
)
output := bytes.NewBuffer(nil)
tt.options.SetOutputWriter(output)
require.NoError(t, Write(ctx, report, tt.options, tt.fromCache))
assert.Equal(t, "AWS", report.Provider)
assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID)
assert.Equal(t, tt.options.AWSOptions.Region, report.Region)
assert.ElementsMatch(t, tt.options.AWSOptions.Services, report.ServicesInScope)
if tt.options.Format == "json" {
// json output can be formatted/ordered differently - we just care that the data matches
assert.JSONEq(t, tt.expected, output.String())
} else {
assert.Equal(t, tt.expected, output.String())
}
})
}
}
func createTestResults() scan.Results {
baseRule := scan.Rule{
AVDID: "AVD-AWS-9999",
Aliases: []string{"AWS999"},
ShortCode: "no-bad-stuff",
Summary: "Do not use bad stuff",
Explanation: "Bad stuff is... bad",
Impact: "Bad things",
Resolution: "Remove bad stuff",
Provider: "AWS",
Severity: "HIGH",
}
var s3Results scan.Results
s3Results.Add(
"something failed",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket1",
}).String()),
)
s3Results.Add(
"something else failed",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket2",
}).String()),
)
s3Results.Add(
"something else failed again",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket2",
}).String()),
)
s3Results.AddPassed(
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "s3",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "bucket3",
}).String()),
)
baseRule.Service = "s3"
s3Results.SetRule(baseRule)
var ec2Results scan.Results
ec2Results.Add(
"instance is bad",
iacTypes.NewRemoteMetadata((arn.ARN{
Partition: "aws",
Service: "ec2",
Region: "us-east-1",
AccountID: "1234567890",
Resource: "instance1",
}).String()),
)
baseRule.Service = "ec2"
ec2Results.SetRule(baseRule)
return append(s3Results, ec2Results...)
}

View File

@@ -7,16 +7,12 @@ import (
"fmt"
"io"
"os"
"sort"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/xerrors"
awsScanner "github.com/aquasecurity/trivy-aws/pkg/scanner"
awscommands "github.com/aquasecurity/trivy/pkg/cloud/aws/commands"
"github.com/aquasecurity/trivy/pkg/commands/artifact"
"github.com/aquasecurity/trivy/pkg/commands/convert"
"github.com/aquasecurity/trivy/pkg/commands/server"
@@ -97,7 +93,7 @@ func NewApp() *cobra.Command {
NewKubernetesCommand(globalFlags),
NewSBOMCommand(globalFlags),
NewVersionCommand(globalFlags),
NewAWSCommand(globalFlags),
NewAWSCommand(),
NewVMCommand(globalFlags),
)
@@ -1019,77 +1015,11 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
return cmd
}
func NewAWSCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
reportFlagGroup := flag.NewReportFlagGroup()
compliance := flag.ComplianceFlag
compliance.Values = []string{
types.ComplianceAWSCIS12,
types.ComplianceAWSCIS14,
}
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
reportFlagGroup.ShowSuppressed = nil // disable '--show-suppressed'
awsFlags := &flag.Flags{
GlobalFlagGroup: globalFlags,
AWSFlagGroup: flag.NewAWSFlagGroup(),
CloudFlagGroup: flag.NewCloudFlagGroup(),
MisconfFlagGroup: flag.NewMisconfFlagGroup(),
RegoFlagGroup: flag.NewRegoFlagGroup(),
ReportFlagGroup: reportFlagGroup,
}
services := awsScanner.AllSupportedServices()
sort.Strings(services)
func NewAWSCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "aws [flags]",
Aliases: []string{},
GroupID: groupScanning,
Args: cobra.ExactArgs(0),
Short: "[EXPERIMENTAL] Scan AWS account",
Long: fmt.Sprintf(`Scan an AWS account for misconfigurations. Trivy uses the same authentication methods as the AWS CLI. See https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
The following services are supported:
- %s
`, strings.Join(services, "\n- ")),
Example: ` # basic scanning
$ trivy aws --region us-east-1
# limit scan to a single service:
$ trivy aws --region us-east-1 --service s3
# limit scan to multiple services:
$ trivy aws --region us-east-1 --service s3 --service ec2
# force refresh of cache for fresh results
$ trivy aws --region us-east-1 --update-cache
`,
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := awsFlags.Bind(cmd); err != nil {
return xerrors.Errorf("flag bind error: %w", err)
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
opts, err := awsFlags.ToOptions(args)
if err != nil {
return xerrors.Errorf("flag error: %w", err)
}
if opts.Timeout < time.Hour {
opts.Timeout = time.Hour
log.Info("Timeout is set to less than 1 hour - upgrading to 1 hour for this command.")
}
return awscommands.Run(cmd.Context(), opts)
},
SilenceErrors: true,
SilenceUsage: true,
Deprecated: "Trivy AWS is now available as an optional plugin. See github.com/aquasecurity/trivy-aws for details",
Use: "aws [flags]",
}
cmd.SetFlagErrorFunc(flagErrorFunc)
awsFlags.AddFlags(cmd)
cmd.SetUsageTemplate(fmt.Sprintf(usageTemplate, awsFlags.Usages(cmd)))
return cmd
}