Skip to main content

libdd_trace_obfuscation/
obfuscation_config.rs

1// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4use log::{debug, error};
5use serde::Deserialize;
6use std::{collections::HashSet, env};
7
8use libdd_common::config::parse_env;
9
10use crate::{
11    replacer::{self, ReplaceRule},
12    sql::{SqlObfuscateConfig, SqlObfuscationMode},
13};
14
15#[derive(Debug, Default, Deserialize)]
16#[serde(default, deny_unknown_fields)]
17pub struct MemcachedConfig {
18    pub enabled: bool,
19    pub keep_command: bool,
20}
21
22#[derive(Debug, Default, Deserialize)]
23#[serde(default, deny_unknown_fields)]
24pub struct CreditCardConfig {
25    pub enabled: bool,
26    pub luhn: bool,
27    pub keep_values: HashSet<String>,
28}
29
30pub type JsonStringTransformer = fn(&str) -> String;
31
32#[derive(Debug, Default, Clone, Deserialize)]
33#[serde(default, deny_unknown_fields)]
34pub struct JsonObfuscatorConfig {
35    pub enabled: bool,
36    /// `keep_keys` will specify a set of keys for which their values will
37    /// not be obfuscated.
38    pub keep_keys: HashSet<String>,
39    /// `transform_keys` will specify a set of keys for which their values will be transformed
40    /// through `transformer`
41    #[serde(skip)]
42    pub transform_keys: HashSet<String>,
43    /// `transformer` is an optional String -> String function which will transform values
44    /// specified in `transform_keys`
45    #[serde(skip)]
46    pub transformer: Option<JsonStringTransformer>,
47}
48
49impl JsonObfuscatorConfig {
50    pub fn disabled() -> Self {
51        Self {
52            enabled: false,
53            ..Default::default()
54        }
55    }
56
57    pub fn enabled() -> Self {
58        Self {
59            enabled: true,
60            ..Default::default()
61        }
62    }
63}
64
65#[derive(Debug, Default, Deserialize)]
66#[serde(default, deny_unknown_fields)]
67pub struct RedisConfig {
68    pub enabled: bool,
69    pub remove_all_args: bool,
70}
71
72#[derive(Debug, Default, Deserialize)]
73#[serde(default, deny_unknown_fields)]
74pub struct HttpConfig {
75    // pub enabled: bool,
76    pub remove_query_string: bool,
77    pub remove_paths_with_digits: bool,
78}
79
80#[derive(Debug, Default, Deserialize)]
81#[serde(default, deny_unknown_fields)]
82pub struct ObfuscationConfig {
83    pub tag_replace_rules: Option<Vec<ReplaceRule>>,
84    pub http: HttpConfig,
85    pub memcached: MemcachedConfig,
86    pub redis: RedisConfig,
87    pub valkey: RedisConfig,
88    pub credit_cards: CreditCardConfig,
89    pub sql: SqlObfuscateConfig,
90    pub elasticsearch: JsonObfuscatorConfig,
91    pub opensearch: JsonObfuscatorConfig,
92    pub mongodb: JsonObfuscatorConfig,
93}
94
95// Small subset of `ObfuscationConfig` for stats obfuscation only
96#[derive(Default)]
97pub struct StatsObfuscationConfig {
98    pub sql_obfuscation_mode: SqlObfuscationMode,
99}
100
101impl ObfuscationConfig {
102    pub fn new() -> Result<ObfuscationConfig, Box<dyn std::error::Error>> {
103        let tag_replace_rules: Option<Vec<ReplaceRule>> = match env::var("DD_APM_REPLACE_TAGS") {
104            Ok(replace_rules_str) => match replacer::parse_rules_from_string(&replace_rules_str) {
105                Ok(res) => {
106                    debug!("Successfully parsed DD_APM_REPLACE_TAGS: {res:?}");
107                    Some(res)
108                }
109                Err(e) => {
110                    error!("Failed to parse DD_APM_REPLACE_TAGS: {e}");
111                    None
112                }
113            },
114            Err(_) => None,
115        };
116        let http_remove_query_string =
117            parse_env::bool("DD_APM_OBFUSCATION_HTTP_REMOVE_QUERY_STRING").unwrap_or(false);
118        let http_remove_path_digits =
119            parse_env::bool("DD_APM_OBFUSCATION_HTTP_REMOVE_PATHS_WITH_DIGITS").unwrap_or(false);
120        let obfuscation_redis_enabled =
121            parse_env::bool("DD_APM_OBFUSCATION_REDIS_ENABLED").unwrap_or(false);
122        let obfuscation_redis_remove_all_args =
123            parse_env::bool("DD_APM_OBFUSCATION_REDIS_REMOVE_ALL_ARGS").unwrap_or(false);
124
125        let obfuscate_memcached =
126            parse_env::bool("DD_APM_OBFUSCATION_MEMCACHED_ENABLED").unwrap_or(false);
127
128        Ok(ObfuscationConfig {
129            tag_replace_rules,
130            http: HttpConfig {
131                remove_query_string: http_remove_query_string,
132                remove_paths_with_digits: http_remove_path_digits,
133            },
134            memcached: MemcachedConfig {
135                enabled: obfuscate_memcached,
136                keep_command: true,
137            },
138            credit_cards: CreditCardConfig {
139                enabled: true,
140                luhn: true,
141                keep_values: HashSet::new(),
142            },
143            redis: RedisConfig {
144                enabled: obfuscation_redis_enabled,
145                remove_all_args: obfuscation_redis_remove_all_args,
146            },
147            ..Default::default()
148        })
149    }
150}