mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
BREAKING(aws): Deprecate trivy aws as subcmd in favour of a plugin (#6819)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
63
go.mod
@@ -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
123
go.sum
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
132
pkg/cloud/aws/cache/cache.go
vendored
132
pkg/cloud/aws/cache/cache.go
vendored
@@ -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)
|
||||
}
|
||||
@@ -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
8
pkg/cloud/aws/commands/testdata/.trivyignore
vendored
8
pkg/cloud/aws/commands/testdata/.trivyignore
vendored
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
261
pkg/cloud/aws/commands/testdata/s3onlycache.json
vendored
261
pkg/cloud/aws/commands/testdata/s3onlycache.json
vendored
@@ -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"
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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...")
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package cloud
|
||||
|
||||
const (
|
||||
ProviderAWS = "AWS"
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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...)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user