Line data Source code
1 : #pragma once
2 :
3 : #include <list>
4 : #include <optional>
5 : #include <string>
6 :
7 : #include "envoy/api/api.h"
8 : #include "envoy/common/optref.h"
9 : #include "envoy/event/timer.h"
10 : #include "envoy/http/message.h"
11 : #include "envoy/server/factory_context.h"
12 :
13 : #include "source/common/common/lock_guard.h"
14 : #include "source/common/common/logger.h"
15 : #include "source/common/common/thread.h"
16 : #include "source/common/init/target_impl.h"
17 : #include "source/common/protobuf/message_validator_impl.h"
18 : #include "source/common/protobuf/utility.h"
19 : #include "source/extensions/common/aws/credentials_provider.h"
20 : #include "source/extensions/common/aws/metadata_fetcher.h"
21 :
22 : #include "absl/strings/string_view.h"
23 :
24 : namespace Envoy {
25 : namespace Extensions {
26 : namespace Common {
27 : namespace Aws {
28 :
29 : /**
30 : * CreateMetadataFetcherCb is a callback interface for creating a MetadataFetcher instance.
31 : */
32 : using CreateMetadataFetcherCb =
33 : std::function<MetadataFetcherPtr(Upstream::ClusterManager&, absl::string_view)>;
34 : using ServerFactoryContextOptRef = OptRef<Server::Configuration::ServerFactoryContext>;
35 :
36 : /**
37 : * Retrieve AWS credentials from the environment variables.
38 : *
39 : * Adheres to conventions specified in:
40 : * https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
41 : */
42 : class EnvironmentCredentialsProvider : public CredentialsProvider,
43 : public Logger::Loggable<Logger::Id::aws> {
44 : public:
45 : Credentials getCredentials() override;
46 : };
47 :
48 : class CachedCredentialsProviderBase : public CredentialsProvider,
49 : public Logger::Loggable<Logger::Id::aws> {
50 : public:
51 5 : Credentials getCredentials() override {
52 5 : refreshIfNeeded();
53 5 : return cached_credentials_;
54 5 : }
55 :
56 : protected:
57 : SystemTime last_updated_;
58 : Credentials cached_credentials_;
59 : Thread::MutexBasicLockable lock_;
60 :
61 : void refreshIfNeeded();
62 :
63 : virtual bool needsRefresh() PURE;
64 : virtual void refresh() PURE;
65 : };
66 :
67 : /**
68 : * Retrieve AWS credentials from the credentials file.
69 : *
70 : * Adheres to conventions specified in:
71 : * https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
72 : */
73 : class CredentialsFileCredentialsProvider : public CachedCredentialsProviderBase {
74 : public:
75 6 : CredentialsFileCredentialsProvider(Api::Api& api) : api_(api) {}
76 :
77 : private:
78 : Api::Api& api_;
79 :
80 : bool needsRefresh() override;
81 : void refresh() override;
82 : void extractCredentials(const std::string& credentials_file, const std::string& profile);
83 : };
84 :
85 : class MetadataCredentialsProviderBase : public CachedCredentialsProviderBase {
86 : public:
87 : using CurlMetadataFetcher = std::function<absl::optional<std::string>(Http::RequestMessage&)>;
88 : using OnAsyncFetchCb = std::function<void(const std::string&&)>;
89 :
90 : MetadataCredentialsProviderBase(
91 : Api::Api& api, ServerFactoryContextOptRef context,
92 : const CurlMetadataFetcher& fetch_metadata_using_curl,
93 : CreateMetadataFetcherCb create_metadata_fetcher_cb, absl::string_view cluster_name,
94 : const envoy::config::cluster::v3::Cluster::DiscoveryType cluster_type, absl::string_view uri);
95 :
96 : Credentials getCredentials() override;
97 :
98 : // Get the Metadata credentials cache duration.
99 : static std::chrono::seconds getCacheDuration();
100 :
101 : protected:
102 : struct ThreadLocalCredentialsCache : public ThreadLocal::ThreadLocalObject {
103 6 : ThreadLocalCredentialsCache() {
104 6 : credentials_ = std::make_shared<Credentials>(); // Creating empty credentials as default.
105 6 : }
106 : // The credentials object.
107 : CredentialsConstSharedPtr credentials_;
108 : };
109 :
110 0 : const std::string& clusterName() const { return cluster_name_; }
111 :
112 : // Handle fetch done.
113 : void handleFetchDone();
114 :
115 : // Set Credentials shared_ptr on all threads.
116 : void setCredentialsToAllThreads(CredentialsConstUniquePtr&& creds);
117 :
118 : // Returns true if http async client can be used instead of libcurl to fetch the aws credentials,
119 : // else false.
120 : bool useHttpAsyncClient();
121 :
122 : Api::Api& api_;
123 : // The optional server factory context.
124 : ServerFactoryContextOptRef context_;
125 : // Store the method to fetch metadata from libcurl (deprecated)
126 : CurlMetadataFetcher fetch_metadata_using_curl_;
127 : // The callback used to create a MetadataFetcher instance.
128 : CreateMetadataFetcherCb create_metadata_fetcher_cb_;
129 : // The cluster name to use for internal static cluster pointing towards the credentials provider.
130 : const std::string cluster_name_;
131 : // The cluster type to use for internal static cluster pointing towards the credentials provider.
132 : const envoy::config::cluster::v3::Cluster::DiscoveryType cluster_type_;
133 : // The uri of internal static cluster credentials provider.
134 : const std::string uri_;
135 : // The cache duration of the fetched credentials.
136 : const std::chrono::seconds cache_duration_;
137 : // The thread local slot for cache.
138 : ThreadLocal::TypedSlotPtr<ThreadLocalCredentialsCache> tls_;
139 : // The timer to trigger fetch due to cache duration.
140 : Envoy::Event::TimerPtr cache_duration_timer_;
141 : // The Metadata fetcher object.
142 : MetadataFetcherPtr metadata_fetcher_;
143 : // Callback function to call on successful metadata fetch.
144 : OnAsyncFetchCb on_async_fetch_cb_;
145 : // To determine if credentials fetching can continue even after metadata fetch failure.
146 : bool continue_on_async_fetch_failure_ = false;
147 : // Reason to log on fetch failure while continue.
148 : std::string continue_on_async_fetch_failure_reason_ = "";
149 : // Last update time to determine expiration.
150 : SystemTime last_updated_;
151 : // Cache credentials when using libcurl.
152 : Credentials cached_credentials_;
153 : // Lock guard.
154 : Thread::MutexBasicLockable lock_;
155 : // The init target.
156 : std::unique_ptr<Init::TargetImpl> init_target_;
157 : // Used in logs.
158 : const std::string debug_name_;
159 : };
160 :
161 : /**
162 : * Retrieve AWS credentials from the instance metadata.
163 : *
164 : * https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials
165 : */
166 : class InstanceProfileCredentialsProvider : public MetadataCredentialsProviderBase,
167 : public MetadataFetcher::MetadataReceiver {
168 : public:
169 : InstanceProfileCredentialsProvider(Api::Api& api, ServerFactoryContextOptRef context,
170 : const CurlMetadataFetcher& fetch_metadata_using_curl,
171 : CreateMetadataFetcherCb create_metadata_fetcher_cb,
172 : absl::string_view cluster_name);
173 :
174 : // Following functions are for MetadataFetcher::MetadataReceiver interface
175 : void onMetadataSuccess(const std::string&& body) override;
176 : void onMetadataError(Failure reason) override;
177 :
178 : private:
179 : bool needsRefresh() override;
180 : void refresh() override;
181 : void fetchInstanceRole(const std::string&& token, bool async = false);
182 0 : void fetchInstanceRoleAsync(const std::string&& token) {
183 0 : fetchInstanceRole(std::move(token), true);
184 0 : }
185 : void fetchCredentialFromInstanceRole(const std::string&& instance_role, const std::string&& token,
186 : bool async = false);
187 : void fetchCredentialFromInstanceRoleAsync(const std::string&& instance_role,
188 0 : const std::string&& token) {
189 0 : fetchCredentialFromInstanceRole(std::move(instance_role), std::move(token), true);
190 0 : }
191 : void extractCredentials(const std::string&& credential_document_value, bool async = false);
192 0 : void extractCredentialsAsync(const std::string&& credential_document_value) {
193 0 : extractCredentials(std::move(credential_document_value), true);
194 0 : }
195 : };
196 :
197 : /**
198 : * Retrieve AWS credentials from the task metadata.
199 : *
200 : * https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html#enable_task_iam_roles
201 : */
202 : class TaskRoleCredentialsProvider : public MetadataCredentialsProviderBase,
203 : public MetadataFetcher::MetadataReceiver {
204 : public:
205 : TaskRoleCredentialsProvider(Api::Api& api, ServerFactoryContextOptRef context,
206 : const CurlMetadataFetcher& fetch_metadata_using_curl,
207 : CreateMetadataFetcherCb create_metadata_fetcher_cb,
208 : absl::string_view credential_uri,
209 : absl::string_view authorization_token,
210 : absl::string_view cluster_name);
211 :
212 : // Following functions are for MetadataFetcher::MetadataReceiver interface
213 : void onMetadataSuccess(const std::string&& body) override;
214 : void onMetadataError(Failure reason) override;
215 :
216 : private:
217 : SystemTime expiration_time_;
218 : const std::string credential_uri_;
219 : const std::string authorization_token_;
220 :
221 : bool needsRefresh() override;
222 : void refresh() override;
223 : void extractCredentials(const std::string&& credential_document_value);
224 : };
225 :
226 : /**
227 : * Retrieve AWS credentials from Security Token Service using a web identity token (e.g. OAuth,
228 : * OpenID)
229 : */
230 : class WebIdentityCredentialsProvider : public MetadataCredentialsProviderBase,
231 : public MetadataFetcher::MetadataReceiver {
232 : public:
233 : WebIdentityCredentialsProvider(Api::Api& api, ServerFactoryContextOptRef context,
234 : const CurlMetadataFetcher& fetch_metadata_using_curl,
235 : CreateMetadataFetcherCb create_metadata_fetcher_cb,
236 : absl::string_view token_file_path, absl::string_view sts_endpoint,
237 : absl::string_view role_arn, absl::string_view role_session_name,
238 : absl::string_view cluster_name);
239 :
240 : // Following functions are for MetadataFetcher::MetadataReceiver interface
241 : void onMetadataSuccess(const std::string&& body) override;
242 : void onMetadataError(Failure reason) override;
243 :
244 : private:
245 : SystemTime expiration_time_;
246 : const std::string token_file_path_;
247 : const std::string sts_endpoint_;
248 : const std::string role_arn_;
249 : const std::string role_session_name_;
250 :
251 : bool needsRefresh() override;
252 : void refresh() override;
253 : void extractCredentials(const std::string&& credential_document_value);
254 : };
255 :
256 : /**
257 : * AWS credentials provider chain, able to fallback between multiple credential providers.
258 : */
259 : class CredentialsProviderChain : public CredentialsProvider,
260 : public Logger::Loggable<Logger::Id::aws> {
261 : public:
262 6 : ~CredentialsProviderChain() override = default;
263 :
264 18 : void add(const CredentialsProviderSharedPtr& credentials_provider) {
265 18 : providers_.emplace_back(credentials_provider);
266 18 : }
267 :
268 : Credentials getCredentials() override;
269 :
270 : protected:
271 : std::list<CredentialsProviderSharedPtr> providers_;
272 : };
273 :
274 : class CredentialsProviderChainFactories {
275 : public:
276 6 : virtual ~CredentialsProviderChainFactories() = default;
277 :
278 : virtual CredentialsProviderSharedPtr createEnvironmentCredentialsProvider() const PURE;
279 :
280 : virtual CredentialsProviderSharedPtr
281 : createCredentialsFileCredentialsProvider(Api::Api& api) const PURE;
282 :
283 : virtual CredentialsProviderSharedPtr createWebIdentityCredentialsProvider(
284 : Api::Api& api, ServerFactoryContextOptRef context,
285 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
286 : CreateMetadataFetcherCb create_metadata_fetcher_cb, absl::string_view cluster_name,
287 : absl::string_view token_file_path, absl::string_view sts_endpoint, absl::string_view role_arn,
288 : absl::string_view role_session_name) const PURE;
289 :
290 : virtual CredentialsProviderSharedPtr createTaskRoleCredentialsProvider(
291 : Api::Api& api, ServerFactoryContextOptRef context,
292 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
293 : CreateMetadataFetcherCb create_metadata_fetcher_cb, absl::string_view cluster_name,
294 : absl::string_view credential_uri, absl::string_view authorization_token = {}) const PURE;
295 :
296 : virtual CredentialsProviderSharedPtr createInstanceProfileCredentialsProvider(
297 : Api::Api& api, ServerFactoryContextOptRef context,
298 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
299 : CreateMetadataFetcherCb create_metadata_fetcher_cb,
300 : absl::string_view cluster_name) const PURE;
301 : };
302 :
303 : /**
304 : * Default AWS credentials provider chain.
305 : *
306 : * Reference implementation:
307 : * https://github.com/aws/aws-sdk-cpp/blob/master/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp#L44
308 : */
309 : class DefaultCredentialsProviderChain : public CredentialsProviderChain,
310 : public CredentialsProviderChainFactories {
311 : public:
312 : DefaultCredentialsProviderChain(
313 : Api::Api& api, ServerFactoryContextOptRef context, absl::string_view region,
314 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl)
315 6 : : DefaultCredentialsProviderChain(api, context, region, fetch_metadata_using_curl, *this) {}
316 :
317 : DefaultCredentialsProviderChain(
318 : Api::Api& api, ServerFactoryContextOptRef context, absl::string_view region,
319 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
320 : const CredentialsProviderChainFactories& factories);
321 :
322 : private:
323 6 : CredentialsProviderSharedPtr createEnvironmentCredentialsProvider() const override {
324 6 : return std::make_shared<EnvironmentCredentialsProvider>();
325 6 : }
326 :
327 : CredentialsProviderSharedPtr
328 6 : createCredentialsFileCredentialsProvider(Api::Api& api) const override {
329 6 : return std::make_shared<CredentialsFileCredentialsProvider>(api);
330 6 : }
331 :
332 : CredentialsProviderSharedPtr createTaskRoleCredentialsProvider(
333 : Api::Api& api, ServerFactoryContextOptRef context,
334 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
335 : CreateMetadataFetcherCb create_metadata_fetcher_cb, absl::string_view cluster_name,
336 0 : absl::string_view credential_uri, absl::string_view authorization_token = {}) const override {
337 0 : return std::make_shared<TaskRoleCredentialsProvider>(api, context, fetch_metadata_using_curl,
338 0 : create_metadata_fetcher_cb, credential_uri,
339 0 : authorization_token, cluster_name);
340 0 : }
341 :
342 : CredentialsProviderSharedPtr createInstanceProfileCredentialsProvider(
343 : Api::Api& api, ServerFactoryContextOptRef context,
344 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
345 : CreateMetadataFetcherCb create_metadata_fetcher_cb,
346 6 : absl::string_view cluster_name) const override {
347 6 : return std::make_shared<InstanceProfileCredentialsProvider>(
348 6 : api, context, fetch_metadata_using_curl, create_metadata_fetcher_cb, cluster_name);
349 6 : }
350 :
351 : CredentialsProviderSharedPtr createWebIdentityCredentialsProvider(
352 : Api::Api& api, ServerFactoryContextOptRef context,
353 : const MetadataCredentialsProviderBase::CurlMetadataFetcher& fetch_metadata_using_curl,
354 : CreateMetadataFetcherCb create_metadata_fetcher_cb, absl::string_view cluster_name,
355 : absl::string_view token_file_path, absl::string_view sts_endpoint, absl::string_view role_arn,
356 0 : absl::string_view role_session_name) const override {
357 0 : return std::make_shared<WebIdentityCredentialsProvider>(
358 0 : api, context, fetch_metadata_using_curl, create_metadata_fetcher_cb, token_file_path,
359 0 : sts_endpoint, role_arn, role_session_name, cluster_name);
360 0 : }
361 : };
362 :
363 : using InstanceProfileCredentialsProviderPtr = std::shared_ptr<InstanceProfileCredentialsProvider>;
364 : using TaskRoleCredentialsProviderPtr = std::shared_ptr<TaskRoleCredentialsProvider>;
365 : using WebIdentityCredentialsProviderPtr = std::shared_ptr<WebIdentityCredentialsProvider>;
366 :
367 : } // namespace Aws
368 : } // namespace Common
369 : } // namespace Extensions
370 : } // namespace Envoy
|