Security and privacy
This page describes what Lumaft holds, what it deliberately refuses to hold, who can reach it, and how to report a problem. It describes the current build; where a control is not implemented, it says so.
Threat model in eight rules
Lumaft sits between your Pulumi state and a browser. It is a read-only observer with a durable memory, and its security design follows from that.
- Accept evidence only from a known source through its authorized path. Backend evidence arrives only through the observer's own read of a configured backend. Runner evidence arrives only over the ingestion API with a bearer integration token, never through a browser session.
- Keep assertions immutable and conflicts visible. Evidence is appended, never edited.
Disagreeing assertions surface as a
conflictoutcome rather than being resolved silently. - Never let a pruned, replayed, or replaced source delete accepted evidence. Only retention policy, an explicitly confirmed administrative action, or a restore changes what is stored.
- Retain only exact allowlisted normalized fields. Raw state, source payloads, provider messages, secrets, and unbounded text are rejected at the boundary, not filtered later.
- Derive outcomes, coverage, and retention from Lumaft's own rules, not from untrusted source timestamps. A source clock that disagrees with Lumaft's is flagged, not trusted.
- Separate every permission. Read, export, retention, purge, and evidence-write are distinct, and evidence-write is unreachable from any browser role.
- Keep background work bounded and observable.
- Fail closed without disclosure. Failures use closed reason codes and never expose SQL, paths, object keys, credentials, source content, or the existence of records the caller may not see.
The assets: the normalized operation and resource evidence (customer confidential), the retention policy and its audit trail, the deletion and tombstone records, and the database with its backups and exports — which, together, is everything Lumaft knows. Anyone who can read the volume can read everything Lumaft holds, regardless of Lumaft's own permissions. Filesystem and infrastructure access sit outside Lumaft's authorization boundary and belong to your deployment.
The read-only boundary to your infrastructure
Base observation sends two S3 requests, ListObjectsV2 and GetObject, scoped to the configured
namespace. A backend with version reads enabled adds ListObjectVersions and versioned
GetObject. On AWS the IAM actions are s3:ListBucket and s3:GetObject, plus
s3:ListBucketVersions and s3:GetObjectVersion for the opt-in. All are read-only. There is no
configuration that turns the observer into a writer, and Lumaft needs no bucket administration,
object creation, overwrite, deletion, or deployment permission.
This is a permanent boundary, not a starter policy. Backend credentials come from the environment's credential chain and can never be placed in the backend configuration file: the file rejects unknown fields, and credential-bearing endpoint URLs are rejected outright.
Lumaft's own tests hold this line: its identity is granted only list and read against a fixture store, completes every observation under that grant, and has its explicit overwrite and delete attempts refused.
What is never stored
From each Pulumi update-history record, Lumaft admits an exact, closed field set:
backendId, historyId, layout, projectName, stackName,
kind, startTime, endTime, result, resourceChanges, sourceVersion
Everything else is discarded unread. The update message, environment, and config are
never inspected, stored, or logged. A record with an unknown field is rejected whole. The one
exception is bounded by grammar: at most one anchored [lumaft:v1:<uuid>] correlation marker is
parsed from the message, only its UUID is kept, and every other byte is discarded.
Checkpoint observation follows the same rule. Lumaft normalizes resource identity and a closed
list of metadata fields (type, parent, protect, retainOnDelete, pendingReplacement,
deletePending, external, custom, kind, createdAt, modifiedAt). Resource inputs and
outputs are not retained as history.
Where the current inventory shows stack outputs, Pulumi-marked secrets are redacted before they reach a browser-facing model. Unmarked plaintext in an output is not a secret to Pulumi and will not be invented as one by Lumaft. If your state contains sensitive values Pulumi does not mark, treat Lumaft's database and backups accordingly.
Lumaft records no human identity for a deployment. Pulumi state does not carry one, and Lumaft does not infer one.
What the metadata is for
| Metadata | Purpose |
|---|---|
| Evidence digests and commitments | Detect tampering with, or divergence in, the evidence covered by integrity controls |
| Acceptance time and policy revision per assertion | Make retention deterministic and auditable |
| Coverage records | Let the console state honestly what interval it can speak for |
| Source and correlation replay fences | Prevent a pruned-then-replayed record from re-entering history |
| Tombstones and deletion audits | Prove what was deleted, when, and by which action, without the deleted payload |
| Token name, authority kind, scope, last use | Credential audit |
| Per-user reviewed marks and recent stacks | Console convenience, scoped to one account |
Access control and transport
- One fixed role per local account —
administrator,viewer,transcript-reader— assigned explicitly. Only the reader role includes transcript-body access. No self-service signup or invitation flow. - Business custom roles compose permissions within the author's own authority and can never include evidence-write. On license lapse, assignments fall back to viewer.
- Enterprise OIDC, SAML, and trusted-proxy sign-in use registered immutable subjects, never email or external group claims. SCIM provisions viewers and disables identities; it never selects a role. Local sign-in stays available when federation fails.
- Enterprise stack grants narrow retained-history reads; live observation pages remain installation-wide. These are not full tenant isolation.
- Sessions are server-side and revocable, with a twelve-hour absolute lifetime. The cookie is
HttpOnly, SameSite=Strict, and Secure (
__Host-lumaft-session). Lumaft stores only a SHA-256 digest of the session token, and an Argon2id-derived credential for passwords. - Five failed sign-ins from one address, or for one username, block for fifteen minutes.
- Integration tokens reach the ingestion API only, are limited to 60 requests per minute, and return one indistinguishable not-found for out-of-scope and nonexistent targets.
- TLS is the deployment's responsibility. Lumaft expects a reverse proxy or load balancer
to terminate HTTPS.
LUMAFT_ALLOW_HTTP=trueexists for loopback evaluation on one machine; over plain HTTP the password, the cookie, and everything the session protects cross the network in cleartext. - Encryption at rest is the deployment's responsibility. Lumaft enforces owner-only mode on the SQLite file and expects a protected parent directory; it does not encrypt the volume, backups, or exports. Transcript bodies are the exception, encrypted with a separately held key.
Full configuration is in Users and permissions.
Transcripts
Optional capture requires three opt-ins and defaults off. The runner redacts before queuing and
the server redacts again before storing. Bodies use authenticated encryption with a 32-byte key
mounted outside the data directory; the key must be backed up separately from the database, and
there is no automatic rotation or recovery. Missing or wrong keys make text unavailable while
metadata stays readable. Every body read or download is audited before bytes are served, and
only the transcript-reader role can perform one.
Redaction removes patterns Lumaft recognizes. It cannot find every secret. Treat transcripts as sensitive, and note that downloaded copies leave Lumaft's retention boundary.
Retention and deletion
Retention is installation-wide, versioned, and append-only: applying a policy appends a revision, and the revision history is the audit trail. Two windows — operation summaries and resource changes — default to 90 days on a new installation, adjustable up to 365 on Community and 3,650 on paid editions. A policy change is prospective; shortening retention for evidence already stored is a separate, previewed, confirmed action.
Three deletion paths exist, all administrator-only, all preview-then-confirm, all audited: retroactive application of a shorter policy, exact-stack purge, and forget (which retires the replay identity left after expiry and requires the backend to be disabled first).
Two properties matter for a deletion or privacy request:
- What survives expiry. Expired payload leaves a compact replay fence — source identity, digest, identifiers, acceptance time, policy revision — with no operation payload and no resource changes. It exists so a pruned source cannot be replayed into history and remains until forget is explicitly invoked.
- What backups retain. Deleting evidence in the live database does not delete it from copies you have taken. A deletion commitment to a third party must account for your backup lifetime, which Lumaft neither manages nor verifies.
Deletion also does not free disk until an offline VACUUM; see
Database integration.
Connected license identity
One Business or Enterprise agreement covers one installation, bound at first activation to a
durable random installation ID that Lumaft does not derive from hardware, IP, hostname, or
customer data. Public health endpoints expose no licensing metadata. A different installation
presenting the same key receives only installation-conflict. Copying persisted identity can
produce indistinguishable clones; the protocol is not clone detection.
Diagnostics that are safe to share
Only Lumaft-authored lines in a documented closed format are safe to share. A Lumaft HTTP failure line carries a correlation UUID, an integer status, an allowlisted method, a fixed route-family label, and a bounded cause classification — never the URL, parameters, error text, or stack.
Safe: a Lumaft-authored line verbatim, closed reason codes, HTTP status codes, the image version and digest, the schema revision from the version stamp, health and readiness results, and the shape of your backends file with bucket, prefix, and endpoint values removed.
Never: the database or any part of it, a backup, an export document, Pulumi state, credentials or tokens, or infrastructure identifiers you would not publish.
Reporting a security issue
Do not report a suspected vulnerability through a public issue. Use the private vulnerability-reporting channel on the Lumaft distribution repository. A report should include the Lumaft version and image digest, the deployment environment, and a minimal reproduction — and must not include Pulumi state, credentials, secret outputs, or customer infrastructure identifiers.
Each release's SBOM and provenance are attested against the published digest and referenced from the release record, so you can enumerate what the image contains and scan it against your own policy. See Upgrades and versioning.