Lakekeeper: an Iceberg REST Catalog in Rust with Policy Outside the Engine
Apache Iceberg REST Catalog in Rust — access control, credential vending and audit for every engine and AI agent. Apache 2.0.
At a glance
- What is it?
- Lakekeeper is an Apache-2.0 implementation of the Apache Iceberg REST Catalog specification written in Rust, built around access control, credential vending and change events. It is a good fit if you want one authorization decision to apply across Spark, Trino, PyIceberg and StarRocks, and a poor fit if you need a catalog that runs without a database, an identity provider and an authorization service behind it.
- Who is it for?
- Adopt Lakekeeper if you already run an OpenID provider and can operate OpenFGA and PostgreSQL alongside it, and if the thing you actually want is one policy definition enforced for every engine rather than per-engine grants.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Lakekeeper targets: policy that lives in the catalog, not in each engine
In a lakehouse built on the Iceberg REST Catalog specification, the catalog answers metadata questions. It resolves table names, hands out table metadata, coordinates commits. It does not, by itself, decide who may read a table. That decision normally lands in the compute engine: a Spark grant here, a Trino access control plugin there, a warehouse-level role in the object store underneath. Duplicate those rules across four engines and they drift. The README states the intent directly: define access control once, in the catalog, and enforce it across every compute engine, with no rules duplicated per engine. It also states that every request is checked against your policy before any data is read, and recorded. That is the whole pitch, and it is narrower than it sounds. Lakekeeper is not a query engine, not a table format, and not a storage layer. It is the component that decides whether a request proceeds and what credentials the requester receives. The audience is platform teams running more than one engine against the same tables, who are tired of reconciling grants in several places. A single-engine shop with one team does not have the problem this solves.
How the pieces fit: REST catalog, OpenFGA, credential vending, CloudEvents
The catalog implements the Iceberg REST Catalog specification, built on apache/iceberg-rust. Requests arrive over that HTTP interface and are authenticated against an OpenID provider; the README gives the setting as LAKEKEEPER__OPENID_PROVIDER_URI. Authorization is separate. The default authorization system uses OpenFGA, and the README describes the Authorizer trait as the extension point if your company already has a different access management system. Data access is then handled by credential vending and remote signing for S3, with AWS, Azure, GCP and on-premise S3 listed as supported. The practical consequence is that the engine never holds long-lived storage credentials; it asks the catalog, the catalog checks policy, and the engine receives scoped credentials or a signed request. Alongside that, Lakekeeper emits change events as CloudEvents, and it exposes a ContractVerification trait so an external system can block a change that would violate a data contract or a quality SLO. The extension surface is unusually broad: the README lists the Database implementation (Catalog), SecretsStore, Authorizer, CloudEventBackend and ContractVerification as traits. That is the architecture in one sentence: a stateless Rust binary in front of a database, an authorization service and an identity provider, with hooks at every boundary for systems you already run.
Getting it running: the compose file, the UI port and the one setting that matters
The README gives a three-line quickstart. Clone the repository, change into examples/minimal, run docker compose up. A container image is published on quay.io under lakekeeper/catalog. After startup, the README points to localhost:8888 for example Jupyter notebooks and localhost:8181 for the Lakekeeper UI, which is the separate open-source Console project. For anything beyond that demonstration, the README defers to the Getting Started Guide at docs.lakekeeper.io. The only configuration key named in the supplied material is LAKEKEEPER__OPENID_PROVIDER_URI, described as the setting that connects your own identity provider. The double-underscore convention is visible in that key and is worth noting if you go looking for further settings: the README does not enumerate them here, so treat the docs site as the source rather than guessing at names. Deployment paths named in the material are a Docker image, a Helm chart in lakekeeper/lakekeeper-charts, and an Artifact Hub listing. Kubernetes service accounts can be authenticated natively, and the README notes that Kubernetes and OpenID authentication can be used simultaneously. A Kubernetes Operator is described as currently in development, so do not plan around it as an existing component.
Where the design gets in the way: dependencies, the operator gap and the storage table
The costs are structural, not incidental. Lakekeeper is not a self-contained catalog. To get the access control that distinguishes it from other REST catalog implementations, you need an OpenID provider and, for the default path, OpenFGA. That is two additional services to run, monitor and upgrade, on top of whatever database backs the Catalog trait. The stateless binary is genuinely stateless, which is what makes horizontal scaling straightforward, but statelessness in the catalog does not mean statelessness in the deployment. The second constraint is the Kubernetes Operator. The README says it is currently in development, which means any workflow that assumes a CRD-driven install is premature. The Helm chart exists; the operator does not yet. The third constraint is storage coverage, and this is the one to read carefully. The status table in the README marks S3 on AWS, custom S3 (MinIO, Ceph and other S3-compatible stores), Cloudflare R2 and Alibaba Cloud OSS as done, with the Azure ADLS Gen2 row cut off in the material available here. Do not assume a storage profile is supported because the marketing line says all major hyperscalers; check the table row for the backend you actually use. Finally, the ContractVerification trait lets an external system reject changes, which is powerful and also a new failure mode: if that external approver is unavailable, the question of whether commits proceed is a policy decision you have to make and test, and the supplied material does not answer it.
How it compares to a JVM-based catalog with per-engine grants
The obvious alternative is a catalog implemented in Java alongside an engine's own authorization, which is the pattern many Iceberg deployments start with: the catalog serves metadata, and each engine enforces its own rules. The difference is where the decision lives and what language the process is written in. With per-engine grants, adding a fifth engine means writing a fifth set of rules, and auditing means reading five systems. With Lakekeeper, the rule is written once against OpenFGA and every engine that speaks the REST specification inherits it, because the check happens before the engine receives credentials or metadata. The Rust choice matters for a different reason: the README describes it as a single all-in-one binary with no JVM or Python environment required, which removes a runtime from the deployment and from the upgrade path. That is a real operational difference, not a stylistic one, though it is not automatically an advantage. A team whose operational tooling, memory tuning and debugging habits are all JVM-shaped will find a Rust binary unfamiliar in exactly the moments when something is wrong. The other distinction is the trait surface. Where a JVM catalog typically expects you to work through its plugin system, Lakekeeper names the interfaces it intends you to implement: Authorizer, SecretsStore, Catalog, CloudEventBackend, ContractVerification. If your company already has an authorization system, that is the seam, and the README frames it as implementing a handful of methods rather than adopting OpenFGA.
Maintenance, releases and what the Apache-2.0 licence leaves you to decide
The release cadence visible in the material is active: v0.13.0 and v0.13.1 both landed on 2026-06-30, and v0.13.3 followed on 2026-08-17. Two things follow from that. First, the project is still on a 0.x line, so minor versions are where behaviour changes land, and a patch bump after two minor releases in a single day suggests the team ships fixes quickly rather than holding them. Second, pinning matters more than usual. The README advertises Helm charts and a Docker image on quay.io; both are versioned artefacts, and running a floating tag against a 0.x catalog is a choice you make deliberately rather than by default. On licensing, Lakekeeper is Apache-2.0, which is permissive and carries no copyleft obligation on your own code, but the licence covers this project only. Your deployment pulls in OpenFGA, an OpenID provider, a database and the Console UI, each under its own terms, and the supplied material does not state what those are. Checking the licence of each component you actually deploy is a task for your own review, not something this article can settle. Integration coverage is stated as Spark, PyIceberg, Trino and StarRocks, each with its own workflow, which is the concrete signal to look at when judging whether your engine is a first-class target or an untested one.
Who should run Lakekeeper and what to confirm before the first commit
The fit is a platform team with several engines, an existing OpenID provider, and a governance requirement that can be expressed as policy in one place. The misfit is a single team running one engine, or anyone who wants a catalog they can start with docker compose up and forget about. That compose file exists to demonstrate the catalog next to common query engines, and the README presents it that way; treating it as a production topology ignores the identity provider, the authorization service and the database that the real configuration assumes. If you are evaluating, the order of checks is: confirm your storage backend has a done row in the status table rather than an assumption, confirm your engine appears in the integration workflows, and read the Getting Started Guide for the configuration keys, since the only one named in the supplied material is LAKEKEEPER__OPENID_PROVIDER_URI. Then decide whether you are adopting OpenFGA or implementing the Authorizer trait against something you already run. That single decision determines how much of Lakekeeper's stated value you actually get, and it is the one the README leaves open.
Editorial conclusion
Adopt Lakekeeper if you already run an OpenID provider and can operate OpenFGA and PostgreSQL alongside it, and if the thing you actually want is one policy definition enforced for every engine rather than per-engine grants. Do not adopt it as a lightweight local catalog for a single laptop or a single engine; the Docker compose file in examples/minimal is a demonstration, not a deployment model, and the catalog expects an identity provider and an authorization backend to be meaningful. Before committing, verify three concrete things: that the storage profile you use appears as supported in the README status table, that your engine is covered by the integration test workflows, and that the current release line is one you can pin, given that v0.13.3 is a patch on top of v0.13.0 and v0.13.1.
Community notes