forked from Deuxfleurs/bottin
161 lines
7.4 KiB
Markdown
161 lines
7.4 KiB
Markdown
# Bottin
|
|
|
|
[![status-badge](https://woodpecker.deuxfleurs.fr/api/badges/38/status.svg)](https://woodpecker.deuxfleurs.fr/repos/38)
|
|
|
|
<img src="https://git.deuxfleurs.fr/Deuxfleurs/bottin/raw/branch/main/bottin.png" style="height: 150px; display: block; margin-left: auto; margin-right: auto" />
|
|
|
|
|
|
Bottin is a LDAP server that uses Consul's key-value store as a storage backend,
|
|
in order to provide a redundant (high-availability) LDAP server on a Nomad+Consul cluster.
|
|
It is a reimplementation of [superboum's Bottin](https://github.com/superboum/bottin)
|
|
using the Go programming language.
|
|
|
|
**Use case:** [Deuxfleurs](https://deuxfleurs.fr) is a self-hosting collective
|
|
where we try to build a resilient infrastructure with commodity hardware by
|
|
having redundancy and auto-reconfiguration (this is why we use the Nomad+Consul
|
|
stack). We try to use replicated/high availability data stores everywhere we
|
|
can, and Bottin helps us do this for the LDAP service. We are not managing a
|
|
high number of users at the moment and scalability is not our highest priority.
|
|
|
|
Features:
|
|
|
|
- most LDAP operations implemented (add, modify, delete, compare, search with most basic filters)
|
|
- TLS support with STARTTLS
|
|
- Access control through an ACL (hardcoded in the configuration file)
|
|
|
|
|
|
A Docker image is provided on the [Docker hub](https://hub.docker.com/r/dxflrs/bottin) (built in `default.nix`).
|
|
An example for running Bottin on a Nomad cluster can be found in `bottin.hcl.example`.
|
|
|
|
Bottin takes a single command line argument, `-config <filename>`, which is the
|
|
path to its config file (defaults to `./config.json`).
|
|
The configuration file is a JSON file whose contents is described in the following section.
|
|
|
|
[Guichet](https://git.deuxfleurs.fr/Deuxfleurs/guichet) is a simple LDAP web administration
|
|
interface that works well with Bottin.
|
|
|
|
Bottin is licensed under the terms of the GPLv3.
|
|
|
|
|
|
## Building Bottin
|
|
|
|
Bottin requires go 1.13 or later.
|
|
|
|
To build Bottin, clone this repository outside of your `$GOPATH`.
|
|
Then, run `make` in the root of the repo.
|
|
|
|
## Releasing
|
|
|
|
```bash
|
|
nix-build -A bin
|
|
nix-build -A docker
|
|
```
|
|
|
|
```bash
|
|
docker load < $(nix-build -A docker)
|
|
docker push dxflrs/bottin:???
|
|
```
|
|
|
|
## Server initialization
|
|
|
|
When Bottin is launched on an empty database,
|
|
it creates a special admin entity with the name `cn=admin,your_suffix`.
|
|
It will have a randomly generated password that is printed out by the server.
|
|
Check your logs to retrieve the password.
|
|
|
|
The admin entity has no powers other than those granted by the ACL rules,
|
|
so unless you don't want to use it, make sure to keep rules that allow to
|
|
bind to the admin entity and that allows the admin entity to do everything.
|
|
|
|
|
|
## Configuration of Bottin
|
|
|
|
### Logging
|
|
|
|
Bottin supports all of the log levels of [logrus](https://github.com/sirupsen/logrus).
|
|
The log level can be specified in the key `log_level` of the json config file,
|
|
or in the environment variable `BOTTIN_LOG_LEVEL`.
|
|
By default, the log level is set to `info`.
|
|
|
|
### The LDAP suffix
|
|
|
|
Bottin only handles LDAP entries under a given path, which is typically of
|
|
the form `dn=sld,dn=tld`, where `sld.tld` is your domain name. Specify this
|
|
suffix in the `suffix` key of the json config file.
|
|
|
|
### Connection to the Consul server
|
|
|
|
By default, Bottin connects to the Consul server on localhost.
|
|
Change this by specifying the `consul_host` key in the json config file.
|
|
|
|
### Bind addresses
|
|
|
|
#### Insecure port
|
|
|
|
By default, Bottin listens on all interfaces on port 389 for standard
|
|
non-TLS connections. Change the value of the `bind` key in the json config
|
|
file to change this behaviour (default value: `0.0.0.0:389`). An empty string
|
|
will disable this port and Bottin will not listen for non-TLS connections.
|
|
|
|
#### Secure port
|
|
|
|
If a TLS configuration is provided (see next section), Bottin also listens
|
|
on all interfaces on port 636 for TLS connections. Change the value of the
|
|
`bind_secure` key in the json config file to change this behaviour (default
|
|
value: `0.0.0.0:636`). An empty string will disable this port and Bottin
|
|
will not listen for TLS connections.
|
|
|
|
### TLS
|
|
|
|
Bottin supports TLS connections using either fully secure connections or
|
|
using the STARTLS functionnality of the LDAP protocol to upgrade from an
|
|
insecure connection. To use it, specify the following three keys in the json
|
|
config file:
|
|
|
|
- `tls_server_name`: the host name that clients will use to reach your LDAP server
|
|
- `tls_cert_file`: path to your TLS certificate (a `.pem` file)
|
|
- `tls_key_file`: path to your TLS key (a `.pem` file)
|
|
|
|
If a TLS configuration is provided, the `STARTTLS` mechanism may be used on the
|
|
insecure port, independently of whether the secure port is enabled or not.
|
|
|
|
The secure port is disabled and a warning is shown if the `bind_secure` value
|
|
is set (non-empty) and no valid TLS configuration is provided.
|
|
|
|
### Access control list
|
|
|
|
Bottin supports a flexible syntax to specify access rights to items in the database.
|
|
The ACL is specified as a list of rules. A request will be allowed if there exists a rule that allows it. Otherwise an insufficient permission error will be returned.
|
|
|
|
The list of ACL rules are specified in the `acl` key of the json config file, as a list of strings whose structure is defined in the next paragraph.
|
|
|
|
#### Rule format
|
|
|
|
A rule is a string composed of five fields separated by `:`. The fields are the following:
|
|
|
|
1. The name of the user that must be bound (logged in) for the rule to apply. May contain wildcards such as `*` (see the format used by Go's `path.Match`). The special name `ANONYMOUS` applies to clients before they bind to an LDAP entity.
|
|
2. The groups that the user must be a part of, separated by spaces. Wildcards may also be used. If several groups (or wildcard group patterns) are specified, for each pattern the user must be part of a group that matches it.
|
|
3. The action, a subset of `bind`, `read`, `add`, `delete`, `modify`, `modifyAdd` separated by spaces. `modifyAdd` is a special value that only authorizes modifications that add new values to a given attribute. This can be used to allow users to add other users to a group but not remove users from the group.
|
|
4. The target entity of the action as a pattern that may contain wildcards. The special word `SELF` is replaced by the entity name of the bound user before trying to match.
|
|
5. The allowed attributes for a read, add or modify operation. This is specified as a list of patterns to include and exclude attributes, separated by spaces. A pattern that starts by `!` is an exclude pattern, otherwise it is an include pattern. To read/write an attribute, it has to match at least one include pattern and not match any exclude pattern. Delete operations do not check for any attribute, thus as soon as `delete` is included in the allowed actions, the right to delete entities is granted.
|
|
|
|
|
|
#### Rule examples
|
|
|
|
- Anybody (before binding) can bind to an entity under `ou=users,dc=bottin,dc=eu`:
|
|
`ANONYMOUS::bind:*,ou=users,dc=bottin,dc=eu:`
|
|
|
|
- Anybody (before binding) can bind to the specific admin entity:
|
|
`ANONYMOUS::bind:cn=admin,dc=bottin,dc=eu:`
|
|
|
|
- Anybody who is logged in can read anything that is not a userpassword attribute:
|
|
`*,dc=bottin,dc=eu::read:*:* !userpassword`
|
|
|
|
- Anybody can read and modify anything from their own entry:
|
|
`*::read modify:SELF:*`
|
|
|
|
- The admin can read, add, modify, delete anything:
|
|
`cn=admin,dc=bottin,dc=eu::read add modify delete:*:*`
|
|
|
|
- Members of the admin group can read, add, modify, delete anything:
|
|
`*:cn=admin,ou=groups,dc=bottin,dc=eu:read add modify delete:*:*`
|