-
Notifications
You must be signed in to change notification settings - Fork 34
使用 openssl 进行 tls 证书认证,支持自动格式化数据 #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,7 @@ use crate::transport::user::{ReadableKeys, SerializablePermission, SerializableU | |
| use crate::utils::k8s_formatter; | ||
| use etcd_client::{ | ||
| AlarmAction, AlarmType, Client, CompactionOptions, ConnectOptions, Error, GetOptions, | ||
| GetResponse, Identity, LeaseGrantOptions, LeaseTimeToLiveOptions, PermissionType, PutOptions, | ||
| GetResponse, LeaseGrantOptions, LeaseTimeToLiveOptions, PermissionType, PutOptions, | ||
| RoleRevokePermissionOptions, SortOrder, SortTarget, WatchOptions, WatchStream, Watcher, | ||
| }; | ||
| use log::{debug, error, info, warn}; | ||
|
|
@@ -85,11 +85,15 @@ impl EtcdConnector { | |
| }; | ||
|
|
||
| if let Some(identity) = tls.identity { | ||
| tls_option = | ||
| tls_option.identity(Identity::from_pem(identity.cert, identity.key)); | ||
| let cert = filter_pem(&identity.cert, "CERTIFICATE"); | ||
| let key = filter_pem(&identity.key, "PRIVATE KEY"); | ||
| if cert.is_empty() || key.is_empty() { | ||
| warn!("Identity cert or key is empty after filtering. Original cert len: {}, key len: {}", identity.cert.len(), identity.key.len()); | ||
| } | ||
| tls_option = tls_option.identity(Identity::from_pem(cert, key)); | ||
| }; | ||
|
|
||
| option = option.with_tls(tls_option) | ||
| option = option.with_tls(tls_option); | ||
| } | ||
|
|
||
| #[cfg(feature = "etcd-client-tls-openssl")] | ||
|
|
@@ -121,8 +125,9 @@ impl EtcdConnector { | |
| }; | ||
|
|
||
| if let Some(identity) = tls.identity { | ||
| openssl_config = openssl_config | ||
| .client_cert_pem_and_key(identity.cert.as_slice(), identity.key.as_slice()); | ||
| let cert = filter_pem(&identity.cert, "CERTIFICATE"); | ||
| let key = filter_pem(&identity.key, "PRIVATE KEY"); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里也和前面 rust-tls 处理一样,PEM文件交由下层工具处理,除非下层无法正确处理PEM文件 |
||
| openssl_config = openssl_config.client_cert_pem_and_key(&cert, &key); | ||
| }; | ||
|
|
||
| option = option.with_openssl_tls(openssl_config); | ||
|
|
@@ -150,7 +155,19 @@ impl EtcdConnector { | |
|
|
||
| let address = format!("{}:{}", host, port); | ||
| info!("Connect to etcd server: {}", address); | ||
| let client = Client::connect([address], Some(option)).await?; | ||
|
|
||
| let client_res = Client::connect([address], Some(option)).await; | ||
| let client = match client_res { | ||
| Ok(c) => c, | ||
| Err(e) => { | ||
| error!("!!! ETCD CONNECTION FAILED !!!"); | ||
| error!("Error detail: {:?}", e); | ||
| if let etcd_client::Error::TransportError(ref msg) = e { | ||
| error!("Transport error message: {}", msg); | ||
| } | ||
| return Err(LogicError::EtcdClientError(e)); | ||
| } | ||
| }; | ||
|
|
||
| Ok(EtcdConnector { | ||
| namespace, | ||
|
|
@@ -1217,6 +1234,36 @@ fn key_next(key: &mut Vec<u8>) { | |
| key[len - 1] += 1 | ||
| } | ||
| } | ||
|
|
||
| /// 过滤 PEM 内容,只保留指定标签的数据块。 | ||
| /// 例如:label 为 "CERTIFICATE" 时,只保留 BEGIN/END CERTIFICATE 之间的部分。 | ||
| fn filter_pem(data: &[u8], label: &str) -> Vec<u8> { | ||
| let content = String::from_utf8_lossy(data); | ||
| let mut filtered = String::new(); | ||
| let begin_tag = format!("-----BEGIN {}", label); | ||
| let end_tag = format!("-----END {}", label); | ||
|
|
||
| let mut in_block = false; | ||
| for line in content.lines() { | ||
| if line.contains(&begin_tag) { | ||
| in_block = true; | ||
| } | ||
| if in_block { | ||
| filtered.push_str(line); | ||
| filtered.push('\n'); | ||
| } | ||
| if line.contains(&end_tag) { | ||
| in_block = false; | ||
| } | ||
| } | ||
|
Comment on lines
+1246
to
+1258
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里存在一个可能的漏洞,当PEM中存在多个密钥段时,可能会读取到错误的密钥内容,例如这样的文件: 当然如果此函数可以移除,这个问题可以忽略 |
||
|
|
||
| // 如果没有找到完全匹配的 label,尝试模糊匹配(例如 PRIVATE KEY 匹配 EC PRIVATE KEY) | ||
| if filtered.is_empty() && label == "PRIVATE KEY" { | ||
| return filter_pem(data, "EC PRIVATE KEY"); | ||
| } | ||
|
|
||
| filtered.into_bytes() | ||
| } | ||
| pub struct SnapshotTask { | ||
| pub name: String, | ||
| pub folder: String, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里为什么需要手动过滤掉 PEM 中的标识块?底层工具可以自动处理这些标识,并且去掉了key的标识信息可能会导致无法读取对应的算法,例如:
ssl工具根据标识块信息得知密钥算法为RSA,需要以
PKCS#1格式解析其中内容同理,你在
filter_pem函数中兼容的EC PRIVATE KEY块中EC也可能是有用信息,另外还有Ed25519等。建议在交生成 identity 之前不要手动处理 PEM 文件内容,这可能存在兼容性问题