Skip to content

Commit 1ce5dcc

Browse files
committed
elasticsearch: support a ca cert
#222
1 parent e09e2ca commit 1ce5dcc

File tree

6 files changed

+60
-12
lines changed

6 files changed

+60
-12
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
https://github.com/jasonish/evebox/issues/52
2121
- [sqlite] Use server side events to stream back data such as
2222
aggregations, so updates in the UI can start right away.
23+
- [elastic] Support custom certificate authority: https://github.com/jasonish/evebox/issues/222
2324

2425
## 0.19.0 - 2024-12-13
2526

examples/evebox.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ database:
5656
#username: username
5757
#password: password
5858

59+
#cacert: http_ca.crt
60+
5961
retention:
6062
# Only keep events for the past 7 days.
6163
# - SQLite only

src/bin/evebox.rs

+8
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ async fn evebox_main() -> Result<(), Box<dyn std::error::Error>> {
122122
.env("EVEBOX_ELASTICSEARCH_PASSWORD")
123123
.hide(true),
124124
)
125+
.arg(
126+
clap::Arg::new("database.elasticsearch.cacert")
127+
.long("elasticsearch-cacert")
128+
.action(ArgAction::Set)
129+
.value_name("FILENAME")
130+
.help("Elasticsearch CA certificate filename")
131+
.env("EVEBOX_ELASTICSEARCH_CACERT"),
132+
)
125133
.arg(
126134
clap::Arg::new("database.elasticsearch.index")
127135
.short('i')

src/elastic/client.rs

+44-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use serde::Serialize;
66
use serde_json::Value;
77
use std::cmp::Ordering;
88
use std::collections::HashMap;
9+
use std::io::BufReader;
10+
use std::io::Read;
911
use std::time::Duration;
1012
use tracing::warn;
1113

@@ -23,23 +25,13 @@ pub enum ClientError {
2325
String(String),
2426
}
2527

26-
#[derive(Debug, Default)]
28+
#[derive(Debug, Default, Clone)]
2729
pub(crate) struct Client {
2830
pub url: String,
2931
pub disable_certificate_validation: bool,
3032
pub username: Option<String>,
3133
pub password: Option<String>,
32-
}
33-
34-
impl Clone for Client {
35-
fn clone(&self) -> Self {
36-
Self {
37-
url: self.url.clone(),
38-
disable_certificate_validation: self.disable_certificate_validation,
39-
username: self.username.clone(),
40-
password: self.password.clone(),
41-
}
42-
}
34+
cert: Option<reqwest::Certificate>,
4335
}
4436

4537
fn default_username() -> Option<String> {
@@ -50,12 +42,38 @@ fn default_password() -> Option<String> {
5042
std::env::var("EVEBOX_ELASTICSEARCH_PASSWORD").ok()
5143
}
5244

45+
fn load_certificate_from_file(filename: &str) -> anyhow::Result<reqwest::Certificate> {
46+
let file = std::fs::File::open(filename)?;
47+
let mut reader = BufReader::new(file);
48+
let mut buffer = vec![];
49+
reader.read_to_end(&mut buffer)?;
50+
Ok(reqwest::Certificate::from_pem(&buffer)?)
51+
}
52+
53+
/// Load a certificate from the specified in
54+
/// EVEBOX_ELASTICSEARCH_HTTP_CA_CERT. Returning None if not set, or
55+
/// if an error occurs. But log the error before returning None.
56+
fn load_certificate_from_env() -> Option<reqwest::Certificate> {
57+
if let Ok(filename) = std::env::var("EVEBOX_ELASTICSEARCH_CACERT") {
58+
match load_certificate_from_file(&filename) {
59+
Ok(cert) => Some(cert),
60+
Err(err) => {
61+
warn!("Failed to load Elasticsearch HTTP CA certificate from {}, will continue without: {}", filename, err);
62+
None
63+
}
64+
}
65+
} else {
66+
None
67+
}
68+
}
69+
5370
impl Client {
5471
pub fn new(url: &str) -> Self {
5572
Self {
5673
url: url.to_string(),
5774
username: std::env::var("EVEBOX_ELASTICSEARCH_USERNAME").ok(),
5875
password: std::env::var("EVEBOX_ELASTICSEARCH_PASSWORD").ok(),
76+
cert: load_certificate_from_env(),
5977
..Default::default()
6078
}
6179
}
@@ -65,6 +83,11 @@ impl Client {
6583
if self.disable_certificate_validation {
6684
builder = builder.danger_accept_invalid_certs(true);
6785
}
86+
87+
if let Some(cert) = self.cert.clone() {
88+
builder = builder.add_root_certificate(cert);
89+
}
90+
6891
builder.build()
6992
}
7093

@@ -272,6 +295,7 @@ pub(crate) struct ClientBuilder {
272295
disable_certificate_validation: bool,
273296
username: Option<String>,
274297
password: Option<String>,
298+
cert: Option<reqwest::Certificate>,
275299
}
276300

277301
impl ClientBuilder {
@@ -280,6 +304,7 @@ impl ClientBuilder {
280304
url: url.to_string(),
281305
username: default_username(),
282306
password: default_password(),
307+
cert: load_certificate_from_env(),
283308
..ClientBuilder::default()
284309
}
285310
}
@@ -299,14 +324,21 @@ impl ClientBuilder {
299324
self
300325
}
301326

327+
pub(crate) fn with_cacert(mut self, cacert: &str) -> anyhow::Result<Self> {
328+
self.cert = Some(load_certificate_from_file(cacert)?);
329+
Ok(self)
330+
}
331+
302332
pub fn build(self) -> Client {
303333
Client {
304334
url: self.url.clone(),
305335
disable_certificate_validation: self.disable_certificate_validation,
306336
username: self.username,
307337
password: self.password,
338+
cert: self.cert,
308339
}
309340
}
341+
310342
}
311343

312344
#[derive(Deserialize, Serialize, Debug)]

src/server/main.rs

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub async fn main(args: &clap::ArgMatches) -> Result<()> {
7878
server_config.elastic_ecs = config.get_bool("database.elasticsearch.ecs")?;
7979
server_config.elastic_username = config.get("database.elasticsearch.username")?;
8080
server_config.elastic_password = config.get("database.elasticsearch.password")?;
81+
server_config.elastic_cacert = config.get("database.elasticsearch.cacert")?;
8182
server_config.data_directory = config.get("data-directory")?;
8283
server_config.no_check_certificate = config
8384
.get_bool("database.elasticsearch.disable-certificate-check")?
@@ -459,6 +460,9 @@ async fn configure_datastore(config: Config, server_config: &ServerConfig) -> Re
459460
if let Some(password) = &server_config.elastic_password {
460461
client = client.with_password(password);
461462
}
463+
if let Some(cacert) = &server_config.elastic_cacert {
464+
client = client.with_cacert(cacert)?;
465+
}
462466
client = client.disable_certificate_validation(server_config.no_check_certificate);
463467

464468
let client = client.build();

src/server/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub(crate) struct ServerConfig {
6666
pub elastic_no_index_suffix: bool,
6767
pub elastic_username: Option<String>,
6868
pub elastic_password: Option<String>,
69+
pub elastic_cacert: Option<String>,
6970
pub elastic_ecs: bool,
7071
pub data_directory: Option<String>,
7172
pub authentication_required: bool,

0 commit comments

Comments
 (0)