Skip to content
Snippets Groups Projects
Commit b0349f35 authored by Christian Elberfeld's avatar Christian Elberfeld
Browse files

remove ldap and keycloak

parent d7bdb1b1
No related branches found
No related tags found
No related merge requests found
Showing
with 1 addition and 563 deletions
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to * by self read by * search
#!/bin/bash
ldapmodify -Y EXTERNAL -H ldapi:// -f /opt/helper/acl-allow-user-self-read.ldif
ldapsearch -Y EXTERNAL -H ldapi:// -b "cn=config" "olcDatabase={1}hdb"
#!/bin/bash
# Usage: sh search_admin.sh "(objectClass=*)"
ldapsearch -h {{ int_ip4 }} -b "{{ ldap_base_dn }}" -D "{{ ldap_admin_bind_dn }}" -w "{{ ldap_admin_pass }}" -s sub "$1"
#!/bin/bash
# Usage: sh search_user.sh "testuser" "(objectClass=*)"
ldapsearch -h {{ int_ip4 }} -b "{{ ldap_base_dn }}" -D "uid=$1,ou=users,{{ ldap_base_dn }}" -W -s sub "$2"
---
- include_tasks: ../functions/get_secret.yml
with_items:
- { path: /srv/ldap/secret/ldap_admin_pass, length: 24 }
- { path: /srv/ldap/secret/ldap_readonly_pass, length: 24 }
- name: create folder struct for ldap
file:
path: "/srv/ldap/{{ item.path }}"
state: "directory"
recurse: yes
with_items:
- { path: 'database' }
- { path: 'config' }
- name: Docker Compose Konfig-Datei erstellen
template:
src: "{{ item }}"
dest: "/srv/ldap/{{ item }}"
with_items:
- docker-compose.yml
- Dockerfile
- syncrepl_exporter.yml
register: config
- name: "stop {{ servicename}} docker"
community.docker.docker_compose_v2:
project_src: "{{ basedir }}"
state: absent
when: config.changed
- name: "start {{ servicename}} docker"
community.docker.docker_compose_v2:
project_src: "{{ basedir }}"
state: present
FROM golang:1.21.6
RUN go get github.com/ThoreKr/syncrepl_exporter
EXPOSE 9328
CMD ["/go/bin/syncrepl_exporter","--path.config=/syncrepl_exporter.yml"]
services:
openldap:
image: osixia/openldap:1.3.0
restart: always
command: --loglevel debug
volumes:
- /srv/ldap/database:/var/lib/ldap
- /srv/ldap/config:/etc/ldap/slapd.d
ports:
- {{ int_ip4 }}:389:389
- {{ int_ip4 }}:636:636
environment:
- HOSTNAME={{ inventory_hostname }}-sync
- LDAP_BACKEND=hdb
- LDAP_ORGANISATION={{ ldap_org }}
- LDAP_DOMAIN={{ ldap_domain }}
- LDAP_ADMIN_PASSWORD={{ ldap_admin_pass }}
- LDAP_CONFIG_PASSWORD={{ ldap_admin_pass }}
- LDAP_READONLY_USER=true
- LDAP_READONLY_USER_USERNAME=readonly
- LDAP_READONLY_USER_PASSWORD={{ ldap_readonly_pass }}
- LDAP_TLS_VERIFY_CLIENT=never
networks:
- default
phpldapadmin:
image: osixia/phpldapadmin:0.9.0
restart: always
depends_on:
- openldap
environment:
- PHPLDAPADMIN_LDAP_HOSTS=openldap
- PHPLDAPADMIN_HTTPS=false
- PHPLDAPADMIN_TRUST_PROXY_SSL=true
labels:
- traefik.enable=true
- traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
- traefik.http.routers.{{ servicename }}.entrypoints=websecure
- traefik.http.services.{{ servicename }}.loadbalancer.server.port=80
networks:
- default
- web
networks:
web:
external: true
---
ldap:
host: 'openldap'
port: '636'
basedn: '{{ ldap_base_dn }}'
starttls: false
bind: true
bindcn: '{{ ldap_readonly_bind_dn }}'
bindpass: '{{ ldap_readonly_pass }}'
# Globale Variablen für alle produktiven Server
# Ports des LDAP Servers
ldap_port_default: 389
ldap_port_secure: 636
# IP Adresse des LDAP Servers
# Extern läuft auf dem webserver
ldap_ip_ext: 10.42.1.1
# Basis-Informationen der LDAP Konfiguration
ldap_org: Warpzone
ldap_domain: warpzone.ms
ldap_base_dn: dc=warpzone,dc=ms
ldap_admin_bind_dn: cn=admin,dc=warpzone,dc=ms
ldap_readonly_bind_dn: cn=readonly,dc=warpzone,dc=ms
ldap_group_dn: ou=groups,dc=warpzone,dc=ms
ldap_group_active_dn: cn=active,ou=groups,dc=warpzone,dc=ms
# SMTP Settings # SMTP Settings
smtp_domain: warpzone.ms smtp_domain: warpzone.ms
......
# SMTP Settings # SMTP Settings
smtp_domain: test-warpzone.de smtp_domain: test-warpzone.de
smtp_host: mailserver.test-warpzone.de smtp_host: mailserver.test-warpzone.de
......
...@@ -36,8 +36,6 @@ webserver_domains: ...@@ -36,8 +36,6 @@ webserver_domains:
- "gitlab.warpzone.ms" - "gitlab.warpzone.ms"
- "matrix.warpzone.ms" - "matrix.warpzone.ms"
- "mailserver.warpzone.ms" - "mailserver.warpzone.ms"
- "ldap.warpzone.ms"
- "keycloak.warpzone.ms"
- "md.warpzone.ms" - "md.warpzone.ms"
- "privatebin.warpzone.ms" - "privatebin.warpzone.ms"
# - "turn.warpzone.ms" # - "turn.warpzone.ms"
...@@ -84,8 +82,6 @@ alert: ...@@ -84,8 +82,6 @@ alert:
- { name: "icinga-auth-1" } - { name: "icinga-auth-1" }
- { name: "icinga-db-1" } - { name: "icinga-db-1" }
- { name: "icinga-graphite-1" } - { name: "icinga-graphite-1" }
- { name: "ldap-openldap-1" }
- { name: "ldap-phpldapadmin-1" }
- { name: "mail-admin-1" } - { name: "mail-admin-1" }
- { name: "mail-antispam-1" } - { name: "mail-antispam-1" }
- { name: "mail-certdumper-1" } - { name: "mail-certdumper-1" }
......
...@@ -291,12 +291,6 @@ ...@@ -291,12 +291,6 @@
basedir: "/srv/{{ servicename }}", basedir: "/srv/{{ servicename }}",
domain: "uffd.warpzone.ms", domain: "uffd.warpzone.ms",
} }
- {
role: common/docker_ldap, tags: [ ldap, docker_services ],
servicename: ldap,
basedir: /srv/ldap,
domain: "ldap.warpzone.ms"
}
- { - {
role: common/docker_traefik, tags: [ traefik, docker_services ], role: common/docker_traefik, tags: [ traefik, docker_services ],
servicename: traefik, servicename: traefik,
...@@ -342,12 +336,6 @@ ...@@ -342,12 +336,6 @@
basedir: /srv/hackmd, basedir: /srv/hackmd,
domain: "md.warpzone.ms" domain: "md.warpzone.ms"
} }
- {
role: webserver/docker_keycloak, tags: [ keycloak, docker_services ],
servicename: "keycloak",
basedir: /srv/keycloak,
domain: "keycloak.warpzone.ms"
}
- { - {
role: webserver/docker_mail, tags: [ mail, docker_services ], role: webserver/docker_mail, tags: [ mail, docker_services ],
servicename: mail, servicename: mail,
......
---
- include_tasks: ../functions/get_secret.yml
with_items:
- { path: /srv/shared/noreply_email_pass, length: -1 }
- { path: /srv/keycloak/keycloak_admin_pass, length: 32 }
- { path: /srv/keycloak/postgres_user_pass, length: 24 }
- name: create folder struct for keycloak
file:
path: "{{ item }}"
state: "directory"
with_items:
- /srv/keycloak/
- /srv/keycloak/db/
- /srv/keycloak/sync-group-active/
- /srv/keycloak/themes/
- /srv/keycloak/themes/keycloak/
- /srv/keycloak/themes/keycloak/account/
- /srv/keycloak/themes/keycloak/login/
- /srv/keycloak/welcome-content/
- name: Konfig-Dateien erstellen
template:
src: "{{ item }}"
dest: "/srv/keycloak/{{ item }}"
with_items:
- docker-compose.yml
- sync-group-active/Dockerfile
- sync-group-active/main.py
- themes/keycloak/account/account.ftl
- themes/keycloak/login/register.ftl
- welcome-content/index.html
- welcome-content/robots.txt
register: config
- name: stop keycloak docker
community.docker.docker_compose_v2:
project_src: /srv/keycloak/
state: absent
when: config.changed
- name: start keycloak docker
community.docker.docker_compose_v2:
project_src: /srv/keycloak/
state: present
services:
app:
# values set in configuration: noreply_email_user - noreply_email_pass - smtp_host - smtp_port
image: jboss/keycloak:16.1.1
restart: always
depends_on:
- db
volumes:
- /srv/keycloak/welcome-content:/opt/jboss/keycloak/welcome-content
- /srv/keycloak/themes/keycloak/account/account.ftl:/opt/jboss/keycloak/themes/keycloak/account/account.ftl
- /srv/keycloak/themes/keycloak/login/register.ftl:/opt/jboss/keycloak/themes/keycloak/login/register.ftl
environment:
KEYCLOAK_USER: "keycloakadmin"
KEYCLOAK_PASSWORD: "{{ keycloak_admin_pass }}"
DB_VENDOR: "POSTGRES"
DB_ADDR: "db"
DB_DATABASE: "keycloak"
DB_USER: "keycloak"
DB_PASSWORD: "{{ postgres_user_pass }}"
PROXY_ADDRESS_FORWARDING: "true"
labels:
- com.centurylinklabs.watchtower.enable=false
- traefik.enable=true
- traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
- traefik.http.routers.{{ servicename }}.entrypoints=websecure
- traefik.http.services.{{ servicename }}.loadbalancer.server.port=8080
networks:
- default
- web
db:
image: postgres:13.6
restart: always
volumes:
- /srv/keycloak/db:/var/lib/postgresql/data
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: "{{ postgres_user_pass }}"
networks:
- default
sync-group-active:
build:
context: /srv/keycloak/sync-group-active/
dockerfile: /srv/keycloak/sync-group-active/Dockerfile
restart: always
depends_on:
- app
volumes:
- /srv/keycloak/sync-group-active/:/usr/src/app/
networks:
- default
networks:
web:
external: true
FROM python:3.10-alpine3.13
RUN pip install python-keycloak
WORKDIR /usr/src/app
CMD [ "python", "/usr/src/app/main.py" ]
# Automatische Verwaltung der /active -Gruppe, damit diese auch im LDAP korrekt zugewiesen wird.
# Die Gruppe wird für legacy-Anwendungen benötigt, die lediglich auf dem LDAP basieren.
# Python API: https://pypi.org/project/python-keycloak/
import logging
from datetime import datetime, timezone
from time import sleep
from threading import Timer
from keycloak import KeycloakAdmin
# Debug flag
DEBUG = False
llevel = logging.INFO
if DEBUG:
llevel = logging.DEBUG
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S %Z', level=llevel)
# Sleep time for loops
LOOP_START_SECONDS = 60
LOOP_SLEEP_SECONDS = 4*60*60
if DEBUG:
LOOP_START_SECONDS = 20
LOOP_SLEEP_SECONDS = 30
# Keycloak Setup
KEYCLOAK_URL = "https://keycloak.warpzone.ms/auth/"
KEYCLOAK_REALM = "master"
KEYCLOAK_ADMIN_USER = "keycloakadmin"
KEYCLOAK_ADMIN_PASS = "{{ keycloak_admin_pass }}"
def main_loop():
while(True):
keycloak_admin = KeycloakAdmin(server_url=KEYCLOAK_URL, username=KEYCLOAK_ADMIN_USER, password=KEYCLOAK_ADMIN_PASS, realm_name=KEYCLOAK_REALM, verify=True)
logging.info("START: connected to keycloak")
group_active = keycloak_admin.get_group_by_path(path='/active', search_in_subgroups=False)
logging.debug("Group /active: %s" % group_active)
# Abfrage der aktiven Benutzer mit verifizierter E-Mail Adresse
# Wenn diese noch nicht die Rolle /active haben wird diese zugewiesen
users_active = keycloak_admin.get_users({ 'enabled': True, 'emailVerified': True })
for user in users_active:
logging.debug("User active %s" % user['username'])
if user['username'] == KEYCLOAK_ADMIN_USER:
continue
groups = keycloak_admin.get_user_groups(user['id'])
logging.debug(groups)
has_group = False
for group in groups:
if group['id'] == group_active['id']:
has_group = True
logging.debug("has_group = %s" % has_group)
if has_group == False:
logging.info('User: %s => Add group active' % user['username'])
keycloak_admin.group_user_add(user['id'], group_active['id'])
# Abfrage der inaktiven Benutzer und entfernen der Gruppe /active falls diese noch zugewiesen ist
users_inactive = keycloak_admin.get_users({ 'enabled': False })
for user in users_inactive:
logging.debug("User inactive %s" % user['username'])
if user['username'] == KEYCLOAK_ADMIN_USER:
continue
groups = keycloak_admin.get_user_groups(user['id'])
logging.debug(groups)
for group in groups:
if group['id'] == group_active['id']:
logging.info('User: %s => Remove group active' % user['username'])
keycloak_admin.group_user_remove(user['id'], group_active['id'])
logging.info("DONE (loop)")
# sleep and repeat
sleep(LOOP_SLEEP_SECONDS)
logging.info("START (pre-loop)")
t = Timer(LOOP_START_SECONDS, main_loop)
t.start()
t.join()
logging.info("DONE (final)")
<#import "template.ftl" as layout>
<@layout.mainLayout active='account' bodyClass='user'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("editAccountHtmlTitle")}</h2>
</div>
<div class="col-md-2 subtitle">
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
</div>
</div>
<form action="${url.accountUrl}" class="form-horizontal" method="post">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<#if !realm.registrationEmailAsUsername>
<div class="form-group ${messagesPerField.printIfExists('username','has-error')}">
<div class="col-sm-2 col-md-2">
<label for="username" class="control-label">${msg("username")}</label> <#if realm.editUsernameAllowed><span class="required">*</span></#if>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="username" name="username" <#if !realm.editUsernameAllowed>disabled="disabled"</#if> value="${(account.username!'')}"/>
</div>
</div>
</#if>
<div class="form-group ${messagesPerField.printIfExists('email','has-error')}">
<div class="col-sm-2 col-md-2">
<label for="email" class="control-label">${msg("email")}</label> <span class="required">*</span>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="email" name="email" autofocus value="${(account.email!'')}"/>
</div>
</div>
<div class="form-group">
<div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
<div class="">
<#if url.referrerURI??><a href="${url.referrerURI}">${kcSanitize(msg("backToApplication")?no_esc)}</a></#if>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Save">${msg("doSave")}</button>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Cancel">${msg("doCancel")}</button>
</div>
</div>
</div>
</form>
</@layout.mainLayout>
<#import "template.ftl" as layout>
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('firstName','lastName','email','username','password','password-confirm'); section>
<#if section = "header">
${msg("registerTitle")}
<#elseif section = "form">
<form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input type="text" id="email" class="${properties.kcInputClass!}" name="email"
value="${(register.formData.email!'')}" autocomplete="email"
aria-invalid="<#if messagesPerField.existsError('email')>true</#if>"
/>
<#if messagesPerField.existsError('email')>
<span id="input-error-email" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('email'))?no_esc}
</span>
</#if>
</div>
</div>
<#if !realm.registrationEmailAsUsername>
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input type="text" id="username" class="${properties.kcInputClass!}" name="username"
value="${(register.formData.username!'')}" autocomplete="username"
aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"
/>
<#if messagesPerField.existsError('username')>
<span id="input-error-username" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('username'))?no_esc}
</span>
</#if>
</div>
</div>
</#if>
<#if passwordRequired??>
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input type="password" id="password" class="${properties.kcInputClass!}" name="password"
autocomplete="new-password"
aria-invalid="<#if messagesPerField.existsError('password','password-confirm')>true</#if>"
/>
<#if messagesPerField.existsError('password')>
<span id="input-error-password" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password'))?no_esc}
</span>
</#if>
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="password-confirm"
class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
</div>
<div class="${properties.kcInputWrapperClass!}">
<input type="password" id="password-confirm" class="${properties.kcInputClass!}"
name="password-confirm"
aria-invalid="<#if messagesPerField.existsError('password-confirm')>true</#if>"
/>
<#if messagesPerField.existsError('password-confirm')>
<span id="input-error-password-confirm" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
${kcSanitize(messagesPerField.get('password-confirm'))?no_esc}
</span>
</#if>
</div>
</div>
</#if>
<#if recaptchaRequired??>
<div class="form-group">
<div class="${properties.kcInputWrapperClass!}">
<div class="g-recaptcha" data-size="compact" data-sitekey="${recaptchaSiteKey}"></div>
</div>
</div>
</#if>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">
<span><a href="${url.loginUrl}">${kcSanitize(msg("backToLogin"))?no_esc}</a></span>
</div>
</div>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doRegister")}"/>
</div>
</div>
</form>
</#if>
</@layout.registrationLayout>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="refresh" content="0; url=/auth/realms/master/account/" />
<meta name="robots" content="noindex, nofollow">
<script type="text/javascript">
window.location.href = "/auth/realms/master/account/"
</script>
</head>
<body>
If you are not redirected automatically, follow this <a href='/auth/realms/master/account/'>link</a>.
</body>
</html>
\ No newline at end of file
User-agent: *
Disallow:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment