-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
Copy pathcredentials.go
166 lines (141 loc) · 6.51 KB
/
credentials.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
package aws
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/url"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
awssdk "github.com/aws/aws-sdk-go-v2/aws"
awsConfig "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/elastic/elastic-agent-libs/logp"
"github.com/elastic/elastic-agent-libs/transport/httpcommon"
"github.com/elastic/elastic-agent-libs/transport/tlscommon"
)
// OptionalGovCloudFIPS is a list of services on AWS GovCloud that is not FIPS by default.
// These services follow the standard <service name>-fips.<region>.amazonaws.com format.
var OptionalGovCloudFIPS = map[string]bool{
"s3": true,
}
// ConfigAWS is a structure defined for AWS credentials
type ConfigAWS struct {
AccessKeyID string `config:"access_key_id"`
SecretAccessKey string `config:"secret_access_key"`
SessionToken string `config:"session_token"`
ProfileName string `config:"credential_profile_name"`
SharedCredentialFile string `config:"shared_credential_file"`
Endpoint string `config:"endpoint"`
RoleArn string `config:"role_arn"`
ProxyUrl string `config:"proxy_url"`
FIPSEnabled bool `config:"fips_enabled"`
TLS *tlscommon.Config `config:"ssl" yaml:"ssl,omitempty" json:"ssl,omitempty"`
DefaultRegion string `config:"default_region"`
}
// InitializeAWSConfig function creates the awssdk.Config object from the provided config
func InitializeAWSConfig(beatsConfig ConfigAWS) (awssdk.Config, error) {
awsConfig, _ := GetAWSCredentials(beatsConfig)
if awsConfig.Region == "" {
if beatsConfig.DefaultRegion != "" {
awsConfig.Region = beatsConfig.DefaultRegion
} else {
awsConfig.Region = "us-east-1"
}
}
// Assume IAM role if iam_role config parameter is given
if beatsConfig.RoleArn != "" {
addAssumeRoleProviderToAwsConfig(beatsConfig, &awsConfig)
}
var proxy func(*http.Request) (*url.URL, error)
if beatsConfig.ProxyUrl != "" {
proxyUrl, err := httpcommon.NewProxyURIFromString(beatsConfig.ProxyUrl)
if err != nil {
return awsConfig, err
}
proxy = http.ProxyURL(proxyUrl.URI())
}
var tlsConfig *tls.Config
if beatsConfig.TLS != nil {
TLSConfig, _ := tlscommon.LoadTLSConfig(beatsConfig.TLS)
tlsConfig = TLSConfig.ToConfig()
}
awsConfig.HTTPClient = &http.Client{
Transport: &http.Transport{
Proxy: proxy,
TLSClientConfig: tlsConfig,
},
}
return awsConfig, nil
}
// GetAWSCredentials function gets aws credentials from the config.
// If access keys given, use them as credentials.
// If access keys are not given, then load from AWS config file. If credential_profile_name is not
// given, default profile will be used.
// If role_arn is given, assume the IAM role either with access keys or default profile.
func GetAWSCredentials(beatsConfig ConfigAWS) (awssdk.Config, error) {
// Check if accessKeyID or secretAccessKey or sessionToken is given from configuration
if beatsConfig.AccessKeyID != "" || beatsConfig.SecretAccessKey != "" || beatsConfig.SessionToken != "" {
return getConfigForKeys(beatsConfig), nil
}
return getConfigSharedCredentialProfile(beatsConfig)
}
// getConfigForKeys creates a default AWS config and adds a CredentialsProvider using the provided Beats config.
// Provided config must contain an accessKeyID, secretAccessKey and sessionToken to generate a valid CredentialsProfile
func getConfigForKeys(beatsConfig ConfigAWS) awssdk.Config {
config := awssdk.NewConfig()
awsCredentials := awssdk.Credentials{
AccessKeyID: beatsConfig.AccessKeyID,
SecretAccessKey: beatsConfig.SecretAccessKey,
}
if beatsConfig.SessionToken != "" {
awsCredentials.SessionToken = beatsConfig.SessionToken
}
addStaticCredentialsProviderToAwsConfig(beatsConfig, config)
return *config
}
// getConfigSharedCredentialProfile If accessKeyID, secretAccessKey or sessionToken is not given,
// then load from default config // Please see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
//
// with more details. If credential_profile_name is empty, then default profile is used.
func getConfigSharedCredentialProfile(beatsConfig ConfigAWS) (awssdk.Config, error) {
logger := logp.NewLogger("WithSharedConfigProfile")
var options []func(*awsConfig.LoadOptions) error
if beatsConfig.ProfileName != "" {
options = append(options, awsConfig.WithSharedConfigProfile(beatsConfig.ProfileName))
}
// If shared_credential_file is empty, then external.LoadDefaultAWSConfig
// function will load AWS config from current user's home directory.
// Linux/OSX: "$HOME/.aws/credentials"
// Windows: "%USERPROFILE%\.aws\credentials"
if beatsConfig.SharedCredentialFile != "" {
options = append(options, awsConfig.WithSharedConfigFiles([]string{beatsConfig.SharedCredentialFile}))
}
cfg, err := awsConfig.LoadDefaultConfig(context.TODO(), options...)
if err != nil {
return cfg, fmt.Errorf("awsConfig.LoadDefaultConfig failed with shared credential profile given: [%w]", err)
}
logger.Debug("Using shared credential profile for AWS credential")
return cfg, nil
}
// addAssumeRoleProviderToAwsConfig adds the credentials provider to the current AWS config by using the role ARN stored in Beats config
func addAssumeRoleProviderToAwsConfig(config ConfigAWS, awsConfig *awssdk.Config) {
logger := logp.NewLogger("addAssumeRoleProviderToAwsConfig")
logger.Debug("Switching credentials provider to AssumeRoleProvider")
stsSvc := sts.NewFromConfig(*awsConfig)
stsCredProvider := stscreds.NewAssumeRoleProvider(stsSvc, config.RoleArn)
awsConfig.Credentials = stsCredProvider
}
// addStaticCredentialsProviderToAwsConfig adds a static credentials provider to the current AWS config by using the keys stored in Beats config
func addStaticCredentialsProviderToAwsConfig(beatsConfig ConfigAWS, awsConfig *awssdk.Config) {
logger := logp.NewLogger("addStaticCredentialsProviderToAwsConfig")
logger.Debug("Switching credentials provider to AssumeRoleProvider")
staticCredentialsProvider := credentials.NewStaticCredentialsProvider(
beatsConfig.AccessKeyID,
beatsConfig.SecretAccessKey,
beatsConfig.SessionToken)
awsConfig.Credentials = staticCredentialsProvider
}