summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2020-01-02 20:55:49 +0000
committerevergreen <evergreen@mongodb.com>2020-01-02 20:55:49 +0000
commit87f947409fdd0074acf4c8301355dabe4d4098f9 (patch)
tree6ec4c9f070dc02f44cb25ed306828f323097652e
parentc86d4ad8c63e27f733b29c5f6bdb394540975782 (diff)
downloadmongo-87f947409fdd0074acf4c8301355dabe4d4098f9.tar.gz
SERVER-45241 Use instance metadata service v2 instead of v1
-rw-r--r--src/mongo/client/sasl_iam_client_conversation.cpp45
-rw-r--r--src/mongo/client/sasl_iam_client_protocol.cpp7
-rw-r--r--src/mongo/util/net/http_client.h5
-rw-r--r--src/mongo/util/net/http_client_curl.cpp15
-rw-r--r--src/mongo/util/net/http_client_winhttp.cpp5
5 files changed, 63 insertions, 14 deletions
diff --git a/src/mongo/client/sasl_iam_client_conversation.cpp b/src/mongo/client/sasl_iam_client_conversation.cpp
index a5b7f0c8b71..89fdc13794e 100644
--- a/src/mongo/client/sasl_iam_client_conversation.cpp
+++ b/src/mongo/client/sasl_iam_client_conversation.cpp
@@ -47,6 +47,7 @@ namespace iam {
SASLIamClientGlobalParams saslIamClientGlobalParams;
} // namespace iam
+namespace {
std::string getDefaultEC2Host() {
return iam::saslIamClientGlobalParams.awsEC2InstanceMetadataUrl;
}
@@ -55,6 +56,14 @@ std::string getDefaultECSHost() {
return iam::saslIamClientGlobalParams.awsECSInstanceMetadataUrl;
}
+StringData toString(DataBuilder& builder) {
+ ConstDataRange cdr = builder.getCursor();
+ StringData str;
+ cdr.readInto<StringData>(&str);
+ return str;
+}
+} // namespace
+
SaslIAMClientConversation::SaslIAMClientConversation(SaslClientSession* saslClientSession)
: SaslClientConversation(saslClientSession) {}
@@ -91,6 +100,7 @@ iam::AWSCredentials SaslIAMClientConversation::_getLocalAWSCredentials() const {
return _getEc2Credentials();
}
+
iam::AWSCredentials SaslIAMClientConversation::_getEc2Credentials() const {
try {
@@ -99,13 +109,25 @@ iam::AWSCredentials SaslIAMClientConversation::_getEc2Credentials() const {
// The local web server is just a normal HTTP server
httpClient->allowInsecureHTTP(true);
+ // Get the token for authenticating with Instance Metadata Version 2
+ // Set a lifetime of 30 seconds since we are only going to use this token for one set of
+ // requests.
+ std::vector<std::string> headers{"X-aws-ec2-metadata-token-ttl-seconds: 30"};
+ httpClient->setHeaders(headers);
+ DataBuilder getToken = httpClient->put(getDefaultEC2Host() + "/latest/api/token",
+ ConstDataRange(nullptr, nullptr));
+
+ StringData token = toString(getToken);
+
+ headers.clear();
+ headers.push_back("X-aws-ec2-metadata-token: " + token);
+ httpClient->setHeaders(headers);
+
// Retrieve the role attached to the EC2 instance
DataBuilder getRoleResult =
httpClient->get(getDefaultEC2Host() + "/latest/meta-data/iam/security-credentials/");
- ConstDataRange cdrRole = getRoleResult.getCursor();
- StringData getRoleOutput;
- cdrRole.readInto<StringData>(&getRoleOutput);
+ StringData getRoleOutput = toString(getRoleResult);
std::string role = iam::parseRoleFromEC2IamSecurityCredentials(getRoleOutput);
@@ -114,15 +136,15 @@ iam::AWSCredentials SaslIAMClientConversation::_getEc2Credentials() const {
str::stream() << getDefaultEC2Host() + "/latest/meta-data/iam/security-credentials/"
<< role);
- ConstDataRange cdrCredentials = getRoleCredentialsResult.getCursor();
- StringData getRoleCredentialsOutput;
- cdrCredentials.readInto<StringData>(&getRoleCredentialsOutput);
+ StringData getRoleCredentialsOutput = toString(getRoleCredentialsResult);
return iam::parseCredentialsFromEC2IamSecurityCredentials(getRoleCredentialsOutput);
} catch (const DBException& e) {
// Wrap exceptions from HTTP to make them clearer
- uassertStatusOKWithContext(e.toStatus(),
- "Failed to retrieve EC2 Instance Metadata Credentials");
+ uassertStatusOKWithContext(
+ e.toStatus(),
+ "Failed to retrieve EC2 Instance Metadata Service Credentials. Ensure there is a role "
+ "via an instance profile assigned to this machine.");
}
MONGO_UNREACHABLE;
@@ -139,15 +161,14 @@ iam::AWSCredentials SaslIAMClientConversation::_getEcsCredentials(StringData rel
// Retrieve the security token attached to the ECS task
DataBuilder getRoleResult = httpClient->get(getDefaultECSHost() + relativeUri);
- ConstDataRange cdrRole = getRoleResult.getCursor();
- StringData getRoleOutput;
- cdrRole.readInto<StringData>(&getRoleOutput);
+ StringData getRoleOutput = toString(getRoleResult);
return iam::parseCredentialsFromECSTaskIamCredentials(getRoleOutput);
} catch (const DBException& e) {
// Wrap exceptions from HTTP to make them clearer
uassertStatusOKWithContext(e.toStatus(),
- "Failed to retrieve ECS Instance Metadata Credentials");
+ "Failed to retrieve ECS Tasks Metadata Credentials. Ensure "
+ "there is an execution role assigned to this ECS task.");
}
MONGO_UNREACHABLE;
diff --git a/src/mongo/client/sasl_iam_client_protocol.cpp b/src/mongo/client/sasl_iam_client_protocol.cpp
index b6c6c4a3a51..41137c322cb 100644
--- a/src/mongo/client/sasl_iam_client_protocol.cpp
+++ b/src/mongo/client/sasl_iam_client_protocol.cpp
@@ -214,10 +214,13 @@ std::string getRegionFromHost(StringData host) {
}
std::string parseRoleFromEC2IamSecurityCredentials(StringData data) {
+ // Before the Nov 2019 AWS update, they added \n to the role_name.
size_t pos = data.find('\n');
- uassert(
- 51294, "Failed to parse role name from EC2 instance metadata", pos != std::string::npos);
+ if (pos == std::string::npos) {
+ pos = data.size();
+ }
+
return data.substr(0, pos).toString();
}
diff --git a/src/mongo/util/net/http_client.h b/src/mongo/util/net/http_client.h
index 9f5767b51fd..f6dea4b4ab5 100644
--- a/src/mongo/util/net/http_client.h
+++ b/src/mongo/util/net/http_client.h
@@ -80,6 +80,11 @@ public:
virtual DataBuilder post(StringData url, ConstDataRange data) const = 0;
/**
+ * Perform a PUT request to specified URL.
+ */
+ virtual DataBuilder put(StringData url, ConstDataRange data) const = 0;
+
+ /**
* Perform a GET request from the specified URL.
*/
virtual DataBuilder get(StringData url) const = 0;
diff --git a/src/mongo/util/net/http_client_curl.cpp b/src/mongo/util/net/http_client_curl.cpp
index ca51d73111f..20ca65442b3 100644
--- a/src/mongo/util/net/http_client_curl.cpp
+++ b/src/mongo/util/net/http_client_curl.cpp
@@ -277,6 +277,21 @@ public:
return doRequest(myHandle.get(), url);
}
+ DataBuilder put(StringData url, ConstDataRange cdr) const final {
+ // Make a local copy of the base handle for this request.
+ CurlHandle myHandle(curl_easy_duphandle(_handle.get()));
+ uassert(ErrorCodes::InternalError, "Curl initialization failed", myHandle);
+
+ curl_easy_setopt(myHandle.get(), CURLOPT_PUT, 1);
+
+ ConstDataRangeCursor cdrc(cdr);
+ curl_easy_setopt(myHandle.get(), CURLOPT_READFUNCTION, ReadMemoryCallback);
+ curl_easy_setopt(myHandle.get(), CURLOPT_READDATA, &cdrc);
+ curl_easy_setopt(myHandle.get(), CURLOPT_INFILESIZE_LARGE, (long)cdrc.length());
+
+ return doRequest(myHandle.get(), url);
+ }
+
private:
/**
* Helper for use with curl_easy_setopt which takes a vararg list,
diff --git a/src/mongo/util/net/http_client_winhttp.cpp b/src/mongo/util/net/http_client_winhttp.cpp
index f774e7387e4..1a54d4be355 100644
--- a/src/mongo/util/net/http_client_winhttp.cpp
+++ b/src/mongo/util/net/http_client_winhttp.cpp
@@ -163,6 +163,11 @@ public:
L"POST", url, const_cast<void*>(static_cast<const void*>(cdr.data())), cdr.length());
}
+ DataBuilder put(StringData url, ConstDataRange cdr) const final {
+ return doRequest(
+ L"PUT", url, const_cast<void*>(static_cast<const void*>(cdr.data())), cdr.length());
+ }
+
DataBuilder get(StringData url) const final {
return doRequest(L"GET", url, nullptr, 0);
}