Skip to content

Commit 39862e0

Browse files
author
Bryan Fang
committed
support multiple aws accounts with credentials
1 parent e7d41d3 commit 39862e0

File tree

5 files changed

+697
-50
lines changed

5 files changed

+697
-50
lines changed

cmd/aws_credentials.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cmd
2+
3+
type Account struct {
4+
AwsAccessKeyID string `mapstructure:"aws_access_key_id"`
5+
AwsSecretAccessKey string `mapstructure:"aws_secret_access_key"`
6+
Regions []string `yaml:"regions"`
7+
}
8+
9+
type AWSCredentials struct {
10+
Accounts []Account `yaml:"accounts"`
11+
}

cmd/helper.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"context"
55
"fmt"
66
"log/slog"
7+
"reflect"
78

89
"github.com/aws/aws-sdk-go-v2/aws"
910
"github.com/aws/aws-sdk-go-v2/config"
11+
"github.com/aws/aws-sdk-go-v2/credentials"
1012
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
1113
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
1214
"github.com/aws/aws-sdk-go-v2/service/sts"
@@ -54,3 +56,35 @@ func getAWSSessionInformation(cfg aws.Config) (string, string, error) {
5456

5557
return *output.Account, cfg.Region, nil
5658
}
59+
60+
func getAWSConfigurationByCredentials(logger *slog.Logger, configuration exporterConfig) ([]aws.Config, error) {
61+
var configs []aws.Config
62+
accountsFromYaml := configuration.AwsCredentials
63+
if reflect.ValueOf(accountsFromYaml).IsZero() {
64+
logger.Error("AWS accounts not configured in yaml")
65+
return nil, nil
66+
} else {
67+
accounts := accountsFromYaml.Accounts
68+
for _, c := range accounts {
69+
aws_access_key_id := c.AwsAccessKeyID
70+
aws_secret_access_key := c.AwsSecretAccessKey
71+
staticProvider := credentials.NewStaticCredentialsProvider(
72+
aws_access_key_id,
73+
aws_secret_access_key,
74+
"",
75+
)
76+
cfg, err := config.LoadDefaultConfig(
77+
context.Background(),
78+
config.WithCredentialsProvider(staticProvider),
79+
)
80+
if err != nil {
81+
return nil, err
82+
}
83+
for _, region := range c.Regions {
84+
cfg.Region = region
85+
configs = append(configs, cfg)
86+
}
87+
}
88+
}
89+
return configs, nil
90+
}

cmd/root.go

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const (
2828
)
2929

3030
var cfgFile string
31+
var actRegionClient []exporter.AccountRegionClients
3132

