|
13 | 13 | #include <Disks/ObjectStorages/S3/S3ObjectStorage.h>
|
14 | 14 | #include <Disks/ObjectStorages/S3/diskSettings.h>
|
15 | 15 |
|
| 16 | +#include <Interpreters/evaluateConstantExpression.h> |
| 17 | + |
16 | 18 | #include <Parsers/ASTFunction.h>
|
17 | 19 | #include <Parsers/ASTIdentifier.h>
|
18 | 20 | #include <Parsers/ASTLiteral.h>
|
@@ -45,6 +47,9 @@ namespace S3AuthSetting
|
45 | 47 | extern const S3AuthSettingsString secret_access_key;
|
46 | 48 | extern const S3AuthSettingsString session_token;
|
47 | 49 | extern const S3AuthSettingsBool use_environment_credentials;
|
| 50 | + extern const S3AuthSettingsString role_arn; |
| 51 | + extern const S3AuthSettingsString role_session_name; |
| 52 | + extern const S3AuthSettingsString sts_endpoint_override; |
48 | 53 | }
|
49 | 54 |
|
50 | 55 | namespace ErrorCodes
|
@@ -109,6 +114,7 @@ StorageS3Configuration::StorageS3Configuration(const StorageS3Configuration & ot
|
109 | 114 | url = other.url;
|
110 | 115 | static_configuration = other.static_configuration;
|
111 | 116 | headers_from_ast = other.headers_from_ast;
|
| 117 | + extra_credentials_from_ast = other.extra_credentials_from_ast; |
112 | 118 | keys = other.keys;
|
113 | 119 | }
|
114 | 120 |
|
@@ -190,8 +196,66 @@ void StorageS3Configuration::fromNamedCollection(const NamedCollection & collect
|
190 | 196 | keys = {url.key};
|
191 | 197 | }
|
192 | 198 |
|
| 199 | +void StorageS3Configuration::extractExtraCreds(ASTs & args, ContextPtr context) |
| 200 | +{ |
| 201 | + ASTs::iterator extra_creds_it = args.end(); |
| 202 | + |
| 203 | + for (auto * arg_it = args.begin(); arg_it != args.end(); ++arg_it) |
| 204 | + { |
| 205 | + const auto * extra_creds_ast_function = (*arg_it)->as<ASTFunction>(); |
| 206 | + if (extra_creds_ast_function && extra_creds_ast_function->name == "extra_credentials") |
| 207 | + { |
| 208 | + if (extra_creds_it != args.end()) |
| 209 | + throw Exception( |
| 210 | + ErrorCodes::BAD_ARGUMENTS, |
| 211 | + "S3 table function can have only one extra_credentials argument"); |
| 212 | + |
| 213 | + const auto * extra_creds_function_args_expr = assert_cast<const ASTExpressionList *>(extra_creds_ast_function->arguments.get()); |
| 214 | + auto extra_creds_function_args = extra_creds_function_args_expr->children; |
| 215 | + |
| 216 | + for (auto & extra_cred_arg : extra_creds_function_args) |
| 217 | + { |
| 218 | + const auto * extra_cred_ast = extra_cred_arg->as<ASTFunction>(); |
| 219 | + if (!extra_cred_ast || extra_cred_ast->name != "equals") |
| 220 | + throw Exception(ErrorCodes::BAD_ARGUMENTS, "extra_credentials argument is incorrect: shall be key=value"); |
| 221 | + |
| 222 | + const auto * extra_cred_args_expr = assert_cast<const ASTExpressionList *>(extra_cred_ast->arguments.get()); |
| 223 | + auto extra_cred_args = extra_cred_args_expr->children; |
| 224 | + if (extra_cred_args.size() != 2) |
| 225 | + throw Exception( |
| 226 | + ErrorCodes::BAD_ARGUMENTS, |
| 227 | + "extra_credentials argument is incorrect: expected 2 arguments, got {}", |
| 228 | + extra_cred_args.size()); |
| 229 | + |
| 230 | + auto ast_literal = evaluateConstantExpressionOrIdentifierAsLiteral(extra_cred_args[0], context); |
| 231 | + auto arg_name_value = ast_literal->as<ASTLiteral>()->value; |
| 232 | + if (arg_name_value.getType() != Field::Types::Which::String) |
| 233 | + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected string as extra_credentials name"); |
| 234 | + auto arg_name = arg_name_value.safeGet<String>(); |
| 235 | + |
| 236 | + ast_literal = evaluateConstantExpressionOrIdentifierAsLiteral(extra_cred_args[1], context); |
| 237 | + auto arg_value = ast_literal->as<ASTLiteral>()->value; |
| 238 | + if (arg_value.getType() != Field::Types::Which::String) |
| 239 | + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected string as extra_credentials value"); |
| 240 | + |
| 241 | + extra_credentials_from_ast.emplace_back(arg_name, arg_value.safeGet<String>()); |
| 242 | + } |
| 243 | + |
| 244 | + extra_creds_it = arg_it; |
| 245 | + continue; |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + /// To avoid making unnecessary changes and avoid potential conflicts in future, |
| 250 | + /// simply remove the "extra" argument after processing if it exists. |
| 251 | + if (extra_creds_it != args.end()) |
| 252 | + args.erase(extra_creds_it); |
| 253 | +} |
| 254 | + |
193 | 255 | void StorageS3Configuration::fromAST(ASTs & args, ContextPtr context, bool with_structure)
|
194 | 256 | {
|
| 257 | + extractExtraCreds(args, context); |
| 258 | + |
195 | 259 | size_t count = StorageURL::evalArgsAndCollectHeaders(args, headers_from_ast, context);
|
196 | 260 |
|
197 | 261 | if (count == 0 || count > getMaxNumberOfArguments(with_structure))
|
@@ -389,6 +453,23 @@ void StorageS3Configuration::fromAST(ASTs & args, ContextPtr context, bool with_
|
389 | 453 | if (no_sign_request)
|
390 | 454 | auth_settings[S3AuthSetting::no_sign_request] = no_sign_request;
|
391 | 455 |
|
| 456 | + if (!extra_credentials_from_ast.empty()) |
| 457 | + { |
| 458 | + auto extract_extra_cred_value = [&extra_creds = this->extra_credentials_from_ast](const String & cred_name) -> String |
| 459 | + { |
| 460 | + auto role_arn_it = std::find_if(extra_creds.begin(), extra_creds.end(), |
| 461 | + [&cred_name](const HTTPHeaderEntry & entry) { return entry.name == cred_name; }); |
| 462 | + if (role_arn_it != extra_creds.end()) |
| 463 | + return role_arn_it->value; |
| 464 | + |
| 465 | + return {}; |
| 466 | + }; |
| 467 | + |
| 468 | + auth_settings[S3AuthSetting::role_arn] = extract_extra_cred_value("role_arn"); |
| 469 | + auth_settings[S3AuthSetting::role_session_name] = extract_extra_cred_value("role_session_name"); |
| 470 | + auth_settings[S3AuthSetting::sts_endpoint_override] = extract_extra_cred_value("sts_endpoint_override"); |
| 471 | + } |
| 472 | + |
392 | 473 | static_configuration = !auth_settings[S3AuthSetting::access_key_id].value.empty() || auth_settings[S3AuthSetting::no_sign_request].changed;
|
393 | 474 | auth_settings[S3AuthSetting::no_sign_request] = no_sign_request;
|
394 | 475 |
|
@@ -586,6 +667,52 @@ void StorageS3Configuration::addStructureAndFormatToArgsIfNeeded(
|
586 | 667 | }
|
587 | 668 | }
|
588 | 669 |
|
| 670 | +ASTPtr StorageS3Configuration::createArgsWithAccessData() const |
| 671 | +{ |
| 672 | + auto arguments = std::make_shared<ASTExpressionList>(); |
| 673 | + |
| 674 | + arguments->children.push_back(std::make_shared<ASTLiteral>(url.uri_str)); |
| 675 | + if (auth_settings[S3AuthSetting::no_sign_request]) |
| 676 | + { |
| 677 | + arguments->children.push_back(std::make_shared<ASTLiteral>("NOSIGN")); |
| 678 | + } |
| 679 | + else |
| 680 | + { |
| 681 | + arguments->children.push_back(std::make_shared<ASTLiteral>(auth_settings[S3AuthSetting::access_key_id].value)); |
| 682 | + arguments->children.push_back(std::make_shared<ASTLiteral>(auth_settings[S3AuthSetting::secret_access_key].value)); |
| 683 | + if (!auth_settings[S3AuthSetting::session_token].value.empty()) |
| 684 | + arguments->children.push_back(std::make_shared<ASTLiteral>(auth_settings[S3AuthSetting::session_token].value)); |
| 685 | + if (format != "auto") |
| 686 | + arguments->children.push_back(std::make_shared<ASTLiteral>(format)); |
| 687 | + if (!compression_method.empty()) |
| 688 | + arguments->children.push_back(std::make_shared<ASTLiteral>(compression_method)); |
| 689 | + |
| 690 | + if (!auth_settings[S3AuthSetting::role_arn].value.empty()) |
| 691 | + { |
| 692 | + auto extra_creds_ast_function = std::make_shared<ASTFunction>(); |
| 693 | + extra_creds_ast_function->name = "extra_credentials"; |
| 694 | + |
| 695 | + auto role_arn_ast = std::make_shared<ASTFunction>(); |
| 696 | + role_arn_ast->name = "equals"; |
| 697 | + role_arn_ast->children.push_back(std::make_shared<ASTLiteral>("role_arn")); |
| 698 | + role_arn_ast->children.push_back(std::make_shared<ASTLiteral>(auth_settings[S3AuthSetting::role_arn].value)); |
| 699 | + |
| 700 | + extra_creds_ast_function->children.push_back(role_arn_ast); |
| 701 | + |
| 702 | + auto role_session_name_ast = std::make_shared<ASTFunction>(); |
| 703 | + role_session_name_ast->name = "equals"; |
| 704 | + role_session_name_ast->children.push_back(std::make_shared<ASTLiteral>("role_session_name")); |
| 705 | + role_session_name_ast->children.push_back(std::make_shared<ASTLiteral>(auth_settings[S3AuthSetting::role_session_name].value)); |
| 706 | + |
| 707 | + extra_creds_ast_function->children.push_back(role_session_name_ast); |
| 708 | + |
| 709 | + arguments->children.push_back(extra_creds_ast_function); |
| 710 | + } |
| 711 | + } |
| 712 | + |
| 713 | + return arguments; |
| 714 | +} |
| 715 | + |
589 | 716 | }
|
590 | 717 |
|
591 | 718 | #endif
|
0 commit comments