Skip to content

Commit

Permalink
Allow aws checks to use existing credentials without assumerole
Browse files Browse the repository at this point in the history
  • Loading branch information
jesusfcr committed Jan 20, 2025
1 parent 855d111 commit 0f252df
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 393 deletions.
96 changes: 18 additions & 78 deletions cmd/vulcan-aws-alerts/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
91 changes: 40 additions & 51 deletions cmd/vulcan-aws-alerts/rds.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
}
},
})

}
}
}
Expand Down
Loading

0 comments on commit 0f252df

Please sign in to comment.