feat(misconf): Support skipping services (#4686)

* feat(misconf): Add support for `--skip-service` flag.

Fixes: https://github.com/aquasecurity/trivy/issues/4619
Signed-off-by: Simar <simar@linux.com>

* update docs

Signed-off-by: Simar <simar@linux.com>

* update go mod

* refactor processOptions to reduce cyclo complexity

Signed-off-by: Simar <simar@linux.com>

* fix a bug with multiple skip services

Signed-off-by: Simar <simar@linux.com>

* refactor tests

Signed-off-by: Simar <simar@linux.com>

* use x/slice and x/xerrors

Signed-off-by: Simar <simar@linux.com>

* go mod tidy

* lint

---------

Signed-off-by: Simar <simar@linux.com>
This commit is contained in:
simar7
2023-06-26 05:11:59 -06:00
committed by GitHub
parent 46e784c8a9
commit 5d73b47dbc
6 changed files with 1369 additions and 410 deletions

View File

@@ -92,6 +92,7 @@ trivy aws [flags]
--service strings Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc. --service strings Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc.
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") -s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
--skip-policy-update skip fetching rego policy updates --skip-policy-update skip fetching rego policy 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 -t, --template string output template
--tf-vars strings specify paths to override the Terraform tfvars files --tf-vars strings specify paths to override the Terraform tfvars files
--trace enable more verbose trace output for custom queries --trace enable more verbose trace output for custom queries

View File

@@ -3,9 +3,10 @@ package commands
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"strings" "strings"
"golang.org/x/exp/slices"
"github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/aws-sdk-go-v2/service/sts"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@@ -22,6 +23,8 @@ import (
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
) )
var allSupportedServicesFunc = awsScanner.AllSupportedServices
func getAccountIDAndRegion(ctx context.Context, region string) (string, string, error) { func getAccountIDAndRegion(ctx context.Context, region string) (string, string, error) {
log.Logger.Debug("Looking for AWS credentials provider...") log.Logger.Debug("Looking for AWS credentials provider...")
@@ -38,16 +41,31 @@ func getAccountIDAndRegion(ctx context.Context, region string) (string, string,
log.Logger.Debug("Looking up AWS caller identity...") log.Logger.Debug("Looking up AWS caller identity...")
result, err := svc.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}) result, err := svc.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
if err != nil { if err != nil {
return "", "", fmt.Errorf("failed to discover AWS caller identity: %w", err) return "", "", xerrors.Errorf("failed to discover AWS caller identity: %w", err)
} }
if result.Account == nil { if result.Account == nil {
return "", "", fmt.Errorf("missing account id for aws account") return "", "", xerrors.Errorf("missing account id for aws account")
} }
log.Logger.Debugf("Verified AWS credentials for account %s!", *result.Account) log.Logger.Debugf("Verified AWS credentials for account %s!", *result.Account)
return *result.Account, cfg.Region, nil 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 { 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 // support comma separated services too
var splitServices []string var splitServices []string
for _, service := range opt.Services { for _, service := range opt.Services {
@@ -55,8 +73,14 @@ func processOptions(ctx context.Context, opt *flag.Options) error {
} }
opt.Services = splitServices 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 != "" { if len(opt.Services) != 1 && opt.ARN != "" {
return fmt.Errorf("you must specify the single --service which the --arn relates to") return xerrors.Errorf("you must specify the single --service which the --arn relates to")
} }
if opt.Account == "" || opt.Region == "" { if opt.Account == "" || opt.Region == "" {
@@ -67,14 +91,34 @@ func processOptions(ctx context.Context, opt *flag.Options) error {
} }
} }
if len(opt.Services) == 0 { err := filterServices(opt)
if err != nil {
return err
}
log.Logger.Debug("scanning services: ", opt.Services)
return nil
}
func filterServices(opt *flag.Options) error {
if len(opt.Services) == 0 && len(opt.SkipServices) == 0 {
log.Logger.Debug("No service(s) specified, scanning all services...") log.Logger.Debug("No service(s) specified, scanning all services...")
opt.Services = awsScanner.AllSupportedServices() opt.Services = allSupportedServicesFunc()
} else { } else if len(opt.SkipServices) > 0 {
log.Logger.Debug("excluding 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)
}
}
} else if len(opt.Services) > 0 {
log.Logger.Debugf("Specific services were requested: [%s]...", strings.Join(opt.Services, ", ")) log.Logger.Debugf("Specific services were requested: [%s]...", strings.Join(opt.Services, ", "))
for _, service := range opt.Services { for _, service := range opt.Services {
var found bool var found bool
supported := awsScanner.AllSupportedServices() supported := allSupportedServicesFunc()
for _, allowed := range supported { for _, allowed := range supported {
if allowed == service { if allowed == service {
found = true found = true
@@ -82,11 +126,10 @@ func processOptions(ctx context.Context, opt *flag.Options) error {
} }
} }
if !found { if !found {
return fmt.Errorf("service '%s' is not currently supported - supported services are: %s", service, strings.Join(supported, ", ")) return xerrors.Errorf("service '%s' is not currently supported - supported services are: %s", service, strings.Join(supported, ", "))
} }
} }
} }
return nil return nil
} }
@@ -96,7 +139,7 @@ func Run(ctx context.Context, opt flag.Options) error {
defer cancel() defer cancel()
if err := log.InitLogger(opt.Debug, false); err != nil { if err := log.InitLogger(opt.Debug, false); err != nil {
return fmt.Errorf("logger error: %w", err) return xerrors.Errorf("logger error: %w", err)
} }
var err error var err error
@@ -118,7 +161,7 @@ func Run(ctx context.Context, opt flag.Options) error {
log.Logger.Warnf("Adapter error: %s", e) log.Logger.Warnf("Adapter error: %s", e)
} }
} else { } else {
return fmt.Errorf("aws scan error: %w", err) return xerrors.Errorf("aws scan error: %w", err)
} }
} }
@@ -149,7 +192,7 @@ func Run(ctx context.Context, opt flag.Options) error {
r := report.New(cloud.ProviderAWS, opt.Account, opt.Region, res, opt.Services) r := report.New(cloud.ProviderAWS, opt.Account, opt.Region, res, opt.Services)
if err := report.Write(r, opt, cached); err != nil { if err := report.Write(r, opt, cached); err != nil {
return fmt.Errorf("unable to write results: %w", err) return xerrors.Errorf("unable to write results: %w", err)
} }
operation.Exit(opt, r.Failed()) operation.Exit(opt, r.Failed())

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -19,6 +19,12 @@ var (
Value: []string{}, Value: []string{},
Usage: "Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc.", Usage: "Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc.",
} }
awsSkipServicesFlag = Flag{
Name: "skip-service",
ConfigName: "cloud.aws.skip-service",
Value: []string{},
Usage: "Skip selected AWS Service(s) specified with this flag. Can specify multiple services using --skip-service A --skip-service B etc.",
}
awsAccountFlag = Flag{ awsAccountFlag = Flag{
Name: "account", Name: "account",
ConfigName: "cloud.aws.account", ConfigName: "cloud.aws.account",
@@ -34,28 +40,31 @@ var (
) )
type AWSFlagGroup struct { type AWSFlagGroup struct {
Region *Flag Region *Flag
Endpoint *Flag Endpoint *Flag
Services *Flag Services *Flag
Account *Flag SkipServices *Flag
ARN *Flag Account *Flag
ARN *Flag
} }
type AWSOptions struct { type AWSOptions struct {
Region string Region string
Endpoint string Endpoint string
Services []string Services []string
Account string SkipServices []string
ARN string Account string
ARN string
} }
func NewAWSFlagGroup() *AWSFlagGroup { func NewAWSFlagGroup() *AWSFlagGroup {
return &AWSFlagGroup{ return &AWSFlagGroup{
Region: &awsRegionFlag, Region: &awsRegionFlag,
Endpoint: &awsEndpointFlag, Endpoint: &awsEndpointFlag,
Services: &awsServiceFlag, Services: &awsServiceFlag,
Account: &awsAccountFlag, SkipServices: &awsSkipServicesFlag,
ARN: &awsARNFlag, Account: &awsAccountFlag,
ARN: &awsARNFlag,
} }
} }
@@ -64,15 +73,16 @@ func (f *AWSFlagGroup) Name() string {
} }
func (f *AWSFlagGroup) Flags() []*Flag { func (f *AWSFlagGroup) Flags() []*Flag {
return []*Flag{f.Region, f.Endpoint, f.Services, f.Account, f.ARN} return []*Flag{f.Region, f.Endpoint, f.Services, f.SkipServices, f.Account, f.ARN}
} }
func (f *AWSFlagGroup) ToOptions() AWSOptions { func (f *AWSFlagGroup) ToOptions() AWSOptions {
return AWSOptions{ return AWSOptions{
Region: getString(f.Region), Region: getString(f.Region),
Endpoint: getString(f.Endpoint), Endpoint: getString(f.Endpoint),
Services: getStringSlice(f.Services), Services: getStringSlice(f.Services),
Account: getString(f.Account), SkipServices: getStringSlice(f.SkipServices),
ARN: getString(f.ARN), Account: getString(f.Account),
ARN: getString(f.ARN),
} }
} }