|
14 | 14 | #include <Disks/ObjectStorages/S3/S3ObjectStorage.h>
|
15 | 15 | #include <Disks/ObjectStorages/S3/diskSettings.h>
|
16 | 16 |
|
| 17 | +#include <Interpreters/evaluateConstantExpression.h> |
| 18 | + |
17 | 19 | #include <Parsers/ASTFunction.h>
|
18 | 20 | #include <Parsers/ASTIdentifier.h>
|
19 | 21 | #include <Parsers/ASTLiteral.h>
|
@@ -46,6 +48,9 @@ namespace S3AuthSetting
|
46 | 48 | extern const S3AuthSettingsString secret_access_key;
|
47 | 49 | extern const S3AuthSettingsString session_token;
|
48 | 50 | extern const S3AuthSettingsBool use_environment_credentials;
|
| 51 | + extern const S3AuthSettingsString role_arn; |
| 52 | + extern const S3AuthSettingsString role_session_name; |
| 53 | + extern const S3AuthSettingsString sts_endpoint_override; |
49 | 54 | }
|
50 | 55 |
|
51 | 56 | namespace ErrorCodes
|
@@ -182,8 +187,66 @@ void StorageS3Configuration::fromNamedCollection(const NamedCollection & collect
|
182 | 187 | keys = {url.key};
|
183 | 188 | }
|
184 | 189 |
|
| 190 | +void StorageS3Configuration::extractExtraCreds(ASTs & args, ContextPtr context) |
| 191 | +{ |
| 192 | + ASTs::iterator extra_creds_it = args.end(); |
| 193 | + |
| 194 | + for (auto * arg_it = args.begin(); arg_it != args.end(); ++arg_it) |
| 195 | + { |
| 196 | + const auto * extra_creds_ast_function = (*arg_it)->as<ASTFunction>(); |
| 197 | + if (extra_creds_ast_function && extra_creds_ast_function->name == "extra_credentials") |
| 198 | + { |
| 199 | + if (extra_creds_it != args.end()) |
| 200 | + throw Exception( |
| 201 | + ErrorCodes::BAD_ARGUMENTS, |
| 202 | + "S3 table function can have only one extra_credentials argument"); |
| 203 | + |
| 204 | + const auto * extra_creds_function_args_expr = assert_cast<const ASTExpressionList *>(extra_creds_ast_function->arguments.get()); |
| 205 | + auto extra_creds_function_args = extra_creds_function_args_expr->children; |
| 206 | + |
| 207 | + for (auto & extra_cred_arg : extra_creds_function_args) |
| 208 | + { |
| 209 | + const auto * extra_cred_ast = extra_cred_arg->as<ASTFunction>(); |
| 210 | + if (!extra_cred_ast || extra_cred_ast->name != "equals") |
| 211 | + throw Exception(ErrorCodes::BAD_ARGUMENTS, "extra_credentials argument is incorrect: shall be key=value"); |
| 212 | + |
| 213 | + const auto * extra_cred_args_expr = assert_cast<const ASTExpressionList *>(extra_cred_ast->arguments.get()); |
| 214 | + auto extra_cred_args = extra_cred_args_expr->children; |
| 215 | + if (extra_cred_args.size() != 2) |
| 216 | + throw Exception( |
| 217 | + ErrorCodes::BAD_ARGUMENTS, |
| 218 | + "extra_credentials argument is incorrect: expected 2 arguments, got {}", |
| 219 | + extra_cred_args.size()); |
| 220 | + |
| 221 | + auto ast_literal = evaluateConstantExpressionOrIdentifierAsLiteral(extra_cred_args[0], context); |
| 222 | + auto arg_name_value = ast_literal->as<ASTLiteral>()->value; |
| 223 | + if (arg_name_value.getType() != Field::Types::Which::String) |
| 224 | + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected string as extra_credentials name"); |
| 225 | + auto arg_name = arg_name_value.safeGet<String>(); |
| 226 | + |
| 227 | + ast_literal = evaluateConstantExpressionOrIdentifierAsLiteral(extra_cred_args[1], context); |
| 228 | + auto arg_value = ast_literal->as<ASTLiteral>()->value; |
| 229 | + if (arg_value.getType() != Field::Types::Which::String) |
| 230 | + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected string as extra_credentials value"); |
| 231 | + |
| 232 | + extra_credentials_from_ast.emplace_back(arg_name, arg_value.safeGet<String>()); |
| 233 | + } |
| 234 | + |
| 235 | + extra_creds_it = arg_it; |
| 236 | + continue; |
| 237 | + } |
| 238 | + } |
| 239 | + |
| 240 | + /// To avoid making unnecessary changes and avoid potential conflicts in future, |
| 241 | + /// simply remove the "extra" argument after processing if it exists. |
| 242 | + if (extra_creds_it != args.end()) |
| 243 | + args.erase(extra_creds_it); |
| 244 | +} |
| 245 | + |
185 | 246 | void StorageS3Configuration::fromAST(ASTs & args, ContextPtr context, bool with_structure)
|
186 | 247 | {
|
| 248 | + extractExtraCreds(args, context); |
| 249 | + |
187 | 250 | size_t count = StorageURL::evalArgsAndCollectHeaders(args, headers_from_ast, context);
|
188 | 251 |
|
189 | 252 | if (count == 0 || count > getMaxNumberOfArguments(with_structure))
|
@@ -381,6 +444,23 @@ void StorageS3Configuration::fromAST(ASTs & args, ContextPtr context, bool with_
|
381 | 444 | if (no_sign_request)
|
382 | 445 | auth_settings[S3AuthSetting::no_sign_request] = no_sign_request;
|
383 | 446 |
|
| 447 | + if (!extra_credentials_from_ast.empty()) |
| 448 | + { |
| 449 | + auto extract_extra_cred_value = [&extra_creds = this->extra_credentials_from_ast](const String & cred_name) -> String |
| 450 | + { |
| 451 | + auto role_arn_it = std::find_if(extra_creds.begin(), extra_creds.end(), |
| 452 | + [&cred_name](const HTTPHeaderEntry & entry) { return entry.name == cred_name; }); |
| 453 | + if (role_arn_it != extra_creds.end()) |
| 454 | + return role_arn_it->value; |
| 455 | + |
| 456 | + return {}; |
| 457 | + }; |
| 458 | + |
| 459 | + auth_settings[S3AuthSetting::role_arn] = extract_extra_cred_value("role_arn"); |
| 460 | + auth_settings[S3AuthSetting::role_session_name] = extract_extra_cred_value("role_session_name"); |
| 461 | + auth_settings[S3AuthSetting::sts_endpoint_override] = extract_extra_cred_value("sts_endpoint_override"); |
| 462 | + } |
| 463 | + |
384 | 464 | static_configuration = !auth_settings[S3AuthSetting::access_key_id].value.empty() || auth_settings[S3AuthSetting::no_sign_request].changed;
|
385 | 465 | auth_settings[S3AuthSetting::no_sign_request] = no_sign_request;
|
386 | 466 |
|
|
0 commit comments