-
Notifications
You must be signed in to change notification settings - Fork 49
Directory Sync : authentik integration #2347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
a6e8a40
feat : WIP authentik integration errors and types are added
manab-pr c28e43a
added authentik , fulfilling all the requirements
manab-pr 35f75df
response struct changes and one api replaced as well
manab-pr 02a4435
Merge branch 'main' into feature/authentik
manab-pr d917e74
using go-client instead of http-client and added more identity as well
manab-pr 4c6412c
Merge branch 'feature/authentik' of https://github.com/manab-pr/core …
manab-pr 7e0d3f2
Merge branch 'main' into feature/authentik
manab-pr 75f6431
added uid instead of pk for directory ac and members
manab-pr 3968a73
Merge branch 'feature/authentik' of https://github.com/manab-pr/core …
manab-pr a2bfc86
Both extractHost and extractScheme now use url.Parse and propagate e…
manab-pr 832fe47
listDirectoryUsers now accept lastRunAt ,SkipDefaultLookback: true ad…
manab-pr a49aabc
Merge branch 'main' into feature/authentik
manab-pr 7dc6b63
Merge branch 'main' into feature/authentik
manab-pr ec4db77
Merge branch 'main' into feature/authentik
manab-pr cd364b4
added user,group,members test json files as mappingtest suggests and …
manab-pr 4838e29
Update internal/integrations/definitions/authentik/mappings.go
manab-pr 19abcd8
Merge branch 'main' into feature/authentik
manab-pr 2e0678a
fixed linting
manab-pr d7b1413
Merge branch 'feature/authentik' of https://github.com/manab-pr/core …
manab-pr e9ed521
Merge branch 'main' into feature/authentik
manab-pr 3ed015c
fixed mapping , moved compose file to docker directory and added task…
manab-pr c2759fd
the IntegrationMappingDirectoryAccountAccountType is written in one line
manab-pr c56f7d1
Merge branch 'main' into feature/authentik
manab-pr 0b56e51
Update internal/integrations/definitions/authentik/operation_director…
manab-pr d4589a1
Update internal/integrations/definitions/authentik/operation_director…
manab-pr 3766015
Apply suggestions from code review
manab-pr 0b883e9
Update internal/integrations/definitions/authentik/types.go
manab-pr e647435
using defualt postgre container now , user need not to provide eenvs …
manab-pr 3d67413
Merge branch 'main' into feature/authentik
manab-pr a407c38
lint issue fixed
manab-pr 20035a8
Merge branch 'feature/authentik' of https://github.com/manab-pr/core …
manab-pr 50a7f1a
test bug removed
manab-pr c2b3acb
test failing fix
manab-pr 3056032
Merge branch 'main' into feature/authentik
manab-pr bc5f719
yml modification and mapping modification as well
manab-pr 461428c
Merge branch 'feature/authentik' of https://github.com/manab-pr/core …
manab-pr 292e98f
added missing env
manab-pr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| AUTHENTIK_SECRET_KEY=change-me | ||
| AUTHENTIK_BOOTSTRAP_PASSWORD=change-me | ||
| AUTHENTIK_POSTGRESQL__PASSWORD=password |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| services: | ||
| authentik-server: | ||
| command: server | ||
| depends_on: | ||
| redis: | ||
| condition: service_started | ||
| env_file: | ||
| - ${PWD}/docker/configs/authentik/.env-example | ||
| environment: | ||
| AUTHENTIK_POSTGRESQL__HOST: postgres | ||
| AUTHENTIK_POSTGRESQL__NAME: authentik | ||
| AUTHENTIK_POSTGRESQL__USER: postgres | ||
| AUTHENTIK_REDIS__HOST: redis | ||
| image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2.2} | ||
| ports: | ||
| - ${COMPOSE_PORT_HTTP:-9000}:9000 | ||
| - ${COMPOSE_PORT_HTTPS:-9443}:9443 | ||
| restart: unless-stopped | ||
| shm_size: 512mb | ||
| volumes: | ||
| - authentik-data:/data | ||
| - authentik-custom-templates:/templates | ||
| networks: | ||
| - default | ||
|
|
||
| authentik-worker: | ||
| command: worker | ||
| depends_on: | ||
| redis: | ||
| condition: service_started | ||
| env_file: | ||
| - ${PWD}/docker/configs/authentik/.env-example | ||
| environment: | ||
| AUTHENTIK_POSTGRESQL__HOST: postgres | ||
| AUTHENTIK_POSTGRESQL__NAME: authentik | ||
| AUTHENTIK_POSTGRESQL__USER: postgres | ||
| AUTHENTIK_REDIS__HOST: redis | ||
| image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2.2} | ||
| restart: unless-stopped | ||
| shm_size: 512mb | ||
| user: root | ||
| volumes: | ||
| - /var/run/docker.sock:/var/run/docker.sock | ||
| - authentik-data:/data | ||
| - authentik-certs:/certs | ||
| - authentik-custom-templates:/templates | ||
| networks: | ||
| - default | ||
|
|
||
| redis: | ||
| image: redis:7.4.9-alpine | ||
| restart: unless-stopped | ||
| networks: | ||
| - default | ||
|
|
||
| volumes: | ||
| authentik-data: | ||
| driver: local | ||
| authentik-certs: | ||
| driver: local | ||
| authentik-custom-templates: | ||
| driver: local | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| package authentik | ||
|
|
||
| import ( | ||
| "github.com/theopenlane/core/internal/ent/integrationgenerated" | ||
| "github.com/theopenlane/core/internal/integrations/providerkit" | ||
| "github.com/theopenlane/core/internal/integrations/registry" | ||
| "github.com/theopenlane/core/internal/integrations/types" | ||
| ) | ||
|
|
||
| // Builder returns the Authentik definition builder | ||
| func Builder() registry.Builder { | ||
| return registry.Builder(func() (types.Definition, error) { | ||
| return types.Definition{ | ||
| DefinitionSpec: types.DefinitionSpec{ | ||
| ID: definitionID.ID(), | ||
| Family: "Authentik", | ||
| DisplayName: "Authentik", | ||
| Description: "Collect Authentik directory users, groups, and memberships for identity posture and access governance.", | ||
| Category: "identity", | ||
| DocsURL: "https://docs.theopenlane.io/docs/platform/integrations/authentik/overview", | ||
| Tags: []string{"directory"}, | ||
| Active: false, | ||
| Visible: false, | ||
| }, | ||
| UserInput: &types.UserInputRegistration{ | ||
| Schema: providerkit.SchemaFrom[UserInput](), | ||
| }, | ||
| CredentialRegistrations: []types.CredentialRegistration{ | ||
| { | ||
| Ref: authentikCredential.ID(), | ||
| Name: "Authentik Credential", | ||
| Description: "API token used to access Authentik instance data.", | ||
| Schema: authentikCredentialSchema, | ||
| }, | ||
| }, | ||
| Connections: []types.ConnectionRegistration{ | ||
| { | ||
| CredentialRef: authentikCredential.ID(), | ||
| Name: "Authentik API Token", | ||
| Description: "Configure Authentik access using an API token from your instance.", | ||
| CredentialRefs: []types.CredentialSlotID{authentikCredential.ID()}, | ||
| ClientRefs: []types.ClientID{authentikClient.ID()}, | ||
| ValidationOperation: healthCheckOperation.Name(), | ||
| Integration: integration.Registration(), | ||
| Disconnect: &types.DisconnectRegistration{ | ||
| CredentialRef: authentikCredential.ID(), | ||
| Description: "Removes the stored API token from Openlane. If the token is no longer needed, revoke it in your Authentik admin panel under Directory > Tokens.", | ||
| }, | ||
| }, | ||
| }, | ||
| Clients: []types.ClientRegistration{ | ||
| { | ||
| Ref: authentikClient.ID(), | ||
| CredentialRefs: []types.CredentialSlotID{authentikCredential.ID()}, | ||
| Description: "Authentik API client", | ||
| Build: Client{}.Build, | ||
| }, | ||
| }, | ||
| Operations: []types.OperationRegistration{ | ||
| { | ||
| Name: healthCheckOperation.Name(), | ||
| Description: "Call Authentik API to verify token and instance connectivity", | ||
| Topic: definitionID.OperationTopic(healthCheckOperation.Name()), | ||
| ClientRef: authentikClient.ID(), | ||
| Policy: types.ExecutionPolicy{Inline: true}, | ||
| ConfigSchema: healthCheckSchema, | ||
| Handle: HealthCheck{}.Handle(), | ||
| }, | ||
| { | ||
| Name: directorySyncOperation.Name(), | ||
| Description: "Collect Authentik directory users, groups, and memberships as directory accounts", | ||
| Topic: definitionID.OperationTopic(directorySyncOperation.Name()), | ||
| ClientRef: authentikClient.ID(), | ||
| ConfigSchema: directorySyncSchema, | ||
| Policy: types.ExecutionPolicy{Reconcile: true}, | ||
| SkipDefaultLookback: true, | ||
| Ingest: []types.IngestContract{ | ||
|
manab-pr marked this conversation as resolved.
|
||
| { | ||
| Schema: integrationgenerated.IntegrationMappingSchemaDirectoryAccount, | ||
| }, | ||
| { | ||
| Schema: integrationgenerated.IntegrationMappingSchemaDirectoryGroup, | ||
| }, | ||
| { | ||
| Schema: integrationgenerated.IntegrationMappingSchemaDirectoryMembership, | ||
| }, | ||
| }, | ||
| IngestHandle: DirectorySync{}.IngestHandle(), | ||
| }, | ||
| }, | ||
| Mappings: authentikMappings(), | ||
| }, nil | ||
| }) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| package authentik | ||
|
|
||
| import ( | ||
| "context" | ||
| "net/http" | ||
| "net/url" | ||
| "time" | ||
|
|
||
| authentikSDK "goauthentik.io/api/v3" | ||
|
|
||
| "github.com/theopenlane/core/internal/integrations/types" | ||
| ) | ||
|
|
||
| const ( | ||
| // authentikRequestTimeout is the per-request timeout for Authentik API calls | ||
| authentikRequestTimeout = 30 * time.Second | ||
| ) | ||
|
|
||
| // Client builds Authentik API clients for one installation | ||
| type Client struct{} | ||
|
|
||
| // Build constructs the Authentik API client for one installation | ||
| func (Client) Build(_ context.Context, req types.ClientBuildRequest) (any, error) { | ||
| cred, err := resolveCredential(req.Credentials) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if cred.Token == "" { | ||
| return nil, ErrAPITokenMissing | ||
| } | ||
|
|
||
| if cred.BaseURL == "" { | ||
| return nil, ErrBaseURLMissing | ||
| } | ||
|
|
||
| host, err := extractHost(cred.BaseURL) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| scheme, err := extractScheme(cred.BaseURL) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| cfg := authentikSDK.NewConfiguration() | ||
| cfg.Host = host | ||
| cfg.Scheme = scheme | ||
| cfg.HTTPClient = &http.Client{Timeout: authentikRequestTimeout} | ||
| cfg.AddDefaultHeader("Authorization", "Bearer "+cred.Token) | ||
|
|
||
| return authentikSDK.NewAPIClient(cfg), nil | ||
| } | ||
|
|
||
| // resolveCredential extracts the CredentialSchema from the provided credential bindings | ||
| func resolveCredential(bindings types.CredentialBindings) (CredentialSchema, error) { | ||
| cred, ok, err := authentikCredential.Resolve(bindings) | ||
| if err != nil { | ||
| return CredentialSchema{}, ErrCredentialDecode | ||
| } | ||
|
|
||
| if !ok { | ||
| return CredentialSchema{}, ErrCredentialDecode | ||
| } | ||
|
|
||
| return cred, nil | ||
| } | ||
|
|
||
| // extractHost extracts the host from a base URL | ||
| func extractHost(baseURL string) (string, error) { | ||
| u, err := url.Parse(baseURL) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| return u.Host, nil | ||
| } | ||
|
|
||
| // extractScheme extracts the scheme from a base URL | ||
| func extractScheme(baseURL string) (string, error) { | ||
| u, err := url.Parse(baseURL) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| return u.Scheme, nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| // Package authentik provides an integration definition for Authentik | ||
| // (https://goauthentik.io), an open-source identity provider designed for | ||
| // self-hosted and on-premise deployments. | ||
| // | ||
| // # Overview | ||
| // | ||
| // This integration connects an Authentik instance to OpenLane using API token | ||
| // authentication, enabling directory sync of users, groups, and group | ||
| // memberships for identity posture and access governance workflows. | ||
| // | ||
| // # Authentication | ||
| // | ||
| // The integration authenticates using a static API token generated from the | ||
| // Authentik admin panel. The token is scoped to a service account and passed | ||
| // as a Bearer token on every API request. No OAuth2 flow or token refresh is | ||
| // required. | ||
| // | ||
| // # Directory Sync | ||
| // | ||
| // The directory sync operation pulls the following resources from the connected | ||
| // Authentik instance and normalizes them into OpenLane's internal directory | ||
| // schemas: | ||
| // | ||
| // - DirectoryAccount: Authentik users (internal and external types) | ||
| // - DirectoryGroup: Authentik groups with classification derived from is_superuser | ||
| // - DirectoryMembership: Group membership relationships between accounts and groups | ||
| // | ||
| // Users of type service_account and internal_service_account are included in | ||
| // the sync but mapped to the SERVICE account type. Group sync can be disabled | ||
| // via the DisableGroupSync option in UserInput. | ||
| // | ||
| // # Configuration | ||
| // | ||
| // The following options are available when connecting an Authentik instance: | ||
| // | ||
| // - BaseURL: The base URL of the Authentik instance (e.g. https://authentik.mycompany.com) | ||
| // - Token: A static API token generated from the Authentik admin panel | ||
| // - DisableGroupSync: When true, only users are synced; groups and memberships are skipped | ||
| // - PrimaryDirectory: Marks this installation as the authoritative source for identity holder enrichment | ||
| // - FilterExpr: An optional CEL expression applied to records before ingestion | ||
| // | ||
| // # SDK | ||
| // | ||
| // This integration uses the official Authentik Go SDK (goauthentik.io/api/v3), | ||
| // which is generated from Authentik's OpenAPI schema and versioned per Authentik | ||
| // release. This ensures breaking API changes are caught at compile time when the | ||
| // SDK version is updated. | ||
| package authentik |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package authentik | ||
|
|
||
| import "errors" | ||
|
|
||
| var ( | ||
| // ErrAPITokenMissing indicates the API token is missing from the credential | ||
| ErrAPITokenMissing = errors.New("authentik: api token missing") | ||
| // ErrBaseURLMissing indicates the Authentik base URL is missing from the credential | ||
| ErrBaseURLMissing = errors.New("authentik: base url missing") | ||
| // ErrClientType indicates the provided client is not the expected authentik client type | ||
| ErrClientType = errors.New("authentik: unexpected client type") | ||
| // ErrClientConfigInvalid indicates the Authentik client configuration is invalid | ||
| ErrClientConfigInvalid = errors.New("authentik: client config invalid") | ||
| // ErrCredentialEncode indicates the credential could not be serialized | ||
| ErrCredentialEncode = errors.New("authentik: credential encode failed") | ||
| // ErrCredentialDecode indicates the credential could not be deserialized | ||
| ErrCredentialDecode = errors.New("authentik: credential decode failed") | ||
| // ErrHealthCheckFailed indicates the health check request failed | ||
| ErrHealthCheckFailed = errors.New("authentik: health check failed") | ||
| // ErrDirectoryUsersFetchFailed indicates the users listing failed | ||
| ErrDirectoryUsersFetchFailed = errors.New("authentik: directory users fetch failed") | ||
| // ErrDirectoryGroupsFetchFailed indicates the groups listing failed | ||
| ErrDirectoryGroupsFetchFailed = errors.New("authentik: directory groups fetch failed") | ||
| // ErrDirectoryGroupMembersFetchFailed indicates the group members listing failed | ||
| ErrDirectoryGroupMembersFetchFailed = errors.New("authentik: directory group members fetch failed") | ||
| // ErrPayloadEncode indicates a provider payload could not be serialized | ||
| ErrPayloadEncode = errors.New("authentik: payload encode failed") | ||
| // ErrResultEncode indicates an operation result could not be serialized | ||
| ErrResultEncode = errors.New("authentik: result encode failed") | ||
| ) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.