3233
type exporterConfig struct {
3334
Debug bool `mapstructure:"debug"`
@@ -46,6 +47,7 @@ type exporterConfig struct {
4647
CollectQuotas bool `mapstructure:"collect-quotas"`
4748
CollectUsages bool `mapstructure:"collect-usages"`
4849
OTELTracesEnabled bool `mapstructure:"enable-otel-traces"`
50+
AwsCredentials AWSCredentials
4951
}
5052

5153
func run(configuration exporterConfig) {
@@ -54,24 +56,6 @@ func run(configuration exporterConfig) {
5456
fmt.Println("ERROR: Fail to initialize logger: %w", err)
5557
panic(err)
5658
}
57-
58-
cfg, err := getAWSConfiguration(logger, configuration.AWSAssumeRoleArn, configuration.AWSAssumeRoleSession)
59-
if err != nil {
60-
logger.Error("can't initialize AWS configuration", "reason", err)
61-
os.Exit(awsErrorExitCode)
62-
}
63-
64-
awsAccountID, awsRegion, err := getAWSSessionInformation(cfg)
65-
if err != nil {
66-
logger.Error("can't identify AWS account and/or region", "reason", err)
67-
os.Exit(awsErrorExitCode)
68-
}
69-
70-
rdsClient := rds.NewFromConfig(cfg)
71-
ec2Client := ec2.NewFromConfig(cfg)
72-
cloudWatchClient := cloudwatch.NewFromConfig(cfg)
73-
servicequotasClient := servicequotas.NewFromConfig(cfg)
74-
7559
collectorConfiguration := exporter.Configuration{
7660
CollectInstanceMetrics: configuration.CollectInstanceMetrics,
7761
CollectInstanceTypes: configuration.CollectInstanceTypes,
@@ -82,16 +66,65 @@ func run(configuration exporterConfig) {
8266
CollectUsages: configuration.CollectUsages,
8367
}
8468

85-
collector := exporter.NewCollector(*logger, collectorConfiguration, awsAccountID, awsRegion, rdsClient, ec2Client, cloudWatchClient, servicequotasClient)
69+
cfgs, err := getAWSConfigurationByCredentials(logger, configuration)
70+
if err != nil {
71+
logger.Error("can't initialize AWS configuration", "reason", err)
72+
os.Exit(awsErrorExitCode)
73+
}
74+
if cfgs == nil {
75+
logger.Info("Didn't configure aws IAM User credentials in configuration file, will use default aws configuration")
76+
cfg, err := getAWSConfiguration(logger, configuration.AWSAssumeRoleArn, configuration.AWSAssumeRoleSession)
77+
if err != nil {
78+
logger.Error("can't initialize AWS configuration", "reason", err)
79+
os.Exit(awsErrorExitCode)
80+
}
81+
awsAccountID, awsRegion, err := getAWSSessionInformation(cfg)
82+
if err != nil {
83+
logger.Error("can't identify AWS account and/or region", "reason", err)
84+
os.Exit(awsErrorExitCode)
85+
}
86+
87+
rdsClient := rds.NewFromConfig(cfg)
88+
ec2Client := ec2.NewFromConfig(cfg)
89+
cloudWatchClient := cloudwatch.NewFromConfig(cfg)
90+
servicequotasClient := servicequotas.NewFromConfig(cfg)
91+
92+
collector := exporter.NewCollector(*logger, collectorConfiguration, awsAccountID, awsRegion, rdsClient, ec2Client, cloudWatchClient, servicequotasClient)
93+
94+
prometheus.MustRegister(collector)
8695

87-
prometheus.MustRegister(collector)
96+
} else {
97+
for _, cfg := range cfgs {
98+
awsAccountID, awsRegion, err := getAWSSessionInformation(cfg)
99+
if err != nil {
100+
logger.Error("can't identify AWS account and/or region", "reason", err)
101+
os.Exit(awsErrorExitCode)
102+
}
103+
104+
rdsClient := rds.NewFromConfig(cfg)
105+
ec2Client := ec2.NewFromConfig(cfg)
106+
cloudWatchClient := cloudwatch.NewFromConfig(cfg)
107+
servicequotasClient := servicequotas.NewFromConfig(cfg)
108+
109+
var accountRegionClients exporter.AccountRegionClients
110+
accountRegionClients.AwsAccountID = awsAccountID
111+
accountRegionClients.AwsRegion = awsRegion
112+
accountRegionClients.RdsClient = rdsClient
113+
accountRegionClients.Ec2Client = ec2Client
114+
accountRegionClients.CloudWatchClient = cloudWatchClient
115+
accountRegionClients.ServicequotasClient = servicequotasClient
116+
actRegionClient = append(actRegionClient, accountRegionClients)
117+
}
118+
collector := exporter.NewMultiCollector(*logger, collectorConfiguration, actRegionClient)
119+
prometheus.MustRegister(collector)
120+
}
88121

122+
// http configurations for exporter service
89123
serverConfiguration := http.Config{
90-
ListenAddress: configuration.ListenAddress,
91-
MetricPath: configuration.MetricPath,
92-
TLSCertPath: configuration.TLSCertPath,
93-
TLSKeyPath: configuration.TLSKeyPath,
94-
OTELTracesEnabled: configuration.OTELTracesEnabled,
124+
ListenAddress: configuration.ListenAddress,
125+
MetricPath: configuration.MetricPath,
126+
TLSCertPath: configuration.TLSCertPath,
127+
TLSKeyPath: configuration.TLSKeyPath,
95128
}
96129

97130
server := http.New(*logger, serverConfiguration)
@@ -118,6 +151,7 @@ func NewRootCommand() (*cobra.Command, error) {
118151

119152
return
120153
}
154+
viper.UnmarshalKey("accounts", &c.AwsCredentials.Accounts)
121155
run(c)
122156
},
123157
}

configs/prometheus-rds-exporter/prometheus-rds-exporter.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@
2727
#
2828
# AWS credentials
2929
#
30+
# accounts:
31+
# - aws_access_key_id: <placeholder>
32+
# aws_secret_access_key: <placeholder>
33+
# regions:
34+
# - ap-northeast-1
35+
# - eu-central-1
36+
# - us-east-1
3037

3138
# AWS IAM ARN role to assume to fetch metrics
3239
# aws-assume-role-arn: arn:aws:iam::000000000000:role/prometheus-rds-exporter

0 commit comments

Comments
 (0)