Skip to content

Role-Based Access Control (RBAC)

Info

This feature is available with lakeFS Enterprise. Start a free trial.

RBAC Model

Access to resources is managed very much like AWS IAM.

There are five basic components to the system:

  1. Users - Representing entities that access and use the system. A user is given one or more Access Credentials for authentication.
  2. Actions - Representing a logical action within the system - reading a file, creating a repository, etc.
  3. Resources - A unique identifier representing a specific resource in the system - a repository, an object, a user, etc.
  4. Policies - Representing a set of Actions, a Resource and an effect: whether or not these actions are allowed or denied for the given resource(s).
  5. Groups - A named collection of users. Users can belong to multiple groups.

Controlling access is done by attaching Policies, either directly to Users, or to Groups they belong to.

Authorization process

Every action in the system - be it an API request, UI interaction, S3 Gateway call, or CLI command - requires a set of actions to be allowed for one or more resources.

When a user makes a request to perform that action, the following process takes place:

  1. Authentication - the credentials passed in the request are evaluated and the user's identity is extracted.
  2. Action permission resolution - lakeFS then calculates the set of allowed actions and resources that this request requires.
  3. Effective policy resolution - the user's policies (either attached directly or through group memberships) are calculated.
  4. Policy/Permission evaluation - lakeFS will compare the given user policies with the request actions and determine whether or not the request is allowed to continue.

Policy Precedence

Each policy attached to a user or a group has an Effect - either allow or deny. During evaluation of a request, deny would take precedence over any other allow policy.

This helps us compose policies together. For example, we could attach a very permissive policy to a user and use deny rules to then selectively restrict what that user can do.

Policy Conditions

lakeFS policies support optional conditions that provide additional control over when a policy statement is in effect.

Conditions are specified using condition operators that evaluate to true or false based on the request context. When a condition evaluates to false, the policy statement does not apply.

Condition Structure

Conditions are added to policy statements using the optional condition field:

{
  "statement": [
    {
      "action": ["fs:ReadObject"],
      "effect": "allow",
      "resource": "arn:lakefs:fs:::repository/myrepo/object/*",
      "condition": {
        "IpAddress": {
          "SourceIp": ["203.0.113.0/24", "198.51.100.25/32"]
        }
      }
    }
  ]
}

Supported Condition Operators

IpAddress / NotIpAddress

The IpAddress condition operator matches the client's source IP address against one or more IP addresses or CIDR blocks. The NotIpAddress condition operator matches when the client's source IP address does NOT match any of the specified IP addresses or CIDR blocks (negation of IpAddress).

Supported Fields:

  • SourceIp - The IP address of the client making the request

Value Format: - Single IP address: "203.0.113.5" - CIDR notation: "203.0.113.0/24" - Array of IPs and/or CIDRs: ["203.0.113.0/24", "198.51.100.25/32"]

Example - Allow access only from specific IP range:

{
  "statement": [
    {
      "action": ["fs:*"],
      "effect": "allow",
      "resource": "*",
      "condition": {
        "IpAddress": {
          "SourceIp": ["10.0.0.0/8", "172.16.0.0/12"]
        }
      }
    }
  ]
}

Example - Deny access from specific IPs:

{
  "statement": [
    {
      "action": ["fs:*"],
      "effect": "deny",
      "resource": "*",
      "condition": {
        "IpAddress": {
          "SourceIp": ["192.0.2.0/24"]
        }
      }
    }
  ]
}

Example - Deny access from IPs NOT in allowed ranges:

{
  "statement": [
    {
      "action": ["fs:*"],
      "effect": "deny",
      "resource": "*",
      "condition": {
        "NotIpAddress": {
          "SourceIp": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
        }
      }
    }
  ]
}

IP Address Extraction:

lakeFS extracts the client IP address from the request using the following priority:

  1. X-Forwarded-For header (first IP in the list) - for requests through proxies/load balancers
  2. X-Real-IP header - as a fallback
  3. Remote address from the TCP connection

