diff options
author | Yehuda Sadeh <yehuda@redhat.com> | 2021-02-19 18:42:12 +0100 |
---|---|---|
committer | Yehuda Sadeh <yehuda@redhat.com> | 2021-03-09 11:04:58 +0100 |
commit | d98ed0cb9f4f90266503dfc889746c678b7f946d (patch) | |
tree | 17a1833a70255724170faefe2435114151f10a3c | |
parent | rgw: rest client: sign awsv4 content (if possible) (diff) | |
download | ceph-d98ed0cb9f4f90266503dfc889746c678b7f946d.tar.xz ceph-d98ed0cb9f4f90266503dfc889746c678b7f946d.zip |
rgw: auth v4: extract service from url
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
-rw-r--r-- | src/rgw/rgw_auth_s3.cc | 7 | ||||
-rw-r--r-- | src/rgw/rgw_auth_s3.h | 3 | ||||
-rw-r--r-- | src/rgw/rgw_rest_client.cc | 62 | ||||
-rw-r--r-- | src/rgw/rgw_rest_client.h | 1 | ||||
-rw-r--r-- | src/rgw/rgw_rest_s3.cc | 3 | ||||
-rw-r--r-- | src/rgw/rgw_rest_s3.h | 1 |
6 files changed, 54 insertions, 23 deletions
diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index 0ea45f19721..f59f3126344 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -495,7 +495,8 @@ int parse_v4_credentials(const req_info& info, /* in */ } string gen_v4_scope(const ceph::real_time& timestamp, - const string& region) + const string& region, + const string& service) { auto sec = real_clock::to_time_t(timestamp); @@ -507,8 +508,8 @@ string gen_v4_scope(const ceph::real_time& timestamp, auto mon = bt.tm_mon + 1; auto day = bt.tm_mday; - return fmt::format(FMT_STRING("{:d}{:02d}{:02d}/{:s}/s3/aws4_request"), - year, mon, day, region); + return fmt::format(FMT_STRING("{:d}{:02d}{:02d}/{:s}/{:s}/aws4_request"), + year, mon, day, region, service); } std::string get_v4_canonical_qs(const req_info& info, const bool using_qs) diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index f0598495bd2..7b479894dbf 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -467,7 +467,8 @@ int parse_v4_credentials(const req_info& info, /* in */ const DoutPrefixProvider *dpp); /* in */ string gen_v4_scope(const ceph::real_time& timestamp, - const string& region); + const string& region, + const string& service); static inline bool char_needs_aws4_escaping(const char c, bool encode_slash) { diff --git a/src/rgw/rgw_rest_client.cc b/src/rgw/rgw_rest_client.cc index 1918adbc800..ccdf0f38817 100644 --- a/src/rgw/rgw_rest_client.cc +++ b/src/rgw/rgw_rest_client.cc @@ -187,7 +187,9 @@ void RGWHTTPSimpleRequest::get_out_headers(map<string, string> *pheaders) out_headers.clear(); } -static int sign_request(const DoutPrefixProvider *dpp, RGWAccessKey& key, const string& region, RGWEnv& env, req_info& info) +static int sign_request(const DoutPrefixProvider *dpp, RGWAccessKey& key, + const string& region, const string& service, + RGWEnv& env, req_info& info) { /* don't sign if no key is provided */ if (key.key.empty()) { @@ -204,7 +206,7 @@ static int sign_request(const DoutPrefixProvider *dpp, RGWAccessKey& key, const rgw::auth::s3::AWSSignerV4 signer(dpp); - auto sigv4_data = signer.prepare(key.id, region, info, true); + auto sigv4_data = signer.prepare(key.id, region, service, info, true); auto sigv4_headers = sigv4_data.signature_factory(dpp, key.key, sigv4_data); for (auto& entry : sigv4_headers) { @@ -227,46 +229,67 @@ static string extract_region_name(string&& s) } -static std::optional<string> identify_region(CephContext *cct, const string& host) +static bool identify_scope(CephContext *cct, + const string& host, + string *region, + string *service) { if (!boost::algorithm::ends_with(host, "amazonaws.com")) { ldout(cct, 20) << "NOTICE: cannot identify region for connection to: " << host << dendl; - return std::nullopt; + return false; } vector<string> vec; get_str_vec(host, ".", vec); + *service = "s3"; /* default */ + for (auto iter = vec.begin(); iter != vec.end(); ++iter) { auto& s = *iter; if (s == "s3" || s == "execute-api") { + if (s == "execute-api") { + *service = s; + } ++iter; if (iter == vec.end()) { ldout(cct, 0) << "WARNING: cannot identify region name from host name: " << host << dendl; - return std::nullopt; + return false; } auto& next = *iter; if (next == "amazonaws") { - return "us-east-1"; + *region = "us-east-1"; + return true; } - return next; + *region = next; + return true; } else if (boost::algorithm::starts_with(s, "s3-")) { - return extract_region_name(std::move(s)); + *region = extract_region_name(std::move(s)); + return true; } } - return std::nullopt; + return false; } -static string region_from_api_name(CephContext *cct, const string& host, std::optional<string> api_name) +static void scope_from_api_name(CephContext *cct, + const string& host, + std::optional<string> api_name, + string *region, + string *service) { - if (!api_name) { - api_name = identify_region(cct, host); + if (api_name) { + *region = *api_name; + *service = "s3"; + return; + } + + if (!identify_scope(cct, host, region, service)) { + *region = cct->_conf->rgw_zonegroup; + *service = "s3"; + return; } -#warning need to be period->api_name instead of rgw_zonegroup - return api_name.value_or(cct->_conf->rgw_zonegroup); } int RGWRESTSimpleRequest::forward_request(RGWAccessKey& key, req_info& info, size_t max_response, bufferlist *inbl, bufferlist *outbl, optional_yield y) @@ -299,14 +322,17 @@ int RGWRESTSimpleRequest::forward_request(RGWAccessKey& key, req_info& info, siz new_env.set("HTTP_CONTENT_MD5", content_md5); } - string region = region_from_api_name(cct, host, api_name); + string region; + string service; + + scope_from_api_name(cct, host, api_name, ®ion, &service); const char *maybe_payload_hash = info.env->get("HTTP_X_AMZ_CONTENT_SHA256"); if (maybe_payload_hash) { new_env.set("HTTP_X_AMZ_CONTENT_SHA256", maybe_payload_hash); } - int ret = sign_request(this, key, region, new_env, new_info); + int ret = sign_request(this, key, region, service, new_env, new_info); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to sign request" << dendl; return ret; @@ -475,7 +501,7 @@ void RGWRESTGenerateHTTPHeaders::init(const string& _method, const string& host, const string& resource, const param_vec_t& params, std::optional<string> api_name) { - region = region_from_api_name(cct, host, api_name); + scope_from_api_name(cct, host, api_name, ®ion, &service); string params_str; map<string, string>& args = new_info->args.get_params(); @@ -592,7 +618,7 @@ void RGWRESTGenerateHTTPHeaders::set_content(const bufferlist& bl) int RGWRESTGenerateHTTPHeaders::sign(RGWAccessKey& key) { - int ret = sign_request(this, key, region, *new_env, *new_info); + int ret = sign_request(this, key, region, service, *new_env, *new_info); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to sign request" << dendl; return ret; diff --git a/src/rgw/rgw_rest_client.h b/src/rgw/rgw_rest_client.h index 03b12a730ff..3bf95c68143 100644 --- a/src/rgw/rgw_rest_client.h +++ b/src/rgw/rgw_rest_client.h @@ -80,6 +80,7 @@ class RGWRESTGenerateHTTPHeaders : public DoutPrefix { RGWEnv *new_env; req_info *new_info; string region; + string service; string method; string url; string resource; diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 2b9ca215935..5c28caff731 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -5200,6 +5200,7 @@ AWSGeneralAbstractor::get_v4_canonical_headers( AWSSignerV4::prepare_result_t AWSSignerV4::prepare(const std::string& access_key_id, const string& region, + const string& service, const req_info& info, bool s3_op) const { @@ -5214,7 +5215,7 @@ AWSSignerV4::prepare(const std::string& access_key_id, std::string date = ceph::to_iso_8601_no_separators(timestamp, ceph::iso_8601_format::YMDhms); - std::string credential_scope = gen_v4_scope(timestamp, region); + std::string credential_scope = gen_v4_scope(timestamp, region, service); extra_headers["x-amz-date"] = date; auto iter = info.x_meta_map.find("x-amz-content-sha256"); diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index fc48693692a..025b7cf24c0 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -1110,6 +1110,7 @@ public: prepare_result_t prepare(const std::string& access_key_id, const string& region, + const string& service, const req_info& info, bool s3_op) const; }; |