diff --git a/.package/docker-compose.yml b/.package/docker-compose.yml index 839a45e89..778749dd5 100644 --- a/.package/docker-compose.yml +++ b/.package/docker-compose.yml @@ -13,6 +13,8 @@ services: - "53:53/udp" - "80:80" - "389:389" + - "3268:3268" + - "3269:3269" - "443:443" - "464:464" - "636:636" @@ -67,8 +69,6 @@ services: depends_on: - api_server - - migrations: image: ghcr.io/multidirectorylab/multidirectory:${VERSION:-latest} container_name: multidirectory_migrations @@ -127,7 +127,7 @@ services: - traefik.tcp.routers.ldaps.tls.certResolver=md-resolver - traefik.tcp.services.ldaps.loadbalancer.server.port=636 - traefik.tcp.services.ldaps.loadbalancer.proxyprotocol.version=2 - + cldap_server: image: ghcr.io/multidirectorylab/multidirectory:${VERSION:-latest} restart: unless-stopped @@ -155,6 +155,52 @@ services: - traefik.udp.routers.cldap.service=cldap - traefik.udp.services.cldap.loadbalancer.server.port=389 + global_ldap_server: + image: ghcr.io/multidirectorylab/multidirectory:${VERSION:-latest} + restart: unless-stopped + deploy: + mode: replicated + replicas: 2 + endpoint_mode: dnsrr + resources: + reservations: + cpus: "0.25" + memory: 100M + environment: + - SERVICE_NAME=global_ldap_server + volumes: + - ./app:/app + - ./certs:/certs + - ldap_keytab:/LDAP_keytab/ + env_file: local.env + command: python -OO multidirectory.py --global_ldap_server + tty: true + depends_on: + migrations: + condition: service_completed_successfully + healthcheck: + test: ["CMD-SHELL", "nc -zv 127.0.0.1 3268 3269"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 3s + labels: + - traefik.enable=true + + - traefik.tcp.routers.global_ldap.rule=HostSNI(`*`) + - traefik.tcp.routers.global_ldap.entrypoints=global_ldap + - traefik.tcp.routers.global_ldap.service=global_ldap + - traefik.tcp.services.global_ldap.loadbalancer.server.port=3268 + - traefik.tcp.services.global_ldap.loadbalancer.proxyprotocol.version=2 + + - traefik.tcp.routers.global_ldap_tls.rule=HostSNI(`*`) + - traefik.tcp.routers.global_ldap_tls.entrypoints=global_ldap_tls + - traefik.tcp.routers.global_ldap_tls.service=global_ldap_tls + - traefik.tcp.routers.global_ldap_tls.tls=true + - traefik.tcp.routers.global_ldap_tls.tls.certresolver=md-resolver + - traefik.tcp.services.global_ldap_tls.loadbalancer.server.port=3269 + - traefik.tcp.services.global_ldap_tls.loadbalancer.proxyprotocol.version=2 + api_server: image: ghcr.io/multidirectorylab/multidirectory:${VERSION:-latest} container_name: multidirectory_api diff --git a/.package/traefik.yml b/.package/traefik.yml index 77c0f9594..bb8d711de 100644 --- a/.package/traefik.yml +++ b/.package/traefik.yml @@ -24,6 +24,14 @@ entryPoints: address: ":389" proxyProtocol: insecure: true + global_ldap: + address: ":3268" + proxyProtocol: + insecure: true + global_ldap_tls: + address: ":3269" + proxyProtocol: + insecure: true ldaps: address: ":636" proxyProtocol: diff --git a/app/config.py b/app/config.py index e5b82da31..423eb2bf8 100644 --- a/app/config.py +++ b/app/config.py @@ -41,6 +41,8 @@ class Settings(BaseModel): PORT: int = 389 TLS_PORT: int = 636 HTTP_PORT: int = 8000 + GLOBAL_LDAP_PORT: int = 3268 + GLOBAL_LDAP_TLS_PORT: int = 3269 USE_CORE_TLS: bool = False LDAP_LOAD_SSL_CERT: bool = False @@ -197,6 +199,23 @@ def get_copy_4_tls(self) -> "Settings": tls_settings.PORT = tls_settings.TLS_PORT return tls_settings + def get_copy_4_global(self) -> "Settings": + """Create a copy for global LDAP server.""" + from copy import copy + + global_settings = copy(self) + global_settings.PORT = global_settings.GLOBAL_LDAP_PORT + return global_settings + + def get_copy_4_global_tls(self) -> "Settings": + """Create a copy for global LDAP server with TLS.""" + from copy import copy + + global_tls_settings = copy(self) + global_tls_settings.USE_CORE_TLS = True + global_tls_settings.PORT = global_tls_settings.GLOBAL_LDAP_TLS_PORT + return global_tls_settings + def check_certs_exist(self) -> bool: """Check if certs exist.""" return os.path.exists(self.SSL_CERT) and os.path.exists(self.SSL_KEY) diff --git a/app/ioc.py b/app/ioc.py index 3ad06c6b4..c111396dd 100644 --- a/app/ioc.py +++ b/app/ioc.py @@ -704,6 +704,46 @@ async def get_session( await session.disconnect() +class GlobalLDAPServerProvider(Provider): + """Provider with session scope.""" + + scope = Scope.SESSION + + @provide(scope=Scope.SESSION, provides=LDAPSession) + async def get_session( + self, + storage: SessionStorage, + ) -> AsyncIterator[LDAPSession]: + """Create ldap session.""" + session = LDAPSession(storage=storage) + await session.start() + yield session + await session.disconnect() + + bind_request_context = provide( + LDAPBindRequestContext, + scope=Scope.REQUEST, + ) + search_request_context = provide( + LDAPSearchRequestContext, + scope=Scope.REQUEST, + ) + unbind_request_context = provide( + LDAPUnbindRequestContext, + scope=Scope.REQUEST, + ) + + network_policy_validator = provide( + NetworkPolicyValidatorGateway, + provides=NetworkPolicyValidatorProtocol, + scope=Scope.REQUEST, + ) + network_policy_validator_use_case = provide( + NetworkPolicyValidatorUseCase, + scope=Scope.REQUEST, + ) + + class MFACredsProvider(Provider): """Creds provider.""" diff --git a/app/multidirectory.py b/app/multidirectory.py index 613dce878..88ffa955f 100644 --- a/app/multidirectory.py +++ b/app/multidirectory.py @@ -41,6 +41,7 @@ from extra.dump_acme_certs import dump_acme_cert from ioc import ( EventSenderProvider, + GlobalLDAPServerProvider, HTTPProvider, LDAPServerProvider, MainProvider, @@ -214,6 +215,28 @@ async def cldap_factory(settings: Settings) -> None: await CLDAPUDPServer(settings, container).start() +async def global_ldap_server_factory(settings: Settings) -> None: + """Run global_ldap_server_factory.""" + servers = [] + + for setting in ( + settings.get_copy_4_global(), + settings.get_copy_4_global_tls(), + ): + container = make_async_container( + GlobalLDAPServerProvider(), + MainProvider(), + MFAProvider(), + MFACredsProvider(), + context={Settings: setting}, + ) + + settings = await container.get(Settings) + servers.append(PoolClientHandler(settings, container).start()) + + await asyncio.gather(*servers) + + async def event_handler_factory(settings: Settings) -> None: """Run event handler.""" main_container = make_async_container( @@ -244,6 +267,10 @@ async def event_sender_factory(settings: Settings) -> None: ldap = partial(run_entrypoint, factory=ldap_factory) cldap = partial(run_entrypoint, factory=cldap_factory) +global_ldap_server = partial( + run_entrypoint, + factory=global_ldap_server_factory, +) scheduler = partial(run_entrypoint, factory=scheduler_factory) create_shadow_app = partial(create_prod_app, factory=_create_shadow_app) event_handler = partial(run_entrypoint, factory=event_handler_factory) @@ -257,6 +284,11 @@ async def event_sender_factory(settings: Settings) -> None: group = parser.add_mutually_exclusive_group(required=True) group.add_argument("--ldap", action="store_true", help="Run ldap") group.add_argument("--cldap", action="store_true", help="Run cldap") + group.add_argument( + "--global_ldap_server", + action="store_true", + help="Run global_ldap_server", + ) group.add_argument("--http", action="store_true", help="Run http") group.add_argument("--shadow", action="store_true", help="Run http") group.add_argument("--scheduler", action="store_true", help="Run tasks") @@ -286,9 +318,12 @@ async def event_sender_factory(settings: Settings) -> None: if args.ldap: ldap(settings=settings) - if args.cldap: + elif args.cldap: cldap(settings=settings) + elif args.global_ldap_server: + global_ldap_server(settings=settings) + elif args.event_sender: event_sender(settings=settings) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index a562245b7..1373e1744 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -121,6 +121,59 @@ services: - traefik.udp.routers.cldap.service=cldap - traefik.udp.services.cldap.loadbalancer.server.port=389 + global_ldap_server: + image: multidirectory + restart: unless-stopped + build: + context: . + dockerfile: ./.docker/dev.Dockerfile + args: + DOCKER_BUILDKIT: 1 + target: runtime + deploy: + mode: replicated + replicas: 2 + endpoint_mode: dnsrr + resources: + reservations: + cpus: "0.25" + memory: 100M + environment: + - SERVICE_NAME=global_ldap_server + volumes: + - ./app:/app + - ./certs:/certs + - ldap_keytab:/LDAP_keytab/ + env_file: local.env + command: python -OO multidirectory.py --global_ldap_server + tty: true + depends_on: + migrations: + condition: service_completed_successfully + cert_local_check: + condition: service_completed_successfully + healthcheck: + test: ["CMD-SHELL", "nc -zv 127.0.0.1 3268 3269"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 3s + labels: + - traefik.enable=true + + - traefik.tcp.routers.global_ldap.rule=HostSNI(`*`) + - traefik.tcp.routers.global_ldap.entrypoints=global_ldap + - traefik.tcp.routers.global_ldap.service=global_ldap + - traefik.tcp.services.global_ldap.loadbalancer.server.port=3268 + - traefik.tcp.services.global_ldap.loadbalancer.proxyprotocol.version=2 + + - traefik.tcp.routers.global_ldap_tls.rule=HostSNI(`*`) + - traefik.tcp.routers.global_ldap_tls.entrypoints=global_ldap_tls + - traefik.tcp.routers.global_ldap_tls.service=global_ldap_tls + - traefik.tcp.routers.global_ldap_tls.tls=true + - traefik.tcp.routers.global_ldap_tls.tls.certresolver=md-resolver + - traefik.tcp.services.global_ldap_tls.loadbalancer.server.port=3269 + - traefik.tcp.services.global_ldap_tls.loadbalancer.proxyprotocol.version=2 cert_local_check: image: multidirectory @@ -313,7 +366,7 @@ services: condition: service_healthy restart: true command: krb5kdc -n - + ports: - "88:88" - "88:88/udp" @@ -447,4 +500,4 @@ volumes: dns_server_file: dns_server_config: ldap_keytab: - dragonflydata: \ No newline at end of file + dragonflydata: diff --git a/docker-compose.yml b/docker-compose.yml index 891095345..2bc4dce87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,8 @@ services: - "8080:8080" - "389:389" - "389:389/udp" + - "3268:3268" + - "3269:3269" - "636:636" - "749:749" - "464:464" @@ -113,6 +115,59 @@ services: - traefik.udp.routers.cldap.service=cldap - traefik.udp.services.cldap.loadbalancer.server.port=389 + global_ldap_server: + image: multidirectory + restart: unless-stopped + build: + context: . + dockerfile: ./.docker/dev.Dockerfile + args: + DOCKER_BUILDKIT: 1 + target: runtime + deploy: + mode: replicated + replicas: 2 + endpoint_mode: dnsrr + resources: + reservations: + cpus: "0.25" + memory: 100M + environment: + - SERVICE_NAME=global_ldap_server + volumes: + - ./app:/app + - ./certs:/certs + - ldap_keytab:/LDAP_keytab/ + env_file: local.env + command: python -OO multidirectory.py --global_ldap_server + tty: true + depends_on: + migrations: + condition: service_completed_successfully + cert_local_check: + condition: service_completed_successfully + healthcheck: + test: ["CMD-SHELL", "nc -zv 127.0.0.1 3268 3269"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 3s + labels: + - traefik.enable=true + + - traefik.tcp.routers.global_ldap.rule=HostSNI(`*`) + - traefik.tcp.routers.global_ldap.entrypoints=global_ldap + - traefik.tcp.routers.global_ldap.service=global_ldap + - traefik.tcp.services.global_ldap.loadbalancer.server.port=3268 + - traefik.tcp.services.global_ldap.loadbalancer.proxyprotocol.version=2 + + - traefik.tcp.routers.global_ldap_tls.rule=HostSNI(`*`) + - traefik.tcp.routers.global_ldap_tls.entrypoints=global_ldap_tls + - traefik.tcp.routers.global_ldap_tls.service=global_ldap_tls + - traefik.tcp.routers.global_ldap_tls.tls=true + - traefik.tcp.services.global_ldap_tls.loadbalancer.server.port=3269 + - traefik.tcp.services.global_ldap_tls.loadbalancer.proxyprotocol.version=2 + api: image: multidirectory container_name: multidirectory_api @@ -159,7 +214,7 @@ services: postgres: condition: service_healthy restart: true - + cert_check: image: multidirectory container_name: multidirectory_certs_check diff --git a/interface b/interface index f31962020..017b7f344 160000 --- a/interface +++ b/interface @@ -1 +1 @@ -Subproject commit f31962020a6689e6a4c61fb3349db5b5c7895f92 +Subproject commit 017b7f344e290814e3af5ca0f210a592afaf08ed diff --git a/traefik.yml b/traefik.yml index 7b2384086..f95bf72f3 100644 --- a/traefik.yml +++ b/traefik.yml @@ -22,6 +22,14 @@ entryPoints: address: ":636" proxyProtocol: insecure: true + global_ldap: + address: ":3268" + proxyProtocol: + insecure: true + global_ldap_tls: + address: ":3269" + proxyProtocol: + insecure: true kadmind: address: ":749" kpasswd: