2022-09-15 14:06:22 +00:00
|
|
|
#include <IO/S3Common.h>
|
2019-12-06 14:37:21 +00:00
|
|
|
|
2022-09-15 14:06:22 +00:00
|
|
|
#include <Common/Exception.h>
|
2022-09-15 10:11:09 +00:00
|
|
|
#include <Poco/Util/AbstractConfiguration.h>
|
2022-09-28 08:45:15 +00:00
|
|
|
#include "config.h"
|
2022-09-15 10:11:09 +00:00
|
|
|
|
2019-12-06 14:37:21 +00:00
|
|
|
#if USE_AWS_S3
|
|
|
|
|
2022-12-16 22:57:09 +00:00
|
|
|
# include <IO/HTTPHeaderEntries.h>
|
2023-02-03 13:30:52 +00:00
|
|
|
# include <IO/S3/Client.h>
|
|
|
|
# include <IO/S3/Requests.h>
|
2024-01-07 01:16:29 +00:00
|
|
|
# include <Common/quoteString.h>
|
2022-04-27 15:05:45 +00:00
|
|
|
# include <Common/logger_useful.h>
|
2019-11-05 07:54:13 +00:00
|
|
|
|
2021-11-08 07:59:43 +00:00
|
|
|
|
2022-09-19 18:40:32 +00:00
|
|
|
namespace ProfileEvents
|
|
|
|
{
|
2023-01-14 02:17:31 +00:00
|
|
|
extern const Event S3GetObjectAttributes;
|
|
|
|
extern const Event S3GetObjectMetadata;
|
2022-09-19 18:40:32 +00:00
|
|
|
extern const Event S3HeadObject;
|
2023-01-16 19:14:39 +00:00
|
|
|
extern const Event DiskS3GetObjectAttributes;
|
2023-01-14 02:17:31 +00:00
|
|
|
extern const Event DiskS3GetObjectMetadata;
|
2022-09-19 18:40:32 +00:00
|
|
|
extern const Event DiskS3HeadObject;
|
|
|
|
}
|
|
|
|
|
2022-09-06 11:59:55 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
bool S3Exception::isRetryableError() const
|
|
|
|
{
|
|
|
|
/// Looks like these list is quite conservative, add more codes if you wish
|
|
|
|
static const std::unordered_set<Aws::S3::S3Errors> unretryable_errors = {
|
|
|
|
Aws::S3::S3Errors::NO_SUCH_KEY,
|
|
|
|
Aws::S3::S3Errors::ACCESS_DENIED,
|
|
|
|
Aws::S3::S3Errors::INVALID_ACCESS_KEY_ID,
|
|
|
|
Aws::S3::S3Errors::INVALID_SIGNATURE,
|
|
|
|
Aws::S3::S3Errors::NO_SUCH_UPLOAD,
|
|
|
|
Aws::S3::S3Errors::NO_SUCH_BUCKET,
|
|
|
|
};
|
|
|
|
|
|
|
|
return !unretryable_errors.contains(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-02-13 12:28:04 +00:00
|
|
|
namespace DB::ErrorCodes
|
2019-12-06 15:14:39 +00:00
|
|
|
{
|
2022-03-21 14:52:26 +00:00
|
|
|
extern const int S3_ERROR;
|
2019-12-03 01:22:25 +00:00
|
|
|
}
|
|
|
|
|
2022-09-15 10:11:09 +00:00
|
|
|
#endif
|
2022-09-15 07:45:28 +00:00
|
|
|
|
2022-09-15 10:11:09 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
2022-09-15 07:45:28 +00:00
|
|
|
|
2022-09-15 10:11:09 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int INVALID_CONFIG_PARAMETER;
|
2019-11-05 07:54:13 +00:00
|
|
|
}
|
|
|
|
|
2022-09-15 10:11:09 +00:00
|
|
|
namespace S3
|
|
|
|
{
|
|
|
|
|
2023-04-12 16:59:37 +00:00
|
|
|
HTTPHeaderEntries getHTTPHeaders(const std::string & config_elem, const Poco::Util::AbstractConfiguration & config)
|
|
|
|
{
|
|
|
|
HTTPHeaderEntries headers;
|
|
|
|
Poco::Util::AbstractConfiguration::Keys subconfig_keys;
|
|
|
|
config.keys(config_elem, subconfig_keys);
|
|
|
|
for (const std::string & subkey : subconfig_keys)
|
|
|
|
{
|
|
|
|
if (subkey.starts_with("header"))
|
|
|
|
{
|
|
|
|
auto header_str = config.getString(config_elem + "." + subkey);
|
|
|
|
auto delimiter = header_str.find(':');
|
|
|
|
if (delimiter == std::string::npos)
|
|
|
|
throw Exception(ErrorCodes::INVALID_CONFIG_PARAMETER, "Malformed s3 header value");
|
|
|
|
headers.emplace_back(header_str.substr(0, delimiter), header_str.substr(delimiter + 1, String::npos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return headers;
|
|
|
|
}
|
|
|
|
|
2023-04-12 17:01:07 +00:00
|
|
|
ServerSideEncryptionKMSConfig getSSEKMSConfig(const std::string & config_elem, const Poco::Util::AbstractConfiguration & config)
|
|
|
|
{
|
|
|
|
ServerSideEncryptionKMSConfig sse_kms_config;
|
|
|
|
|
|
|
|
if (config.has(config_elem + ".server_side_encryption_kms_key_id"))
|
|
|
|
sse_kms_config.key_id = config.getString(config_elem + ".server_side_encryption_kms_key_id");
|
|
|
|
|
|
|
|
if (config.has(config_elem + ".server_side_encryption_kms_encryption_context"))
|
|
|
|
sse_kms_config.encryption_context = config.getString(config_elem + ".server_side_encryption_kms_encryption_context");
|
|
|
|
|
|
|
|
if (config.has(config_elem + ".server_side_encryption_kms_bucket_key_enabled"))
|
|
|
|
sse_kms_config.bucket_key_enabled = config.getBool(config_elem + ".server_side_encryption_kms_bucket_key_enabled");
|
|
|
|
|
|
|
|
return sse_kms_config;
|
|
|
|
}
|
|
|
|
|
2022-09-15 14:06:22 +00:00
|
|
|
AuthSettings AuthSettings::loadFromConfig(const std::string & config_elem, const Poco::Util::AbstractConfiguration & config)
|
2022-09-15 10:11:09 +00:00
|
|
|
{
|
|
|
|
auto access_key_id = config.getString(config_elem + ".access_key_id", "");
|
|
|
|
auto secret_access_key = config.getString(config_elem + ".secret_access_key", "");
|
2023-12-14 08:02:21 +00:00
|
|
|
auto session_token = config.getString(config_elem + ".session_token", "");
|
|
|
|
|
2022-09-15 10:11:09 +00:00
|
|
|
auto region = config.getString(config_elem + ".region", "");
|
|
|
|
auto server_side_encryption_customer_key_base64 = config.getString(config_elem + ".server_side_encryption_customer_key_base64", "");
|
|
|
|
|
|
|
|
std::optional<bool> use_environment_credentials;
|
|
|
|
if (config.has(config_elem + ".use_environment_credentials"))
|
|
|
|
use_environment_credentials = config.getBool(config_elem + ".use_environment_credentials");
|
|
|
|
|
|
|
|
std::optional<bool> use_insecure_imds_request;
|
|
|
|
if (config.has(config_elem + ".use_insecure_imds_request"))
|
|
|
|
use_insecure_imds_request = config.getBool(config_elem + ".use_insecure_imds_request");
|
|
|
|
|
2023-03-10 10:06:32 +00:00
|
|
|
std::optional<uint64_t> expiration_window_seconds;
|
|
|
|
if (config.has(config_elem + ".expiration_window_seconds"))
|
|
|
|
expiration_window_seconds = config.getUInt64(config_elem + ".expiration_window_seconds");
|
|
|
|
|
2023-03-27 14:44:34 +00:00
|
|
|
std::optional<bool> no_sign_request;
|
|
|
|
if (config.has(config_elem + ".no_sign_request"))
|
|
|
|
no_sign_request = config.getBool(config_elem + ".no_sign_request");
|
|
|
|
|
2023-04-12 16:59:37 +00:00
|
|
|
HTTPHeaderEntries headers = getHTTPHeaders(config_elem, config);
|
2023-04-12 17:01:07 +00:00
|
|
|
ServerSideEncryptionKMSConfig sse_kms_config = getSSEKMSConfig(config_elem, config);
|
2022-09-15 10:11:09 +00:00
|
|
|
|
|
|
|
return AuthSettings
|
|
|
|
{
|
2023-12-14 08:02:21 +00:00
|
|
|
std::move(access_key_id), std::move(secret_access_key), std::move(session_token),
|
2022-09-15 10:11:09 +00:00
|
|
|
std::move(region),
|
|
|
|
std::move(server_side_encryption_customer_key_base64),
|
2023-04-12 17:01:07 +00:00
|
|
|
std::move(sse_kms_config),
|
2022-09-15 10:11:09 +00:00
|
|
|
std::move(headers),
|
|
|
|
use_environment_credentials,
|
2023-03-10 10:06:32 +00:00
|
|
|
use_insecure_imds_request,
|
2023-03-27 14:44:34 +00:00
|
|
|
expiration_window_seconds,
|
|
|
|
no_sign_request
|
2022-09-15 10:11:09 +00:00
|
|
|
};
|
2019-12-01 11:24:55 +00:00
|
|
|
}
|
2019-12-06 14:37:21 +00:00
|
|
|
|
2024-01-07 01:16:29 +00:00
|
|
|
bool AuthSettings::hasUpdates(const AuthSettings & other) const
|
|
|
|
{
|
|
|
|
AuthSettings copy = *this;
|
|
|
|
copy.updateFrom(other);
|
|
|
|
return copy != other;
|
|
|
|
}
|
2022-09-27 07:28:26 +00:00
|
|
|
|
|
|
|
void AuthSettings::updateFrom(const AuthSettings & from)
|
|
|
|
{
|
|
|
|
/// Update with check for emptyness only parameters which
|
|
|
|
/// can be passed not only from config, but via ast.
|
|
|
|
|
|
|
|
if (!from.access_key_id.empty())
|
|
|
|
access_key_id = from.access_key_id;
|
|
|
|
if (!from.secret_access_key.empty())
|
|
|
|
secret_access_key = from.secret_access_key;
|
2023-12-14 08:02:21 +00:00
|
|
|
if (!from.session_token.empty())
|
|
|
|
session_token = from.session_token;
|
2022-09-27 07:28:26 +00:00
|
|
|
|
|
|
|
headers = from.headers;
|
|
|
|
region = from.region;
|
|
|
|
server_side_encryption_customer_key_base64 = from.server_side_encryption_customer_key_base64;
|
2023-04-12 17:01:07 +00:00
|
|
|
server_side_encryption_kms_config = from.server_side_encryption_kms_config;
|
2023-03-29 11:08:44 +00:00
|
|
|
|
2023-03-29 12:54:57 +00:00
|
|
|
if (from.use_environment_credentials.has_value())
|
2023-03-29 11:08:44 +00:00
|
|
|
use_environment_credentials = from.use_environment_credentials;
|
|
|
|
|
2023-03-29 12:54:57 +00:00
|
|
|
if (from.use_insecure_imds_request.has_value())
|
2023-03-29 11:08:44 +00:00
|
|
|
use_insecure_imds_request = from.use_insecure_imds_request;
|
|
|
|
|
2023-03-29 12:54:57 +00:00
|
|
|
if (from.expiration_window_seconds.has_value())
|
2023-03-29 11:08:44 +00:00
|
|
|
expiration_window_seconds = from.expiration_window_seconds;
|
2023-03-27 14:44:34 +00:00
|
|
|
|
|
|
|
if (from.no_sign_request.has_value())
|
2024-01-07 01:16:29 +00:00
|
|
|
no_sign_request = from.no_sign_request;
|
2022-09-27 07:28:26 +00:00
|
|
|
}
|
|
|
|
|
2022-09-15 10:11:09 +00:00
|
|
|
}
|
|
|
|
}
|