From 0f252dfd98eb7d758368b9fca01607eeaca28ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Carpintero?= Date: Tue, 3 Dec 2024 17:00:07 +0100 Subject: [PATCH] Allow aws checks to use existing credentials without assumerole --- cmd/vulcan-aws-alerts/main.go | 96 +++----------- cmd/vulcan-aws-alerts/rds.go | 91 ++++++------- cmd/vulcan-aws-trusted-advisor/main.go | 123 ++---------------- cmd/vulcan-prowler/Dockerfile | 2 +- cmd/vulcan-prowler/main.go | 131 ++++--------------- cmd/vulcan-prowler/prowler.go | 14 +- go.mod | 23 ++-- go.sum | 113 +++++++++++----- internal/awshelpers/awshelpers.go | 171 +++++++++++++++++++++++++ 9 files changed, 371 insertions(+), 393 deletions(-) create mode 100644 internal/awshelpers/awshelpers.go diff --git a/cmd/vulcan-aws-alerts/main.go b/cmd/vulcan-aws-alerts/main.go index 5d5345f10..ca71971a9 100644 --- a/cmd/vulcan-aws-alerts/main.go +++ b/cmd/vulcan-aws-alerts/main.go @@ -5,104 +5,44 @@ Copyright 2020 Adevinta package main import ( - "bytes" "context" - "encoding/json" "fmt" - "io" - "net/http" "os" - "github.com/aws/aws-sdk-go/aws/credentials" - check "github.com/adevinta/vulcan-check-sdk" - "github.com/adevinta/vulcan-check-sdk/helpers" checkstate "github.com/adevinta/vulcan-check-sdk/state" + "github.com/adevinta/vulcan-checks/internal/awshelpers" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/arn" ) -var ( - checkName = "vulcan-aws-alerts" - logger = check.NewCheckLog(checkName) -) +var checkName = "vulcan-aws-alerts" func main() { run := func(ctx context.Context, target, assetType, optJSON string, state checkstate.State) error { - if target == "" { - return fmt.Errorf("check target missing") - } + logger := check.NewCheckLog(checkName) - vulcanAssumeRoleEndpoint := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") - if vulcanAssumeRoleEndpoint == "" { - return fmt.Errorf("VULCAN_ASSUME_ROLE_ENDPOINT option is missing") - } - roleName := os.Getenv("ROLE_NAME") - - isReachable, err := helpers.IsReachable(target, assetType, - helpers.NewAWSCreds(vulcanAssumeRoleEndpoint, roleName)) + parsedARN, err := arn.Parse(target) if err != nil { - logger.Warnf("Can not check asset reachability: %v", err) - } - if !isReachable { - return checkstate.ErrAssetUnreachable + return fmt.Errorf("unable to parse ARN: %w", err) } + assumeRoleEndpoint := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") + roleName := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") - parsedARN, err := arn.Parse(target) + var cfg aws.Config + if assumeRoleEndpoint == "" { + cfg, err = awshelpers.GetAwsConfig(target, roleName, 3600) + } else { + cfg, err = awshelpers.GetAwsConfigWithVulcanAssumeRole(assumeRoleEndpoint, parsedARN.AccountID, roleName, 3600) + + } if err != nil { - return err + logger.Errorf("unable to get AWS config: %v", err) + return checkstate.ErrAssetUnreachable } - return caCertificateRotation(parsedARN.AccountID, vulcanAssumeRoleEndpoint, roleName, state) + return caCertificateRotation(logger, cfg, parsedARN.AccountID, state) } c := check.NewCheckFromHandler(checkName, run) c.RunAndServe() } - -// AssumeRoleResponse represent a response from vulcan-assume-role -type AssumeRoleResponse struct { - AccessKey string `json:"access_key"` - SecretAccessKey string `json:"secret_access_key"` - SessionToken string `json:"session_token"` -} - -func getCredentials(url string, accountID, role string) (*credentials.Credentials, error) { - m := map[string]string{"account_id": accountID} - if role != "" { - m["role"] = role - } - jsonBody, err := json.Marshal(m) - if err != nil { - return nil, err - } - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/json") - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - logger.Errorf("cannot do request: %s", err.Error()) - return nil, err - } - defer resp.Body.Close() - - assumeRoleResponse := AssumeRoleResponse{} - buf, err := io.ReadAll(resp.Body) - if err != nil { - logger.Errorf("Cannot read request body %s", err.Error()) - return nil, err - } - - err = json.Unmarshal(buf, &assumeRoleResponse) - if err != nil { - logger.Errorf("Cannot decode request %s", err.Error()) - logger.Errorf("RequestBody: %s", string(buf)) - return nil, err - } - - return credentials.NewStaticCredentials( - assumeRoleResponse.AccessKey, - assumeRoleResponse.SecretAccessKey, - assumeRoleResponse.SessionToken), nil -} diff --git a/cmd/vulcan-aws-alerts/rds.go b/cmd/vulcan-aws-alerts/rds.go index 8f31ef291..a79024309 100644 --- a/cmd/vulcan-aws-alerts/rds.go +++ b/cmd/vulcan-aws-alerts/rds.go @@ -9,35 +9,27 @@ import ( "fmt" report "github.com/adevinta/vulcan-report" + "github.com/sirupsen/logrus" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/rds" "github.com/adevinta/vulcan-check-sdk/helpers" "github.com/adevinta/vulcan-check-sdk/state" ) -func caCertificateRotation(target string, vulcanAssumeRoleEndpoint string, roleName string, state state.State) error { - sess, err := session.NewSession(&aws.Config{}) - if err != nil { - return err - } - - creds, err := getCredentials(vulcanAssumeRoleEndpoint, target, roleName) - if err != nil { - return err - } - +func caCertificateRotation(logger *logrus.Entry, cfg aws.Config, target string, state state.State) error { // Iterate over all AWS regions where RDS is available + // TODO: Looks there is no replacemente for this on aws-sdk-go-v2. + var err error for region := range endpoints.AwsPartition().Services()[endpoints.RdsServiceID].Regions() { - sess.Config.Region = aws.String(region) - s := rds.New(sess, &aws.Config{Credentials: creds}) + cfg.Region = region + rdsClient := rds.NewFromConfig(cfg) ctx := context.Background() logger.Info(fmt.Sprintf("Describing pending maintenance actions on RDS for %s region", region)) - result, err := s.DescribePendingMaintenanceActionsWithContext(ctx, &rds.DescribePendingMaintenanceActionsInput{}) + result, err := rdsClient.DescribePendingMaintenanceActions(ctx, &rds.DescribePendingMaintenanceActionsInput{}) if err != nil { logger.Error(err) continue @@ -49,52 +41,49 @@ func caCertificateRotation(target string, vulcanAssumeRoleEndpoint string, roleN for _, action := range result.PendingMaintenanceActions { for _, details := range action.PendingMaintenanceActionDetails { if *details.Action == "ca-certificate-rotation" { - result, err := s.DescribeDBInstancesWithContext( + result, err := rdsClient.DescribeDBInstances( ctx, &rds.DescribeDBInstancesInput{ DBInstanceIdentifier: action.ResourceIdentifier, }) if err != nil { - logger.Error(err) + logger.Info(err) continue } for _, instance := range result.DBInstances { - if instance != nil { - state.AddVulnerabilities( - report.Vulnerability{ - AffectedResource: aws.StringValue(instance.DBInstanceArn), - Labels: []string{"issue"}, - Fingerprint: helpers.ComputeFingerprint(details.AutoAppliedAfterDate), - Summary: `Managed AWS databases using CA about to expire`, - Score: report.SeverityThresholdHigh, - Description: `Due to the expiration of the AWS RDS CA, and to prevent downtime ` + - `in your applications, you should add the new CA to your clients using a ` + - `managed (i.e. RDS or Aurora) database through SSL/TLS and perform maintenance ` + - `on the affected database instances before the certificate expiration date.`, - References: []string{"https://aws.amazon.com/blogs/database/amazon-rds-customers-update-your-ssl-tls-certificates-by-february-5-2020/"}, - Resources: []report.ResourcesGroup{ - { - Name: `Instances`, - Header: []string{"Identifier", "Account", "Region", "DBName", "Engine", "ARN", "AutoAppliedAfterDate", "CurrentApplyDate"}, - Rows: []map[string]string{ - { - "AutoAppliedAfterDate": aws.TimeValue(details.AutoAppliedAfterDate).String(), - "CurrentApplyDate": aws.TimeValue(details.CurrentApplyDate).String(), - "Identifier": aws.StringValue(instance.DBInstanceIdentifier), - "Account": target, - "Region": region, - "DBName": aws.StringValue(instance.DBName), - "Engine": aws.StringValue(instance.Engine), - "ARN": aws.StringValue(instance.DBInstanceArn), - }, + state.AddVulnerabilities( + report.Vulnerability{ + AffectedResource: aws.ToString(instance.DBInstanceArn), + Labels: []string{"issue"}, + Fingerprint: helpers.ComputeFingerprint(details.AutoAppliedAfterDate), + Summary: `Managed AWS databases using CA about to expire`, + Score: report.SeverityThresholdHigh, + Description: `Due to the expiration of the AWS RDS CA, and to prevent downtime ` + + `in your applications, you should add the new CA to your clients using a ` + + `managed (i.e. RDS or Aurora) database through SSL/TLS and perform maintenance ` + + `on the affected database instances before the certificate expiration date.`, + References: []string{"https://aws.amazon.com/blogs/database/amazon-rds-customers-update-your-ssl-tls-certificates-by-february-5-2020/"}, + Resources: []report.ResourcesGroup{ + { + Name: `Instances`, + Header: []string{"Identifier", "Account", "Region", "DBName", "Engine", "ARN", "AutoAppliedAfterDate", "CurrentApplyDate"}, + Rows: []map[string]string{ + { + "AutoAppliedAfterDate": aws.ToTime(details.AutoAppliedAfterDate).String(), + "CurrentApplyDate": aws.ToTime(details.CurrentApplyDate).String(), + "Identifier": aws.ToString(instance.DBInstanceIdentifier), + "Account": target, + "Region": region, + "DBName": aws.ToString(instance.DBName), + "Engine": aws.ToString(instance.Engine), + "ARN": aws.ToString(instance.DBInstanceArn), }, }, }, - }) - } else { - logger.Warn("Received nil instance from DescribeDBInstancesWithContext") - } + }, + }) + } } } diff --git a/cmd/vulcan-aws-trusted-advisor/main.go b/cmd/vulcan-aws-trusted-advisor/main.go index d57498f49..c52679c03 100644 --- a/cmd/vulcan-aws-trusted-advisor/main.go +++ b/cmd/vulcan-aws-trusted-advisor/main.go @@ -4,13 +4,9 @@ Copyright 2019 Adevinta package main import ( - "bytes" "context" "encoding/json" - "errors" "fmt" - "io" - "net/http" "os" "regexp" "strings" @@ -19,14 +15,11 @@ import ( check "github.com/adevinta/vulcan-check-sdk" "github.com/adevinta/vulcan-check-sdk/helpers" checkstate "github.com/adevinta/vulcan-check-sdk/state" + "github.com/adevinta/vulcan-checks/internal/awshelpers" report "github.com/adevinta/vulcan-report" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/arn" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/credentials" - "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/aws-sdk-go-v2/service/support" "github.com/sirupsen/logrus" ) @@ -106,43 +99,23 @@ func extractLinesFromHTML(htmlText string) []string { } func scanAccount(opt options, target, _ string, logger *logrus.Entry, state checkstate.State) error { - assumeRoleEndpoint := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") - role := os.Getenv("ROLE_NAME") - parsedARN, err := arn.Parse(target) if err != nil { - return err + return fmt.Errorf("unable to parse ARN: %w", err) } + assumeRoleEndpoint := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") + roleName := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") + var cfg aws.Config - if assumeRoleEndpoint != "" { - creds, err := getCredentials(assumeRoleEndpoint, parsedARN.AccountID, role, logger) - if err != nil { - if errors.Is(err, errNoCredentials) { - return checkstate.ErrAssetUnreachable - } - return err - } - credsProvider := credentials.NewStaticCredentialsProvider(creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken) - cfg, err = config.LoadDefaultConfig(context.Background(), - config.WithRegion("us-east-1"), - config.WithCredentialsProvider(credsProvider), - ) - if err != nil { - return fmt.Errorf("unable to create AWS config: %w", err) - } + if assumeRoleEndpoint == "" { + cfg, err = awshelpers.GetAwsConfig(target, roleName, 3600) } else { - // try to access with the default credentials - cfg, err = config.LoadDefaultConfig(context.Background(), config.WithRegion("us-east-1")) - if err != nil { - return fmt.Errorf("unable to create AWS config: %w", err) - } - } + cfg, err = awshelpers.GetAwsConfigWithVulcanAssumeRole(assumeRoleEndpoint, parsedARN.AccountID, roleName, 3600) - // Validate that the account id in the target ARN matches the account id in the credentials - if req, err := sts.NewFromConfig(cfg).GetCallerIdentity(context.TODO(), &sts.GetCallerIdentityInput{}); err != nil { - return fmt.Errorf("unable to get caller identity: %w", err) - } else if *req.Account != parsedARN.AccountID { - return fmt.Errorf("account id in target ARN does not match the account id in the credentials (target ARN: %s, credentials account id: %s)", parsedARN.AccountID, *req.Account) + } + if err != nil { + logger.Errorf("unable to get AWS config: %v", err) + return checkstate.ErrAssetUnreachable } s := support.NewFromConfig(cfg) @@ -311,7 +284,7 @@ func scanAccount(opt options, target, _ string, logger *logrus.Entry, state chec } // Get the alias of the account only if we did not get previously. if alias == nil { - res, err := accountAlias(cfg) + res, err := awshelpers.GetAcountAlias(cfg) if err != nil { return err } @@ -397,73 +370,3 @@ func scanAccount(opt options, target, _ string, logger *logrus.Entry, state chec } return err } - -// AssumeRoleResponse represent a response from vulcan-assume-role -type AssumeRoleResponse struct { - AccessKey string `json:"access_key"` - SecretAccessKey string `json:"secret_access_key"` - SessionToken string `json:"session_token"` -} - -var errNoCredentials = errors.New("unable to decode credentials") - -func getCredentials(url string, accountID, role string, logger *logrus.Entry) (*aws.Credentials, error) { - m := map[string]any{"account_id": accountID, "duration": 3600} - if role != "" { - m["role"] = role - } - jsonBody, err := json.Marshal(m) - if err != nil { - return nil, fmt.Errorf("unable to marshal assume role request body for account %s: %w", accountID, err) - } - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) - if err != nil { - return nil, fmt.Errorf("unable to create request for the assume role service: %w", err) - } - req.Header.Set("Content-Type", "application/json") - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - logger.Errorf("cannot do request: %s", err.Error()) - return nil, err - } - defer resp.Body.Close() // nolint - - assumeRoleResponse := AssumeRoleResponse{} - buf, err := io.ReadAll(resp.Body) - if err != nil { - logger.Errorf("can not read request body %s", err.Error()) - return nil, err - } - - err = json.Unmarshal(buf, &assumeRoleResponse) - if err != nil { - logger.Errorf("Cannot decode request: %s", err.Error()) - logger.Errorf("ResponseBody: %s", string(buf)) - return nil, errNoCredentials - } - return &aws.Credentials{ - AccessKeyID: assumeRoleResponse.AccessKey, - SecretAccessKey: assumeRoleResponse.SecretAccessKey, - SessionToken: assumeRoleResponse.SessionToken, - }, nil -} - -// accountAlias gets one of the current aliases of the account that the -// credentials passed belong to. -func accountAlias(cfg aws.Config) (string, error) { - svc := iam.NewFromConfig(cfg) - resp, err := svc.ListAccountAliases(context.Background(), &iam.ListAccountAliasesInput{}) - if err != nil { - return "", err - } - if len(resp.AccountAliases) == 0 { - // No aliases found for the aws account. - return "", nil - } - if len(resp.AccountAliases) < 1 { - return "", errors.New("no result getting aliases for aws account") - } - a := resp.AccountAliases[0] - return a, nil -} diff --git a/cmd/vulcan-prowler/Dockerfile b/cmd/vulcan-prowler/Dockerfile index c15b19b17..c550db9f5 100644 --- a/cmd/vulcan-prowler/Dockerfile +++ b/cmd/vulcan-prowler/Dockerfile @@ -6,7 +6,7 @@ FROM toniblyx/prowler:2.12.1 ENTRYPOINT ["/usr/bin/env"] # Copy CIS controls info file -COPY cis_controls.json cis_controls.json +COPY cis_controls.json /prowler/cis_controls.json # Install check ARG TARGETOS TARGETARCH diff --git a/cmd/vulcan-prowler/main.go b/cmd/vulcan-prowler/main.go index df941c147..3ed60bd0e 100644 --- a/cmd/vulcan-prowler/main.go +++ b/cmd/vulcan-prowler/main.go @@ -5,26 +5,21 @@ Copyright 2020 Adevinta package main import ( - "bytes" "context" "encoding/json" "errors" "fmt" - "io" - "net/http" "os" "sort" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" check "github.com/adevinta/vulcan-check-sdk" "github.com/adevinta/vulcan-check-sdk/helpers" checkstate "github.com/adevinta/vulcan-check-sdk/state" + "github.com/adevinta/vulcan-checks/internal/awshelpers" report "github.com/adevinta/vulcan-report" ) @@ -34,9 +29,6 @@ const ( defaultAPIRegion = `eu-west-1` defaultSessionDuration = 3600 // 1 hour. - envEndpoint = `VULCAN_ASSUME_ROLE_ENDPOINT` - envRole = `ROLE_NAME` - envKeyID = `AWS_ACCESS_KEY_ID` envKeySecret = `AWS_SECRET_ACCESS_KEY` envToken = `AWS_SESSION_TOKEN` @@ -206,46 +198,41 @@ func buildOptions(optJSON string) (options, error) { func main() { run := func(ctx context.Context, target, assetType, optJSON string, state checkstate.State) error { - if target == "" { - return errors.New("check target missing") - } parsedARN, err := arn.Parse(target) if err != nil { - return err + return fmt.Errorf("unable to parse ARN: %w", err) } + assumeRoleEndpoint := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") + roleName := os.Getenv("VULCAN_ASSUME_ROLE_ENDPOINT") - opts, err := buildOptions(optJSON) - if err != nil { - return err - } + var cfg aws.Config + if assumeRoleEndpoint == "" { + cfg, err = awshelpers.GetAwsConfig(target, roleName, 3600) + } else { + cfg, err = awshelpers.GetAwsConfigWithVulcanAssumeRole(assumeRoleEndpoint, parsedARN.AccountID, roleName, 3600) - endpoint := os.Getenv(envEndpoint) - if endpoint == "" { - return fmt.Errorf("%s env var must have a non-empty value", envEndpoint) } - role := os.Getenv(envRole) - - logger.Infof("using endpoint '%s' and role '%s'", endpoint, role) - - isReachable, err := helpers.IsReachable(target, assetType, - helpers.NewAWSCreds(endpoint, role)) if err != nil { - logger.Warnf("Can not check asset reachability: %v", err) - } - if !isReachable { + logger.Errorf("unable to get AWS config: %v", err) return checkstate.ErrAssetUnreachable } - if err := loadCredentials(endpoint, parsedARN.AccountID, role, opts.SessionDuration); err != nil { - return fmt.Errorf("can not get credentials for the role '%s' from the endpoint '%s': %w", endpoint, role, err) + creds, err := cfg.Credentials.Retrieve(context.Background()) + if err != nil { + return fmt.Errorf("unable to get AWS credentials: %w", err) } - alias, err := accountAlias(credentials.NewEnvCredentials()) + alias, err := awshelpers.GetAcountAlias(cfg) if err != nil { - return fmt.Errorf("can not retrieve account alias: %w", err) + return err } - logger.Infof("account alias: '%s'", alias) + + opts, err := buildOptions(optJSON) + if err != nil { + return err + } + groups, err := groupsFromOpts(opts) if err != nil { return err @@ -260,7 +247,7 @@ func main() { if err != nil { return err } - r, err := runProwler(ctx, opts.Region, groups) + r, err := runProwler(ctx, logger, creds, opts.Region, groups) if err != nil { return err } @@ -450,73 +437,3 @@ func parseControl(raw string) (control string, description string, err error) { description = strings.Replace(parts[1], "(Scored)", "", -1) return } - -type assumeRoleResponse struct { - AccessKey string `json:"access_key"` - SecretAccessKey string `json:"secret_access_key"` - SessionToken string `json:"session_token"` -} - -func loadCredentials(url string, accountID, role string, sessionDuration int) error { - m := map[string]interface{}{"account_id": accountID} - if role != "" { - m["role"] = role - } - if sessionDuration != 0 { - m["duration"] = sessionDuration - } - jsonBody, err := json.Marshal(m) - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) - req.Header.Set("Content-Type", "application/json") - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - buf, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - var r assumeRoleResponse - err = json.Unmarshal(buf, &r) - if err != nil { - logger.Errorf("can not decode response body '%s'", string(buf)) - return err - } - - if err := os.Setenv(envKeyID, r.AccessKey); err != nil { - return err - } - - if err := os.Setenv(envKeySecret, r.SecretAccessKey); err != nil { - return err - } - - if err := os.Setenv(envToken, r.SessionToken); err != nil { - return err - } - - return nil -} - -// accountAlias gets one of the current aliases for the account that the -// credentials passed belong to. -func accountAlias(creds *credentials.Credentials) (string, error) { - svc := iam.New(session.New(&aws.Config{Credentials: creds})) - resp, err := svc.ListAccountAliases(&iam.ListAccountAliasesInput{}) - if err != nil { - return "", err - } - if len(resp.AccountAliases) == 0 { - logger.Warn("No aliases found for the account") - return "", nil - } - a := resp.AccountAliases[0] - if a == nil { - return "", errors.New("unexpected nil getting aliases for aws account") - } - return *a, nil -} diff --git a/cmd/vulcan-prowler/prowler.go b/cmd/vulcan-prowler/prowler.go index fdaaa0695..3afae4845 100644 --- a/cmd/vulcan-prowler/prowler.go +++ b/cmd/vulcan-prowler/prowler.go @@ -13,6 +13,8 @@ import ( "strings" "github.com/adevinta/vulcan-check-sdk/helpers/command" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/sirupsen/logrus" ) const ( @@ -62,7 +64,7 @@ func buildParams(region string, groups []string) []string { return params } -func runProwler(ctx context.Context, region string, groups []string) (*prowlerReport, error) { +func runProwler(ctx context.Context, logger *logrus.Entry, cfg aws.Credentials, region string, groups []string) (*prowlerReport, error) { logger.Infof("using region: %+v, and groups: %+v", region, groups) params := buildParams(region, groups) @@ -72,6 +74,16 @@ func runProwler(ctx context.Context, region string, groups []string) (*prowlerRe } logger.Infof("prowler version: %s", version) + // TODO: Pass env to toe command.Execute function when it is implemented by vulcan-check-sdk + // env := []string{ + // fmt.Sprintf("%s=%s", envKeyID, cfg.AccessKeyID), + // fmt.Sprintf("%s=%s", envKeySecret, cfg.SecretAccessKey), + // fmt.Sprintf("%s=%s", envToken, cfg.SessionToken), + // } + // output, status, err := command.ExecuteEnvs(ctx, logger, env, prowlerCmd, params...) + os.Setenv(envKeyID, cfg.AccessKeyID) + os.Setenv(envKeySecret, cfg.SecretAccessKey) + os.Setenv(envToken, cfg.SessionToken) output, status, err := command.Execute(ctx, logger, prowlerCmd, params...) if err != nil { return nil, err diff --git a/go.mod b/go.mod index 67e50ec5a..d781dc159 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.29.0 github.com/aws/aws-sdk-go-v2/credentials v1.17.53 github.com/aws/aws-sdk-go-v2/service/iam v1.38.2 + github.com/aws/aws-sdk-go-v2/service/rds v1.92.0 github.com/aws/aws-sdk-go-v2/service/sts v1.33.8 github.com/aws/aws-sdk-go-v2/service/support v1.26.7 github.com/cenkalti/backoff/v4 v4.3.0 @@ -34,10 +35,10 @@ require ( require ( cloud.google.com/go/compute v1.23.4 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - dario.cat/mergo v1.0.0 // indirect github.com/BurntSushi/toml v1.2.1 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v1.1.3 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230411080316-8b3893ee7fca // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.24 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 // indirect @@ -47,14 +48,13 @@ require ( github.com/aws/aws-sdk-go-v2/service/sso v1.24.10 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.9 // indirect github.com/aws/smithy-go v1.22.1 // indirect - github.com/cloudflare/circl v1.3.7 // indirect - github.com/cyphar/filepath-securejoin v0.2.5 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.6.0 // indirect - github.com/go-git/go-git/v5 v5.13.0 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.4.1 // indirect + github.com/go-git/go-git/v5 v5.6.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -63,6 +63,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/imdario/mergo v0.3.15 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -71,9 +72,9 @@ require ( github.com/miekg/dns v1.1.62 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect - github.com/skeema/knownhosts v1.3.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/skeema/knownhosts v1.1.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect diff --git a/go.sum b/go.sum index 3c9143dad..898671b3b 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,6 @@ cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wv cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -13,10 +11,13 @@ github.com/FiloSottile/Heartbleed v0.2.1-0.20150408030656-4a3332ca1dc0/go.mod h1 github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= -github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/ProtonMail/go-crypto v0.0.0-20230411080316-8b3893ee7fca h1:3N4LNZ++dKh8SXcBRsT6P6mxhDm5swmkgmahlIS9yb0= +github.com/ProtonMail/go-crypto v0.0.0-20230411080316-8b3893ee7fca/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/adevinta/restuss v1.1.0 h1:ufdZrDEaPfY43xNvkughifyybEJ31mN8X5qUvnZp32A= github.com/adevinta/restuss v1.1.0/go.mod h1:W4IeLE5TV42aNW+4YHlxQSe3gv2dx8wKPDt3gS/OMCo= github.com/adevinta/vulcan-check-sdk v1.3.0 h1:nZ1oS0ftjM/yqN1pldbCpWVhm+cdbqQ5+8owcVXactw= @@ -53,6 +54,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhv github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9 h1:TQmKDyETFGiXVhZfQ/I0cCFziqqX58pi4tKJGYGFSz0= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9/go.mod h1:HVLPK2iHQBUx7HfZeOQSEu3v2ubZaAY2YPbAm5/WUyY= +github.com/aws/aws-sdk-go-v2/service/rds v1.92.0 h1:W0gUYAjO24u/M6tpR041wMHJWGzleOhxtCnNLImdrZs= +github.com/aws/aws-sdk-go-v2/service/rds v1.92.0/go.mod h1:ADD2uROOoEIXjbjDPEvDDZWnGmfKFYMddgKwG5RlBGw= github.com/aws/aws-sdk-go-v2/service/sso v1.24.10 h1:DyZUj3xSw3FR3TXSwDhPhuZkkT14QHBiacdbUVcD0Dg= github.com/aws/aws-sdk-go-v2/service/sso v1.24.10/go.mod h1:Ro744S4fKiCCuZECXgOi760TiYylUM8ZBf6OGiZzJtY= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.9 h1:I1TsPEs34vbpOnR81GIcAq4/3Ud+jRHVGwx6qLQUHLs= @@ -63,23 +66,21 @@ github.com/aws/aws-sdk-go-v2/service/support v1.26.7 h1:gpkRODbW+NVab3hpJq4VDLrn github.com/aws/aws-sdk-go-v2/service/support v1.26.7/go.mod h1:m4+I9KoS7f9TpWwWLd+G3mu02hEY3rcsMLjZPkxypmY= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= -github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug= -github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -88,16 +89,17 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= -github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= -github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E= -github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw= +github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= +github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= +github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= +github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= +github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk= +github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -128,6 +130,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= @@ -141,8 +144,12 @@ github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/ github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -154,6 +161,7 @@ github.com/jroimartin/sarif v0.1.0/go.mod h1:lD6QBiB8nZwpHJdBtpO25GGSwhYCABcTDwz github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -162,12 +170,14 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lair-framework/go-nmap v0.0.0-20191202052157-3507e0b03523 h1:N4NQR4on0n3Kc3xlBXUYzCZorFdordwkR2kcZMk9te0= github.com/lair-framework/go-nmap v0.0.0-20191202052157-3507e0b03523/go.mod h1:7Em1Lxm3DFdLvXWUZ6bQ/xIbGlxFy7jl07bziQMZ/kU= +github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 h1:YocNLcTBdEdvY3iDK6jfWXvEaM5OCKkjxPKoJRdB3Gg= github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= @@ -179,17 +189,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= -github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= +github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= +github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -199,8 +210,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yhat/scrape v0.0.0-20161128144610-24b7890b0945 h1:6Ju8pZBYFTN9FaV/JvNBiIHcsgEmP4z4laciqjfjY8E= @@ -218,19 +229,25 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -244,6 +261,11 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -253,24 +275,38 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -278,6 +314,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -287,6 +326,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -327,6 +368,7 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= @@ -334,11 +376,14 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/awshelpers/awshelpers.go b/internal/awshelpers/awshelpers.go new file mode 100644 index 000000000..8f0dab2b5 --- /dev/null +++ b/internal/awshelpers/awshelpers.go @@ -0,0 +1,171 @@ +package awshelpers + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/aws/aws-sdk-go/aws/arn" +) + +var errNoCredentials = errors.New("unable to decode credentials") + +// VulcanAssumeRoleProvider is a custom AWS credentials provider that assumes a role using the Vulcan assume role service. +type VulcanAssumeRoleProvider struct { + URL string + AccountID string + Role string + Duration int +} + +// NewVulcanAssumeRoleProvider creates a VulcanAssumeRoleProvider. +func NewVulcanAssumeRoleProvider(url, accountID, role string, duration int) *VulcanAssumeRoleProvider { + return &VulcanAssumeRoleProvider{ + URL: url, + AccountID: accountID, + Role: role, + Duration: duration, + } +} + +// Retrieve retrieves the credentials from the Vulcan assume role service. +func (p *VulcanAssumeRoleProvider) Retrieve(ctx context.Context) (aws.Credentials, error) { + var emptyCreds aws.Credentials + m := map[string]any{"account_id": p.AccountID, "duration": p.Duration} + if p.Role != "" { + m["role"] = p.Role + } + expires := time.Now().Add(time.Second * time.Duration(p.Duration)) + jsonBody, _ := json.Marshal(m) // nolint + req, err := http.NewRequest("POST", p.URL, bytes.NewBuffer(jsonBody)) + if err != nil { + return emptyCreds, fmt.Errorf("unable to create request for the assume role service: %w", err) + } + req.Header.Set("Content-Type", "application/json") + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return emptyCreds, fmt.Errorf("cannot do request: %w", err) + } + defer resp.Body.Close() // nolint + + type AssumeRoleResponse struct { + AccessKey string `json:"access_key"` + SecretAccessKey string `json:"secret_access_key"` + SessionToken string `json:"session_token"` + } + assumeRoleResponse := AssumeRoleResponse{} + buf, err := io.ReadAll(resp.Body) + if err != nil { + return emptyCreds, fmt.Errorf("can not read request body %w", err) + } + + err = json.Unmarshal(buf, &assumeRoleResponse) + if err != nil { + return emptyCreds, fmt.Errorf("cannot decode request: %s body: %s: %w", err.Error(), string(buf), errNoCredentials) + } + return aws.Credentials{ + Source: "VulcanAssumeRoleProvider", + AccessKeyID: assumeRoleResponse.AccessKey, + SecretAccessKey: assumeRoleResponse.SecretAccessKey, + SessionToken: assumeRoleResponse.SessionToken, + AccountID: p.AccountID, + CanExpire: true, + Expires: expires, + }, nil +} + +// GetAwsConfigWithVulcanAssumeRole returns an AWS config with the provided assume role endpoint, account ARN, role and duration. +func GetAwsConfigWithVulcanAssumeRole(assumeRoleEndpoint, accountArn, role string, duration int) (aws.Config, error) { + var cfg aws.Config + parsedARN, err := arn.Parse(accountArn) + if err != nil { + return cfg, err + } + cfg, err = config.LoadDefaultConfig( + context.Background(), + config.WithCredentialsProvider( + NewVulcanAssumeRoleProvider(assumeRoleEndpoint, parsedARN.AccountID, role, duration), + )) + if err != nil { + return cfg, fmt.Errorf("unable to create AWS config: %w", err) + } + // Validate that the account id in the target ARN matches the account id in the credentials + if req, err := sts.NewFromConfig(cfg).GetCallerIdentity(context.TODO(), &sts.GetCallerIdentityInput{}); err != nil { + return cfg, fmt.Errorf("unable to get caller identity: %w", err) + } else if *req.Account != parsedARN.AccountID { + return cfg, fmt.Errorf("account id in target ARN does not match the account id in the credentials (target ARN: %s, credentials account id: %s)", parsedARN.AccountID, *req.Account) + } + return cfg, nil +} + +// GetAwsConfig returns an AWS config with the provided account ARN and role. +// If role is not empty, the config will be created with the provided role and the specified duration. +func GetAwsConfig(accountArn, role string, duration int) (aws.Config, error) { + var cfg aws.Config + parsedARN, err := arn.Parse(accountArn) + if err != nil { + return cfg, err + } + + cfg, err = config.LoadDefaultConfig( + context.Background(), + config.WithRegion("us-east-1")) + if err != nil { + return cfg, fmt.Errorf("unable to create default AWS config: %w", err) + } + if role != "" { + cfg, err = config.LoadDefaultConfig( + context.Background(), + config.WithRegion("us-east-1"), + config.WithCredentialsProvider( + stscreds.NewAssumeRoleProvider( + sts.NewFromConfig(cfg), + fmt.Sprintf("arn:aws:iam::%s:role/%s", parsedARN.AccountID, role), + func(o *stscreds.AssumeRoleOptions) { + if duration != 0 { + o.Duration = time.Duration(duration) * time.Second + } + }, + ))) + } + if err != nil { + return cfg, fmt.Errorf("unable to create AWS config: %w", err) + } + // Validate that the account id in the target ARN matches the account id in the credentials + if req, err := sts.NewFromConfig(cfg).GetCallerIdentity(context.TODO(), &sts.GetCallerIdentityInput{}); err != nil { + return cfg, fmt.Errorf("unable to get caller identity: %w", err) + } else if *req.Account != parsedARN.AccountID { + return cfg, fmt.Errorf("account id in target ARN does not match the account id in the credentials (target ARN: %s, credentials account id: %s)", parsedARN.AccountID, *req.Account) + } + return cfg, nil +} + +// GetAcountAlias gets the first one of the current aliases for the account that the +// credentials passed belong to. +func GetAcountAlias(cfg aws.Config) (string, error) { + svc := iam.NewFromConfig(cfg) + resp, err := svc.ListAccountAliases(context.Background(), &iam.ListAccountAliasesInput{}) + if err != nil { + return "", err + } + if len(resp.AccountAliases) == 0 { + // No aliases found for the aws account. + return "", nil + } + if len(resp.AccountAliases) < 1 { + return "", errors.New("no result getting aliases for aws account") + } + a := resp.AccountAliases[0] + return a, nil +}