blob: 29b8c69dbe175793366c59a9b792581a2ade7ca9 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "kudu/ranger-kms/ranger_kms_client.h"
#include <string>
#include <vector>
#include <glog/logging.h>
#include <rapidjson/document.h>
#include "kudu/gutil/strings/escaping.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/util/curl_util.h"
#include "kudu/util/easy_json.h"
#include "kudu/util/faststring.h"
#include "kudu/util/jsonreader.h"
using rapidjson::Value;
using std::string;
using std::vector;
using strings::a2b_hex;
using strings::b2a_hex;
using strings::Substitute;
using strings::WebSafeBase64Escape;
using strings::WebSafeBase64Unescape;
namespace kudu {
namespace security {
Status RangerKMSClient::DecryptKey(const string& encrypted_key,
const string& iv,
const string& key_version,
string* decrypted_key) {
EasyJson payload;
payload.Set("name", cluster_key_name_);
string iv_plain = a2b_hex(iv);
string iv_b64;
WebSafeBase64Escape(iv_plain, &iv_b64);
payload.Set("iv", iv_b64);
string eek_plain = a2b_hex(encrypted_key);
string eek_b64;
WebSafeBase64Escape(eek_plain, &eek_b64);
payload.Set("material", eek_b64);
EasyCurl curl;
curl.set_auth(CurlAuthType::SPNEGO);
string url = Substitute("$0/v1/keyversion/$1/_eek?eek_op=decrypt",
kms_url_, key_version);
faststring resp;
RETURN_NOT_OK_PREPEND(
curl.PostToURL(url, payload.ToString(), &resp, {"Content-Type: application/json"}),
"failed to decrypt server key");
JsonReader r(resp.ToString());
RETURN_NOT_OK(r.Init());
string dek_b64;
RETURN_NOT_OK(r.ExtractString(r.root(), "material", &dek_b64));
string dek_plain;
WebSafeBase64Unescape(dek_b64, &dek_plain);
*decrypted_key = b2a_hex(dek_plain);
return Status::OK();
}
Status RangerKMSClient::GenerateEncryptedServerKey(string* encrypted_key,
string* iv,
string* key_version) {
EasyCurl curl;
curl.set_auth(CurlAuthType::SPNEGO);
string url = Substitute("$0/v1/key/$1/_eek?eek_op=generate&num_keys=1",
kms_url_, cluster_key_name_);
faststring resp;
RETURN_NOT_OK_PREPEND(curl.FetchURL(url, &resp), "failed to generate server key");
JsonReader r(resp.ToString());
RETURN_NOT_OK(r.Init());
vector<const Value*> keys;
RETURN_NOT_OK(r.ExtractObjectArray(r.root(), nullptr, &keys));
string iv_b64;
DCHECK_GT(keys.size(), 0);
const Value* key = keys[0];
RETURN_NOT_OK(r.ExtractString(key, "iv", &iv_b64));
string iv_plain;
if (!WebSafeBase64Unescape(iv_b64, &iv_plain)) {
return Status::Corruption("Invalid IV received");
}
*iv = b2a_hex(iv_plain);
RETURN_NOT_OK(r.ExtractString(key, "versionName", key_version));
const Value* ekv = nullptr;
RETURN_NOT_OK(r.ExtractObject(key, "encryptedKeyVersion", &ekv));
string key_b64;
RETURN_NOT_OK(r.ExtractString(ekv, "material", &key_b64));
string key_plain;
if (!WebSafeBase64Unescape(key_b64, &key_plain)) {
return Status::Corruption("Invalid encryption key received");
}
*encrypted_key = b2a_hex(key_plain);
return Status::OK();
}
} // namespace security
} // namespace kudu