Skip to content

Commit 6cd01c7

Browse files
committed
Use AwsCredentialsProvider to allow other AWS Credential types
Can now set the credential type and use different ways for setting the credentials
1 parent ea3c615 commit 6cd01c7

File tree

14 files changed

+234
-118
lines changed

14 files changed

+234
-118
lines changed

cloud/aws/aws_env.cc

Lines changed: 157 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
#include "util/string_util.h"
1313

1414
#ifdef USE_AWS
15-
1615
#include <aws/core/utils/threading/Executor.h>
16+
#endif
1717

1818
#include "cloud/aws/aws_file.h"
1919
#include "cloud/aws/aws_kafka.h"
@@ -26,6 +26,149 @@ namespace rocksdb {
2626
#pragma GCC diagnostic push
2727
#pragma GCC diagnostic ignored "-Wunused-parameter"
2828

29+
static const std::unordered_map<std::string, AwsAccessType> AwsAccessTypeMap = {
30+
{"undefined", AwsAccessType::kUndefined},
31+
{"simple", AwsAccessType::kSimple},
32+
{"instance", AwsAccessType::kInstance},
33+
{"EC2", AwsAccessType::kInstance},
34+
{"environment", AwsAccessType::kEnvironment},
35+
{"config", AwsAccessType::kConfig},
36+
{"anonymous", AwsAccessType::kAnonymous},
37+
};
38+
39+
template <typename T>
40+
bool ParseEnum(const std::unordered_map<std::string, T>& type_map,
41+
const std::string& type, T* value) {
42+
auto iter = type_map.find(type);
43+
if (iter != type_map.end()) {
44+
*value = iter->second;
45+
return true;
46+
}
47+
return false;
48+
}
49+
50+
AwsCloudAccessCredentials::AwsCloudAccessCredentials() {
51+
#ifdef USE_AWS
52+
type = AwsAccessType::kUndefined;
53+
#else
54+
type = AwsAccessType::kSimple;
55+
#endif
56+
}
57+
58+
AwsAccessType AwsCloudAccessCredentials::GetAccessType() const {
59+
if (type != AwsAccessType::kUndefined) {
60+
return type;
61+
} else if (!config_file.empty()) {
62+
return AwsAccessType::kConfig;
63+
} else if (!access_key_id.empty() || !secret_key.empty()) {
64+
return AwsAccessType::kSimple;
65+
}
66+
if (getenv("AWS_ACCESS_KEY_ID") || getenv("AWS_SECRET_ACCESS_KEY") ||
67+
getenv("AWS_SESSION_TOKEN") || getenv("AWS_DEFAULT_PROFILE") ||
68+
getenv("AWS_SHARED_CREDENTIALS_FILE") || getenv("AWS_CONFIG_FILE")) {
69+
return AwsAccessType::kEnvironment;
70+
}
71+
72+
return AwsAccessType::kUndefined;
73+
}
74+
75+
Status AwsCloudAccessCredentials::TEST_Initialize() {
76+
std::string type_str;
77+
if (CloudEnvOptions::GetNameFromEnvironment(
78+
"ROCKSDB_AWS_ACCESS_TYPE", "rocksdb_aws_access_type", &type_str)) {
79+
ParseEnum<AwsAccessType>(AwsAccessTypeMap, type_str, &type);
80+
}
81+
return HasValid();
82+
}
83+
84+
Status AwsCloudAccessCredentials::CheckCredentials(
85+
const AwsAccessType& aws_type) const {
86+
#ifndef USE_AWS
87+
return Status::NotSupported("AWS not supported");
88+
#else
89+
if (aws_type == AwsAccessType::kSimple) {
90+
if ((access_key_id.empty() && getenv("AWS_ACCESS_KEY_ID") == nullptr) ||
91+
(secret_key.empty() && getenv("AWS_SECRET_ACCESS_KEY") == nullptr)) {
92+
return Status::InvalidArgument(
93+
"AWS Credentials require both access ID and secret keys");
94+
}
95+
} else if (aws_type == AwsAccessType::kTaskRole) {
96+
return Status::InvalidArgument(
97+
"AWS access type: Task Role access is not supported.");
98+
} else if (aws_type == AwsAccessType::kUndefined) {
99+
return Status::InvalidArgument("Invalid AWS Credentials configuration");
100+
}
101+
return Status::OK();
102+
#endif
103+
}
104+
105+
void AwsCloudAccessCredentials::InitializeSimple(
106+
const std::string& aws_access_key_id, const std::string& aws_secret_key) {
107+
type = AwsAccessType::kSimple;
108+
access_key_id = aws_access_key_id;
109+
secret_key = aws_secret_key;
110+
}
111+
112+
void AwsCloudAccessCredentials::InitializeConfig(
113+
const std::string& aws_config_file) {
114+
type = AwsAccessType::kConfig;
115+
config_file = aws_config_file;
116+
}
117+
118+
Status AwsCloudAccessCredentials::HasValid() const {
119+
AwsAccessType aws_type = GetAccessType();
120+
Status status = CheckCredentials(aws_type);
121+
return status;
122+
}
123+
124+
Status AwsCloudAccessCredentials::GetCredentialsProvider(
125+
std::shared_ptr<Aws::Auth::AWSCredentialsProvider>* result) const {
126+
result->reset();
127+
128+
AwsAccessType aws_type = GetAccessType();
129+
Status status = CheckCredentials(aws_type);
130+
if (status.ok()) {
131+
switch (aws_type) {
132+
#ifdef USE_AWS
133+
case AwsAccessType::kSimple: {
134+
const char* access_key =
135+
(access_key_id.empty() ? getenv("AWS_ACCESS_KEY_ID")
136+
: access_key_id.c_str());
137+
const char* secret =
138+
(secret_key.empty() ? getenv("AWS_SECRET_ACCESS_KEY")
139+
: secret_key.c_str());
140+
result->reset(
141+
new Aws::Auth::SimpleAWSCredentialsProvider(access_key, secret));
142+
break;
143+
}
144+
case AwsAccessType::kConfig:
145+
if (!config_file.empty()) {
146+
result->reset(new Aws::Auth::ProfileConfigFileAWSCredentialsProvider(
147+
config_file.c_str()));
148+
} else {
149+
result->reset(
150+
new Aws::Auth::ProfileConfigFileAWSCredentialsProvider());
151+
}
152+
break;
153+
case AwsAccessType::kInstance:
154+
result->reset(new Aws::Auth::InstanceProfileCredentialsProvider());
155+
break;
156+
case AwsAccessType::kAnonymous:
157+
result->reset(new Aws::Auth::AnonymousAWSCredentialsProvider());
158+
break;
159+
case AwsAccessType::kEnvironment:
160+
result->reset(new Aws::Auth::EnvironmentAWSCredentialsProvider());
161+
break;
162+
#endif
163+
default:
164+
status = Status::NotSupported("AWS credentials type not supported");
165+
break; // not supported
166+
}
167+
}
168+
return status;
169+
}
170+
171+
#ifdef USE_AWS
29172
namespace detail {
30173

31174
using ScheduledJob =
@@ -202,7 +345,7 @@ Aws::S3::Model::CreateBucketOutcome AwsS3ClientWrapper::CreateBucket(
202345
Aws::S3::Model::HeadBucketOutcome AwsS3ClientWrapper::HeadBucket(
203346
const Aws::S3::Model::HeadBucketRequest& request) {
204347
CloudRequestCallbackGuard t(cloud_request_callback_.get(),
205-
CloudRequestOpType::kInfoOp);
348+
CloudRequestOpType::kInfoOp);
206349
return client_->HeadBucket(request);
207350
}
208351

@@ -278,12 +421,12 @@ AwsEnv::AwsEnv(Env* underlying_env, const CloudEnvOptions& _cloud_env_options,
278421
}
279422
}
280423

281-
unique_ptr<Aws::Auth::AWSCredentials> creds;
282-
if (!cloud_env_options.credentials.access_key_id.empty() &&
283-
!cloud_env_options.credentials.secret_key.empty()) {
284-
creds.reset(new Aws::Auth::AWSCredentials(
285-
ToAwsString(cloud_env_options.credentials.access_key_id),
286-
ToAwsString(cloud_env_options.credentials.secret_key)));
424+
shared_ptr<Aws::Auth::AWSCredentialsProvider> creds;
425+
create_bucket_status_ =
426+
cloud_env_options.credentials.GetCredentialsProvider(&creds);
427+
if (!create_bucket_status_.ok()) {
428+
Log(InfoLogLevel::INFO_LEVEL, info_log,
429+
"[aws] NewAwsEnv - Bad AWS credentials");
287430
}
288431

289432
Header(info_log_, " AwsEnv.src_bucket_name: %s",
@@ -324,8 +467,8 @@ AwsEnv::AwsEnv(Env* underlying_env, const CloudEnvOptions& _cloud_env_options,
324467
Log(InfoLogLevel::ERROR_LEVEL, info_log,
325468
"[aws] NewAwsEnv Buckets %s, %s in two different regions %s, %s "
326469
"is not supported",
327-
cloud_env_options.src_bucket.GetBucketName().c_str(),
328-
cloud_env_options.dest_bucket.GetBucketName().c_str(),
470+
cloud_env_options.src_bucket.GetBucketName().c_str(),
471+
cloud_env_options.dest_bucket.GetBucketName().c_str(),
329472
cloud_env_options.src_bucket.GetRegion().c_str(),
330473
cloud_env_options.dest_bucket.GetRegion().c_str());
331474
return;
@@ -340,10 +483,10 @@ AwsEnv::AwsEnv(Env* underlying_env, const CloudEnvOptions& _cloud_env_options,
340483
GetBucketLocationConstraintForName(config.region);
341484

342485
{
343-
auto s3client = creds ? std::make_shared<Aws::S3::S3Client>(*creds, config)
486+
auto s3client = creds ? std::make_shared<Aws::S3::S3Client>(creds, config)
344487
: std::make_shared<Aws::S3::S3Client>(config);
345488

346-
s3client_ = std::make_shared<AwsS3ClientWrapper>(
489+
s3client_ = std::make_shared<AwsS3ClientWrapper>(
347490
std::move(s3client), cloud_env_options.cloud_request_callback);
348491
}
349492

@@ -390,7 +533,7 @@ AwsEnv::AwsEnv(Env* underlying_env, const CloudEnvOptions& _cloud_env_options,
390533
if (cloud_env_options.log_type == kLogKinesis) {
391534
std::unique_ptr<Aws::Kinesis::KinesisClient> kinesis_client;
392535
kinesis_client.reset(creds
393-
? new Aws::Kinesis::KinesisClient(*creds, config)
536+
? new Aws::Kinesis::KinesisClient(creds, config)
394537
: new Aws::Kinesis::KinesisClient(config));
395538

396539
if (!kinesis_client) {
@@ -1895,47 +2038,6 @@ Status AwsEnv::NewAwsEnv(Env* base_env,
18952038
return status;
18962039
}
18972040

1898-
//
1899-
// Retrieves the AWS credentials from two environment variables
1900-
// called "aws_access_key_id" and "aws_secret_access_key".
1901-
//
1902-
Status AwsEnv::GetTestCredentials(std::string* aws_access_key_id,
1903-
std::string* aws_secret_access_key,
1904-
std::string* region) {
1905-
Status st;
1906-
char* id = getenv("AWS_ACCESS_KEY_ID");
1907-
if (id == nullptr) {
1908-
id = getenv("aws_access_key_id");
1909-
}
1910-
char* secret = getenv("AWS_SECRET_ACCESS_KEY");
1911-
if (secret == nullptr) {
1912-
secret = getenv("aws_secret_access_key");
1913-
}
1914-
1915-
if (id == nullptr || secret == nullptr) {
1916-
std::string msg =
1917-
"Skipping AWS tests. "
1918-
"AWS credentials should be set "
1919-
"using environment varaibles AWS_ACCESS_KEY_ID and "
1920-
"AWS_SECRET_ACCESS_KEY";
1921-
return Status::IOError(msg);
1922-
}
1923-
aws_access_key_id->assign(id);
1924-
aws_secret_access_key->assign(secret);
1925-
1926-
char* reg = getenv("AWS_DEFAULT_REGION");
1927-
if (reg == nullptr) {
1928-
reg = getenv("aws_default_region");
1929-
}
1930-
1931-
if (reg != nullptr) {
1932-
region->assign(reg);
1933-
} else {
1934-
region->assign("us-west-2");
1935-
}
1936-
return st;
1937-
}
1938-
19392041
std::string AwsEnv::GetWALCacheDir() {
19402042
return cloud_log_controller_->GetCacheDir();
19412043
}
@@ -1967,6 +2069,6 @@ Status CloudLogController::Retry(Env* env, RetryType func) {
19672069
}
19682070

19692071
#pragma GCC diagnostic pop
2072+
#endif // USE_AWS
19702073
} // namespace rocksdb
19712074

1972-
#endif

cloud/aws/aws_env.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,6 @@ class AwsEnv : public CloudEnvImpl {
249249
// AWS's utility to help out with uploading and downloading S3 file
250250
std::shared_ptr<Aws::Transfer::TransferManager> awsTransferManager_;
251251

252-
//
253-
// Get credentials for running unit tests
254-
//
255-
static Status GetTestCredentials(std::string* aws_access_key_id,
256-
std::string* aws_secret_access_key,
257-
std::string* region);
258-
259252
Status StartTailingStream();
260253

261254
// Saves and retrieves the dbid->dirname mapping in S3

cloud/cloud_env.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ void CloudEnvOptions::TEST_Initialize(const std::string& bucket,
3636
const std::string& region) {
3737
src_bucket.TEST_Initialize(bucket, object, region);
3838
dest_bucket = src_bucket;
39+
credentials.TEST_Initialize();
3940
}
4041

4142
BucketOptions::BucketOptions() {

cloud/cloud_env_impl.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,7 @@ Status CloudEnvImpl::SanitizeDirectory(const DBOptions& options,
827827
return st;
828828
}
829829
}
830-
return LoadCloudManifest(local_name, read_only);
830+
return st;
831831
}
832832

833833
Status CloudEnvImpl::FetchCloudManifest(const std::string& local_dbname,

cloud/cloud_env_options.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#ifndef ROCKSDB_LITE
33

44
#include <cinttypes>
5-
#include "cloud/aws/aws_env.h"
65
#include "cloud/cloud_env_impl.h"
76
#include "cloud/cloud_env_wrapper.h"
87
#include "cloud/db_cloud_impl.h"

cloud/db_cloud_impl.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,13 @@ Status DBCloud::Open(const Options& opt, const std::string& local_dbname,
7878
}
7979

8080
st = cenv->SanitizeDirectory(options, local_dbname, read_only);
81+
82+
if (st.ok()) {
83+
st = cenv->LoadCloudManifest(local_dbname, read_only);
84+
}
8185
if (!st.ok()) {
8286
return st;
8387
}
84-
8588
// If a persistent cache path is specified, then we set it in the options.
8689
if (!persistent_cache_path.empty() && persistent_cache_size_gb) {
8790
// Get existing options. If the persistent cache is already set, then do

cloud/db_cloud_test.cc

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,15 @@ class CloudTest : public testing::Test {
5151
&options_.info_log);
5252
options_.info_log->SetInfoLogLevel(InfoLogLevel::DEBUG_LEVEL);
5353

54-
// Get cloud credentials
55-
std::string dummy;
56-
AwsEnv::GetTestCredentials(&cloud_env_options_.credentials.access_key_id,
57-
&cloud_env_options_.credentials.secret_key,
58-
&dummy);
5954
Cleanup();
6055
}
6156

6257
void Cleanup() {
6358
ASSERT_TRUE(!aenv_);
6459

60+
// check cloud credentials
61+
ASSERT_TRUE(cloud_env_options_.credentials.HasValid().ok());
62+
6563
CloudEnv* aenv;
6664
// create a dummy aws env
6765
ASSERT_OK(CloudEnv::NewAwsEnv(base_env_, cloud_env_options_,
@@ -114,8 +112,7 @@ class CloudTest : public testing::Test {
114112

115113
// Open database via the cloud interface
116114
void OpenDB() {
117-
ASSERT_NE(cloud_env_options_.credentials.access_key_id.size(), 0);
118-
ASSERT_NE(cloud_env_options_.credentials.secret_key.size(), 0);
115+
ASSERT_TRUE(cloud_env_options_.credentials.HasValid().ok());
119116

120117
// Create new AWS env
121118
CreateAwsEnv();
@@ -1346,7 +1343,7 @@ int main(int argc, char** argv) {
13461343

13471344
#include <stdio.h>
13481345

1349-
int main(int argc, char** argv) {
1346+
int main(int, char**) {
13501347
fprintf(stderr,
13511348
"SKIPPED as DBCloud is supported only when USE_AWS is defined.\n");
13521349
return 0;

cloud/examples/clone_example.cc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,13 @@ int main() {
8888
// with every new cloud-db.
8989
std::unique_ptr<CloudEnv> cloud_env;
9090

91-
// Retrieve aws access keys from env
92-
char* keyid = getenv("AWS_ACCESS_KEY_ID");
93-
char* secret = getenv("AWS_SECRET_ACCESS_KEY");
94-
if (keyid == nullptr || secret == nullptr) {
91+
if (!cloud_env_options.credentials.HasValid().ok()) {
9592
fprintf(
9693
stderr,
9794
"Please set env variables "
9895
"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY with cloud credentials");
9996
return -1;
10097
}
101-
cloud_env_options.credentials.access_key_id.assign(keyid);
102-
cloud_env_options.credentials.secret_key.assign(secret);
10398

10499
// Append the user name to the bucket name in an attempt to make it
105100
// globally unique. S3 bucket-namess need to be globlly unique.

0 commit comments

Comments
 (0)