This ensures that IP-based conditions work correctly even when lakeFS is deployed behind a load balancer or reverse proxy.

StringEquals / StringNotEquals

The StringEquals condition operator matches a context value against one or more exact strings. The StringNotEquals condition operator matches when the context value does NOT equal any of the specified strings (negation of StringEquals).

StringLike / StringNotLike

The StringLike condition operator matches a context value against one or more wildcard patterns. The StringNotLike condition operator matches when the context value does NOT match any of the specified patterns (negation of StringLike).

Wildcard characters: * matches zero or more characters, ? matches exactly one character.

Attribute-Based Access Control for Repositories

Info

This feature is available with lakeFS Enterprise. Start a free trial.

Beyond role-based access, lakeFS supports attribute-based access control (ABAC): policy conditions that gate access based on attributes of the repository being accessed. This lets you enforce data governance policies automatically — for example, restricting access to PII or production repositories — without managing a separate policy per repository.

ABAC conditions can use user-defined metadata on repositories to filter. You attach key-value tags to repositories (e.g. env=staging, team=data-platform, classification=pii) and then reference those tags in policy conditions.

Managing repository metadata

Set (merge) metadata on a repository using the lakeFS REST API. Keys not included in the request are preserved — this is a merge, not a replacement:

curl -X POST https://<lakefs-host>/api/v1/repositories/<repo>/metadata \
  -H "Content-Type: application/json" \
  -u ${LAKECTL_CREDENTIALS_ACCESS_KEY_ID}:${LAKECTL_CREDENTIALS_SECRET_ACCESS_KEY} \
  -d '{"metadata": {"env": "staging", "team": "data-platform", "classification": "pii"}}'

Read metadata back to verify what is set:

curl -X POST https://$LAKECTL_SERVER_ENDPOINT/api/v1/repositories/<repo>/metadata \
  -u ${LAKECTL_CREDENTIALS_ACCESS_KEY_ID}:${LAKECTL_CREDENTIALS_SECRET_ACCESS_KEY} \

Delete specific metadata keys:

curl -X DELETE https://<lakefs-host>/api/v1/repositories/<repo>/metadata \
  -H "Content-Type: application/json" \
  -u ${LAKECTL_CREDENTIALS_ACCESS_KEY_ID}:${LAKECTL_CREDENTIALS_SECRET_ACCESS_KEY} \
  -d '{"keys": ["classification"]}'

Condition key format

lakefs:RepositoryMetadata/<metadata-key>

The <metadata-key> maps directly to a key in the repository's metadata. Matching is case-sensitive — lakefs:RepositoryMetadata/env matches only the metadata key env.

Examples

Allow read access only to repositories tagged env=staging

{
  "statement": [
    {
      "action": ["fs:ReadObject", "fs:ListObjects", "fs:ReadRepository"],
      "effect": "allow",
      "resource": "arn:lakefs:fs:::repository/*",
      "condition": {
        "StringLike": {
          "lakefs:RepositoryMetadata/env": ["staging"]
        }
      }
    }
  ]
}

Deny access to PII repositories, combined with a broad allow

The most common ABAC pattern is to grant a user a broad role (e.g. FSReadAll) and then attach an additional policy that denies access to sensitive repositories. Since deny takes precedence over allow, this ensures the restriction holds regardless of what other policies the user has.

{
  "statement": [
    {
      "action": ["fs:*"],
      "effect": "deny",
      "resource": "arn:lakefs:fs:::repository/*",
      "condition": {
        "StringLike": {
          "lakefs:RepositoryMetadata/classification": ["pii"]
        }
      }
    }
  ]
}

Attach this policy alongside FSReadAll (or any other broad policy): the user can access all repositories except those tagged classification=pii.

Combine multiple metadata keys

When a condition block contains multiple keys, all of them must match for the statement to apply. Multiple values within a single key are evaluated as OR (any match is sufficient):

