diff --git a/group_vars/all/10_ports.yml b/group_vars/all/10_ports.yml index 3410ec8b..8cf87b04 100644 --- a/group_vars/all/10_ports.yml +++ b/group_vars/all/10_ports.yml @@ -18,6 +18,7 @@ ports: web-app-fusiondirectory: 4187 web-app-gitea: 4188 web-app-snipe-it: 4189 + web-app-suitecrm: 4190 ldap: svc-db-openldap: 389 http: diff --git a/roles/sys-front-inj-css/vars/main.yml b/roles/sys-front-inj-css/vars/main.yml index e3310133..1128835c 100644 --- a/roles/sys-front-inj-css/vars/main.yml +++ b/roles/sys-front-inj-css/vars/main.yml @@ -1,8 +1,8 @@ # Constants -CSS_FILES: ['default.css','bootstrap.css'] -CSS_BASE_COLOR: "{{ design.css.colors.base }}" -CSS_COUNT: 7 -CSS_SHADES: 100 +CSS_FILES: ['default.css','bootstrap.css'] +CSS_BASE_COLOR: "{{ design.css.colors.base }}" +CSS_COUNT: 7 +CSS_SHADES: 100 # Variables -css_app_dst: "{{ [cdn_paths_all.role.release.css, 'style.css'] | path_join }}" \ No newline at end of file +css_app_dst: "{{ [cdn_paths_all.role.release.css, 'style.css'] | path_join }}" \ No newline at end of file diff --git a/roles/web-app-shopware/templates/env.j2 b/roles/web-app-shopware/templates/env.j2 index e7f96d69..e6004b3c 100644 --- a/roles/web-app-shopware/templates/env.j2 +++ b/roles/web-app-shopware/templates/env.j2 @@ -1,7 +1,7 @@ # DOMAIN/URL DOMAIN={{ SHOPWARE_DOMAIN }} APP_URL="{{ domains | get_url(application_id, WEB_PROTOCOL) }}" -APP_DEBUG="{{ MODE_DEBUG | ternary(1, 0) }}" +APP_DEBUG="{{ MODE_DEBUG | bool| ternary(1, 0) }}" # Shopware APP_ENV={{ 'dev' if (ENVIRONMENT | lower) == 'development' else 'prod' }} diff --git a/roles/web-app-suitecrm/README.md b/roles/web-app-suitecrm/README.md index c1abed63..92a5fea1 100644 --- a/roles/web-app-suitecrm/README.md +++ b/roles/web-app-suitecrm/README.md @@ -2,7 +2,7 @@ ## Description -Manage your customer relationships with SuiteCRM, a powerful open-source CRM platform extending SugarCRM with advanced modules, workflows, and integrations. This role integrates SuiteCRM into the Infinito.Nexus ecosystem with centralized database, mail, LDAP and OIDC-ready SSO support. 🚀💼 +Manage your customer relationships with SuiteCRM, a powerful open-source CRM platform extending SugarCRM with advanced modules, workflows, and integrations. This role integrates SuiteCRM into the Infinito.Nexus ecosystem with centralized database, mail and LDAP-ready single sign-on integration. 🚀💼 ## Overview @@ -13,7 +13,7 @@ This Ansible role deploys SuiteCRM using Docker and the Infinito.Nexus shared st - Environment variable management through Jinja2 templates - Docker Compose orchestration for the **SuiteCRM** application container - Native **LDAP** authentication via Symfony’s LDAP configuration -- OIDC-ready wiring for integration with Keycloak or other OIDC providers (via reverse proxy or plugin) +- SSO integration via SAML / OAuth2 configured inside SuiteCRM’s Administration Panel With this role, you get a production-ready CRM environment that plugs into your existing IAM stack. @@ -22,23 +22,27 @@ With this role, you get a production-ready CRM environment that plugs into your - **Sales & Service CRM:** Accounts, Contacts, Leads, Opportunities, Cases, Campaigns and more 📊 - **Workflow Engine:** Automate business processes and notifications 🛠️ - **LDAP Authentication:** Centralize user authentication against OpenLDAP 🔐 -- **OIDC-Ready SSO:** Preconfigured OIDC environment variables for use with plugins or an OIDC reverse proxy 🌐 +- **SSO-Ready:** Integrates with SAML / OAuth2 providers (e.g. Keycloak as IdP) via SuiteCRM’s admin UI 🌐 - **Config via Templates:** Fully customizable `.env` and `docker-compose.yml` rendered via Jinja2 ⚙️ - **Health Checks & Logging:** Integrates with Infinito.Nexus health checking and journald logging 📈 - **Modular Role Composition:** Uses shared roles for DB, proxy and monitoring to keep your stack consistent 🔄 + ## Further Resources - [SuiteCRM Official Website](https://suitecrm.com/) 🌍 - [SuiteCRM Documentation](https://docs.suitecrm.com/) 📖 - [Infinito.Nexus Project Repository](https://s.infinito.nexus/code) 🔗 -## OIDC & LDAP Notes +## LDAP & SSO Notes -- **LDAP** is configured using Symfony’s environment variables (`AUTH_TYPE=ldap`, `LDAP_*`) so SuiteCRM 8+ can authenticate directly against your OpenLDAP service. -- **OIDC** is provided at the platform level (e.g. Keycloak + oauth2-proxy or a SuiteCRM OIDC plugin). - This role exposes OIDC client, issuer and endpoint settings as environment variables, so plugins or - sidecar components can consume them without duplicating configuration. +- **LDAP** is configured via environment variables (`AUTH_TYPE=ldap`, `LDAP_*`). + The role writes a `config_override.php` so SuiteCRM’s legacy backend + uses LDAP for authentication against your OpenLDAP service. + +- **SSO** in SuiteCRM 8 is handled via **SAML** (e.g. with Keycloak as IdP) and + **OAuth providers** configured in the Administration panel (for outbound email and API access). + This role does not implement full OIDC login flows; instead, you configure SAML/OAuth inside SuiteCRM’s admin UI. ## Credits diff --git a/roles/web-app-suitecrm/config/main.yml b/roles/web-app-suitecrm/config/main.yml index 8ddddfff..286221ee 100644 --- a/roles/web-app-suitecrm/config/main.yml +++ b/roles/web-app-suitecrm/config/main.yml @@ -3,9 +3,10 @@ features: css: true desktop: true ldap: true - oidc: true # OIDC via Keycloak + reverse proxy / plugin + oidc: false # OIDC isn't available, just SAML for SSO central_database: true logout: true + oauth2: true server: csp: @@ -29,13 +30,17 @@ docker: suitecrm: image: "php" version: "8.2-apache" - # Git tag from https://github.com/SuiteCRM/SuiteCRM - app_version: "7.14.8" + # Git tag from https://github.com/SuiteCRM/SuiteCRM-Core/releases + app_version: "8.9.1" name: "suitecrm" cpus: 1.5 mem_reservation: 1.2g mem_limit: 2g pids_limit: 768 + oauth2_proxy: + origin: + host: "suitecrm" + port: "80" volumes: data: suitecrm_data diff --git a/roles/web-app-suitecrm/files/docker-entrypoint-suitecrm.sh b/roles/web-app-suitecrm/files/docker-entrypoint-suitecrm.sh index 3fc687cf..622db6fa 100644 --- a/roles/web-app-suitecrm/files/docker-entrypoint-suitecrm.sh +++ b/roles/web-app-suitecrm/files/docker-entrypoint-suitecrm.sh @@ -1,49 +1,93 @@ #!/bin/sh -# Minimal SuiteCRM entrypoint for Infinito.Nexus set -eu APP_DIR="/var/www/html" WEB_USER="www-data" WEB_GROUP="www-data" +INSTALL_FLAG="${APP_DIR}/public/installed.flag" log() { printf '%s %s\n' "[suitecrm-entrypoint]" "$*" >&2; } -# Ensure application directory exists +############################################ +# 1) Sanity Checks +############################################ if [ ! -d "$APP_DIR" ]; then log "ERROR: Application directory '$APP_DIR' does not exist." exit 1 fi -# Fix permissions (best-effort, idempotent enough for small instances) -log "Adjusting permissions on ${APP_DIR} (this may take some time on first run)..." +############################################ +# 2) Permissions +############################################ +log "Adjusting file permissions..." chown -R "$WEB_USER:$WEB_GROUP" "$APP_DIR" find "$APP_DIR" -type d -exec chmod 755 {} \; find "$APP_DIR" -type f -exec chmod 644 {} \; -# Writable directories -for d in cache custom modules themes upload; do +for d in cache public/upload public/legacy/upload public/legacy/cache; do if [ -d "${APP_DIR}/${d}" ]; then chmod -R 775 "${APP_DIR}/${d}" + chown -R "$WEB_USER:$WEB_GROUP" "${APP_DIR}/${d}" fi done -# Add a simple healthcheck file -echo "OK" > "${APP_DIR}/healthcheck.html" -chown "$WEB_USER:$WEB_GROUP" "${APP_DIR}/healthcheck.html" +############################################ +# 3) Auto-Install SuiteCRM (only if not yet installed) +############################################ +if [ ! -f "$INSTALL_FLAG" ]; then + log "SuiteCRM 8 is not installed — performing automated installation..." -# (Optional) place for future auto-config (DB, LDAP, OIDC) by editing config.php + # CLI installer (SuiteCRM 8) + # Ref: ./bin/console suitecrm:app:install -u "admin" -p "pass" -U "db_user" -P "db_pass" -H "db_host" -N "db_name" -S "https://crm.example.com" -d "yes" + php bin/console suitecrm:app:install \ + -u "$SUITECRM_ADMIN_USERNAME" \ + -p "$SUITECRM_ADMIN_PASSWORD" \ + -U "$SUITECRM_DB_USER" \ + -P "$SUITECRM_DB_PASSWORD" \ + -H "$SUITECRM_DB_HOST" \ + -N "$SUITECRM_DB_NAME" \ + -S "$SUITECRM_URL" \ + -d "no" -# Hand off to CMD (Apache in foreground by default) -if [ "$#" -gt 0 ]; then - log "Executing CMD: $*" - exec "$@" + # Mark as installed + echo "installed" > "$INSTALL_FLAG" + chown "$WEB_USER:$WEB_GROUP" "$INSTALL_FLAG" + + log "SuiteCRM installation completed successfully." +else + log "SuiteCRM already installed — skipping installer." fi -# Default: start Apache HTTPD in foreground -if command -v apache2-foreground >/dev/null 2>&1; then - log "Starting apache2-foreground..." - exec apache2-foreground +############################################ +# 4) LDAP Auto-Configuration (legacy backend) +############################################ +if [ "${AUTH_TYPE:-disabled}" = "ldap" ]; then + log "Writing LDAP configuration to config_override.php" + + cat > "${APP_DIR}/public/legacy/config_override.php" < "${APP_DIR}/public/healthcheck.html" +chown "$WEB_USER:$WEB_GROUP" "${APP_DIR}/public/healthcheck.html" + +############################################ +# 6) Start Apache +############################################ +log "Starting apache2-foreground..." +exec apache2-foreground diff --git a/roles/web-app-suitecrm/templates/Dockerfile.j2 b/roles/web-app-suitecrm/templates/Dockerfile.j2 index 80bff6a9..b2e60579 100644 --- a/roles/web-app-suitecrm/templates/Dockerfile.j2 +++ b/roles/web-app-suitecrm/templates/Dockerfile.j2 @@ -10,6 +10,8 @@ RUN apt-get update && apt-get install -y \ libicu-dev \ libonig-dev \ libxml2-dev \ + libldap2-dev \ + && docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu \ && docker-php-ext-install \ mysqli \ gd \ @@ -18,6 +20,7 @@ RUN apt-get update && apt-get install -y \ mbstring \ soap \ opcache \ + ldap \ && rm -rf /var/lib/apt/lists/* # Install Apache modules @@ -25,15 +28,22 @@ RUN a2enmod rewrite headers WORKDIR /var/www/html +# Adjust Apache DocumentRoot for SuiteCRM 8 (Symfony public/ dir) +RUN sed -ri 's!/var/www/html!/var/www/html/public!g' \ + /etc/apache2/sites-available/000-default.conf \ + /etc/apache2/apache2.conf + # Install Composer COPY --from=composer:2 /usr/bin/composer /usr/bin/composer -# Download SuiteCRM source +# Download SuiteCRM 8 source from GitHub RUN set -eux; \ SUITECRM_TAG="v{{ SUITECRM_APP_VERSION }}"; \ - wget -qO /tmp/suitecrm.tar.gz "https://github.com/SuiteCRM/SuiteCRM/archive/refs/tags/${SUITECRM_TAG}.tar.gz"; \ + wget -qO /tmp/suitecrm.tar.gz \ + "https://github.com/SuiteCRM/SuiteCRM-Core/archive/refs/tags/${SUITECRM_TAG}.tar.gz"; \ tar --strip-components=1 -xzf /tmp/suitecrm.tar.gz -C /var/www/html; \ - rm /tmp/suitecrm.tar.gz + rm /tmp/suitecrm.tar.gz; \ + chmod +x bin/console # Install PHP dependencies via Composer (critical!) RUN set -eux; \ @@ -41,7 +51,8 @@ RUN set -eux; \ --no-dev \ --prefer-dist \ --no-interaction \ - --optimize-autoloader + --optimize-autoloader \ + --no-scripts # Copy entrypoint COPY {{ SUITECRM_ENTRYPOINT_SCRIPT_HOST_REL }} {{ SUITECRM_ENTRYPOINT_SCRIPT_DOCKER }} diff --git a/roles/web-app-suitecrm/templates/env.j2 b/roles/web-app-suitecrm/templates/env.j2 index 8aa9a01d..49d03344 100644 --- a/roles/web-app-suitecrm/templates/env.j2 +++ b/roles/web-app-suitecrm/templates/env.j2 @@ -4,8 +4,19 @@ ############################################# # ------------------------------------------------ -# Database +# Core Symfony / SuiteCRM 8 settings # ------------------------------------------------ +APP_ENV={{ 'dev' if (ENVIRONMENT | lower) == 'development' else 'prod' }} +APP_DEBUG="{{ MODE_DEBUG | bool| ternary(1, 0) }}" + +# ------------------------------------------------ +# Database (Symfony-style) +# ------------------------------------------------ +DATABASE_URL=mysql://{{ database_username }}:{{ database_password | urlencode }}@{{ database_host }}:{{ database_port }}/{{ database_name }} +DATABASE_DRIVER=pdo_mysql +DATABASE_SERVER_VERSION=10.11 + +# Keep legacy-style vars for external tools or debugging SUITECRM_DB_HOST={{ database_host }} SUITECRM_DB_PORT={{ database_port }} SUITECRM_DB_NAME={{ database_name }} @@ -13,12 +24,11 @@ SUITECRM_DB_USER={{ database_username }} SUITECRM_DB_PASSWORD={{ database_password }} # ------------------------------------------------ -# Initial admin account -# (SuiteCRM installer will use this; can also be set in config_override.php) +# Initial admin account (for your own tooling) # ------------------------------------------------ SUITECRM_ADMIN_USERNAME={{ applications | get_app_conf(application_id, 'users.administrator.username') }} SUITECRM_ADMIN_PASSWORD={{ applications | get_app_conf(application_id, 'credentials.administrator_password') }} -SUITECRM_ADMIN_EMAIL={{ users['contact'].email }} +SUITECRM_ADMIN_EMAIL={{ users['administrator'].email }} # Public base URL of the SuiteCRM instance SUITECRM_URL={{ SUITECRM_URL }} @@ -34,37 +44,19 @@ SUITECRM_SMTP_PROTOCOL={{ "TLS" if SYSTEM_EMAIL.START_TLS else "SSL" }} SUITECRM_EMAIL_FROM_NAME={{ applications | get_app_conf(application_id, 'email.from_name') }} # ------------------------------------------------ -# LDAP settings (optional) +# LDAP settings (native SuiteCRM 8 / Symfony) # ------------------------------------------------ {% if SUITECRM_LDAP_ENABLED | bool %} -SUITECRM_LDAP_ENABLED=true -SUITECRM_LDAP_HOST={{ LDAP.SERVER.DOMAIN }} -SUITECRM_LDAP_PORT={{ LDAP.SERVER.PORT }} -SUITECRM_LDAP_ENCRYPTION={{ LDAP.SERVER.SECURITY | lower if LDAP.SERVER.SECURITY else "none" }} -SUITECRM_LDAP_BASE_DN={{ LDAP.DN.OU.USERS }} -SUITECRM_LDAP_BIND_DN={{ LDAP.DN.ADMINISTRATOR.DATA }} -SUITECRM_LDAP_BIND_PASSWORD={{ LDAP.BIND_CREDENTIAL }} -SUITECRM_LDAP_UID_ATTR={{ LDAP.USER.ATTRIBUTES.ID }} +AUTH_TYPE=ldap +LDAP_HOST={{ LDAP.SERVER.DOMAIN }} +LDAP_PORT={{ LDAP.SERVER.PORT }} +LDAP_ENCRYPTION={{ LDAP.SERVER.SECURITY | lower if LDAP.SERVER.SECURITY else "none" }} # none|ssl|tls +LDAP_BASE_DN={{ LDAP.DN.OU.USERS }} +LDAP_BIND_DN={{ LDAP.DN.ADMINISTRATOR.DATA }} +LDAP_BIND_PASSWORD={{ LDAP.BIND_CREDENTIAL }} +LDAP_UID_KEY={{ LDAP.USER.ATTRIBUTES.ID }} # e.g. uid or mail {% else %} -SUITECRM_LDAP_ENABLED=false -{% endif %} - -# ------------------------------------------------ -# OpenID Connect settings (optional) -# ------------------------------------------------ -{% if SUITECRM_OIDC_ENABLED | bool %} -SUITECRM_OIDC_ENABLED=true -SUITECRM_OIDC_CLIENT_ID={{ OIDC.CLIENT.ID }} -SUITECRM_OIDC_CLIENT_SECRET={{ OIDC.CLIENT.SECRET }} -SUITECRM_OIDC_ISSUER_URL={{ OIDC.CLIENT.ISSUER_URL }} -SUITECRM_OIDC_AUTHORIZATION_URL={{ OIDC.CLIENT.AUTHORIZE_URL }} -SUITECRM_OIDC_TOKEN_URL={{ OIDC.CLIENT.TOKEN_URL }} -SUITECRM_OIDC_USERINFO_URL={{ OIDC.CLIENT.USER_INFO_URL }} -SUITECRM_OIDC_JWKS_URL={{ OIDC.CLIENT.CERTS }} -SUITECRM_OIDC_REDIRECT_URI={{ SUITECRM_URL }}/oidc/callback -SUITECRM_OIDC_SCOPES=openid,profile,email -{% else %} -SUITECRM_OIDC_ENABLED=false +AUTH_TYPE=disabled {% endif %} # ------------------------------------------------ diff --git a/roles/web-app-suitecrm/vars/main.yml b/roles/web-app-suitecrm/vars/main.yml index e2fac010..60704a98 100644 --- a/roles/web-app-suitecrm/vars/main.yml +++ b/roles/web-app-suitecrm/vars/main.yml @@ -24,7 +24,6 @@ SUITECRM_DATA_VOLUME: "{{ applications | get_app_conf(application_id # URLs & feature flags SUITECRM_URL: "{{ domains | get_url(application_id, WEB_PROTOCOL) }}" -SUITECRM_OIDC_ENABLED: "{{ applications | get_app_conf(application_id, 'features.oidc') }}" SUITECRM_LDAP_ENABLED: "{{ applications | get_app_conf(application_id, 'features.ldap') }}" # Simple maintenance toggle (for later extensions)