Merge pull request #36487 from FArthur-cmd/fix_certificates

Add passphrase for certificates
This commit is contained in:
Alexey Milovidov 2022-04-24 04:58:21 +03:00 committed by GitHub
commit da1b0b491f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 75 deletions

View File

@ -81,11 +81,12 @@ void CertificateReloader::tryLoad(const Poco::Util::AbstractConfiguration & conf
{
bool cert_file_changed = cert_file.changeIfModified(std::move(new_cert_path), log);
bool key_file_changed = key_file.changeIfModified(std::move(new_key_path), log);
std::string pass_phrase = config.getString("openSSL.server.privateKeyPassphraseHandler.options.password", "");
if (cert_file_changed || key_file_changed)
{
LOG_DEBUG(log, "Reloading certificate ({}) and key ({}).", cert_file.path, key_file.path);
data.set(std::make_unique<const Data>(cert_file.path, key_file.path));
data.set(std::make_unique<const Data>(cert_file.path, key_file.path, pass_phrase));
LOG_INFO(log, "Reloaded certificate ({}) and key ({}).", cert_file.path, key_file.path);
}
@ -104,8 +105,8 @@ void CertificateReloader::tryLoad(const Poco::Util::AbstractConfiguration & conf
}
CertificateReloader::Data::Data(std::string cert_path, std::string key_path)
: cert(cert_path), key(/* public key */ "", /* private key */ key_path)
CertificateReloader::Data::Data(std::string cert_path, std::string key_path, std::string pass_phrase)
: cert(cert_path), key(/* public key */ "", /* private key */ key_path, pass_phrase)
{
}

View File

@ -49,16 +49,14 @@ public:
int setCertificate(SSL * ssl);
private:
CertificateReloader()
{
}
CertificateReloader() = default;
Poco::Logger * log = &Poco::Logger::get("CertificateReloader");
struct File
{
const char * description;
File(const char * description_) : description(description_) {}
explicit File(const char * description_) : description(description_) {}
std::string path;
std::filesystem::file_time_type modification_time;
@ -74,7 +72,7 @@ private:
Poco::Crypto::X509Certificate cert;
Poco::Crypto::EVPPKey key;
Data(std::string cert_path, std::string key_path);
Data(std::string cert_path, std::string key_path, std::string pass_phrase);
};
MultiVersion<Data> data;

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDPDCCAiQCFBXNOvsLA+dqmX/TkYG9JXdD5m72MA0GCSqGSIb3DQEBCwUAMFox
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmNsaWNraG91c2UwIBcNMjIw
NDIxMTAzNDU1WhgPMjEyMjAzMjgxMDM0NTVaMFkxCzAJBgNVBAYTAkFVMRMwEQYD
VQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM
dGQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAKaXz596N4NC2zZdIqdwZbSYAtNdBCsBVPt5YT9F640aF5zOogPZyxGP
ENyOZwABi/7HhwFbH657xyRvi8lTau8dZL+0tbakyoIn1Tw6j+/3GXTjLduJSy6C
mOf4OzsrFC8mYgU+7p5ijvWVlO9h5NMbLdAPSIB5WSHhmSORH5LgjoK6oMOYdRod
GmfHqSbwPVwy3Li5SXlniCQmJsM0zl64LFbJ/NU+13qETmhBiDgmh0Svi+wzSzqZ
q1PIX92T3k44IXNZbvF7lKbUOS9Xb3BoxA4cDqRcTx4x73xRDwodSmqiuQOC99HI
A0C/tZJ25VNAGjLKukPSHqYscq2PAsUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
IDQwjf/ja3TfOXrz+Gn1eErSKnWS3asjRT9rYWQsy3tzVUkMIcszrG+FqTR16g5H
ZWyuEOi6KIRmda3SYKdLKmtQLrgx6/d/jvH5TQ0LTFZrp6vh0lo3pV+L6fLo1ZRD
V1i8jW/7HHNyqJamUXOjwA0DpPOMkdtwuyV+rJ+2bTG1ZSK33O4Ae2CY5+dad6zy
YI6b1c9flWfDznuNEMH7jDDjKgXwjZGeU53FiuuhHiNyRchsr/B9eIBsom8oykiD
kch4cnAxx2E+m3hLYzupkXHOVQ5CNpVk8PGUCIGcyqDxPt+fOj1WbDQ9laEcfhmV
kR+vHmzOqWZnHU4QeMqDig==
-----END CERTIFICATE-----

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,4E14FF586022476CD22AAFB662BB0E40
dpJZKq5k+fMuC7XECfTSRjPeOEl9wNuVtZkcjEWaHN8ky4umND7ARyRyuU1Nk7cy
fpCFlFKOqDfCkT5zVK/fB6pF32wqAI7sqeSuYPfQY0+L77yRdwM6L46WslzVKZYE
lXD1AmqKT/LgF3+eBY5slkAAJo10zYDgKEwnoQVBp31YW2/+6oAGaY/O6x3p7aTG
dw9CP+SFc0o8lPl1lsSovdNXDUiVCftvClog7hwyDv8AhHyGgynw3UJXX8UlyWu+
Zz5zpgrvB2gvDLeoZZ6qjMGvtpEwlYBh4de9ZOsvQUpXEEfkQFtJV0j613OCQune
LoTxKpYV1V/mZX4HPaJ1oC0OJ7XcliAOSS9K49YobTuz7Kg5Wg3bVGo9xRfYDjch
rVeMP4u5RXSGuHL23FPMfK6EqcldrFyRwLaY/IV1Yl6UNUMKAphn/WMtWVuT3TiT
QMCI2VRt7ItwZwwFn5RgyDweWdFf5v3AmN/lOhATDBqosahkPxDZ1VZ6OBPoJLPM
UrDWH/lqrByeEjtAOwr5UsWKwLuJ8qUxQ4TchHwFKOwy6VsrRwMQ3ZWi2govPF9I
W0sfLj5Ulfjx6zHdqnF48a1Elit4JH6inBEWFuj7bmlOotq+PHoeT61zAwW+gnrG
3JTo3XnaE2WwRDpqvKYHWLv/J218rq8PtIaq9gjr55odPfIt8lkJ1XzF4WQ21rIJ
GNWZ3xz4fxpvrKnQyAKGu0ZcdjA1nqs16oiVr+UnJoXmkM5yBCic4fZYwPTSQHYS
ZxwaTzEjfeGxrSeLrN9CgoweucvogOvUjJOBcW/py80du8vWz0YyzMhg3o0YeGME
C+Kts/YWxmyfw4DaWt8RtWCKl85hEmz8RODvkMLGtLzvVoSyLQWqp1NhGIlFtzXs
7sPLulUeyD2avTC/RB/Pu9Nk80c0368BxCoeYbiFWZpaN70SJmCUE5H59J2d0olw
5v2RVjLBi8wqnzoa0+2L8wnG7IQGadS97dj0eBR+JXNtoJhVrurS80RJ6B0bNxdu
gX8otfnJYsZyK5hbEhcQqLdnyGhDEE8YHe7Hv9stWwLAFOfOMzyzC06lFS1eNiw4
FJyXJUhDieb8EqetouAC8dNVXz4Q1zOTlGuAbGoKm5v0U5IhCQap9GUSW5QiUgOQ
AEMs9aGfd91R+IcDf19mZptsQLYA6MGBN6fm+3O2iZImKIbF+ZZo0S6liFFmn6lm
M+diTzaoiqgEkiXOuRhdQUMaiGV8BMZxv8qUH6/vyC3gSueoTio0f9PfASDYfvXD
A3GuI87P6LF1it2UlN6ssFoXTZdfQQZwRmNuqOqw+BJOJHrR6trcXOCZOQ77Qnvd
M5a348gIzluVUkExAPGCsySQWMx4Of5NBF28jEC3+TAwkRqBV2ZHmfGLWnvwaB+A
YUeKtpWblfG1lsrDAdwL2dilU95oby+35sExX7M2dCrL9Y2P5oTCW3u12//ZSLeL
Yhi1Rzol6LAuesZCVF0Zv/YYDhzAckJfT/qXK5B5pz9saswxCUBEpiKlLpVsjOFJ
2bHm8NgOMD5b3cdh1kvts4wZe+giry7LHsn46f+9VqN+gA6XxeVsPyb4uO1KW3SN
-----END RSA PRIVATE KEY-----

View File

@ -13,9 +13,18 @@ node = cluster.add_instance(
"configs/second.key",
"configs/ECcert.crt",
"configs/ECcert.key",
"configs/WithPassPhrase.crt",
"configs/WithPassPhrase.key",
"configs/cert.xml",
],
)
PASS_PHRASE_TEMPLATE = """<privateKeyPassphraseHandler>
<name>KeyFileHandler</name>
<options>
<password>{pass_phrase}</password>
</options>
</privateKeyPassphraseHandler>
"""
@pytest.fixture(scope="module", autouse=True)
@ -27,7 +36,7 @@ def started_cluster():
cluster.shutdown()
def change_config_to_key(name):
def change_config_to_key(name, pass_phrase=""):
"""
* Generate config with certificate/key name from args.
* Reload config.
@ -48,21 +57,23 @@ def change_config_to_key(name):
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
{pass_phrase}
</server>
</openSSL>
</clickhouse>
EOF""".format(
cur_name=name
cur_name=name, pass_phrase=pass_phrase
),
]
)
node.query("SYSTEM RELOAD CONFIG")
def test_first_than_second_cert():
"""Consistently set first key and check that only it will be accepted, then repeat same for second key."""
def check_certificate_switch(
first, second, pass_phrase_first="", pass_phrase_second=""
):
# Set first key
change_config_to_key("first")
change_config_to_key(first, pass_phrase_first)
# Command with correct certificate
assert (
@ -71,9 +82,7 @@ def test_first_than_second_cert():
"curl",
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="first"
),
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(cur_name=first),
"https://localhost:8443/",
]
)
@ -90,7 +99,7 @@ def test_first_than_second_cert():
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="second"
cur_name=second
),
"https://localhost:8443/",
]
@ -100,7 +109,7 @@ def test_first_than_second_cert():
assert True
# Change to other key
change_config_to_key("second")
change_config_to_key(second, pass_phrase_second)
# Command with correct certificate
assert (
@ -110,7 +119,7 @@ def test_first_than_second_cert():
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="second"
cur_name=second
),
"https://localhost:8443/",
]
@ -126,9 +135,7 @@ def test_first_than_second_cert():
"curl",
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="first"
),
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(cur_name=first),
"https://localhost:8443/",
]
)
@ -137,59 +144,18 @@ def test_first_than_second_cert():
assert True
def test_first_than_second_cert():
"""Consistently set first key and check that only it will be accepted, then repeat same for second key."""
check_certificate_switch("first", "second")
def test_ECcert_reload():
# Set first key
change_config_to_key("first")
"""Check EC certificate"""
check_certificate_switch("first", "ECcert")
# Command with correct certificate
assert (
node.exec_in_container(
[
"curl",
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="first"
),
"https://localhost:8443/",
]
)
== "Ok.\n"
def test_cert_with_pass_phrase():
pass_phrase_for_cert = PASS_PHRASE_TEMPLATE.format(pass_phrase="test")
check_certificate_switch(
"first", "WithPassPhrase", pass_phrase_second=pass_phrase_for_cert
)
# Change to other key
change_config_to_key("ECcert")
# Command with correct certificate
assert (
node.exec_in_container(
[
"curl",
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="ECcert"
),
"https://localhost:8443/",
]
)
== "Ok.\n"
)
# Command with wrong certificate
# Same as previous
try:
node.exec_in_container(
[
"curl",
"--silent",
"--cacert",
"/etc/clickhouse-server/config.d/{cur_name}.crt".format(
cur_name="first"
),
"https://localhost:8443/",
]
)
assert False
except:
assert True