{
  "statement": [
    {
      "action": ["fs:ReadObject", "fs:ListObjects"],
      "effect": "allow",
      "resource": "arn:lakefs:fs:::repository/*",
      "condition": {
        "StringLike": {
          "lakefs:RepositoryMetadata/team": ["ml"],
          "lakefs:RepositoryMetadata/env": ["staging", "dev"],
          "lakefs:RepositoryMetadata/classification": ["public"]
        }
      }
    }
  ]
}

This grants access only to repositories where team=ml and (env=staging or env=dev) and classification=public.

Behavior notes

  • If a repository has no metadata, or if the requested key is absent, the condition evaluates to false and the statement does not apply.
  • Condition keys are case-sensitive: lakefs:RepositoryMetadata/ENV does not match the metadata key env.

Resource naming - ARNs

lakeFS uses ARN identifier - very similar in structure to those used by AWS. The resource segment of the ARN supports wildcards: use * to match 0 or more characters, or ? to match exactly one character.

Here are a some examples of valid ARNs within lakeFS and their meaning:

ARN Meaning
arn:lakefs:auth:::user/jane.doe A specific user
arn:lakefs:auth:::user/* All users
arn:lakefs:fs:::repository/myrepo/* All resources under myrepo
arn:lakefs:fs:::repository/myrepo/object/foo/bar/baz A single object ARN
arn:lakefs:fs:::repository/myrepo/object/* All objects in myrepo
arn:lakefs:fs:::repository/* All repositories
arn:lakefs:fs:::* All resources under the fs ARN prefix
arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} An Iceberg namespace
arn:lakefs:catalog:::table/{repositoryId}/{namespace}/{table} An Iceberg table
arn:lakefs:catalog:::view/{repositoryId}/{namespace}/{view} An Iceberg view
arn:lakefs:audit:::log The lakeFS audit log

Note that Iceberg catalog ARNs are branch-agnostic, the branch is not part of the ARN. A policy granting access to a namespace, a table or a view applies to that resource on every branch in the repository.

Additionally, the current user's ID is interpolated in runtime into the ARN using the ${user} placeholder.

This allows us to create fine-grained policies affecting only a specific subset of resources.

See below for a full reference of ARNs and actions.

Actions and Permissions

For the full list of actions and their required permissions, see the following table:

Action name required action Resource API endpoint S3 gateway operation
List Repositories fs:ListRepositories * GET /repositories ListBuckets
Get Repository fs:ReadRepository arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repositoryId} HeadBucket
Get Commit fs:ReadCommit arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repositoryId}/commits/{commitId} -
Create Commit fs:CreateCommit arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} POST /repositories/{repositoryId}/branches/{branchId}/commits -
Get Commit log fs:ReadBranch arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} GET /repositories/{repositoryId}/branches/{branchId}/commits -
Create Repository fs:CreateRepository arn:lakefs:fs:::repository/{repositoryId} POST /repositories -
Namespace Attach to Repository fs:AttachStorageNamespace arn:lakefs:fs:::namespace/{storageNamespace} POST /repositories -
Import From Source fs:ImportFromStorage arn:lakefs:fs:::namespace/{storageNamespace} POST /repositories/{repositoryId}/branches/{branchId}/import -
Cancel Import fs:ImportCancel arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} DELETE /repositories/{repositoryId}/branches/{branchId}/import -
Delete Repository fs:DeleteRepository arn:lakefs:fs:::repository/{repositoryId} DELETE /repositories/{repositoryId} -
List Branches fs:ListBranches arn:lakefs:fs:::repository/{repositoryId} or arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} (details) GET /repositories/{repositoryId}/branches ListObjects/ListObjectsV2 (with delimiter = / and empty` prefix)
Get Branch fs:ReadBranch arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} GET /repositories/{repositoryId}/branches/{branchId} -
Create Branch fs:CreateBranch arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} POST /repositories/{repositoryId}/branches -
Delete Branch fs:DeleteBranch arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} DELETE /repositories/{repositoryId}/branches/{branchId} -
Merge branches fs:CreateCommit arn:lakefs:fs:::repository/{repositoryId}/branch/{destinationBranchId} POST /repositories/{repositoryId}/refs/{sourceBranchId}/merge/{destinationBranchId} -
Diff branch uncommitted changes fs:ListObjects arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repositoryId}/branches/{branchId}/diff -
Diff refs fs:ListObjects arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repositoryId}/refs/{leftRef}/diff/{rightRef} -
Stat object fs:ReadObject arn:lakefs:fs:::repository/{repositoryId}/object/{objectKey} GET /repositories/{repositoryId}/refs/{ref}/objects/stat HeadObject
Get Object fs:ReadObject arn:lakefs:fs:::repository/{repositoryId}/object/{objectKey} GET /repositories/{repositoryId}/refs/{ref}/objects GetObject
List Objects fs:ListObjects arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repositoryId}/refs/{ref}/objects/ls ListObjects, ListObjectsV2 (no delimiter, or "/" + non-empty` prefix)
Upload Object fs:WriteObject arn:lakefs:fs:::repository/{repositoryId}/object/{objectKey} POST /repositories/{repositoryId}/branches/{branchId}/objects PutObject, CreateMultipartUpload, UploadPart`, CompleteMultipartUpload
Delete Object fs:DeleteObject arn:lakefs:fs:::repository/{repositoryId}/object/{objectKey} DELETE /repositories/{repositoryId}/branches/{branchId}/objects DeleteObject, DeleteObjects`, AbortMultipartUpload
Revert Branch fs:RevertBranch arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId} PUT /repositories/{repositoryId}/branches/{branchId} -
Get Branch Protection Rules branches:GetBranchProtectionRules arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/branch_protection -
Set Branch Protection Rules branches:SetBranchProtectionRules arn:lakefs:fs:::repository/{repositoryId} POST /repositories/{repository}/branch_protection -
Delete Branch Protection Rules branches:SetBranchProtectionRules arn:lakefs:fs:::repository/{repositoryId} DELETE /repositories/{repository}/branch_protection -
Create User auth:CreateUser arn:lakefs:auth:::user/{userId} POST /auth/users -
List Users auth:ListUsers * GET /auth/users -
Get User auth:ReadUser arn:lakefs:auth:::user/{userId} GET /auth/users/{userId} -
Delete User auth:DeleteUser arn:lakefs:auth:::user/{userId} DELETE /auth/users/{userId} -
Get Group auth:ReadGroup arn:lakefs:auth:::group/{groupId} GET /auth/groups/{groupId} -
List Groups auth:ListGroups * GET /auth/groups -
Create Group auth:CreateGroup arn:lakefs:auth:::group/{groupId} POST /auth/groups -
Delete Group auth:DeleteGroup arn:lakefs:auth:::group/{groupId} DELETE /auth/groups/{groupId} -
List Policies auth:ListPolicies * GET /auth/policies -
Create Policy auth:CreatePolicy arn:lakefs:auth:::policy/{policyId} POST /auth/policies -
Update Policy auth:UpdatePolicy arn:lakefs:auth:::policy/{policyId} POST /auth/policies -
Delete Policy auth:DeletePolicy arn:lakefs:auth:::policy/{policyId} DELETE /auth/policies/{policyId} -
Get Policy auth:ReadPolicy arn:lakefs:auth:::policy/{policyId} GET /auth/policies/{policyId} -
List Group Members auth:ReadGroup arn:lakefs:auth:::group/{groupId} GET /auth/groups/{groupId}/members -
Add Group Member auth:AddGroupMember arn:lakefs:auth:::group/{groupId} PUT /auth/groups/{groupId}/members/{userId} -
Remove Group Member auth:RemoveGroupMember arn:lakefs:auth:::group/{groupId} DELETE /auth/groups/{groupId}/members/{userId} -
List User Credentials auth:ListCredentials arn:lakefs:auth:::user/{userId} GET /auth/users/{userId}/credentials -
Create User Credentials auth:CreateCredentials arn:lakefs:auth:::user/{userId} POST /auth/users/{userId}/credentials -
Delete User Credentials auth:DeleteCredentials arn:lakefs:auth:::user/{userId} DELETE /auth/users/{userId}/credentials/{accessKeyId} -
Get User Credentials auth:ReadCredentials arn:lakefs:auth:::user/{userId} GET /auth/users/{userId}/credentials/{accessKeyId} -
List User Groups auth:ReadUser arn:lakefs:auth:::user/{userId} GET /auth/users/{userId}/groups -
List User Policies auth:ReadUser arn:lakefs:auth:::user/{userId} GET /auth/users/{userId}/policies -
Attach Policy To User auth:AttachPolicy arn:lakefs:auth:::user/{userId} PUT /auth/users/{userId}/policies/{policyId} -
Detach Policy From User auth:DetachPolicy arn:lakefs:auth:::user/{userId} DELETE /auth/users/{userId}/policies/{policyId} -
List Group Policies auth:ReadGroup arn:lakefs:auth:::group/{groupId} GET /auth/groups/{groupId}/policies -
Attach Policy To Group auth:AttachPolicy arn:lakefs:auth:::group/{groupId} PUT /auth/groups/{groupId}/policies/{policyId} -
Detach Policy From Group auth:DetachPolicy arn:lakefs:auth:::group/{groupId} DELETE /auth/groups/{groupId}/policies/{policyId} -
Attach External Principal to a User auth:CreateUserExternalPrincipal arn:lakefs:auth:::user/{userId} POST /auth/users/{userId}/external/principals -
Delete External Principal Attachment from a User auth:DeleteUserExternalPrincipal arn:lakefs:auth:::user/{userId} DELETE /auth/users/{userId}/external/principals -
Get the User attached to an External Principal auth:ReadExternalPrincipal arn:lakefs:auth:::externalPrincipal/{principalId} GET /auth/external/principals -
Read Storage Config fs:ReadConfig * GET /config/storage -
Get Garbage Collection Rules retention:GetGarbageCollectionRules arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repositoryId}/gc/rules -
Set Garbage Collection Rules retention:SetGarbageCollectionRules arn:lakefs:fs:::repository/{repositoryId} POST /repositories/{repositoryId}/gc/rules -
Prepare Garbage Collection Commits retention:PrepareGarbageCollectionCommits arn:lakefs:fs:::repository/{repositoryId} POST /repositories/{repositoryId}/gc/prepare_commits -
List Repository Action Runs ci:ReadAction arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/actions/runs -
Get Action Run ci:ReadAction arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/actions/runs/{run_id} -
List Action Run Hooks ci:ReadAction arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/actions/runs/{run_id}/hooks -
Get Action Run Hook Output ci:ReadAction arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/actions/runs/{run_id}/hooks/{hook_run_id}/output -
Get Pull Request pr:ReadPullRequest arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/pulls/{pull_request} -
Create Pull Request pr:WritePullRequest arn:lakefs:fs:::repository/{repositoryId} POST /repositories/{repository}/pulls -
Update Pull Request pr:WritePullRequest arn:lakefs:fs:::repository/{repositoryId} PATCH /repositories/{repository}/pulls/{pull_request} -
Merge Pull Request pr:WritePullRequest + Merge Branches arn:lakefs:fs:::repository/{repositoryId} PUT /repositories/{repository}/pulls/{pull_request}/merge -
List Pull Requests pr:ListPullRequests arn:lakefs:fs:::repository/{repositoryId} GET /repositories/{repository}/pulls -
List Namespaces catalog:ListNamespaces arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} GET /iceberg/api/v1/{prefix}/namespaces -
Get Namespace catalog:GetNamespace arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} GET /iceberg/api/v1/{prefix}/namespaces/{namespace} -
Create Namespace catalog:CreateNamespace arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} POST /iceberg/api/v1/{prefix}/namespaces -
Update Namespace catalog:UpdateNamespace arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} POST /iceberg/api/v1/{prefix}/namespaces/{namespace}/properties -
Delete Namespace catalog:DeleteNamespace arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} DELETE /iceberg/api/v1/{prefix}/namespaces/{namespace} -
List Tables catalog:ListTables arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} GET /iceberg/api/v1/{prefix}/namespaces/{namespace}/tables -
Create Table catalog:CreateTable arn:lakefs:catalog:::table/{repositoryId}/{namespace}/{table} POST /iceberg/api/v1/{prefix}/namespaces/{namespace}/tables -
Read Table catalog:ReadTable arn:lakefs:catalog:::table/{repositoryId}/{namespace}/{table} GET /iceberg/api/v1/{prefix}/namespaces/{namespace}/tables/{table} -
Update Table catalog:UpdateTable arn:lakefs:catalog:::table/{repositoryId}/{namespace}/{table} POST /iceberg/api/v1/{prefix}/namespaces/{namespace}/tables/{table} -
Delete Table catalog:DeleteTable arn:lakefs:catalog:::table/{repositoryId}/{namespace}/{table} DELETE /iceberg/api/v1/{prefix}/namespaces/{namespace}/tables/{table} -
List Views catalog:ListViews arn:lakefs:catalog:::namespace/{repositoryId}/{namespace} GET /iceberg/api/v1/{prefix}/namespaces/{namespace}/views -
Create View catalog:CreateView arn:lakefs:catalog:::view/{repositoryId}/{namespace}/{view} POST /iceberg/api/v1/{prefix}/namespaces/{namespace}/views -
Read View catalog:ReadView arn:lakefs:catalog:::view/{repositoryId}/{namespace}/{view} GET /iceberg/api/v1/{prefix}/namespaces/{namespace}/views/{view} -
Update View catalog:UpdateView arn:lakefs:catalog:::view/{repositoryId}/{namespace}/{view} POST /iceberg/api/v1/{prefix}/namespaces/{namespace}/views/{view} -
Delete View catalog:DeleteView arn:lakefs:catalog:::view/{repositoryId}/{namespace}/{view} DELETE /iceberg/api/v1/{prefix}/namespaces/{namespace}/views/{view} -
Read Audit Log audit:ReadAuditLog arn:lakefs:audit:::log Iceberg catalog read operations targeting the lakefssystem repository -
Write Audit Log audit:WriteAuditLog arn:lakefs:audit:::log Iceberg catalog write operations targeting the lakefssystem repository -
Login as Organization Admin (Cloud only) admin:Login * POST /admin/login (part of lakefs cloud, not lakefs endpoint) -

Some APIs may require more than one action. For instance, to create a repository (POST /repositories), you need permission to fs:CreateRepository for the name of the repository and also fs:AttachStorageNamespace for the storage namespace used.

Per-branch scoping for ListBranches

fs:ListBranches accepts either a repo ARN (arn:lakefs:fs:::repository/{repositoryId}, admits every branch in the repository) or a per-branch ARN (arn:lakefs:fs:::repository/{repositoryId}/branch/{branchId}, admits only matching branches), so policies can scope listings to a subset of branches. Listing first requires authorization to list that repository, then filters the branches you may see: a Deny on the repo ARN (or no Allow scoped to the repository) is an operation-level rejection, while a Deny on a branch ARN only hides the matching branches.

Policy shape Result
Allow on repo ARN every branch admitted
Allow on branch ARN matching X branch X admitted, others hidden
Allow on repo ARN + Deny on branch ARN matching X branch X hidden, the rest admitted
No Allow scoped to this repository (none at all, or only on a different one) request returns 401 (REST) / 403 AccessDenied (S3)

Allows are additive — adding a narrower Allow alongside a broader one does not tighten the result set. To restrict what a user sees, either replace the broad Allow with the narrower one, or keep the broad Allow and add a Deny for the subset to hide.

Confine a user to one team's branches:

{
  "Effect":   "Allow",
  "Action":   ["fs:ListBranches", "fs:ReadBranch"],
  "Resource": "arn:lakefs:fs:::repository/myrepo/branch/team-a-*"
}

Allow every branch except a subset (broad allow on the repo, targeted deny on the pattern to hide):

[
  {
    "Effect":   "Allow",
    "Action":   ["fs:ListBranches"],
    "Resource": "arn:lakefs:fs:::repository/myrepo"
  },
  {
    "Effect":   "Deny",
    "Action":   ["fs:ListBranches"],
    "Resource": "arn:lakefs:fs:::repository/myrepo/branch/secret-*"
  }
]

Notes.

  • A user authorized to list the repository whose filter admits no branch — for example an allow on …/branch/team-z-* with no matching branch — receives 200 OK with an empty list.
  • The 401/403 response is the same whether or not the repository exists, so the listing cannot be used to discover repository names.
  • A user whose only allows are per-branch ARNs that don't match the repo's default branch will not see the default branch in the listing (default_branch on GetRepository still reports its name).
  • The S3 gateway's bucket-root listing (aws s3 ls s3://{repo}/) uses the same evaluation and does not require a separate fs:ListObjects permission for the branch-listing case.

Listing visibility is not access control

Scoping fs:ListBranches controls only which branches appear in listings — it does not restrict reading or writing them. Access is governed independently by the per-branch and per-object actions (fs:ReadBranch, fs:ReadObject, fs:WriteObject, …): a user who cannot list a branch can still read or commit to it if they hold those actions. Use fs:ListBranches for discoverability; to confine access, scope the per-branch actions too.

Preconfigured Policies

The following Policies are created during initial setup:

FSFullAccess

{
  "statement": [
    {
      "action": [
        "fs:*"
      ],
      "effect": "allow",
      "resource": "*"
    }
  ]
}

FSReadAll

{
  "statement": [
    {
      "action": [
        "fs:List*",
        "fs:Read*"
      ],
      "effect": "allow",
      "resource": "*"
    }
  ]
}

FSReadWriteAll

{
    "statement": [
        {
            "action": [
                "fs:Read*",
                "fs:List*",
                "fs:WriteObject",
                "fs:DeleteObject",
                "fs:RevertBranch",
                "fs:CreateBranch",
                "fs:CreateTag",
                "fs:DeleteBranch",
                "fs:DeleteTag",
                "fs:CreateCommit"
            ],
            "effect": "allow",
            "resource": "*"
        }
    ]
}

AuthFullAccess

{
  "statement": [
    {
      "action": [
        "auth:*"
      ],
      "effect": "allow",
      "resource": "*"
    }
  ]
}

AuthManageOwnCredentials

{
  "statement": [
    {
      "action": [
        "auth:CreateCredentials",
        "auth:DeleteCredentials",
        "auth:ListCredentials",
        "auth:ReadCredentials"
      ],
      "effect": "allow",
      "resource": "arn:lakefs:auth:::user/${user}"
    }
  ]
}

RepoManagementFullAccess

{
    "statement": [
        {
            "action": [
                "ci:*"
            ],
            "effect": "allow",
            "resource": "*"
        },
        {
            "action": [
                "retention:*"
            ],
            "effect": "allow",
            "resource": "*"
        }
    ]
}

RepoManagementReadAll

{
    "statement": [
        {
            "action": [
                "ci:Read*"
            ],
            "effect": "allow",
            "resource": "*"
        },
        {
            "action": [
                "retention:Get*"
            ],
            "effect": "allow",
            "resource": "*"
        }
    ]
}

AdminFullAccess (lakeFS Cloud only)

{
  "statement": [
    {
      "action": [
        "admin:*"
      ],
      "effect": "allow",
      "resource": "*"
    }
  ]
}

AuditLogRead

Grants read access to the lakeFS audit log. Attached to the Admins group by default. Attach it to other groups or users to delegate audit-log visibility.

{
    "statement": [
        {
            "action": [
                "audit:ReadAuditLog"
            ],
            "effect": "allow",
            "resource": "arn:lakefs:audit:::log"
        }
    ]
}

Additional Policies

You can create additional policies to further limit user access. Use the web UI or the lakectl auth command to create policies.

Here is an example to define read/write access for a specific repository:

{
    "statement": [
        {
            "action": [
                "fs:ReadRepository",
                "fs:ReadCommit",
                "fs:ListBranches",
                "fs:ListTags",
                "fs:ListObjects"
            ],
            "effect": "allow",
            "resource": "arn:lakefs:fs:::repository/<repository-name>"
        },
        {
            "action": [
                "fs:RevertBranch",
                "fs:ReadBranch",
                "fs:CreateBranch",
                "fs:DeleteBranch",
                "fs:CreateCommit"
            ],
            "effect": "allow",
            "resource": "arn:lakefs:fs:::repository/<repository-name>/branch/*"
        },
                {
            "action": [
                "fs:ListObjects",
                "fs:ReadObject",
                "fs:WriteObject",
                "fs:DeleteObject"
            ],
            "effect": "allow",
            "resource": "arn:lakefs:fs:::repository/<repository-name>/object/*"
        },
                {
            "action": [
                "fs:ReadTag",
                "fs:CreateTag",
                "fs:DeleteTag"
            ],
            "effect": "allow",
            "resource": "arn:lakefs:fs:::repository/<repository-name>/tag/*"
        },
        {
            "action": ["fs:ReadConfig"],
            "effect": "allow",
            "resource": "*"
        }
    ]
}

Multiple Resources Statements

lakeFS supports specifying multiple resources in a single RBAC statement. This is available on lakeFS Cloud, or on lakeFS Enterprise if starting at version lakeFS v1.54.0 and Fluffy v0.12.0 In addition to a single resource. The resource field can contain a string representing a JSON-encoded list of resources.

{
    "statement": [
        {
            "action": [
                "fs:Read*"
            ],
            "effect": "allow",
            "resource": "[\"arn:lakefs:fs:::repository/repo1\",\"arn:lakefs:fs:::repository/repo2\"]"
        }
    ]
}

The list must be properly encoded as a JSON string: quote each resource, and escape those quotes as shown. Otherwise, the policy cannot be parsed.

Multi-Resource Policy Creation Using Python SDK

Here is how you can leverage Python SDK to create a multiple resource policy:

import lakefs_sdk
from lakefs_sdk.client import LakeFSClient
from lakefs_sdk import models

configuration = lakefs_sdk.Configuration(
        host=lakefsEndPoint,
        username=lakefsAccessKey,
        password=lakefsSecretKey,
)
clt = LakeFSClient(configuration)

clt.auth_api.create_policy(
    policy=models.Policy(
        id='FSReadTwoRepos',
        statement=[models.Statement(
            effect="deny",
            resource=json.dumps(["arn:lakefs:fs:::repository/repo1","arn:lakefs:fs:::repository/repo2"]),
            action=["fs:ReadRepository"],
        ),
        ]
    )
)

Preconfigured Groups

lakeFS has four preconfigured groups:

  • Admins
  • SuperUsers
  • Developers
  • Viewers

They have the following policies granted to them:

Policy Admins SuperUsers Developers Viewers
FSFullAccess
AuthFullAccess
RepoManagementFullAccess
AuthManageOwnCredentials
RepoManagementReadAll
FSReadWriteAll
FSReadAll
AuditLogRead
AdminFullAccess (Cloud only)

Pluggable Authentication and Authorization

Authorization and authentication is pluggable in lakeFS.

If lakeFS is attached to a remote authentication server (or you are using lakeFS Cloud) then the role-based access control user interface can be used.

If you are using RBAC with your self-managed lakeFS then the lakeFS configuration element auth.ui_config.rbac should be set to external.

An enterprise (paid) solution of lakeFS should set auth.ui_config.rbac as internal.