diff --git a/.github/workflows/esti.yaml b/.github/workflows/esti.yaml index e5fde002666..d200122f2c4 100644 --- a/.github/workflows/esti.yaml +++ b/.github/workflows/esti.yaml @@ -123,15 +123,6 @@ jobs: cache-to: | type=s3,region=us-east-1,bucket=lakefs-docker-cache,name=lakefs,mode=max - - name: Build and Push ACL server - uses: docker/build-push-action@v5 - with: - push: true - tags: ${{ steps.login-ecr.outputs.registry }}/aclserver:${{ needs.gen-code.outputs.tag }} - build-args: VERSION=${{ needs.gen-code.outputs.tag }} - context: . - file: ./contrib/auth/acl/Dockerfile - login-to-amazon-ecr: runs-on: ubuntu-latest needs: [ check-secrets ] @@ -774,7 +765,7 @@ jobs: id: unique run: echo "value=$RANDOM" >> $GITHUB_OUTPUT - # Required for pulling latest fluffy + # Required for pulling fluffy image - name: Login to DockerHub uses: docker/login-action@v2 with: @@ -835,7 +826,7 @@ jobs: id: unique run: echo "value=$RANDOM" >> $GITHUB_OUTPUT - # Required for pulling latest fluffy + # Required for pulling fluffy image - name: Login to DockerHub uses: docker/login-action@v2 with: @@ -896,7 +887,7 @@ jobs: id: unique run: echo "value=$RANDOM" >> $GITHUB_OUTPUT - # Required for pulling latest fluffy + # Required for pulling fluffy image - name: Login to DockerHub uses: docker/login-action@v2 with: @@ -941,7 +932,7 @@ jobs: id: unique run: echo "value=$RANDOM" >> $GITHUB_OUTPUT - # Required for pulling latest fluffy + # Required for pulling fluffy image - name: Login to DockerHub uses: docker/login-action@v2 with: @@ -993,7 +984,7 @@ jobs: id: unique run: echo "value=$RANDOM" >> $GITHUB_OUTPUT - # Required for pulling latest fluffy + # Required for pulling fluffy image - name: Login to DockerHub uses: docker/login-action@v2 with: @@ -1337,58 +1328,6 @@ jobs: }) } - run-system-aws-s3-acl-server: - name: Run latest lakeFS app on AWS S3 + ACL Server - needs: [ deploy-image, login-to-amazon-ecr ] - runs-on: ubuntu-22.04 - env: - TAG: ${{ needs.deploy-image.outputs.tag }} - REPO: ${{ needs.login-to-amazon-ecr.outputs.registry }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - steps: - - name: Check-out code - uses: actions/checkout@v4 - - - name: Generate uniquifying value - id: unique - run: echo "value=$RANDOM" >> $GITHUB_OUTPUT - - - name: Test lakeFS with S3 tests - uses: ./.github/actions/bootstrap-test-lakefs - with: - compose-file: esti/ops/docker-compose-acl.yaml - compose-flags: "--quiet-pull --exit-code-from=esti" - env: - LAKEFS_BLOCKSTORE_TYPE: s3 - LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_KEY_ID: ${{ secrets.ESTI_AWS_ACCESS_KEY_ID }} - LAKEFS_BLOCKSTORE_S3_CREDENTIALS_SECRET_ACCESS_KEY: ${{ secrets.ESTI_AWS_SECRET_ACCESS_KEY }} - LAKEFS_DATABASE_TYPE: postgres - DOCKER_REG: ${{ needs.login-to-amazon-ecr.outputs.registry }} - ESTI_BLOCKSTORE_TYPE: s3 - ESTI_STORAGE_NAMESPACE: s3://esti-system-testing/${{ github.run_number }}/${{ steps.unique.outputs.value }} - ESTI_AWS_ACCESS_KEY_ID: ${{ secrets.ESTI_AWS_ACCESS_KEY_ID }} - ESTI_AWS_SECRET_ACCESS_KEY: ${{ secrets.ESTI_AWS_SECRET_ACCESS_KEY }} - ESTI_VERSION: ${{ needs.deploy-image.outputs.tag }} - - - name: Check files in S3 bucket - run: | - FILES_COUNT=`aws s3 ls s3://esti-system-testing/${{ github.run_number }}/${{ steps.unique.outputs.value }} --recursive | wc -l` - [ $FILES_COUNT -gt 5 ] - - - name: lakeFS Logs on s3 failure - if: ${{ failure() }} - continue-on-error: true - run: docker compose -f esti/ops/docker-compose-acl.yaml logs --tail=1000 lakefs - - - name: Export DB - if: ${{ always() }} - working-directory: esti/ops - run: | - if docker compose ps -q postgres; then - docker compose exec -T postgres pg_dumpall --username=lakefs | gzip | aws s3 cp - s3://esti-system-testing/${{ github.run_number }}/${{ steps.unique.outputs.value }}/dump.gz - fi - run-system-aws-s3-basic-auth: name: Run latest lakeFS app on AWS S3 + Basic Auth needs: [deploy-image, login-to-amazon-ecr] @@ -1416,7 +1355,6 @@ jobs: LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_KEY_ID: ${{ secrets.ESTI_AWS_ACCESS_KEY_ID }} LAKEFS_BLOCKSTORE_S3_CREDENTIALS_SECRET_ACCESS_KEY: ${{ secrets.ESTI_AWS_SECRET_ACCESS_KEY }} LAKEFS_DATABASE_TYPE: postgres - LAKEFS_AUTH_INTERNAL_BASIC: true DOCKER_REG: ${{ needs.login-to-amazon-ecr.outputs.registry }} ESTI_BLOCKSTORE_TYPE: s3 ESTI_STORAGE_NAMESPACE: s3://esti-system-testing/${{ github.run_number }}/${{ steps.unique.outputs.value }} diff --git a/api/swagger.yml b/api/swagger.yml index 076005f3693..c01acb17ee2 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -888,7 +888,7 @@ components: RBAC will remain enabled on GUI if "external". That only works with an external auth service. type: string - enum: [simplified, external] + enum: [none, simplified, external] login_url: description: primary URL to use for login. type: string diff --git a/clients/java-legacy/api/openapi.yaml b/clients/java-legacy/api/openapi.yaml index a6ac7e8b841..d73bd1e6465 100644 --- a/clients/java-legacy/api/openapi.yaml +++ b/clients/java-legacy/api/openapi.yaml @@ -8080,7 +8080,7 @@ components: login_failed_message: login_failed_message logout_url: logout_url login_url: login_url - RBAC: simplified + RBAC: none fallback_login_url: fallback_login_url login_cookie_names: - login_cookie_names @@ -8092,6 +8092,7 @@ components: RBAC will remain enabled on GUI if "external". That only works with an external auth service. enum: + - none - simplified - external type: string @@ -8128,7 +8129,7 @@ components: login_failed_message: login_failed_message logout_url: logout_url login_url: login_url - RBAC: simplified + RBAC: none fallback_login_url: fallback_login_url login_cookie_names: - login_cookie_names diff --git a/clients/java-legacy/docs/LoginConfig.md b/clients/java-legacy/docs/LoginConfig.md index ee91a722819..5431bb7de14 100644 --- a/clients/java-legacy/docs/LoginConfig.md +++ b/clients/java-legacy/docs/LoginConfig.md @@ -21,6 +21,7 @@ Name | Type | Description | Notes Name | Value ---- | ----- +NONE | "none" SIMPLIFIED | "simplified" EXTERNAL | "external" diff --git a/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/LoginConfig.java b/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/LoginConfig.java index 457e1be7920..eeb53768063 100644 --- a/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/LoginConfig.java +++ b/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/LoginConfig.java @@ -36,6 +36,8 @@ public class LoginConfig { */ @JsonAdapter(RBACEnum.Adapter.class) public enum RBACEnum { + NONE("none"), + SIMPLIFIED("simplified"), EXTERNAL("external"); diff --git a/clients/java/api/openapi.yaml b/clients/java/api/openapi.yaml index f991b4f0e81..a58b3ef5514 100644 --- a/clients/java/api/openapi.yaml +++ b/clients/java/api/openapi.yaml @@ -8054,7 +8054,7 @@ components: login_failed_message: login_failed_message logout_url: logout_url login_url: login_url - RBAC: simplified + RBAC: none fallback_login_url: fallback_login_url login_cookie_names: - login_cookie_names @@ -8066,6 +8066,7 @@ components: RBAC will remain enabled on GUI if "external". That only works with an external auth service. enum: + - none - simplified - external type: string @@ -8102,7 +8103,7 @@ components: login_failed_message: login_failed_message logout_url: logout_url login_url: login_url - RBAC: simplified + RBAC: none fallback_login_url: fallback_login_url login_cookie_names: - login_cookie_names diff --git a/clients/java/docs/LoginConfig.md b/clients/java/docs/LoginConfig.md index 6a9da45cdad..0cadc12b5d2 100644 --- a/clients/java/docs/LoginConfig.md +++ b/clients/java/docs/LoginConfig.md @@ -21,6 +21,7 @@ | Name | Value | |---- | -----| +| NONE | "none" | | SIMPLIFIED | "simplified" | | EXTERNAL | "external" | diff --git a/clients/java/src/main/java/io/lakefs/clients/sdk/model/LoginConfig.java b/clients/java/src/main/java/io/lakefs/clients/sdk/model/LoginConfig.java index 961fae7dbb9..e6860d0e294 100644 --- a/clients/java/src/main/java/io/lakefs/clients/sdk/model/LoginConfig.java +++ b/clients/java/src/main/java/io/lakefs/clients/sdk/model/LoginConfig.java @@ -59,6 +59,8 @@ public class LoginConfig { */ @JsonAdapter(RBACEnum.Adapter.class) public enum RBACEnum { + NONE("none"), + SIMPLIFIED("simplified"), EXTERNAL("external"); diff --git a/clients/python-legacy/lakefs_client/model/login_config.py b/clients/python-legacy/lakefs_client/model/login_config.py index ea0188f7d74..766364a6064 100644 --- a/clients/python-legacy/lakefs_client/model/login_config.py +++ b/clients/python-legacy/lakefs_client/model/login_config.py @@ -57,6 +57,7 @@ class LoginConfig(ModelNormal): allowed_values = { ('rbac',): { + 'NONE': "none", 'SIMPLIFIED': "simplified", 'EXTERNAL': "external", }, diff --git a/clients/python/lakefs_sdk/models/login_config.py b/clients/python/lakefs_sdk/models/login_config.py index 3509420a6ce..0e952baf33e 100644 --- a/clients/python/lakefs_sdk/models/login_config.py +++ b/clients/python/lakefs_sdk/models/login_config.py @@ -44,8 +44,8 @@ def rbac_validate_enum(cls, value): if value is None: return value - if value not in ('simplified', 'external'): - raise ValueError("must be one of enum values ('simplified', 'external')") + if value not in ('none', 'simplified', 'external'): + raise ValueError("must be one of enum values ('none', 'simplified', 'external')") return value class Config: diff --git a/clients/python/test/test_login_config.py b/clients/python/test/test_login_config.py index 60fc492974d..b5ed5003400 100644 --- a/clients/python/test/test_login_config.py +++ b/clients/python/test/test_login_config.py @@ -39,7 +39,7 @@ def make_instance(self, include_optional): model = lakefs_sdk.models.login_config.LoginConfig() # noqa: E501 if include_optional : return LoginConfig( - rbac = 'simplified', + rbac = 'none', login_url = '', login_failed_message = '', fallback_login_url = '', diff --git a/clients/python/test/test_setup_state.py b/clients/python/test/test_setup_state.py index 1b981b93515..a7a89d41af5 100644 --- a/clients/python/test/test_setup_state.py +++ b/clients/python/test/test_setup_state.py @@ -42,7 +42,7 @@ def make_instance(self, include_optional): state = 'initialized', comm_prefs_missing = True, login_config = lakefs_sdk.models.login_config.LoginConfig( - rbac = 'simplified', + rbac = 'none', login_url = '', login_failed_message = '', fallback_login_url = '', diff --git a/clients/rust/src/models/login_config.rs b/clients/rust/src/models/login_config.rs index 7f052d5cf82..75e0716ff53 100644 --- a/clients/rust/src/models/login_config.rs +++ b/clients/rust/src/models/login_config.rs @@ -51,6 +51,8 @@ impl LoginConfig { /// RBAC will remain enabled on GUI if \"external\". That only works with an external auth service. #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Rbac { + #[serde(rename = "none")] + None, #[serde(rename = "simplified")] Simplified, #[serde(rename = "external")] @@ -59,7 +61,7 @@ pub enum Rbac { impl Default for Rbac { fn default() -> Rbac { - Self::Simplified + Self::None } } diff --git a/cmd/lakectl/cmd/auth.go b/cmd/lakectl/cmd/auth.go index 6556e82a166..4222a1a93e9 100644 --- a/cmd/lakectl/cmd/auth.go +++ b/cmd/lakectl/cmd/auth.go @@ -7,7 +7,8 @@ import ( var authCmd = &cobra.Command{ Use: "auth [sub-command]", Short: "Manage authentication and authorization", - Long: "manage authentication and authorization including users, groups and ACLs", + Long: `Manage authentication and authorization including users, groups and ACLs +This functionality is supported with an external auth service only.`, } func addPaginationFlags(cmd *cobra.Command) { diff --git a/cmd/lakefs/cmd/run.go b/cmd/lakefs/cmd/run.go index 92202c6864e..abf1e91bfde 100644 --- a/cmd/lakefs/cmd/run.go +++ b/cmd/lakefs/cmd/run.go @@ -18,7 +18,6 @@ import ( "github.com/go-co-op/gocron" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/treeverse/lakefs/contrib/auth/acl" "github.com/treeverse/lakefs/pkg/actions" "github.com/treeverse/lakefs/pkg/api" "github.com/treeverse/lakefs/pkg/auth" @@ -104,34 +103,27 @@ Please run "lakefs superuser -h" and follow the instructions on how to migrate a logger.WithError(err).Fatal("basic auth migration failed") } } - - return auth.NewMonitoredAuthServiceAndInviter(apiService) - } - if cfg.IsAuthTypeAPI() { - apiService, err := auth.NewAPIAuthService( - cfg.Auth.API.Endpoint, - cfg.Auth.API.Token.SecureValue(), - cfg.Auth.AuthenticationAPI.ExternalPrincipalsEnabled, - secretStore, - authparams.ServiceCache(cfg.Auth.Cache), - logger.WithField("service", "auth_api"), - ) - if err != nil { - logger.WithError(err).Fatal("failed to create authentication service") - } - if !cfg.Auth.API.SkipHealthCheck { - if err := apiService.CheckHealth(ctx, logger, cfg.Auth.API.HealthCheckTimeout); err != nil { - logger.WithError(err).Fatal("Auth API health check failed") - } - } - return auth.NewMonitoredAuthServiceAndInviter(apiService) + return auth.NewMonitoredAuthService(apiService) } - authService := acl.NewAuthService( - kvStore, + + // Not Basic - using auth server + apiService, err := auth.NewAPIAuthService( + cfg.Auth.API.Endpoint, + cfg.Auth.API.Token.SecureValue(), + cfg.Auth.AuthenticationAPI.ExternalPrincipalsEnabled, secretStore, authparams.ServiceCache(cfg.Auth.Cache), + logger.WithField("service", "auth_api"), ) - return auth.NewMonitoredAuthService(authService) + if err != nil { + logger.WithError(err).Fatal("failed to create authentication service") + } + if !cfg.Auth.API.SkipHealthCheck { + if err := apiService.CheckHealth(ctx, logger, cfg.Auth.API.HealthCheckTimeout); err != nil { + logger.WithError(err).Fatal("Auth API health check failed") + } + } + return auth.NewMonitoredAuthServiceAndInviter(apiService) } var runCmd = &cobra.Command{ diff --git a/cmd/lakefs/cmd/run_test.go b/cmd/lakefs/cmd/run_test.go index f40dfe01c6f..a5fb3444946 100644 --- a/cmd/lakefs/cmd/run_test.go +++ b/cmd/lakefs/cmd/run_test.go @@ -7,6 +7,7 @@ import ( "github.com/treeverse/lakefs/cmd/lakefs/cmd" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/config" + "github.com/treeverse/lakefs/pkg/kv/kvtest" "github.com/treeverse/lakefs/pkg/logging" ) @@ -23,8 +24,10 @@ func TestGetAuthService(t *testing.T) { }) t.Run("maintain_service", func(t *testing.T) { cfg := &config.Config{} - cfg.Auth.UIConfig.RBAC = config.AuthRBACSimplified - service := cmd.NewAuthService(context.Background(), cfg, logging.ContextUnavailable(), nil, nil) + kvStore := kvtest.GetStore(context.Background(), t) + meta := auth.NewKVMetadataManager("serve_test", cfg.Installation.FixedID, cfg.Database.Type, kvStore) + cfg.Auth.UIConfig.RBAC = config.AuthRBACNone + service := cmd.NewAuthService(context.Background(), cfg, logging.ContextUnavailable(), kvStore, meta) _, ok := service.(auth.EmailInviter) if ok { t.Fatalf("expected Service to not be of type EmailInviter") diff --git a/cmd/lakefs/cmd/setup.go b/cmd/lakefs/cmd/setup.go index 01d63d4147a..46633557484 100644 --- a/cmd/lakefs/cmd/setup.go +++ b/cmd/lakefs/cmd/setup.go @@ -6,11 +6,8 @@ import ( "os" "github.com/spf13/cobra" - "github.com/treeverse/lakefs/contrib/auth/acl" "github.com/treeverse/lakefs/pkg/auth" - "github.com/treeverse/lakefs/pkg/auth/crypt" "github.com/treeverse/lakefs/pkg/auth/model" - authparams "github.com/treeverse/lakefs/pkg/auth/params" "github.com/treeverse/lakefs/pkg/auth/setup" "github.com/treeverse/lakefs/pkg/config" "github.com/treeverse/lakefs/pkg/kv" @@ -63,24 +60,21 @@ var setupCmd = &cobra.Command{ os.Exit(1) } - var ( - authService auth.Service - metadataManager auth.MetadataManager - ) + var authService auth.Service kvStore, err := kv.Open(ctx, kvParams) if err != nil { fmt.Printf("Failed to connect to DB: %s", err) os.Exit(1) } defer kvStore.Close() - logger := logging.ContextUnavailable() - authService = acl.NewAuthService(kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), authparams.ServiceCache(cfg.Auth.Cache)) - metadataManager = auth.NewKVMetadataManager(version.Version, cfg.Installation.FixedID, cfg.Database.Type, kvStore) + logger := logging.FromContext(ctx) + authMetadataManage := auth.NewKVMetadataManager(version.Version, cfg.Installation.FixedID, cfg.Database.Type, kvStore) + authService = NewAuthService(ctx, cfg, logger, kvStore, authMetadataManage) cloudMetadataProvider := stats.BuildMetadataProvider(logger, cfg) - metadata := stats.NewMetadata(ctx, logger, cfg.Blockstore.Type, metadataManager, cloudMetadataProvider) + metadata := stats.NewMetadata(ctx, logger, cfg.Blockstore.Type, authMetadataManage, cloudMetadataProvider) - credentials, err := setupLakeFS(ctx, cfg, metadataManager, authService, userName, accessKeyID, secretAccessKey) + credentials, err := setupLakeFS(ctx, cfg, authMetadataManage, authService, userName, accessKeyID, secretAccessKey) if err != nil { fmt.Printf("Setup failed: %s\n", err) os.Exit(1) diff --git a/cmd/lakefs/cmd/superuser.go b/cmd/lakefs/cmd/superuser.go index a3fdb0539e9..fbc039911b8 100644 --- a/cmd/lakefs/cmd/superuser.go +++ b/cmd/lakefs/cmd/superuser.go @@ -7,7 +7,6 @@ import ( "time" "github.com/spf13/cobra" - "github.com/treeverse/lakefs/contrib/auth/acl" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/auth/crypt" "github.com/treeverse/lakefs/pkg/auth/model" @@ -87,9 +86,8 @@ If the wrong user or credentials were chosen it is possible to delete the user a fmt.Printf("Failed to initialize auth service: %s\n", err) os.Exit(1) } - // TODO (niro): This needs to be removed default: - authService = acl.NewAuthService(kvStore, secretStore, authparams.ServiceCache(cfg.Auth.Cache)) + logger.Fatal("invalid auth mode for superuser command") } authMetadataManager := auth.NewKVMetadataManager(version.Version, cfg.Installation.FixedID, cfg.Database.Type, kvStore) diff --git a/contrib/auth/acl/Dockerfile b/contrib/auth/acl/Dockerfile deleted file mode 100644 index c877c5ed56b..00000000000 --- a/contrib/auth/acl/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# syntax=docker/dockerfile:1 -ARG VERSION=dev - -FROM --platform=$BUILDPLATFORM golang:1.22.6-alpine3.20 AS build -WORKDIR /build -RUN apk add --no-cache build-base ca-certificates -COPY go.mod go.sum ./ -RUN --mount=type=cache,target=/go/pkg go mod download -COPY . ./ - -FROM build as build-aclserver -ARG VERSION TARGETOS TARGETARCH -RUN --mount=type=cache,target=/root/.cache/go-build \ - --mount=type=cache,target=/go/pkg \ - GOOS=$TARGETOS GOARCH=$TARGETARCH \ - go build -ldflags "-X github.com/treeverse/lakefs/pkg/version.Version=${VERSION}" -o acl ./contrib/auth/acl/cmd/acl - -FROM alpine:3.18 AS aclserver -ENV PATH /app:$PATH -COPY ./scripts/wait-for /app/ -COPY --from=build-aclserver /build/acl /app/ -RUN apk add -U --no-cache ca-certificates -RUN addgroup -S lakefs && adduser -S lakefs -G lakefs -USER lakefs -EXPOSE 8001/tcp -ENTRYPOINT ["/app/acl"] -CMD ["run"] - diff --git a/contrib/auth/acl/controller.go b/contrib/auth/acl/controller.go index 84fffac9deb..2917f5b1a8b 100644 --- a/contrib/auth/acl/controller.go +++ b/contrib/auth/acl/controller.go @@ -293,7 +293,6 @@ func (c *Controller) UpdatePolicy(w http.ResponseWriter, r *http.Request, body a writeResponse(w, http.StatusOK, response) } -// ClaimTokenId - TODO (niro): Should be implemented? func (c *Controller) ClaimTokenId(w http.ResponseWriter, _ *http.Request, _ apigen.ClaimTokenIdJSONRequestBody) { writeError(w, http.StatusNotImplemented, "Not implemented") } diff --git a/docs/assets/js/swagger.yml b/docs/assets/js/swagger.yml index 076005f3693..c01acb17ee2 100644 --- a/docs/assets/js/swagger.yml +++ b/docs/assets/js/swagger.yml @@ -888,7 +888,7 @@ components: RBAC will remain enabled on GUI if "external". That only works with an external auth service. type: string - enum: [simplified, external] + enum: [none, simplified, external] login_url: description: primary URL to use for login. type: string diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 87020e2895c..fd31e6b916b 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -480,7 +480,8 @@ Manage authentication and authorization #### Synopsis {:.no_toc} -manage authentication and authorization including users, groups and ACLs +Manage authentication and authorization including users, groups and ACLs +This functionality is supported with an external auth service only. #### Options {:.no_toc} diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index f6f26a7ceb5..0c6b907f68f 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -100,7 +100,7 @@ Configuration section when using `database.type="local"` * `auth.login_duration` `(time duration : "168h")` - The duration the login token is valid for * `auth.login_max_duration` `(time duration : "168h")` - The maximum duration user can ask for a login token * `auth.cookie_domain` `(string : "")` - [Domain attribute](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent) to set the access_token cookie on (the default is an empty string which defaults to the same host that sets the cookie) -* `auth.ui_config.rbac` `(string: "simplified")` - "simplified", "external" or "internal" (enterprise feature). In simplified mode, do not display policy in GUI. +* `auth.ui_config.rbac` `(string: "none")` - "none", "simplified", "external" or "internal" (enterprise feature). If you have configured an external auth server you can set this to "external" to support the policy editor. If you are using the enteprrise version of lakeFS, you can set this to "internal" to use the built-in policy editor. diff --git a/docs/security/access-control-lists.md b/docs/security/access-control-lists.md index a7f161f9f14..71156726ee2 100644 --- a/docs/security/access-control-lists.md +++ b/docs/security/access-control-lists.md @@ -10,67 +10,68 @@ redirect_from: # Access Control Lists (ACLs) {: .note .warning} -> ACLS are [moving out of core lakeFS](https://lakefs.io/blog/why-moving-acls-out-of-core-lakefs/). +> ACLs were [removed from core lakeFS](https://lakefs.io/blog/why-moving-acls-out-of-core-lakefs/). > -> For a more robust authorization solution, please see [Role-Based Access Control](./rbac.html), available in [lakeFS Cloud]({% link cloud/index.md %}) and [lakeFS Enterprise]({% link enterprise/index.md %}). +> For a more robust authorization solution, please see [Role-Based Access Control](./rbac.html), available in [lakeFS Cloud]({% link cloud/index.md %}) and [lakeFS Enterprise]({% link enterprise/index.md %}). +> The following documentation is aimed for users with existing installations who wish to continue working with ACLs. {% include toc.html %} -## ACLs - -You can attach Permissions and scope them to groups in the Groups page. -There are 4 default groups, named after the 4 permissions. Each group is global (applies for all repositories). - -| Group ID | Allows | -|-----------|--------------------------------------------| -| **Read** | Read operations, creating access keys | -| **Write** | Allows all data read and write operations. | -| **Super** | Allows all operations except auth. | -| **Admin** | Allows all operations. | +## Basic Auth Functionality -## Pluggable Authentication and Authorization +New lakeFS versions will provide basic auth functionality featuring a single Admin user with a single set of credentials. +Existing lakeFS installations that have a single user and a single set of credentials will migrate seamlessly to the new version. +Installations that have more than one user / credentials will require to run a command and choose which set of user + credentials to migrate +(more details [here](#migration-of-existing-user)) -Authorization and authentication is pluggable in lakeFS. If lakeFS is attached to a [remote authentication server](remote-authenticator.html) (or you are using lakeFS Cloud) then the [role-based access control](rbac.html) user interface can be used. - -If you are using ACL then the lakeFS configuration element `auth.ui_config.RBAC` should be set to `simplified`. +## ACLs -## Previous versions of ACL in lakeFS +ACL server was moved out of core lakeFS and into a new package under `contrib/auth/acl`. +Though we [decided](https://lakefs.io/blog/why-moving-acls-out-of-core-lakefs/) to move ACLs out, we are committed to making sure existing users who still need the use of ACLs can continue using +this feature. +In order to do that, users will need to run the separate ACL server as part of their lakeFS deployment environment and configure lakeFS to work with it. -Here's a comparison of the current ACL model against the behavior prior to [the changes introduced][security-changes] in v0.98. +### ACL server Configuration -| Permission | Allows | Previous Group Name | Previous Policy Names and Actions | -|------------|--------------------------------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Read** | Read operations, creating access keys. | Viewers | FSReadAll \[fs:List*, fs:Read*] | -| **Write** | Allows all data read and write operations. | Developers | FSReadWriteAll \[fs:ListRepositories, fs:ReadRepository, fs:ReadCommit, fs:ListBranches, fs:ListTags, fs:ListObjects, fs:ReadObject, fs:WriteObject, fs:DeleteObject, fs:RevertBranch, fs:ReadBranch, fs:ReadTag, fs:CreateBranch, fs:CreateTag, fs:DeleteBranch, fs:DeleteTag, fs:CreateCommit] RepoManagementReadAll \[ci:Read*, retention:Get*, branches:Get*, fs:ReadConfig] | -| **Super** | Allows all operations except auth. | SuperUsers (with changes) | FSFullAccess \[fs:*] RepoManagementReadAll \[ci:Read*, retention:Get*, branches:Get*, fs:ReadConfig] | -| **Admin** | Allows all operations. | Admins | AuthFullAccess \[auth:*] FSFullAccess \[fs:*] RepoManagementFullAccess \[ci:*, retention:*, branches:*, fs:ReadConfig] | +Under the `contrib/auth/acl` you will be able to find an ACL server reference. -### Migrating from the previous version of ACLs +{: .note .warning} +> This implementation is a reference and is not fit for production use. +> +> For a more robust authorization solution, please see [Role-Based Access Control](./rbac.html), available in [lakeFS Cloud]({% link cloud/index.md %}) and [lakeFS Enterprise]({% link enterprise/index.md %}). -Upgrading the lakeFS version will require migrating to the new ACL authorization model. -In order to run the migration run: -``` -lakefs migrate up +The configuration of the ACL server is similar to lakeFS configuration, here's an example of an `.aclserver.yaml` config file: + ```yaml + --- + listen_address: "[ACL_SERVER_LISTEN_ADDRESS]" + database: + type: "postgres" + postgres: + connection_string: "[DATABASE_CONNECTION_STRING]" + + encrypt: + # This should be the same encryption key as in lakeFS + secret_key: "[ENCRYPTION_SECRET_KEY]" + ``` +It is possible to use environment variables to configure the server as in lakeFS. Use the `ACLSERVER_` prefix to do so. +For full configuration reference see: [this](https://github.com/treeverse/lakeFS/blob/7b2a0ac2f1afedd2059284c32e7dacb945b2ae90/contrib/auth/acl/config.go#L26) + + +### lakeFS Configuration + +For the ACL server to work, configure the following values in lakeFS: +`auth.ui_config.rbac`: `simplified` +`auth.api.endpoint`: `[ACL_SERVER_LISTEN_ADDRESS]` + +### Migration of existing user + +For installation with multiple users / credentials, upgrading to the new lakeFS version requires choosing which user + credentials will be used for the single user mode. +This is done via the `lakefs superuser` command. +For example, if you have a user with username `` and credential key `` use the following command to migrate that user: +```bash +lakefs superuser --user-name --access-key-id ``` - -The command will run the migration to ACL. The migration process might adjust the current authorization policies to fit ACL, in that case the command will not make any changes, only print warnings. -In case of warnings to apply the migration, re-run with the `--force` flag - -The upgrade will ensure that the 4 default groups exist, and modify existing groups to fit into the new ACLs model: -- When creating the 4 default global groups: if another group exists and has the desired name, upgrading will rename it by appending ".orig". So after upgrading the 4 default global groups exist, with these known names. -- For any group, upgrading configured policies follows these rules, possibly increasing access: - 1. Any "Deny" rules are stripped, and a warning printed. - 2. "Manage own credentials" is added. - 3. If any actions outside of "fs:" and manage own credentials are allowed, the group becomes an Admin group, a warning is printed, and no further changes apply. - 4. The upgrade script unifies repositories: If a resource applies to a set of repositories, permissions are unified to all repositories. - 5. The upgrade script unifies actions: it selects the least permission of Read, Write, Super that contains all of the allowed actions. - -The upgrade will detach every directly attached policy from users - -Note that moving to ACL from RBAC may only be performed once and **will** lose some configuration. The upgrade script will detail the changes made by the transition. - -For any question or concern during the upgrade, don't hesitate to get in touch with us through [Slack](https://lakefs.io/slack) or [email](mailto:support@treeverse.io). - -[security-changes]: {% link posts/security_update.md %}#whats-changing + +After running the command you will be able to access the installation using the user's access key id and its respective secret access key. \ No newline at end of file diff --git a/docs/security/rbac.md b/docs/security/rbac.md index 46ea645e07b..8b9de8acb9d 100644 --- a/docs/security/rbac.md +++ b/docs/security/rbac.md @@ -19,8 +19,6 @@ lakeFS Enterprise {: .note} > RBAC is available on [lakeFS Cloud]({% link cloud/index.md %}) and [lakeFS Enterprise]({% link enterprise/index.md %}). -> -> If you're using the open source version of lakeFS then the [ACL-based authorization mechanism](access-control-lists.html) is an alternative to RBAC. {% include toc.html %} diff --git a/esti/lakefs_util.go b/esti/lakefs_util.go index f19d2058914..3be1c17838f 100644 --- a/esti/lakefs_util.go +++ b/esti/lakefs_util.go @@ -1,7 +1,6 @@ package esti import ( - "strconv" "testing" "github.com/spf13/viper" @@ -14,9 +13,11 @@ func LakefsWithParams(connectionString string) string { func LakefsWithParamsWithBasicAuth(connectionString string, basicAuth bool) string { lakefsCmdline := "LAKEFS_DATABASE_TYPE=postgres" + " LAKEFS_DATABASE_POSTGRES_CONNECTION_STRING=" + connectionString + - " LAKEFS_AUTH_INTERNAL_BASIC=" + strconv.FormatBool(basicAuth) + " LAKEFS_BLOCKSTORE_TYPE=" + viper.GetString("blockstore_type") + " LAKEFS_AUTH_ENCRYPT_SECRET_KEY='some random secret string' " + lakefsLocation() + if basicAuth { + lakefsCmdline = "LAKEFS_AUTH_UI_CONFIG_RBAC=none " + lakefsCmdline + } return lakefsCmdline } diff --git a/esti/ops/docker-compose-acl.yaml b/esti/ops/docker-compose-acl.yaml deleted file mode 100644 index f4ca572090c..00000000000 --- a/esti/ops/docker-compose-acl.yaml +++ /dev/null @@ -1,97 +0,0 @@ -version: "3" -services: - lakefs: - image: "${REPO:-treeverse}/lakefs:${TAG:-dev}" - command: "${COMMAND:-run}" - ports: - - "8000:8000" - depends_on: - - "acl-server" - volumes: - - lakefs-app:/app:ro - environment: - - LAKEFS_AUTH_API_ENDPOINT=http://acl-server:8001/api/v1 - - LAKEFS_AUTH_ENCRYPT_SECRET_KEY=some random secret string - - LAKEFS_DATABASE_TYPE=${LAKEFS_DATABASE_TYPE:-postgres} - - LAKEFS_DATABASE_POSTGRES_CONNECTION_STRING=postgres://lakefs:lakefs@postgres/postgres?sslmode=disable - - LAKEFS_BLOCKSTORE_TYPE=${LAKEFS_BLOCKSTORE_TYPE:-local} - - LAKEFS_BLOCKSTORE_LOCAL_PATH=/home/lakefs - - LAKEFS_BLOCKSTORE_LOCAL_IMPORT_ENABLED=true - - LAKEFS_BLOCKSTORE_LOCAL_ALLOWED_EXTERNAL_PREFIXES=/tmp - - LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - - LAKEFS_BLOCKSTORE_S3_CREDENTIALS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - - LAKEFS_LOGGING_LEVEL=DEBUG - - LAKEFS_BLOCKSTORE_GS_CREDENTIALS_JSON - - LAKEFS_STATS_ENABLED - - AZURE_CLIENT_ID - - AZURE_CLIENT_SECRET - - AZURE_TENANT_ID - - LAKEFSACTION_VAR=this_is_actions_var - entrypoint: ["/app/wait-for", "acl-server:8001", "--", "/app/lakefs", "run"] - - acl-server: - image: "${REPO:-treeverse}/aclserver:${TAG:-dev}" - command: "${COMMAND:-run}" - ports: - - "8001:8001" - depends_on: - - "postgres" - environment: - - ACLSERVER_ENCRYPT_SECRET_KEY=some random secret string - - ACLSERVER_DATABASE_TYPE=${LAKEFS_DATABASE_TYPE:-postgres} - - ACLSERVER_DATABASE_POSTGRES_CONNECTION_STRING=postgres://lakefs:lakefs@postgres/postgres?sslmode=disable - entrypoint: ["/app/wait-for", "postgres:5432", "--", "/app/acl"] - - postgres: - image: "postgres:11" - ports: - - "5433:5432" - environment: - POSTGRES_USER: lakefs - POSTGRES_PASSWORD: lakefs - esti: - image: "golang:1.22.6-alpine3.20" - links: - - lakefs:s3.local.lakefs.io - - lakefs:testmultipartupload.s3.local.lakefs.io - - lakefs:testmultipartuploadabort.s3.local.lakefs.io - - lakefs:testdeleteobjects.s3.local.lakefs.io - - lakefs:testmigrate-testpremigratemultipart.s3.local.lakefs.io - - lakefs:migrate.s3.local.lakefs.io - environment: - - CGO_ENABLED=0 - - AWS_ACCESS_KEY_ID - - AWS_SECRET_ACCESS_KEY - - AWS_REGION=us-east-1 - - ESTI_STORAGE_NAMESPACE - - ESTI_BLOCKSTORE_TYPE - - ESTI_AWS_ACCESS_KEY_ID - - ESTI_SETUP_LAKEFS - - ESTI_AWS_SECRET_ACCESS_KEY - - ESTI_ENDPOINT_URL=http://lakefs:8000 - - ESTI_BINARIES_DIR=/app - - ESTI_DATABASE_CONNECTION_STRING=postgres://lakefs:lakefs@postgres/postgres?sslmode=disable - - ESTI_GOTEST_FLAGS - - ESTI_FLAGS - - ESTI_FORCE_PATH_STYLE - - ESTI_AZURE_STORAGE_ACCOUNT - - ESTI_AZURE_STORAGE_ACCESS_KEY - working_dir: /lakefs - command: - - /bin/sh - - -c - - | - apk add --no-cache util-linux - go test -v $ESTI_GOTEST_FLAGS ./esti --system-tests $ESTI_FLAGS --skip=".*GC" - volumes: - - lakefs-code:/lakefs - - lakefs-app:/app:ro - -volumes: - lakefs-code: - driver: local - driver_opts: - o: bind - type: none - device: ${LAKEFS_ROOT:-.} - lakefs-app: diff --git a/esti/ops/docker-compose.yaml b/esti/ops/docker-compose.yaml index f1a8db63c6c..5e45533b205 100644 --- a/esti/ops/docker-compose.yaml +++ b/esti/ops/docker-compose.yaml @@ -26,7 +26,6 @@ services: - AZURE_CLIENT_SECRET - AZURE_TENANT_ID - LAKEFSACTION_VAR=this_is_actions_var - - LAKEFS_AUTH_INTERNAL_BASIC entrypoint: ["/app/wait-for", "postgres:5432", "--", "/app/lakefs", "run"] postgres: image: "postgres:11" diff --git a/pkg/api/serve_test.go b/pkg/api/serve_test.go index 9b0e39f426a..3a6cf44a88d 100644 --- a/pkg/api/serve_test.go +++ b/pkg/api/serve_test.go @@ -108,8 +108,6 @@ func setupHandler(t testing.TB) (http.Handler, *dependencies) { viper.Set(config.BlockstoreTypeKey, block.BlockstoreTypeMem) } viper.Set("database.type", mem.DriverName) - // Use basic mode - viper.Set("auth.internal_basic", true) // Add endpoint so that 'IsAdvancedAuth' will be in effect viper.Set("auth.api.endpoint", config.DefaultListenAddress) diff --git a/pkg/auth/basic_service.go b/pkg/auth/basic_service.go index a2cc4d75de4..fc8694c64b9 100644 --- a/pkg/auth/basic_service.go +++ b/pkg/auth/basic_service.go @@ -472,7 +472,3 @@ func (s *BasicAuthService) ListGroupPolicies(context.Context, string, *model.Pag func (s *BasicAuthService) ClaimTokenIDOnce(_ context.Context, _ string, _ int64) error { return ErrNotImplemented } - -func (s *BasicAuthService) InviteUser(context.Context, string) error { - return ErrNotImplemented -} diff --git a/pkg/auth/setup/setup.go b/pkg/auth/setup/setup.go index e2605a11e2a..a73736e811b 100644 --- a/pkg/auth/setup/setup.go +++ b/pkg/auth/setup/setup.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - authacl "github.com/treeverse/lakefs/contrib/auth/acl" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/auth/model" "github.com/treeverse/lakefs/pkg/config" @@ -236,10 +235,6 @@ func CreateInitialAdminUserWithKeys(ctx context.Context, authService auth.Servic } func CreateBaseGroups(ctx context.Context, authService auth.Service, cfg *config.Config, ts time.Time) error { - // TODO (niro): need to remove this when transitioning to external auth ACLs server - if cfg.IsAuthUISimplified() && !cfg.IsAuthBasic() && cfg.Auth.API.Endpoint == "" { - return authacl.CreateACLBaseGroups(ctx, authService, ts) - } if !cfg.IsAdvancedAuth() { return nil } diff --git a/pkg/config/config.go b/pkg/config/config.go index 124a3a4d254..1cced8d1e94 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -177,8 +177,6 @@ type Config struct { } Database Database Auth struct { - // TODO (niro): To be removed once we finish the transition - Basic bool `mapstructure:"internal_basic"` Cache struct { Enabled bool `mapstructure:"enabled"` Size int `mapstructure:"size"` @@ -564,15 +562,14 @@ func (c *Config) BlockstoreAzureParams() (blockparams.Azure, error) { } const ( + AuthRBACNone = "none" AuthRBACSimplified = "simplified" AuthRBACExternal = "external" AuthRBACInternal = "internal" ) func (c *Config) IsAuthBasic() bool { - // TODO (niro): Replace once transition is complete - // return c.Auth.UIConfig.RBAC == AuthRBACSimplified && c.Auth.API.Endpoint == "" - return c.Auth.Basic + return c.Auth.UIConfig.RBAC == AuthRBACNone } func (c *Config) IsAuthUISimplified() bool { diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index e0168373db4..ed7794954b5 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -61,7 +61,7 @@ func setDefaults(cfgType string) { viper.SetDefault("auth.login_duration", 7*24*time.Hour) viper.SetDefault("auth.login_max_duration", 14*24*time.Hour) - viper.SetDefault("auth.ui_config.rbac", "simplified") + viper.SetDefault("auth.ui_config.rbac", "none") viper.SetDefault("auth.ui_config.login_failed_message", "The credentials don't match.") viper.SetDefault("auth.ui_config.login_cookie_names", "internal_auth_session") diff --git a/pkg/loadtest/local_load_test.go b/pkg/loadtest/local_load_test.go index 323e57052eb..6595f03ee6e 100644 --- a/pkg/loadtest/local_load_test.go +++ b/pkg/loadtest/local_load_test.go @@ -50,7 +50,7 @@ func TestLocalLoad(t *testing.T) { } kvStore := kvtest.GetStore(ctx, t) - authService := auth.NewBasicAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), authparams.ServiceCache{}, logging.ContextUnavailable()) + authService := auth.NewBasicAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), authparams.ServiceCache{}, logging.FromContext(ctx)) meta := auth.NewKVMetadataManager("local_load_test", conf.Installation.FixedID, conf.Database.Type, kvStore) blockstoreType := os.Getenv(testutil.EnvKeyUseBlockAdapter) diff --git a/webui/src/lib/components/auth/layout.tsx b/webui/src/lib/components/auth/layout.tsx index 88b99c40690..24a4d305ef5 100644 --- a/webui/src/lib/components/auth/layout.tsx +++ b/webui/src/lib/components/auth/layout.tsx @@ -6,7 +6,6 @@ import Col from "react-bootstrap/Col"; import Nav from "react-bootstrap/Nav"; import Card from "react-bootstrap/Card"; -import {auth} from "../../api"; import {Link} from "../nav"; import {useLoginConfigContext} from "../../hooks/conf"; import {useLayoutOutletContext} from "../layout"; @@ -24,22 +23,11 @@ export const AuthLayout = () => { useEffect(() => { setIsLogged(true); }, [setIsLogged]); - const [displayACLDeprecation, setDisplayACLDeprecation] = useState(false); - useEffect(() => { - const listUsers = async () => { - return await auth.listUsers("", "", 2); - } - listUsers().then(r => setDisplayACLDeprecation(r.results.length > 1)); - },[]) return (
- {rbac === 'simplified' && displayACLDeprecation && - {" "}ACLs are moving out of core lakeFS!{" "}See the announcement{" "} - to learn why and how to continue using your existing lakeFS installation in future versions. - } - {rbac === 'simplified' && showRBACAlert && + {rbac === 'simplified' && showRBACAlert && { window.localStorage.setItem(rbacDismissedKey, "true"); setShowRBACAlert(false); @@ -47,43 +35,61 @@ export const AuthLayout = () => { – Available on lakeFS Cloud and lakeFS Enterprise! }
- - - - Access Control - - - + + + + Access Control + + + -
+
- +
+
+ + {rbac === "none" ? + <> + +
+ +

{" "}Role-based access control not configured.

+ This feature is enabled on {" "}lakeFS Cloud{" "} + and lakeFS Enterprise. {" "} + Learn More - - - - +
+
+ + + : + <> + + + + + }
- ); + ) + ; }; export function useAuthOutletContext() {