如何用Rust实现对接Elasticsearch的HTTPS认证请求
需求背景
需要用Rust实现与Python中requests.get等价的HTTPS请求,对接本地运行的Elasticsearch v8服务器(默认启用HTTPS)。对应的Python代码可正常运行,通过HTTPBasicAuth传递用户名密码,并指定CA证书路径验证服务器证书:
# NB these are valid username and password for an account created in the server setup username = 'mike12' password = 'mike12' from requests.auth import HTTPBasicAuth kwargs['auth'] = HTTPBasicAuth(username, password) # set kwargs['verify'] to the CA (certification authority) certificate path os.environ['ES_PATH_CONF'] = r'D:\apps\ElasticSearch\elasticsearch-8.6.2\config' es_path_conf = os.getenv('ES_PATH_CONF') kwargs['verify'] = fr'{es_path_conf}\certs\http_ca.crt' try: response = requests.request('get', "https://localhost:9500", **kwargs) except BaseException as e: ...
尝试过程中的问题
最初尝试用表单提交用户名密码,出现证书信任错误:
let login_fields = [ ("user", "mike12"), ("script", "true"), ("token", "[TOKEN]"), ("password", "mike12"), // 错误的认证方式 ]; let login_response = client .get("https://localhost:9500") .form(&login_fields) .send() .await? .text() .await?; println!("{}", login_response);
错误输出:
Error: reqwest::Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("localhost")), port: Some(9500), path: "/", query: None, fragment: None }, source: hyper::Error(Connect, Os { code: -2146762487, kind: Uncategorized, message: "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider." }) }
后续添加了CA证书,但仍用表单提交,出现406错误:
{"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}
原因是Elasticsearch不支持通过表单提交认证信息,需使用HTTP Basic认证方式。
正确的Rust实现
use reqwest::{Client, Certificate}; use std::fs::File; use std::io::Read; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // 配置ES路径和证书路径 let es_path = r"D:\apps\ElasticSearch\elasticsearch-8.6.2\config"; let cert_path = format!("{es_path}\\certs\\http_ca.crt"); // 读取CA证书文件 let mut cert_buf = Vec::new(); let mut cert_file = File::open(cert_path)?; cert_file.read_to_end(&mut cert_buf)?; // 从PEM格式加载证书 let ca_cert = Certificate::from_pem(&cert_buf)?; // 构建配置了CA证书的客户端 let client = Client::builder() .add_root_certificate(ca_cert) .build()?; // 发送带HTTP Basic认证的GET请求 let response = client .get("https://localhost:9500") .basic_auth("mike12", Some("mike12")) .send() .await?; // 打印响应状态和内容 println!("Response status: {}", response.status()); let response_text = response.text().await?; println!("Response content:\n{}", response_text); Ok(()) }
关键说明
- CA证书处理:通过
Certificate::from_pem读取Elasticsearch生成的http_ca.crt,并添加到客户端的根证书列表,解决证书信任问题。 - HTTP Basic认证:使用reqwest的
basic_auth方法传递用户名和密码,这是Elasticsearch支持的标准认证方式,避免了表单提交带来的406错误。 - 异步运行:reqwest的异步API需要在
tokio::main环境下运行,需在Cargo.toml中添加tokio依赖:tokio = { version = "1.0", features = ["full"] }
内容的提问来源于stack exchange,提问作者mike rodent

