Skip to content
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

Support LDAP over IPC (unix domain sockets) #701

Open
Zepmann opened this issue Oct 6, 2023 · 15 comments
Open

Support LDAP over IPC (unix domain sockets) #701

Zepmann opened this issue Oct 6, 2023 · 15 comments
Labels
backend Issues that require a backend change enhancement New feature or request ldap rust Pull requests that update Rust code

Comments

@Zepmann
Copy link
Contributor

Zepmann commented Oct 6, 2023

For servers which host everything locally, it is unnecessary to use the TCP/IP stack for local client-server connections. Many services which support LDAP for authentication support unix domain sockets. Examples include but are not limited to Authelia, Docker Mailserver and Nextcloud.

To check if your favorite LDAP authenticating software supports LDAP over IPC, see if the ldapi:// URI scheme is supported.

@Zepmann
Copy link
Contributor Author

Zepmann commented Oct 6, 2023

More information can be found here, including motivation and implementation considerations.

This would seem to fit perfectly with the goal of lldap as a light LDAP implementation for authentication.

@Zepmann
Copy link
Contributor Author

Zepmann commented Oct 6, 2023

This feature request also extends to HTTP. Reverse proxies such as HAProxy support connecting to unix domain sockets.

@nitnelave nitnelave added enhancement New feature or request backend Issues that require a backend change ldap rust Pull requests that update Rust code labels Oct 6, 2023
@nitnelave
Copy link
Member

That feature sounds potentially useful. The bulk of the change would have to be in server/src/infra/ldap_server.rs and server/src/infra/tcp_server.rs, where we can use bind_uds instead of bind.

How do you propose to handle the configuration? We'd have to support a socket for LDAP, LDAPS and HTTP. Currently, we have the ldap_host/ldap_port/ldaps_port and the http_host/http_port to configure the LDAP/HTTP servers respectively. There is no standard scheme for UDS as URL (see whatwg/url#577) but we could say that if the host starts with a / it's a UDS.

However, we'll need something more for LDAPS if going this way.

@Zepmann
Copy link
Contributor Author

Zepmann commented Oct 6, 2023

