1
#include "source/extensions/common/aws/region_provider_impl.h"
2

            
3
#include "source/extensions/common/aws/utility.h"
4

            
5
namespace Envoy {
6
namespace Extensions {
7
namespace Common {
8
namespace Aws {
9

            
10
constexpr char AWS_REGION[] = "AWS_REGION";
11
constexpr char AWS_DEFAULT_REGION[] = "AWS_DEFAULT_REGION";
12
constexpr char REGION[] = "REGION";
13
constexpr char AWS_SIGV4A_SIGNING_REGION_SET[] = "AWS_SIGV4A_SIGNING_REGION_SET";
14
constexpr char SIGV4A_SIGNING_REGION_SET[] = "SIGV4A_SIGNING_REGION_SET";
15

            
16
10
absl::optional<std::string> EnvironmentRegionProvider::getRegion() {
17
10
  std::string region;
18

            
19
  // Search for the region in environment variables AWS_REGION and AWS_DEFAULT_REGION
20
10
  region = Utility::getEnvironmentVariableOrDefault(AWS_REGION, "");
21
10
  if (region.empty()) {
22
5
    region = Utility::getEnvironmentVariableOrDefault(AWS_DEFAULT_REGION, "");
23
5
    if (region.empty()) {
24
5
      return absl::nullopt;
25
5
    }
26
5
  }
27
5
  ENVOY_LOG(debug, "EnvironmentRegionProvider: Region string retrieved: {}", region);
28
5
  return region;
29
10
}
30

            
31
5
absl::optional<std::string> EnvironmentRegionProvider::getRegionSet() {
32
5
  std::string regionSet;
33

            
34
  // Search for the region in environment variables AWS_REGION and AWS_DEFAULT_REGION
35
5
  regionSet = Utility::getEnvironmentVariableOrDefault(AWS_SIGV4A_SIGNING_REGION_SET, "");
36
5
  if (regionSet.empty()) {
37
3
    return absl::nullopt;
38
3
  }
39
2
  ENVOY_LOG(debug, "EnvironmentRegionProvider: RegionSet string retrieved: {}", regionSet);
40
2
  return regionSet;
41
5
}
42

            
43
AWSCredentialsFileRegionProvider::AWSCredentialsFileRegionProvider(
44
    const envoy::extensions::common::aws::v3::CredentialsFileCredentialProvider&
45
21
        credential_file_config) {
46
21
  if (credential_file_config.has_credentials_data_source() &&
47
21
      credential_file_config.credentials_data_source().has_filename()) {
48
3
    credential_file_path_ = credential_file_config.credentials_data_source().filename();
49
3
  }
50
21
  if (!credential_file_config.profile().empty()) {
51
1
    profile_ = credential_file_config.profile();
52
1
  }
53
21
}
54

            
55
9
absl::optional<std::string> AWSCredentialsFileRegionProvider::getRegion() {
56
9
  absl::flat_hash_map<std::string, std::string> elements = {{REGION, ""}};
57
9
  absl::flat_hash_map<std::string, std::string>::iterator it;
58

            
59
9
  std::string file_path, profile;
60
9
  file_path = credential_file_path_.has_value() ? credential_file_path_.value()
61
9
                                                : Utility::getCredentialFilePath();
62
9
  profile = profile_.has_value() ? profile_.value() : Utility::getCredentialProfileName();
63

            
64
  // Search for the region in the credentials file
65
9
  if (!Utility::resolveProfileElementsFromFile(file_path, profile, elements)) {
66
3
    return absl::nullopt;
67
3
  }
68
6
  it = elements.find(REGION);
69
6
  if (it == elements.end() || it->second.empty()) {
70
1
    return absl::nullopt;
71
1
  }
72

            
73
5
  ENVOY_LOG(debug, "AWSCredentialsFileRegionProvider: Region string retrieved: {}", it->second);
74
5
  return it->second;
75
6
}
76

            
77
7
absl::optional<std::string> AWSCredentialsFileRegionProvider::getRegionSet() {
78
7
  absl::flat_hash_map<std::string, std::string> elements = {{SIGV4A_SIGNING_REGION_SET, ""}};
79
7
  absl::flat_hash_map<std::string, std::string>::iterator it;
80

            
81
7
  std::string file_path, profile;
82
7
  file_path = credential_file_path_.has_value() ? credential_file_path_.value()
83
7
                                                : Utility::getCredentialFilePath();
84

            
85
7
  profile = profile_.has_value() ? profile_.value() : Utility::getCredentialProfileName();
86

            
87
  // Search for the region in the credentials file
88
7
  if (!Utility::resolveProfileElementsFromFile(file_path, profile, elements)) {
89
3
    return absl::nullopt;
90
3
  }
91
4
  it = elements.find(SIGV4A_SIGNING_REGION_SET);
92
4
  if (it == elements.end() || it->second.empty()) {
93
1
    return absl::nullopt;
94
1
  }
95

            
96
3
  ENVOY_LOG(debug, "AWSCredentialsFileRegionProvider: RegionSet string retrieved: {}", it->second);
97
3
  return it->second;
98
4
}
99

            
100
6
absl::optional<std::string> AWSConfigFileRegionProvider::getRegion() {
101
6
  absl::flat_hash_map<std::string, std::string> elements = {{REGION, ""}};
102
6
  absl::flat_hash_map<std::string, std::string>::iterator it;
103

            
104
  // Search for the region in the config file
105

            
106
6
  if (!Utility::resolveProfileElementsFromFile(Utility::getConfigFilePath(),
107
6
                                               Utility::getConfigProfileName(), elements)) {
108
3
    return absl::nullopt;
109
3
  }
110

            
111
3
  it = elements.find(REGION);
112
3
  if (it == elements.end() || it->second.empty()) {
113
1
    return absl::nullopt;
114
1
  }
115

            
116
2
  ENVOY_LOG(debug, "AWSConfigFileRegionProvider: Region string retrieved: {}", it->second);
117
2
  return it->second;
118
3
}
119

            
120
6
absl::optional<std::string> AWSConfigFileRegionProvider::getRegionSet() {
121
6
  absl::flat_hash_map<std::string, std::string> elements = {{SIGV4A_SIGNING_REGION_SET, ""}};
122
6
  absl::flat_hash_map<std::string, std::string>::iterator it;
123

            
124
  // Search for the region in the config file
125

            
126
6
  if (!Utility::resolveProfileElementsFromFile(Utility::getConfigFilePath(),
127
6
                                               Utility::getConfigProfileName(), elements)) {
128
2
    return absl::nullopt;
129
2
  }
130

            
131
4
  it = elements.find(SIGV4A_SIGNING_REGION_SET);
132
4
  if (it == elements.end() || it->second.empty()) {
133
2
    return absl::nullopt;
134
2
  }
135

            
136
2
  ENVOY_LOG(debug, "AWSConfigFileRegionProvider: RegionSet string retrieved: {}", it->second);
137
2
  return it->second;
138
4
}
139

            
140
// Region provider chain. This allows retrieving region information from the following locations (in
141
// order):
142
// 1. The envoy configuration, in the region parameter
143
// 2. The envoy environment, in AWS_REGION then AWS_DEFAULT_REGION
144
// 3. In the credentials file $HOME/.aws/credentials (or location from
145
//    AWS_SHARED_CREDENTIALS_FILE/AWS_DEFAULT_SHARED_CREDENTIALS_FILE), under profile section
146
//    specified by AWS_PROFILE
147
// 4. In the config file $HOME/.aws/config (or location from AWS_CONFIG_FILE), under profile section
148
// specified by AWS_PROFILE
149
//
150
// Credentials and profile format can be found here:
151
// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
152
//
153
RegionProviderChain::RegionProviderChain(
154
    const envoy::extensions::common::aws::v3::CredentialsFileCredentialProvider&
155
12
        credential_file_config) {
156
  // TODO(nbaws): Verify that bypassing virtual dispatch here was intentional
157
12
  add(RegionProviderChain::createEnvironmentRegionProvider());
158
12
  add(RegionProviderChain::createAWSCredentialsFileRegionProvider(credential_file_config));
159
12
  add(RegionProviderChain::createAWSConfigFileRegionProvider());
160
12
}
161

            
162
8
absl::optional<std::string> RegionProviderChain::getRegion() {
163
15
  for (auto& provider : providers_) {
164
15
    const auto region = provider->getRegion();
165
15
    if (region.has_value()) {
166
5
      return region;
167
5
    }
168
15
  }
169
3
  return absl::nullopt;
170
8
}
171

            
172
4
absl::optional<std::string> RegionProviderChain::getRegionSet() {
173
10
  for (auto& provider : providers_) {
174
10
    const auto regionSet = provider->getRegionSet();
175
10
    if (regionSet.has_value()) {
176
1
      return regionSet;
177
1
    }
178
10
  }
179
3
  return absl::nullopt;
180
4
}
181

            
182
} // namespace Aws
183
} // namespace Common
184
} // namespace Extensions
185
} // namespace Envoy