(cloudwatch) assume role support (#5065)

* (cloudwatch) assume role support

* save godep

* (cloudwatch) add assumeRoleArn field

* (cloudwatch) set cred provider for sts

* (cloudwatch) fix test
This commit is contained in:
Mitsuhiro Tanda
2016-05-18 07:54:24 +02:00
committed by Torkel Ödegaard
parent fc1891320e
commit 07d355851e
11 changed files with 1604 additions and 44 deletions
+81 -32
View File
@@ -4,6 +4,8 @@ import (
"encoding/json"
"errors"
"io/ioutil"
"strings"
"sync"
"time"
"github.com/aws/aws-sdk-go/aws"
@@ -14,6 +16,8 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
@@ -44,31 +48,96 @@ func init() {
}
}
var awsCredentials map[string]*credentials.Credentials = make(map[string]*credentials.Credentials)
type cache struct {
credential *credentials.Credentials
expiration *time.Time
}
func getCredentials(profile string) *credentials.Credentials {
if _, ok := awsCredentials[profile]; ok {
return awsCredentials[profile]
var awsCredentialCache map[string]cache = make(map[string]cache)
var credentialCacheLock sync.RWMutex
func getCredentials(profile string, region string, assumeRoleArn string) *credentials.Credentials {
credentialCacheLock.RLock()
if _, ok := awsCredentialCache[profile]; ok {
if awsCredentialCache[profile].expiration != nil &&
(*awsCredentialCache[profile].expiration).After(time.Now().UTC()) {
result := awsCredentialCache[profile].credential
credentialCacheLock.RUnlock()
return result
}
}
credentialCacheLock.RUnlock()
accessKeyId := ""
secretAccessKey := ""
sessionToken := ""
var expiration *time.Time
expiration = nil
if strings.Index(assumeRoleArn, "arn:aws:iam:") == 0 {
params := &sts.AssumeRoleInput{
RoleArn: aws.String(assumeRoleArn),
RoleSessionName: aws.String("GrafanaSession"),
DurationSeconds: aws.Int64(900),
}
stsSess := session.New()
stsCreds := credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: profile},
&ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(stsSess), ExpiryWindow: 5 * time.Minute},
})
stsConfig := &aws.Config{
Region: aws.String(region),
Credentials: stsCreds,
}
svc := sts.New(session.New(stsConfig), stsConfig)
resp, err := svc.AssumeRole(params)
if err != nil {
// ignore
log.Error(3, "CloudWatch: Failed to assume role", err)
}
if resp.Credentials != nil {
accessKeyId = *resp.Credentials.AccessKeyId
secretAccessKey = *resp.Credentials.SecretAccessKey
sessionToken = *resp.Credentials.SessionToken
expiration = resp.Credentials.Expiration
}
}
sess := session.New()
creds := credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.StaticProvider{Value: credentials.Value{
AccessKeyID: accessKeyId,
SecretAccessKey: secretAccessKey,
SessionToken: sessionToken,
}},
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: profile},
&ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
})
awsCredentials[profile] = creds
credentialCacheLock.Lock()
awsCredentialCache[profile] = cache{
credential: creds,
expiration: expiration,
}
credentialCacheLock.Unlock()
return creds
}
func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
func getAwsConfig(req *cwRequest) *aws.Config {
assumeRoleArn := req.DataSource.JsonData.Get("assumeRoleArn").MustString()
cfg := &aws.Config{
Region: aws.String(req.Region),
Credentials: getCredentials(req.DataSource.Database),
Credentials: getCredentials(req.DataSource.Database, req.Region, assumeRoleArn),
}
return cfg
}
func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
cfg := getAwsConfig(req)
svc := cloudwatch.New(session.New(cfg), cfg)
reqParam := &struct {
@@ -104,11 +173,7 @@ func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
}
func handleListMetrics(req *cwRequest, c *middleware.Context) {
cfg := &aws.Config{
Region: aws.String(req.Region),
Credentials: getCredentials(req.DataSource.Database),
}
cfg := getAwsConfig(req)
svc := cloudwatch.New(session.New(cfg), cfg)
reqParam := &struct {
@@ -144,11 +209,7 @@ func handleListMetrics(req *cwRequest, c *middleware.Context) {
}
func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
cfg := &aws.Config{
Region: aws.String(req.Region),
Credentials: getCredentials(req.DataSource.Database),
}
cfg := getAwsConfig(req)
svc := cloudwatch.New(session.New(cfg), cfg)
reqParam := &struct {
@@ -187,11 +248,7 @@ func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
}
func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
cfg := &aws.Config{
Region: aws.String(req.Region),
Credentials: getCredentials(req.DataSource.Database),
}
cfg := getAwsConfig(req)
svc := cloudwatch.New(session.New(cfg), cfg)
reqParam := &struct {
@@ -227,11 +284,7 @@ func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
}
func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) {
cfg := &aws.Config{
Region: aws.String(req.Region),
Credentials: getCredentials(req.DataSource.Database),
}
cfg := getAwsConfig(req)
svc := cloudwatch.New(session.New(cfg), cfg)
reqParam := &struct {
@@ -263,11 +316,7 @@ func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) {
}
func handleDescribeInstances(req *cwRequest, c *middleware.Context) {
cfg := &aws.Config{
Region: aws.String(req.Region),
Credentials: getCredentials(req.DataSource.Database),
}
cfg := getAwsConfig(req)
svc := ec2.New(session.New(cfg), cfg)
reqParam := &struct {