+96
-57
@@ -2,69 +2,108 @@ $ErrorActionPreference = "Stop"
|
||||
Set-Location $PSScriptRoot
|
||||
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { throw "Docker fehlt." }
|
||||
docker compose version | Out-Null
|
||||
function Hex([int]$bytes) { $b = New-Object byte[] $bytes; [Security.Cryptography.RandomNumberGenerator]::Fill($b); return ([BitConverter]::ToString($b)).Replace("-","").ToLower() }
|
||||
if (-not (Test-Path .env)) {
|
||||
$presetEnrollment = $env:ENROLLMENT_KEY
|
||||
$enrollment = if ([string]::IsNullOrWhiteSpace($presetEnrollment)) { Hex 32 } else { $presetEnrollment }
|
||||
$vals = @{
|
||||
POSTGRES_PASSWORD=Hex 24; CLICKHOUSE_PASSWORD=Hex 24; ENROLLMENT_KEY=$enrollment; UI_PASSWORD=Hex 18;
|
||||
GARAGE_ACCESS_KEY="GK$(Hex 16)"; GARAGE_SECRET_KEY=Hex 32; GARAGE_RPC_SECRET=Hex 32;
|
||||
GARAGE_ADMIN_TOKEN=Hex 32; GARAGE_METRICS_TOKEN=Hex 32
|
||||
}
|
||||
@"
|
||||
INGRESS_BIND=0.0.0.0
|
||||
INGRESS_PORT=8090
|
||||
UI_BIND=0.0.0.0
|
||||
UI_PORT=8080
|
||||
TENANT_ID=default
|
||||
UI_USERNAME=admin
|
||||
UI_PASSWORD=$($vals.UI_PASSWORD)
|
||||
POSTGRES_PASSWORD=$($vals.POSTGRES_PASSWORD)
|
||||
CLICKHOUSE_PASSWORD=$($vals.CLICKHOUSE_PASSWORD)
|
||||
ENROLLMENT_KEY=$($vals.ENROLLMENT_KEY)
|
||||
GARAGE_ACCESS_KEY=$($vals.GARAGE_ACCESS_KEY)
|
||||
GARAGE_SECRET_KEY=$($vals.GARAGE_SECRET_KEY)
|
||||
GARAGE_RPC_SECRET=$($vals.GARAGE_RPC_SECRET)
|
||||
GARAGE_ADMIN_TOKEN=$($vals.GARAGE_ADMIN_TOKEN)
|
||||
GARAGE_METRICS_TOKEN=$($vals.GARAGE_METRICS_TOKEN)
|
||||
GARAGE_BUCKET=siem-raw
|
||||
EVENT_RETENTION_DAYS=90
|
||||
ROLLUP_RETENTION_DAYS=730
|
||||
RAW_RETENTION=720h
|
||||
RAW_ARCHIVE_ENABLED=true
|
||||
KAFKA_RETENTION_MS=86400000
|
||||
KAFKA_PARTITIONS=6
|
||||
DETECTOR_INTERVAL=30s
|
||||
DETECTOR_LOOKBACK=20m
|
||||
UI_QUERY_LIMIT=500
|
||||
"@ | Set-Content .env
|
||||
|
||||
function Hex([int]$bytes) {
|
||||
$b = New-Object byte[] $bytes
|
||||
[Security.Cryptography.RandomNumberGenerator]::Fill($b)
|
||||
return ([BitConverter]::ToString($b)).Replace("-","").ToLower()
|
||||
}
|
||||
$envMap=@{}; Get-Content .env | ForEach-Object { if ($_ -match '^([^#=]+)=(.*)$') {$envMap[$matches[1]]=$matches[2]} }
|
||||
if (-not $envMap.ContainsKey('UI_USERNAME')) { $envMap['UI_USERNAME']='admin'; Add-Content .env "UI_USERNAME=admin" }
|
||||
if (-not $envMap.ContainsKey('UI_PASSWORD') -or [string]::IsNullOrWhiteSpace($envMap['UI_PASSWORD'])) { $envMap['UI_PASSWORD']=Hex 18; Add-Content .env "UI_PASSWORD=$($envMap.UI_PASSWORD)" }
|
||||
(Get-Content deploy/garage/garage.toml.template -Raw).Replace('__GARAGE_RPC_SECRET__',$envMap.GARAGE_RPC_SECRET).Replace('__GARAGE_ADMIN_TOKEN__',$envMap.GARAGE_ADMIN_TOKEN).Replace('__GARAGE_METRICS_TOKEN__',$envMap.GARAGE_METRICS_TOKEN) | Set-Content deploy/garage/garage.toml
|
||||
(Get-Content deploy/clickhouse/init.sql.template -Raw).Replace('__EVENT_RETENTION_DAYS__',$envMap.EVENT_RETENTION_DAYS).Replace('__ROLLUP_RETENTION_DAYS__',$envMap.ROLLUP_RETENTION_DAYS) | Set-Content deploy/clickhouse/init.sql
|
||||
|
||||
function Read-EnvFile([string]$path) {
|
||||
$map = [ordered]@{}
|
||||
if (Test-Path $path) {
|
||||
foreach ($line in [IO.File]::ReadAllLines($path)) {
|
||||
if ($line -match '^([^#=][^=]*)=(.*)$') { $map[$matches[1]] = $matches[2] }
|
||||
}
|
||||
}
|
||||
return $map
|
||||
}
|
||||
|
||||
$template = Read-EnvFile ".env.example"
|
||||
$current = Read-EnvFile ".env"
|
||||
foreach ($k in $template.Keys) {
|
||||
if (-not $current.Contains($k)) { $current[$k] = $template[$k] }
|
||||
}
|
||||
|
||||
$presetEnrollment = $env:ENROLLMENT_KEY
|
||||
$secretLengths = @{
|
||||
POSTGRES_PASSWORD=24; CLICKHOUSE_PASSWORD=24; UI_PASSWORD=18;
|
||||
GARAGE_SECRET_KEY=32; GARAGE_RPC_SECRET=32; GARAGE_ADMIN_TOKEN=32; GARAGE_METRICS_TOKEN=32
|
||||
}
|
||||
foreach ($k in $secretLengths.Keys) {
|
||||
if ([string]::IsNullOrWhiteSpace($current[$k]) -or $current[$k] -eq 'CHANGE_ME') {
|
||||
$current[$k] = Hex $secretLengths[$k]
|
||||
}
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($current['GARAGE_ACCESS_KEY']) -or $current['GARAGE_ACCESS_KEY'] -eq 'CHANGE_ME') {
|
||||
$current['GARAGE_ACCESS_KEY'] = "GK$(Hex 16)"
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($presetEnrollment)) {
|
||||
$current['ENROLLMENT_KEY'] = $presetEnrollment
|
||||
} elseif ([string]::IsNullOrWhiteSpace($current['ENROLLMENT_KEY']) -or $current['ENROLLMENT_KEY'] -eq 'CHANGE_ME') {
|
||||
$current['ENROLLMENT_KEY'] = Hex 32
|
||||
}
|
||||
|
||||
# Write a complete UTF-8 .env. This fixes partial .env files from earlier releases
|
||||
# and preserves custom keys that are not part of the current template.
|
||||
$lines = New-Object System.Collections.Generic.List[string]
|
||||
$templateKeys = New-Object 'System.Collections.Generic.HashSet[string]'
|
||||
foreach ($line in [IO.File]::ReadAllLines(".env.example")) {
|
||||
if ($line -match '^([^#=][^=]*)=(.*)$') {
|
||||
$key = $matches[1]
|
||||
[void]$templateKeys.Add($key)
|
||||
$lines.Add("$key=$($current[$key])")
|
||||
} else {
|
||||
$lines.Add($line)
|
||||
}
|
||||
}
|
||||
foreach ($key in $current.Keys) {
|
||||
if (-not $templateKeys.Contains([string]$key)) {
|
||||
$lines.Add("$key=$($current[$key])")
|
||||
}
|
||||
}
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
[IO.File]::WriteAllLines((Join-Path $PSScriptRoot '.env'), $lines, $utf8NoBom)
|
||||
|
||||
foreach ($key in @('POSTGRES_PASSWORD','CLICKHOUSE_PASSWORD','UI_PASSWORD','ENROLLMENT_KEY','GARAGE_ACCESS_KEY','GARAGE_SECRET_KEY','GARAGE_RPC_SECRET','GARAGE_ADMIN_TOKEN','GARAGE_METRICS_TOKEN')) {
|
||||
if ([string]::IsNullOrWhiteSpace($current[$key]) -or $current[$key] -eq 'CHANGE_ME') {
|
||||
throw "Ungueltige .env: $key fehlt oder ist noch CHANGE_ME."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Pruefe Compose-Konfiguration ..."
|
||||
docker compose config | Out-Null
|
||||
|
||||
Write-Host "Baue und starte Greenfield SIEM ..."
|
||||
docker compose build --pull
|
||||
docker compose up -d --remove-orphans
|
||||
|
||||
Write-Host "Pruefe Dienste ..."
|
||||
Write-Host "Pruefe Readiness ..."
|
||||
$healthy = $false
|
||||
for ($i = 0; $i -lt 60; $i++) {
|
||||
try {
|
||||
Invoke-WebRequest -UseBasicParsing -TimeoutSec 2 "http://127.0.0.1:$($envMap.UI_PORT)/readyz" | Out-Null
|
||||
Invoke-WebRequest -UseBasicParsing -TimeoutSec 2 "http://127.0.0.1:$($envMap.INGRESS_PORT)/readyz" | Out-Null
|
||||
$healthy = $true
|
||||
break
|
||||
} catch {
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
for ($i = 0; $i -lt 90; $i++) {
|
||||
$apiOk = $false; $ingressOk = $false; $chOk = $false; $garageOk = $false
|
||||
try { Invoke-WebRequest -UseBasicParsing -TimeoutSec 2 "http://127.0.0.1:$($current.UI_PORT)/readyz" | Out-Null; $apiOk = $true } catch {}
|
||||
try { Invoke-WebRequest -UseBasicParsing -TimeoutSec 2 "http://127.0.0.1:$($current.INGRESS_PORT)/readyz" | Out-Null; $ingressOk = $true } catch {}
|
||||
docker compose exec -T clickhouse clickhouse-client --user $current.CLICKHOUSE_USER --password $current.CLICKHOUSE_PASSWORD --query "SELECT 1" *> $null
|
||||
if ($LASTEXITCODE -eq 0) { $chOk = $true }
|
||||
docker compose exec -T garage /garage status *> $null
|
||||
if ($LASTEXITCODE -eq 0) { $garageOk = $true }
|
||||
if ($apiOk -and $ingressOk -and $chOk -and $garageOk) { $healthy = $true; break }
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
if (-not $healthy) { throw "Deployment gestartet, Healthcheck noch nicht gruen. Pruefe: docker compose ps; docker compose logs" }
|
||||
|
||||
if (-not $healthy) {
|
||||
Write-Host "Mindestens ein Dienst wurde nicht bereit. Diagnose:" -ForegroundColor Red
|
||||
docker compose ps
|
||||
docker compose logs --tail=120 garage clickhouse clickhouse-schema postgres postgres-schema redpanda redpanda-init ingress processor api
|
||||
throw "Deployment nicht vollstaendig bereit."
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Greenfield SIEM laeuft."
|
||||
Write-Host "UI: http://127.0.0.1:$($envMap.UI_PORT)/ui"
|
||||
Write-Host "Ingress: http://127.0.0.1:$($envMap.INGRESS_PORT)/ingest"
|
||||
Write-Host "UI-Login: $($envMap.UI_USERNAME) / $($envMap.UI_PASSWORD)"
|
||||
Write-Host "Enrollment-Key: $($envMap.ENROLLMENT_KEY)"
|
||||
Write-Host "Secrets stehen in .env (Datei schuetzen und sichern)."
|
||||
Write-Host "UI: http://127.0.0.1:$($current.UI_PORT)/ui"
|
||||
Write-Host "Ingress: http://127.0.0.1:$($current.INGRESS_PORT)/ingest"
|
||||
Write-Host "UI-Login: $($current.UI_USERNAME) / $($current.UI_PASSWORD)"
|
||||
Write-Host "ClickHouse: user=$($current.CLICKHOUSE_USER) db=$($current.CLICKHOUSE_DB) http=127.0.0.1:$($current.CLICKHOUSE_HTTP_PORT) native=127.0.0.1:$($current.CLICKHOUSE_NATIVE_PORT)"
|
||||
Write-Host "Enrollment-Key: $($current.ENROLLMENT_KEY)"
|
||||
Write-Host "Alle Parameter stehen vollstaendig in .env."
|
||||
|
||||
Reference in New Issue
Block a user