47 lines
1.8 KiB
Python
47 lines
1.8 KiB
Python
|
|
"""Masking display filter for KV values (WARDEN-WP-0026 T03).
|
|||
|
|
|
|||
|
|
Defense-in-depth, **not a boundary**: any place warden would otherwise render a
|
|||
|
|
secret value for a human (a status/listing view) shows a *fingerprint* instead —
|
|||
|
|
presence, length, and a short non-reversible hash. Two operators can compare
|
|||
|
|
fingerprints to confirm they hold the same value (e.g. that a rotation landed the
|
|||
|
|
expected token) without either seeing it, and a fingerprint in a transcript
|
|||
|
|
discloses nothing.
|
|||
|
|
|
|||
|
|
Limitation (documented, by design): raw `bao kv get <path>` bypasses this entirely
|
|||
|
|
— warden only masks *warden-mediated* output. The real boundary is OpenBao policy
|
|||
|
|
plus the T01 capabilities-safe verify and T02 no-stdout transports.
|
|||
|
|
"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import hashlib
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
|
|||
|
|
# Short, non-reversible hash: first 8 hex chars of SHA-256. Not a value, and a
|
|||
|
|
# collision is irrelevant for the "same/different?" comparison this supports.
|
|||
|
|
_HASH_PREFIX_LEN = 8
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass(frozen=True)
|
|||
|
|
class Fingerprint:
|
|||
|
|
present: bool
|
|||
|
|
length: int
|
|||
|
|
sha256_prefix: str # "" when the value is empty/absent
|
|||
|
|
|
|||
|
|
def render(self) -> str:
|
|||
|
|
if not self.present:
|
|||
|
|
return "‹absent›"
|
|||
|
|
return f"‹hidden len={self.length} sha256:{self.sha256_prefix}›"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def fingerprint(value: str | None) -> Fingerprint:
|
|||
|
|
"""Compute a non-reversible fingerprint of a value. Never returns the value."""
|
|||
|
|
if not value:
|
|||
|
|
return Fingerprint(present=False, length=0, sha256_prefix="")
|
|||
|
|
digest = hashlib.sha256(value.encode("utf-8")).hexdigest()[:_HASH_PREFIX_LEN]
|
|||
|
|
return Fingerprint(present=True, length=len(value), sha256_prefix=digest)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def mask_value(value: str | None) -> str:
|
|||
|
|
"""Render a value as its masked fingerprint string. Never emits the value."""
|
|||
|
|
return fingerprint(value).render()
|