472 lines
14 KiB
Go
472 lines
14 KiB
Go
package session
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
|
)
|
|
|
|
// EnvProviderName provides a name of the provider when config is loaded from environment.
|
|
const EnvProviderName = "EnvConfigCredentials"
|
|
|
|
// envConfig is a collection of environment values the SDK will read
|
|
// setup config from. All environment values are optional. But some values
|
|
// such as credentials require multiple values to be complete or the values
|
|
// will be ignored.
|
|
type envConfig struct {
|
|
// Environment configuration values. If set both Access Key ID and Secret Access
|
|
// Key must be provided. Session Token and optionally also be provided, but is
|
|
// not required.
|
|
//
|
|
// # Access Key ID
|
|
// AWS_ACCESS_KEY_ID=AKID
|
|
// AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
|
//
|
|
// # Secret Access Key
|
|
// AWS_SECRET_ACCESS_KEY=SECRET
|
|
// AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
|
//
|
|
// # Session Token
|
|
// AWS_SESSION_TOKEN=TOKEN
|
|
Creds credentials.Value
|
|
|
|
// Region value will instruct the SDK where to make service API requests to. If is
|
|
// not provided in the environment the region must be provided before a service
|
|
// client request is made.
|
|
//
|
|
// AWS_REGION=us-east-1
|
|
//
|
|
// # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
|
// # and AWS_REGION is not also set.
|
|
// AWS_DEFAULT_REGION=us-east-1
|
|
Region string
|
|
|
|
// Profile name the SDK should load use when loading shared configuration from the
|
|
// shared configuration files. If not provided "default" will be used as the
|
|
// profile name.
|
|
//
|
|
// AWS_PROFILE=my_profile
|
|
//
|
|
// # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
|
// # and AWS_PROFILE is not also set.
|
|
// AWS_DEFAULT_PROFILE=my_profile
|
|
Profile string
|
|
|
|
// SDK load config instructs the SDK to load the shared config in addition to
|
|
// shared credentials. This also expands the configuration loaded from the shared
|
|
// credentials to have parity with the shared config file. This also enables
|
|
// Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
|
// env values as well.
|
|
//
|
|
// AWS_SDK_LOAD_CONFIG=1
|
|
EnableSharedConfig bool
|
|
|
|
// Shared credentials file path can be set to instruct the SDK to use an alternate
|
|
// file for the shared credentials. If not set the file will be loaded from
|
|
// $HOME/.aws/credentials on Linux/Unix based systems, and
|
|
// %USERPROFILE%\.aws\credentials on Windows.
|
|
//
|
|
// AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
|
SharedCredentialsFile string
|
|
|
|
// Shared config file path can be set to instruct the SDK to use an alternate
|
|
// file for the shared config. If not set the file will be loaded from
|
|
// $HOME/.aws/config on Linux/Unix based systems, and
|
|
// %USERPROFILE%\.aws\config on Windows.
|
|
//
|
|
// AWS_CONFIG_FILE=$HOME/my_shared_config
|
|
SharedConfigFile string
|
|
|
|
// Sets the path to a custom Credentials Authority (CA) Bundle PEM file
|
|
// that the SDK will use instead of the system's root CA bundle.
|
|
// Only use this if you want to configure the SDK to use a custom set
|
|
// of CAs.
|
|
//
|
|
// Enabling this option will attempt to merge the Transport
|
|
// into the SDK's HTTP client. If the client's Transport is
|
|
// not a http.Transport an error will be returned. If the
|
|
// Transport's TLS config is set this option will cause the
|
|
// SDK to overwrite the Transport's TLS config's RootCAs value.
|
|
//
|
|
// Setting a custom HTTPClient in the aws.Config options will override this setting.
|
|
// To use this option and custom HTTP client, the HTTP client needs to be provided
|
|
// when creating the session. Not the service client.
|
|
//
|
|
// AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle
|
|
CustomCABundle string
|
|
|
|
// Sets the TLC client certificate that should be used by the SDK's HTTP transport
|
|
// when making requests. The certificate must be paired with a TLS client key file.
|
|
//
|
|
// AWS_SDK_GO_CLIENT_TLS_CERT=$HOME/my_client_cert
|
|
ClientTLSCert string
|
|
|
|
// Sets the TLC client key that should be used by the SDK's HTTP transport
|
|
// when making requests. The key must be paired with a TLS client certificate file.
|
|
//
|
|
// AWS_SDK_GO_CLIENT_TLS_KEY=$HOME/my_client_key
|
|
ClientTLSKey string
|
|
|
|
csmEnabled string
|
|
CSMEnabled *bool
|
|
CSMPort string
|
|
CSMHost string
|
|
CSMClientID string
|
|
|
|
// Enables endpoint discovery via environment variables.
|
|
//
|
|
// AWS_ENABLE_ENDPOINT_DISCOVERY=true
|
|
EnableEndpointDiscovery *bool
|
|
enableEndpointDiscovery string
|
|
|
|
// Specifies the WebIdentity token the SDK should use to assume a role
|
|
// with.
|
|
//
|
|
// AWS_WEB_IDENTITY_TOKEN_FILE=file_path
|
|
WebIdentityTokenFilePath string
|
|
|
|
// Specifies the IAM role arn to use when assuming an role.
|
|
//
|
|
// AWS_ROLE_ARN=role_arn
|
|
RoleARN string
|
|
|
|
// Specifies the IAM role session name to use when assuming a role.
|
|
//
|
|
// AWS_ROLE_SESSION_NAME=session_name
|
|
RoleSessionName string
|
|
|
|
// Specifies the STS Regional Endpoint flag for the SDK to resolve the endpoint
|
|
// for a service.
|
|
//
|
|
// AWS_STS_REGIONAL_ENDPOINTS=regional
|
|
// This can take value as `regional` or `legacy`
|
|
STSRegionalEndpoint endpoints.STSRegionalEndpoint
|
|
|
|
// Specifies the S3 Regional Endpoint flag for the SDK to resolve the
|
|
// endpoint for a service.
|
|
//
|
|
// AWS_S3_US_EAST_1_REGIONAL_ENDPOINT=regional
|
|
// This can take value as `regional` or `legacy`
|
|
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
|
|
|
|
// Specifies if the S3 service should allow ARNs to direct the region
|
|
// the client's requests are sent to.
|
|
//
|
|
// AWS_S3_USE_ARN_REGION=true
|
|
S3UseARNRegion bool
|
|
|
|
// Specifies the EC2 Instance Metadata Service endpoint to use. If specified it overrides EC2IMDSEndpointMode.
|
|
//
|
|
// AWS_EC2_METADATA_SERVICE_ENDPOINT=http://[::1]
|
|
EC2IMDSEndpoint string
|
|
|
|
// Specifies the EC2 Instance Metadata Service default endpoint selection mode (IPv4 or IPv6)
|
|
//
|
|
// AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE=IPv6
|
|
EC2IMDSEndpointMode endpoints.EC2IMDSEndpointModeState
|
|
|
|
// Specifies that SDK clients must resolve a dual-stack endpoint for
|
|
// services.
|
|
//
|
|
// AWS_USE_DUALSTACK_ENDPOINT=true
|
|
UseDualStackEndpoint endpoints.DualStackEndpointState
|
|
|
|
// Specifies that SDK clients must resolve a FIPS endpoint for
|
|
// services.
|
|
//
|
|
// AWS_USE_FIPS_ENDPOINT=true
|
|
UseFIPSEndpoint endpoints.FIPSEndpointState
|
|
}
|
|
|
|
var (
|
|
csmEnabledEnvKey = []string{
|
|
"AWS_CSM_ENABLED",
|
|
}
|
|
csmHostEnvKey = []string{
|
|
"AWS_CSM_HOST",
|
|
}
|
|
csmPortEnvKey = []string{
|
|
"AWS_CSM_PORT",
|
|
}
|
|
csmClientIDEnvKey = []string{
|
|
"AWS_CSM_CLIENT_ID",
|
|
}
|
|
credAccessEnvKey = []string{
|
|
"AWS_ACCESS_KEY_ID",
|
|
"AWS_ACCESS_KEY",
|
|
}
|
|
credSecretEnvKey = []string{
|
|
"AWS_SECRET_ACCESS_KEY",
|
|
"AWS_SECRET_KEY",
|
|
}
|
|
credSessionEnvKey = []string{
|
|
"AWS_SESSION_TOKEN",
|
|
}
|
|
|
|
enableEndpointDiscoveryEnvKey = []string{
|
|
"AWS_ENABLE_ENDPOINT_DISCOVERY",
|
|
}
|
|
|
|
regionEnvKeys = []string{
|
|
"AWS_REGION",
|
|
"AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
|
}
|
|
profileEnvKeys = []string{
|
|
"AWS_PROFILE",
|
|
"AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
|
}
|
|
sharedCredsFileEnvKey = []string{
|
|
"AWS_SHARED_CREDENTIALS_FILE",
|
|
}
|
|
sharedConfigFileEnvKey = []string{
|
|
"AWS_CONFIG_FILE",
|
|
}
|
|
webIdentityTokenFilePathEnvKey = []string{
|
|
"AWS_WEB_IDENTITY_TOKEN_FILE",
|
|
}
|
|
roleARNEnvKey = []string{
|
|
"AWS_ROLE_ARN",
|
|
}
|
|
roleSessionNameEnvKey = []string{
|
|
"AWS_ROLE_SESSION_NAME",
|
|
}
|
|
stsRegionalEndpointKey = []string{
|
|
"AWS_STS_REGIONAL_ENDPOINTS",
|
|
}
|
|
s3UsEast1RegionalEndpoint = []string{
|
|
"AWS_S3_US_EAST_1_REGIONAL_ENDPOINT",
|
|
}
|
|
s3UseARNRegionEnvKey = []string{
|
|
"AWS_S3_USE_ARN_REGION",
|
|
}
|
|
ec2IMDSEndpointEnvKey = []string{
|
|
"AWS_EC2_METADATA_SERVICE_ENDPOINT",
|
|
}
|
|
ec2IMDSEndpointModeEnvKey = []string{
|
|
"AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE",
|
|
}
|
|
useCABundleKey = []string{
|
|
"AWS_CA_BUNDLE",
|
|
}
|
|
useClientTLSCert = []string{
|
|
"AWS_SDK_GO_CLIENT_TLS_CERT",
|
|
}
|
|
useClientTLSKey = []string{
|
|
"AWS_SDK_GO_CLIENT_TLS_KEY",
|
|
}
|
|
awsUseDualStackEndpoint = []string{
|
|
"AWS_USE_DUALSTACK_ENDPOINT",
|
|
}
|
|
awsUseFIPSEndpoint = []string{
|
|
"AWS_USE_FIPS_ENDPOINT",
|
|
}
|
|
)
|
|
|
|
// loadEnvConfig retrieves the SDK's environment configuration.
|
|
// See `envConfig` for the values that will be retrieved.
|
|
//
|
|
// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value
|
|
// the shared SDK config will be loaded in addition to the SDK's specific
|
|
// configuration values.
|
|
func loadEnvConfig() (envConfig, error) {
|
|
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
|
|
return envConfigLoad(enableSharedConfig)
|
|
}
|
|
|
|
// loadEnvSharedConfig retrieves the SDK's environment configuration, and the
|
|
// SDK shared config. See `envConfig` for the values that will be retrieved.
|
|
//
|
|
// Loads the shared configuration in addition to the SDK's specific configuration.
|
|
// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG`
|
|
// environment variable is set.
|
|
func loadSharedEnvConfig() (envConfig, error) {
|
|
return envConfigLoad(true)
|
|
}
|
|
|
|
func envConfigLoad(enableSharedConfig bool) (envConfig, error) {
|
|
cfg := envConfig{}
|
|
|
|
cfg.EnableSharedConfig = enableSharedConfig
|
|
|
|
// Static environment credentials
|
|
var creds credentials.Value
|
|
setFromEnvVal(&creds.AccessKeyID, credAccessEnvKey)
|
|
setFromEnvVal(&creds.SecretAccessKey, credSecretEnvKey)
|
|
setFromEnvVal(&creds.SessionToken, credSessionEnvKey)
|
|
if creds.HasKeys() {
|
|
// Require logical grouping of credentials
|
|
creds.ProviderName = EnvProviderName
|
|
cfg.Creds = creds
|
|
}
|
|
|
|
// Role Metadata
|
|
setFromEnvVal(&cfg.RoleARN, roleARNEnvKey)
|
|
setFromEnvVal(&cfg.RoleSessionName, roleSessionNameEnvKey)
|
|
|
|
// Web identity environment variables
|
|
setFromEnvVal(&cfg.WebIdentityTokenFilePath, webIdentityTokenFilePathEnvKey)
|
|
|
|
// CSM environment variables
|
|
setFromEnvVal(&cfg.csmEnabled, csmEnabledEnvKey)
|
|
setFromEnvVal(&cfg.CSMHost, csmHostEnvKey)
|
|
setFromEnvVal(&cfg.CSMPort, csmPortEnvKey)
|
|
setFromEnvVal(&cfg.CSMClientID, csmClientIDEnvKey)
|
|
|
|
if len(cfg.csmEnabled) != 0 {
|
|
v, _ := strconv.ParseBool(cfg.csmEnabled)
|
|
cfg.CSMEnabled = &v
|
|
}
|
|
|
|
regionKeys := regionEnvKeys
|
|
profileKeys := profileEnvKeys
|
|
if !cfg.EnableSharedConfig {
|
|
regionKeys = regionKeys[:1]
|
|
profileKeys = profileKeys[:1]
|
|
}
|
|
|
|
setFromEnvVal(&cfg.Region, regionKeys)
|
|
setFromEnvVal(&cfg.Profile, profileKeys)
|
|
|
|
// endpoint discovery is in reference to it being enabled.
|
|
setFromEnvVal(&cfg.enableEndpointDiscovery, enableEndpointDiscoveryEnvKey)
|
|
if len(cfg.enableEndpointDiscovery) > 0 {
|
|
cfg.EnableEndpointDiscovery = aws.Bool(cfg.enableEndpointDiscovery != "false")
|
|
}
|
|
|
|
setFromEnvVal(&cfg.SharedCredentialsFile, sharedCredsFileEnvKey)
|
|
setFromEnvVal(&cfg.SharedConfigFile, sharedConfigFileEnvKey)
|
|
|
|
if len(cfg.SharedCredentialsFile) == 0 {
|
|
cfg.SharedCredentialsFile = defaults.SharedCredentialsFilename()
|
|
}
|
|
if len(cfg.SharedConfigFile) == 0 {
|
|
cfg.SharedConfigFile = defaults.SharedConfigFilename()
|
|
}
|
|
|
|
setFromEnvVal(&cfg.CustomCABundle, useCABundleKey)
|
|
setFromEnvVal(&cfg.ClientTLSCert, useClientTLSCert)
|
|
setFromEnvVal(&cfg.ClientTLSKey, useClientTLSKey)
|
|
|
|
var err error
|
|
// STS Regional Endpoint variable
|
|
for _, k := range stsRegionalEndpointKey {
|
|
if v := os.Getenv(k); len(v) != 0 {
|
|
cfg.STSRegionalEndpoint, err = endpoints.GetSTSRegionalEndpoint(v)
|
|
if err != nil {
|
|
return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// S3 Regional Endpoint variable
|
|
for _, k := range s3UsEast1RegionalEndpoint {
|
|
if v := os.Getenv(k); len(v) != 0 {
|
|
cfg.S3UsEast1RegionalEndpoint, err = endpoints.GetS3UsEast1RegionalEndpoint(v)
|
|
if err != nil {
|
|
return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
var s3UseARNRegion string
|
|
setFromEnvVal(&s3UseARNRegion, s3UseARNRegionEnvKey)
|
|
if len(s3UseARNRegion) != 0 {
|
|
switch {
|
|
case strings.EqualFold(s3UseARNRegion, "false"):
|
|
cfg.S3UseARNRegion = false
|
|
case strings.EqualFold(s3UseARNRegion, "true"):
|
|
cfg.S3UseARNRegion = true
|
|
default:
|
|
return envConfig{}, fmt.Errorf(
|
|
"invalid value for environment variable, %s=%s, need true or false",
|
|
s3UseARNRegionEnvKey[0], s3UseARNRegion)
|
|
}
|
|
}
|
|
|
|
setFromEnvVal(&cfg.EC2IMDSEndpoint, ec2IMDSEndpointEnvKey)
|
|
if err := setEC2IMDSEndpointMode(&cfg.EC2IMDSEndpointMode, ec2IMDSEndpointModeEnvKey); err != nil {
|
|
return envConfig{}, err
|
|
}
|
|
|
|
if err := setUseDualStackEndpointFromEnvVal(&cfg.UseDualStackEndpoint, awsUseDualStackEndpoint); err != nil {
|
|
return cfg, err
|
|
}
|
|
|
|
if err := setUseFIPSEndpointFromEnvVal(&cfg.UseFIPSEndpoint, awsUseFIPSEndpoint); err != nil {
|
|
return cfg, err
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func setFromEnvVal(dst *string, keys []string) {
|
|
for _, k := range keys {
|
|
if v := os.Getenv(k); len(v) != 0 {
|
|
*dst = v
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func setEC2IMDSEndpointMode(mode *endpoints.EC2IMDSEndpointModeState, keys []string) error {
|
|
for _, k := range keys {
|
|
value := os.Getenv(k)
|
|
if len(value) == 0 {
|
|
continue
|
|
}
|
|
if err := mode.SetFromString(value); err != nil {
|
|
return fmt.Errorf("invalid value for environment variable, %s=%s, %v", k, value, err)
|
|
}
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setUseDualStackEndpointFromEnvVal(dst *endpoints.DualStackEndpointState, keys []string) error {
|
|
for _, k := range keys {
|
|
value := os.Getenv(k)
|
|
if len(value) == 0 {
|
|
continue // skip if empty
|
|
}
|
|
|
|
switch {
|
|
case strings.EqualFold(value, "true"):
|
|
*dst = endpoints.DualStackEndpointStateEnabled
|
|
case strings.EqualFold(value, "false"):
|
|
*dst = endpoints.DualStackEndpointStateDisabled
|
|
default:
|
|
return fmt.Errorf(
|
|
"invalid value for environment variable, %s=%s, need true, false",
|
|
k, value)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setUseFIPSEndpointFromEnvVal(dst *endpoints.FIPSEndpointState, keys []string) error {
|
|
for _, k := range keys {
|
|
value := os.Getenv(k)
|
|
if len(value) == 0 {
|
|
continue // skip if empty
|
|
}
|
|
|
|
switch {
|
|
case strings.EqualFold(value, "true"):
|
|
*dst = endpoints.FIPSEndpointStateEnabled
|
|
case strings.EqualFold(value, "false"):
|
|
*dst = endpoints.FIPSEndpointStateDisabled
|
|
default:
|
|
return fmt.Errorf(
|
|
"invalid value for environment variable, %s=%s, need true, false",
|
|
k, value)
|
|
}
|
|
}
|
|
return nil
|
|
}
|