Security & Privacy: PII redaction и авторизация
Security & Privacy: PII redaction и авторизация
Проблема: чувствительные данные в traces
Реальный инцидент:
// Trace в Jaeger (публично доступен всей команде)
{
"trace_id": "a1b2c3d4",
"spans": [
{
"name": "POST /api/users",
"attributes": {
"user.email": "alice@company.com",
"user.phone": "+1-555-0123",
"user.ssn": "123-45-6789",
"credit_card": "4111-1111-1111-1111",
"http.request.header.authorization": "Bearer eyJ..."
}
}
]
}Проблемы:
- ❌ PII (personally identifiable information)
- ❌ Credentials (токены, пароли)
- ❌ Business secrets
- ❌ GDPR/CCPA violation
PII Redaction: OTel Collector
Лучший подход: Удалять PII в Collector (до попадания в storage).
Attributes Processor: удаление атрибутов
processors:
attributes:
actions:
# Удаление PII
- key: user.email
action: delete
- key: user.phone
action: delete
- key: user.ssn
action: delete
# Удаление credentials
- key: http.request.header.authorization
action: delete
- key: http.request.header.cookie
action: delete
# Удаление business secrets
- key: api_key
action: deleteRedaction Processor: маскировка данных
processors:
redaction:
# Маскировка email
allow_all_keys: false
blocked_values:
- "email.*"
- ".*@.*" # Regex для email
# Маскировка IP addresses
- "\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b"
# Маскировка credit cards
- "\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b"Результат:
// До
{
"user.email": "alice@company.com",
"client_ip": "192.168.1.100"
}
// После
{
"user.email": "***REDACTED***",
"client_ip": "***REDACTED***"
}SDK-Level Redaction
Зачем: Предотвратить попадание PII в spans вообще.
const { trace } = require("@opentelemetry/api");
function redactEmail(email) {
if (!email) return null;
const [user, domain] = email.split("@");
return `${user[0]}***@${domain}`;
}
app.post("/users", (req, res) => {
const span = trace.getActiveSpan();
// ❌ Плохо
span.setAttribute("user.email", req.body.email);
// ✅ Хорошо
span.setAttribute("user.email_redacted", redactEmail(req.body.email));
// Result: "a***@company.com"
});GDPR Compliance
Right to be Forgotten
Проблема: Пользователь запросил удаление данных, но его email в traces.
Решение 1: Не логировать PII вообще
// Вместо user.email → user.id (хэш)
span.setAttribute("user.id", hashUserId(email)); // SHA-256Решение 2: TTL для traces
# Tempo config: автоудаление через 7 дней
storage:
trace:
backend: local
local:
path: /tmp/tempo/traces
block:
retention: 168h # 7 daysEncryption in Transit (TLS)
Проблема: Traces передаются по сети незашифрованными.
Решение: TLS для всех connections.
App → Collector (OTLP over TLS)
const {
OTLPTraceExporter,
} = require("@opentelemetry/exporter-trace-otlp-grpc");
const grpc = require("@grpc/grpc-js");
const fs = require("fs");
const exporter = new OTLPTraceExporter({
url: "https://otel-collector:4317",
credentials: grpc.credentials.createSsl(
fs.readFileSync("./ca.crt"), // CA certificate
fs.readFileSync("./client.key"), // Client key
fs.readFileSync("./client.crt") // Client cert
),
});Collector → Jaeger (TLS)
exporters:
jaeger:
endpoint: jaeger:14250
tls:
insecure: false
ca_file: /etc/ssl/ca.crt
cert_file: /etc/ssl/client.crt
key_file: /etc/ssl/client.keyAuthorization: Role-Based Access Control
Проблема: Любой сотрудник видит все traces (включая PII).
Решение: Ограничить доступ к traces по ролям.
Jaeger + OAuth2
# Jaeger query service with OAuth
jaeger-query:
image: jaegertracing/jaeger-query:latest
environment:
- QUERY_BASE_PATH=/jaeger
command:
- --query.bearer-token-propagation=true
- --query.ui-config=/etc/jaeger/ui-config.json
# OAuth proxy (например, oauth2-proxy)
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy
command:
- --upstream=http://jaeger-query:16686
- --email-domain=company.com
- --cookie-secret=***
- --provider=google
ports:
- "4180:4180"Результат: Только авторизованные пользователи видят Jaeger UI.
Audit Logging
Зачем: Знать, кто и когда смотрел traces.
# OTel Collector: audit log processor
processors:
audit:
log_file: /var/log/otel-collector-audit.log
include:
- span_attributes
- resource_attributesAudit log:
{
"timestamp": "2024-01-15T14:32:15Z",
"action": "trace_exported",
"trace_id": "a1b2c3d4",
"user": "alice@company.com",
"service": "api-gateway"
}Multi-tenancy Isolation
Проблема: В shared Jaeger instance видны traces всех tenant'ов.
Решение 1: Отдельный Jaeger на tenant
Tenant A → Collector A → Jaeger A
Tenant B → Collector B → Jaeger BРешение 2: Tenant ID в traces + фильтрация
// Добавляем tenant_id в каждый span
span.setAttribute("tenant.id", getTenantId(req));
// В Jaeger UI фильтруем:
// Tags: tenant.id=tenant-aSecurity Best Practices Checklist
✅ Data Protection
- PII redaction в Collector
- Credentials не логируются
- TLS enabled для всех connections
- Encryption at rest (если требуется)
- Data retention policy (7-30 days)
✅ Access Control
- Authentication для Jaeger UI
- RBAC настроен
- Audit logging включён
- Multi-tenancy изолировано
✅ Compliance
- GDPR Right to be Forgotten
- CCPA compliance
- SOC2 audit trail
- HIPAA (если медицинские данные)
Следующий урок
Финальный урок: Troubleshooting и Best Practices — решение типичных проблем и checklist для production.
Теперь вы можете безопасно использовать трассировку с соблюдением GDPR и защитой PII!