My two cents for LDAP with backwards compatibility in mind:

  • Add the option ldaps_host (simply host under [ldaps_options], but I'll refer to ldaps_host and ldaps_port for clarity). This will allow separate binding of LDAPS to different addresses. If ldaps_host does not exist or is empty and a single address without port number (see next point) is specified in ldap_host, use the single address from ldap_host instead. This will ensure backwards compatibility.

  • Allow a port number to be specified in a binding (e.g.: 0.0.0.0:389, [::]:389). If a port number is not given for a binding and ldap_port/ldaps_port is not set, use default port 389 or 3890 (your preference) for LDAP or 636 or 6360 (dito) for LDAPS.

  • If an address of ldap_host or ldaps_host starts with unix@, consider everything after that a local unix socket to bind to. I borrowed this idea from HAProxy. E.g.: ldap_host = unix@/run/lldap.sock.

  • Add the options ldap_unix_mode and ldaps_unix_mode. Possible values are file permission modes (e.g.: 600) assigned to unix sockets when created. Default value can be 666 for everyone on the system being able to read from and write to the socket, similar to the default of nginx. Lesser values can be used to locally lock access down further from everyone, to the group, and to the owner (the user running lldap).

  • Optional: Allow multiple addresses in ldap_host and ldaps_host. Each address is separated by a comma and whitespace is ignored for interpretation (e.g.: ldap_host = unix@/run/lldap.sock, 192.168.1.16:389, 192.168.2.16:3890, [::1]:389). While not part of this feature request, I do miss the ability to bind to multiple local addresses. Example use case: exposing LLDAP running outside of Docker to Docker containers who cannot refer to localhost as the machine itself.

For HTTP:

  • Allow a port number to be specified in a binding (e.g.: 127.0.0.1:17170, [::/1]:17170). If a port number is not given for a binding and http_port is not set, use default port 17170.
  • If an address of http_host starts with unix@, consider everything after that a local unix socket to bind to.
  • Add the option http_unix_mode. Same as the proposal for LDAP(S). For a management interface, I would imagine one might want to reduce access independently from LDAP(S).
  • Since it concerns a management interface I think multiple bindings are less of a priority compared to LDAP. Often a single binding is enough to make it usable in a secure manner (through SSH, through a reverse proxy, through a TLS offloader, etc.).

@TheRealGramdalf
Copy link

See #700 (comment) for my thoughts on this, I believe it to be relevant

@Zepmann
Copy link
Contributor Author

Zepmann commented Nov 8, 2023

Another addition to my previous comments:

Unix socket support for creating database connections would also be welcome. This is also supported by other services (Authelia, Nextcloud, ...).

@nitnelave
Copy link
Member

Connecting to the DB over UDS should be already possible: See launchbadge/sqlx#449 and launchbadge/sqlx#144 for the syntax.

@Zepmann
Copy link
Contributor Author

Zepmann commented Nov 8, 2023

Thanks for notifying me of that, @nitnelave. I'll test it soon.

@Zepmann
Copy link
Contributor Author

Zepmann commented Nov 8, 2023

I tested MariaDB over IPC support. Running the following works on an empty database:

lldap create_schema -d mysql://someusername:secretpassword@localhost/lldapdatabasename?socket=/run/mysqld/mysqld.sock

Configured with:

database_url = "mysql://someusername:secretpassword@localhost/lldapdatabasename?socket=/run/mysqld/mysqld.sock"

lldap outputs:

[error]: Could not bring up the servers: Connection Error: error communicating with database: Address family not supported by protocol (os error 97): error communicating with database: Address family not supported by protocol (os error 97)

Tested with Arch Linux and MariaDB.

This makes me assume that MySQL/MariaDB over IPC is not fully supported by lldap.

@nitnelave
Copy link
Member

@Zepmann That's very strange. Can you open a new issue and post some more details, including the verbose LLDAP logs?

@Zepmann
Copy link
Contributor Author

Zepmann commented Nov 9, 2023

@nitnelave

It's not a bug in LLDAP, but a result of a too strict systemd service file provided in AUR:

[Service]
RestrictAddressFamilies=AF_INET AF_INET6

Override the value to add AF_UNIX, and everything works as expected.

Sorry about that. This feature request still remains open for unix socket support for LDAP and HTTP protocols. If support for that is added, the noted problem (and solution) would also apply for these protocols over unix sockets.

If support is added, I'll contact the package maintainer to also add AF_UNIX to the default service file. Having support for unix sockets for the database backend, LDAP and HTTP is a better motivation compared to only support for the database backend.

@nitnelave
Copy link
Member

I didn't know we had an AUR package. Maybe you can ask for that patch to be included, so the next person doesn't trip over the same problem?

@Zepmann
Copy link
Contributor Author

Zepmann commented Nov 9, 2023

I didn't know we had an AUR package. Maybe you can ask for that patch to be included, so the next person doesn't trip over the same problem?

There are two! There is lldap and lldap-git, by two different maintainers.

I'll contact them on AUR and ask them to add AF_UNIX to the list of supported address families, since it can already be used with lldap (with a real world use case).

By the way, how should lldap be stylized? Is it lldap, LLDAP, ...? I see it written in different ways in different locations.

@nitnelave
Copy link
Member

In terms of style, I usually use LLDAP in prose, and lldap in code.

@cyprienflx
Copy link

if you want use socket with postgresql :

- LLDAP_DATABASE_URL=postgres://DB_USER:DB_PASSWORD@localhost:5432/DB_NAME?host=/var/run/postgresql

replace :

  • DB_USER
  • DB_PASSWORD
  • DB_NAME
  • /var/run/postgresql

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend Issues that require a backend change enhancement New feature or request ldap rust Pull requests that update Rust code
Projects
None yet
Development

No branches or pull requests

4 participants