-
Notifications
You must be signed in to change notification settings - Fork 0
Rewrite documentation with more specific use cases in mind #119
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
Open
tlater-famedly
wants to merge
2
commits into
main
Choose a base branch
from
tlater/better-docs
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| ## Testing & Development | ||
|
|
||
| This repository uses [`nextest`](https://nexte.st/) to perform test | ||
| env spin-up and teardown. To install it, either see their website, or | ||
| run: | ||
|
|
||
| ``` | ||
| cargo install cargo-nextest --locked | ||
| ``` | ||
|
|
||
| Tests can then be run using: | ||
|
|
||
| ``` | ||
| cargo nextest run [--no-fail-fast] [-E 'test(<specific_test_to_run>)'] | ||
| ``` | ||
|
|
||
| Note that tests need to be executed from the repository root since we | ||
| do not currently implement anything to find files required for tests | ||
| relative to it. | ||
|
|
||
| In addition, a modern docker with the `compose` subcommand is | ||
| required - importantly, this is not true for many distro docker | ||
| packages. Firewalls also need to be configured to allow container <-> | ||
| container as well as container <-> host communication. | ||
|
|
||
| ### E2E test architecture | ||
|
|
||
| For e2e testing, we need an ldap and a zitadel instance to test | ||
| against. These are spun up using docker compose. | ||
|
|
||
| After ldap and zitadel have spun up, another docker container runs, | ||
| which simply executes a script to clean up existing test data and | ||
| create the necessary pre-setup organization structures to support a | ||
| test run. | ||
|
|
||
| Tests are then expected to directly communicate with ldap/zitadel to | ||
| create/delete/modify users and confirm test results. | ||
|
|
||
| Importantly, since the tests run with no teardown between individual | ||
| tests, users created *must* have different LDAP ID/email addresses, so | ||
| that they can be managed independently. | ||
|
|
||
| E2E tests cannot run concurrently, since this would cause | ||
| synchronization to happen concurrently. | ||
|
|
||
| For LDAP-over-TLS, openldap is configured to allow connections without | ||
| client certificates, but if one is provided, it must be verified | ||
| correctly. This allows us to test scenarios with and without client | ||
| certificates. | ||
|
|
||
| ## Contributing | ||
|
|
||
| ### Pre-commit usage | ||
|
|
||
| 1. If not installed, install with your package manager, or `pip install --user pre-commit` | ||
| 2. Run `pre-commit autoupdate` to update the pre-commit config to use the newest template | ||
| 3. Run `pre-commit install` to install the pre-commit hooks to your local environment |
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 |
|---|---|---|
|
|
@@ -7,39 +7,107 @@ Currently supported sources: | |
| - CSV | ||
| - Custom endpoint provided by UKT | ||
|
|
||
| ## Configuration | ||
|
|
||
| > [!WARNING] | ||
| > | ||
| > When creating a service user, limit them to the specific project and | ||
| > organization scope that they are intended to sync. `famedly-sync` | ||
| > currently does not separately limit the scope of the sync, see #103. | ||
|
|
||
| The tool expects a configuration file located at `./config.yaml`. See example configuration files in [./sample-configs/](./sample-configs/). | ||
|
|
||
| The default path can be changed by setting the new path to the environment variable `FAMEDLY_SYNC_CONFIG`. | ||
|
|
||
| Also, individual configuration items and the whole configuration can be set using environment variables. For example, the following YAML configuration: | ||
|
|
||
| ```yaml | ||
| sources: | ||
| ldap: | ||
| url: ldap://localhost:1389 | ||
| ``` | ||
|
|
||
| Could be set using the following environment variable: | ||
|
|
||
| ```bash | ||
| FAMEDLY_SYNC__SOURCES__LDAP__URL="ldap://localhost:1389" | ||
| ``` | ||
|
|
||
| Note that the environment variable name always starts with the prefix `FAMEDLY_SYNC` followed by keys separated by double underscores (`__`). | ||
|
|
||
| Some configuration items take a list of values. In this cases the values should be separated by space. **If an empty list is desired the variable shouldn't be created.** | ||
| ## Deployment | ||
|
|
||
| Config can have **various sources** to sync from. When a source is configured, the sync tool tries to update users in Famedly's Zitadel instance based on the data obtained from the source. | ||
| Note that famedly-sync is currently not designed to be deployed to | ||
| projects with existing users, or projects that have been synced to | ||
| with a different source before. | ||
|
|
||
| **Feature flags** are optional and can be used to enable or disable certain features. | ||
| > [!CAUTION] | ||
| > | ||
| > Since famedly-sync relies on metadata to perform its tasks, if users | ||
| > that were not created by famedly-sync using the same source exist in | ||
| > the instance, they may be **deleted** by a sync, or cause desync | ||
| > issues if they happen to be users with elevated permissions. | ||
|
|
||
| ### LDAP | ||
|
|
||
| To deploy famedly-sync to sync an LDAP server to a Zitadel instance, | ||
| the following need to be collected first: | ||
|
|
||
| - LDAP instance details | ||
| - URL of the LDAP/AD server | ||
| - Bind DN (=~username of the admin user) with which to authenticate | ||
| - Bind password with which to authenticate | ||
| - Base DN under which the users that should be synced are available | ||
| - An LDAP user filter to select specifically the users to sync | ||
| - The mapping of LDAP attributes to Zitadel attributes | ||
| - This may differ between instances, hence it's configurable. It | ||
| is often quite straightforward from listing the users with | ||
| `ldapsearch`, but more on this later | ||
| - TLS certificates, if TLS is used and mTLS is required and/or the | ||
| server certificate is not in the root store | ||
| - Zitadel instance details | ||
| - A service user must be created. | ||
| - The [Zitadel | ||
| documentation](https://zitadel.com/docs/guides/integrate/service-users/private-key-jwt#steps-to-authenticate-a-service-user-with-private-jwt) | ||
| covers creating such a user. | ||
| - The user should be created with *only* the `Iam User Manager` | ||
| role for the organization that should be synced to. | ||
| - The relevant Project and Org IDs | ||
| - These are the "Resource Ids" listed on their pages in the | ||
| Zitadel UI | ||
| - SSO settings | ||
| - When using SSO, an IDP ID needs to be defined. IDP configuration | ||
| is located in the Zitadel instance's default settings - the ID | ||
| of a specific IDP can be glanced from its URL. | ||
| - Currently, this is not optional, see [this | ||
| issue](https://github.com/famedly/famedly-sync/issues/102). For | ||
| now, setting the ID to `000000000000000000` when not needed is a | ||
| reasonable workaround. | ||
|
|
||
| Once this has been gathered, the following steps are advised: | ||
|
|
||
| 1. Asserting correctness of the LDAP configuration | ||
|
|
||
| This can be done using `ldapsearch`, which is part `openldap` (on | ||
| ubuntu hosts, in the `ldap-utils` package). The basic search command | ||
| can be translated from the previously acquired data to: | ||
|
|
||
| ``` | ||
| ldapsearch -H "$LDAP_URL" -D "$LDAP_BIND_DN" -w "$LDAP_BIND_PASSWORD" -b "$LDAP_BASE_DN" "$LDAP_USER_FILTER" | ||
| ``` | ||
|
|
||
| If this does not return all user data required for the attribute | ||
| mapping, also add the expected attributes to the end of the command. | ||
|
|
||
| 2. Writing the famedly-sync configuration | ||
|
|
||
| To prevent this document going out of date, we will not repeat the | ||
| configuration syntax here. See | ||
| [./sample-configs/ldap-config.sample.yaml](./sample-configs/ldap-config.sample.yaml) | ||
| for details. | ||
|
|
||
| Noteworthy is that the `use_attribute_filter` config setting | ||
| *should* be set to true if, and only if, attributes needed to be | ||
| added to the `ldapsearch` command. | ||
|
|
||
| 3. Deploying the docker container | ||
|
|
||
| A relatively fool-proof way of doing this is with `docker | ||
| compose`. This composefile, and a copy of the service user's JWT | ||
| and the just-created configuration in `./opt/`, is all that should | ||
| be required: | ||
|
|
||
| ```yaml | ||
| services: | ||
| famedly-sync-agent: | ||
| image: docker-oss.nexus.famedly.de/famedly-sync-agent:<version> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably split this out into a separate issue, but we should really standardise the name into just |
||
| volumes: | ||
| - type: bind | ||
| source: ./opt | ||
| target: /opt/famedly-sync | ||
| network_mode: host | ||
| ``` | ||
|
|
||
| Assuming a recent-enough docker version, this can then be invoked | ||
| with `docker compose up`. | ||
|
|
||
| Since the `./opt` directory will be bind-mounted to | ||
| `/opt/famedly-sync` in the docker container (and docker containers | ||
| do not permit access to host files by other means), any files | ||
| referenced in the configuration *should* be relative to prevent | ||
| file access issues. | ||
|
|
||
| ## Migrations | ||
|
|
||
|
|
@@ -61,111 +129,42 @@ base64-encoded one. No other values should change during migration. | |
| A Zitadel instance that is already using hex-encoded IDs will not be | ||
| altered (though famedly-sync will still make various HTTP calls). | ||
|
|
||
| ## Testing & Development | ||
|
|
||
| This repository uses [`nextest`](https://nexte.st/) to perform test | ||
| env spin-up and teardown. To install it, either see their website, or | ||
| run: | ||
| ## Kubernetes Deployment | ||
|
|
||
| ``` | ||
| cargo install cargo-nextest --locked | ||
| ``` | ||
|
|
||
| Tests can then be run using: | ||
| The provided manifest `ldap-sync-cronjob.yaml` can be used | ||
| to deploy this tool as a CronJob on a Kubernetes cluster. | ||
|
|
||
| ``` | ||
| cargo nextest run [--no-fail-fast] [-E 'test(<specific_test_to_run>)'] | ||
| kubectl create -f ldap-sync-deployment.yaml | ||
| ``` | ||
|
|
||
| Note that tests need to be executed from the repository root since we | ||
| do not currently implement anything to find files required for tests | ||
| relative to it. | ||
|
|
||
| In addition, a modern docker with the `compose` subcommand is | ||
| required - importantly, this is not true for many distro docker | ||
| packages. Firewalls also need to be configured to allow container <-> | ||
| container as well as container <-> host communication. | ||
|
|
||
| ### E2E test architecture | ||
|
|
||
| For e2e testing, we need an ldap and a zitadel instance to test | ||
| against. These are spun up using docker compose. | ||
|
|
||
| After ldap and zitadel have spun up, another docker container runs, | ||
| which simply executes a script to clean up existing test data and | ||
| create the necessary pre-setup organization structures to support a | ||
| test run. | ||
|
|
||
| Tests are then expected to directly communicate with ldap/zitadel to | ||
| create/delete/modify users and confirm test results. | ||
|
|
||
| Importantly, since the tests run with no teardown between individual | ||
| tests, users created *must* have different LDAP ID/email addresses, so | ||
| that they can be managed independently. | ||
|
|
||
| E2E tests cannot run concurrently, since this would cause | ||
| synchronization to happen concurrently. | ||
|
|
||
| For LDAP-over-TLS, openldap is configured to allow connections without | ||
| client certificates, but if one is provided, it must be verified | ||
| correctly. This allows us to test scenarios with and without client | ||
| certificates. | ||
|
|
||
| ## Contributing | ||
|
|
||
| ### Pre-commit usage | ||
|
|
||
| 1. If not installed, install with your package manager, or `pip install --user pre-commit` | ||
| 2. Run `pre-commit autoupdate` to update the pre-commit config to use the newest template | ||
| 3. Run `pre-commit install` to install the pre-commit hooks to your local environment | ||
|
|
||
| ## Deployment | ||
|
|
||
| The easiest way to deploy this tool is using our published docker | ||
| container through our [composefile](./docker-compose.yaml). | ||
|
|
||
| To prepare for use, we need to provide a handful of files in an `opt` | ||
| directory in the directory where `docker compose` will be | ||
| executed. This is the expected directory structure of the sample | ||
| configuration file: | ||
| It will run `docker-oss.nexus.famedly.de/famedly-sync-agent:v0.4.0` once per day | ||
| at 00:00 in the namespace `ldap-sync`. It requires a ConfigMap named `famedly-sync` | ||
| to be present in the `ldap-sync` namespace. The ConfigMap can be created using | ||
|
|
||
| ``` | ||
| opt | ||
| ├── certs | ||
| │ └── test-ldap.crt # The TLS certificate of the LDAP server | ||
| ├── config.yaml # Example configs can be found in [./sample-configs](./sample-configs) | ||
| └── service-user.json # Provided by famedly | ||
| kubectl create configmap --from-file config.yaml famedly-sync --namespace ldap-sync | ||
| ``` | ||
|
|
||
| Once this is in place, the container can be executed in the parent | ||
| directory of `opt` with: | ||
| ### Configuration through env variables | ||
|
|
||
| ``` | ||
| docker compose up | ||
| ``` | ||
| Since kubernetes deployments prefer env-based configuration, famedly-sync supports this. | ||
|
|
||
| Or alternatively, without `docker compose`: | ||
| Individual configuration items and the whole configuration can be set using environment variables. For example, the following YAML configuration: | ||
|
|
||
| ```yaml | ||
| sources: | ||
| ldap: | ||
| url: ldap://localhost:1389 | ||
| ``` | ||
| docker run --rm -it --network host --volume ./opt:/opt/famedly-sync docker-oss.nexus.famedly.de/famedly-sync-agent:latest | ||
| ``` | ||
|
|
||
| ### Kubernetes Deployment | ||
|
|
||
| The provided manifest `ldap-sync-cronjob.yaml` can be used | ||
| to deploy this tool as a CronJob on a Kubernetes cluster. | ||
| Could be set using the following environment variable: | ||
|
|
||
| ``` | ||
| kubectl create -f ldap-sync-deployment.yaml | ||
| ```bash | ||
| FAMEDLY_SYNC__SOURCES__LDAP__URL="ldap://localhost:1389" | ||
| ``` | ||
|
|
||
| It will run `docker-oss.nexus.famedly.de/famedly-sync-agent:v0.4.0` once per day | ||
| at 00:00 in the namespace `ldap-sync`. It requires a ConfigMap named `famedly-sync` | ||
| to be present in the `ldap-sync` namespace. The ConfigMap can be created using | ||
|
|
||
| ``` | ||
| kubectl create configmap --from-file config.yaml famedly-sync --namespace ldap-sync | ||
| ``` | ||
| Some configuration items take a list of values. In this cases the values should be separated by space. **If an empty list is desired the variable shouldn't be created.** | ||
|
|
||
| ## Quirks & Edge Cases | ||
|
|
||
|
|
||
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would also be good to expand the first part of the README: What does famedly-sync do (and not do)?
What are the potential footguns? How do you troubleshoot problems?
What are the known limitations or design considerations? Are ldap group structures maintained? can you use all three data sources simultaneously? will famedly-sync automagically figure out the special format of our AD that's been running since 1993? etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, this PR focuses on the deployment flow, since infra specifically asked for it - I think we should split this out into a separate ticket so we get the quick win from clearer deployment docs?
FWIW, this should probably make it into more general user docs, but adding it to the readme while we don't have a clear process for that seems reasonable.