Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions scripts/ingest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ param(
[string]$Param2,

[Parameter(Position=2)]
[string]$Param3
[string]$Param3,

[Parameter(Position=3)]
[string]$Param4
)

$ProgressPreference = 'SilentlyContinue'
Expand Down Expand Up @@ -261,11 +264,12 @@ function Restart-FluentBit {
function Setup-FluentBit {
param(
[string]$IngestorHost,
[string]$StreamName,
[string]$ApiKey,
[string]$TenantId
)

if ([string]::IsNullOrWhiteSpace($IngestorHost) -or [string]::IsNullOrWhiteSpace($ApiKey)) {
if ([string]::IsNullOrWhiteSpace($IngestorHost) -or [string]::IsNullOrWhiteSpace($StreamName) -or [string]::IsNullOrWhiteSpace($ApiKey)) {
Write-ErrorMsg "Invalid setup parameters"
exit 1
}
Expand Down Expand Up @@ -336,7 +340,7 @@ function Setup-FluentBit {
}

$configLines += @(
" Header X-P-Stream node-metrics",
" Header X-P-Stream $StreamName",
" Header X-P-Log-Source otel-metrics"
)

Expand All @@ -355,7 +359,7 @@ function Show-Help {
Fluent Bit Setup and Management Script for Windows

Usage:
Setup: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 [host[:port]] [api_key] [tenant_id]
Setup: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 [host[:port]] [stream] [api_key] [tenant_id]
Stop: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 stop
Start: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 start
Restart: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 restart
Expand All @@ -364,8 +368,8 @@ Usage:
Debug: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 debug

Example:
powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 https://your-host.com:443 px_api_key
powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 http://localhost:8000 px_api_key tenant-id
powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 https://your-host.com:443 node-metrics px_api_key
powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 http://localhost:8000 node-metrics px_api_key tenant-id

"@
}
Expand Down Expand Up @@ -420,11 +424,11 @@ switch ($Param1.ToLower()) {
Show-Help
}
default {
if ([string]::IsNullOrWhiteSpace($Param2)) {
Write-ErrorMsg "Usage: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 [host[:port]] [api_key] [tenant_id]"
if ([string]::IsNullOrWhiteSpace($Param2) -or [string]::IsNullOrWhiteSpace($Param3)) {
Write-ErrorMsg "Usage: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 [host[:port]] [stream] [api_key] [tenant_id]"
Write-ErrorMsg " Or: powershell -NoProfile -ExecutionPolicy Bypass -File .\ingest.ps1 [start|stop|restart|status|logs|debug|help]"
exit 1
}
Setup-FluentBit -IngestorHost $Param1 -ApiKey $Param2 -TenantId $Param3
Setup-FluentBit -IngestorHost $Param1 -StreamName $Param2 -ApiKey $Param3 -TenantId $Param4
}
}
29 changes: 15 additions & 14 deletions scripts/ingest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Fluent Bit Setup and Management Script
# Usage:
# Setup: ./ingest.sh <host[:port]> <api_key> [tenant_id]
# Setup: ./ingest.sh <host[:port]> <stream> <api_key> [tenant_id]
# Stop: ./ingest.sh stop
# Restart: ./ingest.sh restart
# Status: ./ingest.sh status
Expand Down Expand Up @@ -241,17 +241,18 @@ install_fluent_bit() {
# Setup function
setup_fluent_bit() {
local INGESTOR_HOST="$1"
local API_KEY="$2"
local TENANT_ID="${3:-}"
local STREAM_NAME="$2"
local API_KEY="$3"
local TENANT_ID="${4:-}"
local TENANT_HEADER=""
local TLS_SETTING="On"
local DEFAULT_PORT="443"
local PORT=""

# Validate all fields are present
if [ -z "$INGESTOR_HOST" ] || [ -z "$API_KEY" ]; then
if [ -z "$INGESTOR_HOST" ] || [ -z "$STREAM_NAME" ] || [ -z "$API_KEY" ]; then
print_error "Invalid setup parameters"
print_error "Expected format: $0 <host[:port]> <api_key> [tenant_id]"
print_error "Expected format: $0 <host[:port]> <stream> <api_key> [tenant_id]"
exit 1
fi

Expand Down Expand Up @@ -330,7 +331,7 @@ setup_fluent_bit() {
TLS $TLS_SETTING
Header X-API-Key $API_KEY
${TENANT_HEADER}
Header X-P-Stream node-metrics
Header X-P-Stream $STREAM_NAME
Header X-P-Log-Source otel-metrics
EOF
chmod 600 "$CONFIG_FILE"
Expand Down Expand Up @@ -363,7 +364,7 @@ case "${1:-}" in
echo ""
echo "Usage:"
echo " Setup and start:"
echo " $0 <host[:port]> <api_key> [tenant_id]"
echo " $0 <host[:port]> <stream> <api_key> [tenant_id]"
echo ""
echo " Management commands:"
echo " $0 start - Start Fluent Bit (if config exists)"
Expand All @@ -373,18 +374,18 @@ case "${1:-}" in
echo " $0 logs - Show Fluent Bit logs"
echo ""
echo "Example:"
echo " $0 https://example.parseable.com:443 px_api_key"
echo " $0 http://localhost:8000 px_api_key tenant-id"
echo " $0 https://example.parseable.com:443 node-metrics px_api_key"
echo " $0 http://localhost:8000 node-metrics px_api_key tenant-id"
;;
*)
# If not a command, treat as setup parameters
if [ $# -lt 2 ] || [ $# -gt 3 ]; then
print_error "Usage: $0 <host[:port]> <api_key> [tenant_id]"
if [ $# -lt 3 ] || [ $# -gt 4 ]; then
print_error "Usage: $0 <host[:port]> <stream> <api_key> [tenant_id]"
print_error " Or: $0 [start|stop|restart|status|logs|help]"
print_error ""
print_error "Example:"
print_error " $0 https://ec9cfee0-2fd4-45eb-8209-d7cd992c4bcc-ingestor.workspace-staging.parseable.com:443 px_api_key"
print_error " $0 http://localhost:8000 px_api_key tenant-id"
print_error " $0 https://ec9cfee0-2fd4-45eb-8209-d7cd992c4bcc-ingestor.workspace-staging.parseable.com:443 node-metrics px_api_key"
print_error " $0 http://localhost:8000 node-metrics px_api_key tenant-id"
print_error ""
print_error "Management commands:"
print_error " $0 status - Check if running"
Expand All @@ -393,6 +394,6 @@ case "${1:-}" in
print_error " $0 logs - View logs"
exit 1
fi
setup_fluent_bit "$1" "$2" "${3:-}"
setup_fluent_bit "$1" "$2" "$3" "${4:-}"
;;
esac
84 changes: 61 additions & 23 deletions src/alerts/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,51 +195,53 @@ pub struct Target {
}

impl Target {
/// Sanitizes a URL by obliterating the trailing path segment.
fn mask_url(url: &Url) -> String {
let mut base = url.clone();
if let Ok(mut segments) = base.path_segments_mut() {
segments.clear();
}
base.set_query(None);
base.set_fragment(None);
base.set_path("/********");
base.to_string()
}

pub fn mask(self) -> Value {
match self.target {
TargetType::Slack(slack_web_hook) => {
let endpoint = slack_web_hook.endpoint.to_string();
let masked_endpoint = if endpoint.len() > 20 {
format!("{}********", &endpoint[..20])
} else {
"********".to_string()
};
let endpoint = Self::mask_url(&slack_web_hook.endpoint);
json!({
"name":self.name,
"type":"slack",
"endpoint":masked_endpoint,
"endpoint": endpoint,
"id":self.id
})
}
TargetType::Other(other_web_hook) => {
let endpoint = other_web_hook.endpoint.to_string();
let masked_endpoint = if endpoint.len() > 20 {
format!("{}********", &endpoint[..20])
} else {
"********".to_string()
};
let endpoint = Self::mask_url(&other_web_hook.endpoint);
let safe_headers: HashMap<String, String> = other_web_hook
.headers
.into_iter()
.map(|(k, _v)| (k, "********".to_string()))
.collect();
json!({
"name":self.name,
"type":"webhook",
"endpoint":masked_endpoint,
"headers":other_web_hook.headers,
"endpoint":endpoint,
"headers":safe_headers,
"skipTlsCheck":other_web_hook.skip_tls_check,
"id":self.id
})
}
TargetType::AlertManager(alert_manager) => {
let endpoint = alert_manager.endpoint.to_string();
let masked_endpoint = if endpoint.len() > 20 {
format!("{}********", &endpoint[..20])
} else {
"********".to_string()
};
let endpoint = Self::mask_url(&alert_manager.endpoint);
if let Some(auth) = alert_manager.auth {
let password = "********";
json!({
"name":self.name,
"type":"webhook",
"endpoint":masked_endpoint,
"endpoint":endpoint,
"username":auth.username,
"password":password,
"skipTlsCheck":alert_manager.skip_tls_check,
Expand All @@ -249,7 +251,7 @@ impl Target {
json!({
"name":self.name,
"type":"webhook",
"endpoint":masked_endpoint,
"endpoint":endpoint,
"username":Value::Null,
"password":Value::Null,
"skipTlsCheck":alert_manager.skip_tls_check,
Expand Down Expand Up @@ -652,3 +654,39 @@ pub struct Auth {
username: String,
password: String,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_masked_target_hides_secrets() {
let target = Target {
name: "test-target".into(),
id: Ulid::new(),
tenant: None,
target: TargetType::AlertManager(AlertManager {
endpoint: "https://internal.corp/api".parse().unwrap(),
auth: Some(Auth {
username: "admin".into(),
password: "SuperSecretPassword123".into(),
}),
skip_tls_check: false,
}),
};

let masked = target.mask();

let masked_str = serde_json::to_string(&masked).unwrap();

// These assertions MUST pass, or the build fails
assert!(
!masked_str.contains("SuperSecretPassword123"),
"Password leaked in masked response!"
);
assert!(
masked_str.contains("********"),
"Expected redaction marker not found!"
);
}
}
Loading
Loading