kubectl logs
kubectl logs without the panic

Your app is logging emails, OTPs, and credit cards. logcloak intercepts them before they hit kubectl logs, /var/log/containers/, or anywhere else. No code changes. Just install and forget.

Get started → Build a pattern GitHub
without logcloak
$ kubectl logs payment-pod Processing payment for user@example.com card=4111111111111111 otp=847291 Bearer eyJhbGciOiJIUzI1NiJ9 .eyJzdWIiOiJ1c2VyIn0.abc
with logcloak
$ kubectl logs payment-pod Processing payment for [REDACTED] card=[REDACTED] otp=[REDACTED] [REDACTED] (same pod · zero changes)

The problem

Your logs are the gap in your security model

Most teams lock down their database with encrypted connections, strict RBAC, and audit logging — then ship the same plaintext data out through every log pipeline they operate. A developer adds one debug line: log.info("order for {}", user.email). That line ends up in Datadog, Elasticsearch, an S3 bucket, your SIEM, and six terminals belonging to people who were only supposed to see latency metrics. Nobody notices. This is the default state of most Kubernetes deployments.

“But anyone with kubectl exec can see everything anyway”

True — and that is a separate control. kubectl exec requires explicit RBAC that is typically restricted, audited, and often disabled in production. kubectl logs is handed out far more broadly — to developers, support teams, CI pipelines, and log agents. logcloak defends the log surface. RBAC defends exec. Use both.

Where PII leaks & whether logcloak stops it
kubectl logs in a developer’s terminal✓ stopped
/var/log/containers/ on the node✓ stopped
Log shippers (Fluent Bit, Fluentd, Promtail)✓ stopped
Third-party platforms (Datadog, Splunk, Elastic)✓ stopped
S3 / GCS log archives✓ stopped
CI/CD pipelines that capture stdout✓ stopped
kubectl exec into a running containerout of scope — use RBAC
Application memory / heap dumpsout of scope

How it works

One FIFO to rule them all

The webhook injects a sidecar that reads from an in-memory pipe. Your app writes normally. Masking happens before containerd sees a single byte.

📨

1. App writes to stdout

Nothing changes in your app. It writes logs exactly as before. The webhook has already redirected its file descriptor to a named pipe.

🔒

2. logcloak reads and masks

The sidecar reads from the FIFO, applies your regex rules in microseconds, and writes clean output to its own stdout. Raw data never leaves the pipe.

3. containerd captures masked output

kubectl logs and /var/log/containers/ only ever see the sidecar's output. The app container's stdout is effectively silent.

🚨

Fail-closed — always

If masking fails for any reason (timeout, panic, pattern error), logcloak drops the line and writes a [LOGCLOAK-DROP] sentinel instead. The raw line never passes through. You can alert on the sentinel in your log aggregator.

~0ns added to your app

Writing to a FIFO is identical to writing to any fd. Your app doesn't wait for masking. It doesn't even know logcloak exists.


Rules system

Two ways to mask, one stack

Platform team sets the baseline. Developers extend per service. Annotations can add rules — they can never remove them.

Annotation / ResourceWho uses itWhat it does
MaskingPolicy CRD Platform / security team Applies to all matching pods in a namespace. The source of truth for company-wide PII rules. Developers cannot override or remove these.
logcloak.io/patterns Developer Enable built-in patterns per pod: logcloak.io/patterns: "uuid,iban"
logcloak.io/regex-<name> Developer Add a custom RE2 regex per pod: logcloak.io/regex-order-id: "ORD-[0-9]{8}"
logcloak.io/skip: "true" Developer Opt this pod out of injection entirely. Useful for debug pods or batch jobs where masking is unwanted.
logcloak.io/exclude-containers Developer Comma-separated list of sidecar containers to leave unwrapped. For postgres sidecars, monitoring agents, etc. Service mesh proxies (Istio, Linkerd, Envoy…) are excluded automatically.

Built-in patterns

10 patterns, zero regex writing

Enable by name. Use the pattern tool to preview against your actual log lines before deploying.

email
RFC 5321 email addresses
user@example.com
phone-e164
E.164 international phone numbers
+12025550104
phone-us
US phone formats with optional +1
(202) 555-0104
otp-6digit
Standalone 6-digit OTP codes
847291
credit-card
13–19 digit card numbers
4111 1111 1111 1111
jwt
eyJ… JWT tokens (the whole thing)
eyJhbGci…
ipv4-private
RFC 1918 private IP addresses
192.168.1.100
uuid
UUID v4 (not v1, not v3, just v4)
550e8400-e29b-41d4-…
iban
International Bank Account Numbers
GB29NWBK60161331926819
ssn
US Social Security Numbers
123-45-6789

Your logs. Your secrets. Keep it that way.

One helm install. Pick your patterns. Done.

Read the guide Try the pattern tool