- Go 82.8%
- Nix 16.4%
- Dockerfile 0.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Deployment: nix flake example wiring the overlay and services.ldapatar
module into a consumer's nixosSystem, with inputs.nixpkgs.follows;
Containerfile note.
- Configuration: full resolution chain for the config file (flag > env >
user config dir via os.UserConfigDir > /etc), precedence order (CLI >
env > file > defaults), and per-option tables (32 rows: flag, env var,
config key, type, default) split by Config file / LDAP / Server / Avatar
/ Log.
- Monitoring: healthz/readyz semantics (readyz gates on initial directory
sync completion, 503 until then), metrics TODO note.
The nix example is machine-verified: extracted verbatim, locked against
the real git+https remote (rev
|
||
| cmd/ldapatar | ||
| nix | ||
| .envrc | ||
| .gitignore | ||
| config.go | ||
| config_test.go | ||
| Containerfile | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| handler.go | ||
| handler_test.go | ||
| ldap.go | ||
| ldap_test.go | ||
| LICENSE | ||
| README.md | ||
| server.go | ||
| server_test.go | ||
LDAPatar
LDAPatar is an LDAP-backed Gravatar-compatible avatar server in a single Go binary. Configure via CLI args, environment variables, and/or config files. Starting it is as simple as:
$ ldapatar -b dc=swag,dc=lgbt
You can then configure other services' GRAVATAR_URL to your ldpatar deployment, and you'll see user's profile photos :)
Deployment
As a go binary, you can simply compile and drop the ldapatar binary wherever you want. A Containerfile and a nix package are also provided for your convenience. Precompiled binaries will be available once I figure out my CI setup.
Nix Service
A Nix flake is provided, exposing a package overlay and a NixOS service module. Consumed from your own flake:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
ldapatar = {
url = "git+https://git.swag.lgbt/cass/ldapatar.git";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { nixpkgs, ldapatar, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
ldapatar.nixosModules.default # provides services.ldapatar
{
nixpkgs.overlays = [ ldapatar.overlays.default ]; # provides pkgs.ldapatar
services.ldapatar = {
enable = true;
settings = {
ldap.url = "ldaps://ldap.swag.lgbt";
server.http.listen = "127.0.0.1:8080";
};
# environmentFile = "/run/secrets/ldapatar"; # LDAPATAR_LDAP_BIND_PASS=...
};
}
];
};
};
}
Configuration
LDAPatar supports layered configuration. An invocation of ldapatar will read configuration from the following sources, ranked in order of precedence:
- CLI Arguments (e.g.
ldapatar --ldap.base-dn="dc=swag,dc=lgbt") - Environment variables (e.g.
LDAPATAR_LDAP_BASE_DN="dc=swag,dc=lgbt" ldapatar) - A config file (e.g.
/etc/ldapatar/ldapatar.yaml). The path to this config file is determined by the following:- The
--configflag (e.g.ldapatar --config ./ldapatar.yaml) - The
LDAPATAR_CONFIGenvironment variable - The user config directory as determined by
os.UserConfigDir(), with/ldapatar/ldapatar.yamlappended (e.g.~/.config/ldapatar/ldapatar.yaml) /etc/ldapatar/ldapatar.yaml
- The
If a config file path is set via the --config flag or the LDAPATAR_CONFIG environment variable, ldapatar will terminate with a fatal error if the path specified doesn't exist. Otherwise, it'll load implicit defaults.
You can specify configuration in multiple ways; for example, a command-line argument and a config file. Configurations are merged at runtime, and any higher-precedence values override lower-precedence ones.
Configuration options
Config file
| Name | Description | CLI Flag | Environment Variable | Config File Setting | Type | Default Value |
|---|---|---|---|---|---|---|
| Config file path | Path to the YAML/JSON configuration file to load | -c, --config |
LDAPATAR_CONFIG |
- | path | see above |
LDAP
| Name | Description | CLI Flag | Environment Variable | Config File Setting | Type | Default Value |
|---|---|---|---|---|---|---|
| LDAP server URL | LDAP server backing the avatar pool | -l, --ldap.url |
LDAPATAR_LDAP_URL |
ldap.url |
string (URL) | ldap://127.0.0.1:3890 |
| LDAP base DN | Base DN for user searches | -b, --ldap.base-dn |
LDAPATAR_LDAP_BASE_DN |
ldap.base-dn |
string (DN) | dc=example,dc=com |
| LDAP bind DN | Bind DN for authenticated searches | -D, --ldap.bind-dn |
LDAPATAR_LDAP_BIND_DN |
ldap.bind-dn |
string (DN) | unset (anonymous) |
| LDAP bind password | Bind password | -w, --ldap.bind-pass |
LDAPATAR_LDAP_BIND_PASS |
ldap.bind-pass |
string | unset — prefer an environment variable or systemd EnvironmentFile; config files are not secret |
| Email fields | LDAP attributes holding user email addresses | --ldap.email-fields |
LDAPATAR_LDAP_EMAIL_FIELDS |
ldap.email-fields |
list of strings | mail |
| Avatar field | LDAP attribute holding the avatar photo | --ldap.avatar-field |
LDAPATAR_LDAP_AVATAR_FIELD |
ldap.avatar-field |
string | jpegPhoto |
| User filter | Search filter clause selecting users | --ldap.user-filter |
LDAPATAR_LDAP_USER_FILTER |
ldap.user-filter |
string | (objectClass=person) |
| Page size | LDAP search page size; 0 disables paging |
--ldap.page-size |
LDAPATAR_LDAP_PAGE_SIZE |
ldap.page-size |
unsigned integer | 500 |
| Timeout | LDAP network dial and search timeout | --ldap.timeout |
LDAPATAR_LDAP_TIMEOUT |
ldap.timeout |
duration string | 10s |
| StartTLS | Upgrade plain connections with StartTLS | --ldap.start-tls |
LDAPATAR_LDAP_START_TLS |
ldap.start-tls |
boolean | false |
| Insecure skip verify | Skip LDAP server TLS certificate verification | --ldap.insecure-skip-verify |
LDAPATAR_LDAP_INSECURE_SKIP_VERIFY |
ldap.insecure-skip-verify |
boolean | false |
| CA certificates | Paths to PEM CA bundles for LDAP TLS | --ldap.ca-certs |
LDAPATAR_LDAP_CA_CERTS |
ldap.ca-certs |
list of paths | unset (system pool) |
Server
| Name | Description | CLI Flag | Environment Variable | Config File Setting | Type | Default Value |
|---|---|---|---|---|---|---|
| HTTP listen | HTTP listen address | -a, --server.http.listen |
LDAPATAR_SERVER_HTTP_LISTEN |
server.http.listen |
string (address) | 127.0.0.1:8080 |
| HTTP read timeout | HTTP read timeout | --server.http.read-timeout |
LDAPATAR_SERVER_HTTP_READ_TIMEOUT |
server.http.read-timeout |
duration string | 10s |
| HTTP write timeout | HTTP write timeout | --server.http.write-timeout |
LDAPATAR_SERVER_HTTP_WRITE_TIMEOUT |
server.http.write-timeout |
duration string | 15s |
| HTTP shutdown timeout | Graceful HTTP server shutdown timeout | --server.http.shutdown-timeout |
LDAPATAR_SERVER_HTTP_SHUTDOWN_TIMEOUT |
server.http.shutdown-timeout |
duration string | 5s |
| Sync interval | Periodic directory sync interval | -r, --server.sync.interval |
LDAPATAR_SERVER_SYNC_INTERVAL |
server.sync.interval |
duration string | 5m |
| Sync cooldown | Minimum cooldown between on-demand refreshes | -m, --server.sync.cooldown |
LDAPATAR_SERVER_SYNC_COOLDOWN |
server.sync.cooldown |
duration string | 30s |
| Photo cache size | Maximum raw photos cached in memory | --server.cache.photo.size |
LDAPATAR_SERVER_CACHE_PHOTO_SIZE |
server.cache.photo.size |
integer | 10000 |
| Photo cache TTL | Raw photo cache TTL | --server.cache.photo.ttl |
LDAPATAR_SERVER_CACHE_PHOTO_TTL |
server.cache.photo.ttl |
duration string | 15m |
| Render cache size | Maximum rendered images cached in memory | --server.cache.render.size |
LDAPATAR_SERVER_CACHE_RENDER_SIZE |
server.cache.render.size |
integer | 10000 |
| Client max-age | Cache-Control max-age for clients |
--server.cache.client.max-age |
LDAPATAR_SERVER_CACHE_CLIENT_MAX_AGE |
server.cache.client.max-age |
duration string | 5m |
| Client stale-while-revalidate | Cache-Control stale-while-revalidate duration |
--server.cache.client.stale-while-revalidate |
LDAPATAR_SERVER_CACHE_CLIENT_STALE_WHILE_REVALIDATE |
server.cache.client.stale-while-revalidate |
duration string | 24h |
Avatar
| Name | Description | CLI Flag | Environment Variable | Config File Setting | Type | Default Value |
|---|---|---|---|---|---|---|
| Upstream URL | Libravatar/Gravatar fallback URL | --avatar.upstream-url |
LDAPATAR_AVATAR_UPSTREAM_URL |
avatar.upstream-url |
string (URL) | https://seccdn.libravatar.org/avatar/ |
| Default size | Default avatar size in pixels when omitted | --avatar.default-size |
LDAPATAR_AVATAR_DEFAULT_SIZE |
avatar.default-size |
integer | 80 |
| Max size | Maximum avatar size in pixels | --avatar.max-size |
LDAPATAR_AVATAR_MAX_SIZE |
avatar.max-size |
integer | 2048 |
| Crop top bias | Top-bias crop ratio for portraits (0.0=top, 0.5=centered) |
--avatar.crop-top-bias |
LDAPATAR_AVATAR_CROP_TOP_BIAS |
avatar.crop-top-bias |
float | 0.2 |
| JPEG quality | JPEG encoding quality (1-100) |
--avatar.jpeg.quality |
LDAPATAR_AVATAR_JPEG_QUALITY |
avatar.jpeg.quality |
integer | 85 |
| GIF num colors | GIF encoding maximum colors (1-256) |
--avatar.gif.num-colors |
LDAPATAR_AVATAR_GIF_NUM_COLORS |
avatar.gif.num-colors |
integer | 256 |
Log
| Name | Description | CLI Flag | Environment Variable | Config File Setting | Type | Default Value |
|---|---|---|---|---|---|---|
| Format | Log format | --log.format |
LDAPATAR_LOG_FORMAT |
log.format |
one of pretty, json, text |
pretty |
| Level | Log level | --log.level |
LDAPATAR_LOG_LEVEL |
log.level |
one of debug, info, warn, error |
info |
Administration
By default, ldapatar provides two health endpoints:
/healthzreturns200when the service is up and running/readyzreturns200after the initial directory sync has completed, and a503until then.
I haven't implemented a Prometheus-compatible /metrics endpoint mostly because I haven't gotten around to it yet. Logging is all structured/leveled, and you can opt in to JSON logging for consumption by log aggregators.