feat(config): implement multi-tenant config system (DAW/furt#89)

- nginx-style furt.conf configuration
- Multi-tenant mail routing per API key
- Custom SMTP support per customer
- Backward compatibility via server.lua adapter

WIP: Ready for testing on werner
This commit is contained in:
michael 2025-08-15 16:18:55 +02:00
parent be3b9614d0
commit 3ed921312f
5 changed files with 625 additions and 86 deletions

90
config/furt.conf.example Normal file
View file

@ -0,0 +1,90 @@
# furt.conf - Multi-Tenant Configuration Example
# Dragons@Work Digital Sovereignty Project
# Server configuration
[server]
host = 127.0.0.1
port = 8080
log_level = info
# Default SMTP settings (used when API keys don't have custom SMTP)
[smtp_default]
host = mail.dragons-at-work.de
port = 465
user = noreply@dragons-at-work.de
password = your-smtp-password-here
use_ssl = true
# Dragons@Work Website
[api_key "daw-frontend-key"]
name = "Dragons@Work Website"
permissions = mail:send
allowed_ips = 127.0.0.1, 10.0.0.0/8, 192.168.0.0/16
mail_to = admin@dragons-at-work.de
mail_from = noreply@dragons-at-work.de
mail_subject_prefix = "[DAW Contact] "
# Biocodie Website (same SMTP, different recipient)
[api_key "bio-frontend-key"]
name = "Biocodie Website"
permissions = mail:send
allowed_ips = 127.0.0.1, 10.0.0.0/8
mail_to = contact@biocodie.de
mail_from = noreply@biocodie.de
mail_subject_prefix = "[Biocodie] "
# Verlag Website
[api_key "verlag-frontend-key"]
name = "Verlag Dragons@Work"
permissions = mail:send
allowed_ips = 127.0.0.1, 10.0.0.0/8
mail_to = verlag@dragons-at-work.de
mail_from = noreply@verlag.dragons-at-work.de
mail_subject_prefix = "[Verlag] "
# Customer with custom SMTP
[api_key "kunde-x-frontend-key"]
name = "Kunde X Website"
permissions = mail:send
allowed_ips = 1.2.3.4/32, 5.6.7.8/32
mail_to = info@kunde-x.de
mail_from = noreply@kunde-x.de
mail_subject_prefix = "[Kunde X] "
# Custom SMTP for this customer
mail_smtp_host = mail.kunde-x.de
mail_smtp_port = 587
mail_smtp_user = noreply@kunde-x.de
mail_smtp_pass = kunde-x-smtp-password
mail_smtp_ssl = true
# Customer with external provider (e.g., Gmail)
[api_key "kunde-y-frontend-key"]
name = "Kunde Y Website"
permissions = mail:send
allowed_ips = 9.10.11.12/32
mail_to = support@kunde-y.com
mail_from = website@kunde-y.com
mail_subject_prefix = "[Kunde Y Support] "
# Gmail SMTP example
mail_smtp_host = smtp.gmail.com
mail_smtp_port = 587
mail_smtp_user = website@kunde-y.com
mail_smtp_pass = gmail-app-password
mail_smtp_ssl = true
# Admin API key (full access for management)
[api_key "admin-management-key"]
name = "Admin Access"
permissions = *, mail:send, auth:status
allowed_ips = 127.0.0.1, 10.0.0.0/8
mail_to = admin@dragons-at-work.de
mail_from = furt-admin@dragons-at-work.de
mail_subject_prefix = "[Furt Admin] "
# Monitoring key (limited access)
[api_key "monitoring-health-key"]
name = "Monitoring Service"
permissions = health:check
allowed_ips = 127.0.0.1, 10.0.0.0/8, 172.16.0.0/12
# No mail config needed for monitoring

View file

@ -1,25 +1,30 @@
-- config/server.lua
-- Server configuration for Furt Lua HTTP-Server
-- Multi-Tenant server configuration using nginx-style config parser
-- Dragons@Work Digital Sovereignty Project
return {
-- HTTP Server settings
host = "127.0.0.1",
port = 8080,
local ConfigParser = require("src.config_parser")
-- Timeouts (seconds)
client_timeout = 10,
-- Load configuration from furt.conf
local config = ConfigParser.load_config()
-- Add legacy compatibility and runtime enhancements
local server_config = {
-- HTTP Server settings (from [server] section)
host = config.server.host,
port = config.server.port,
-- Timeouts and limits
client_timeout = config.server.client_timeout or 10,
-- CORS Configuration
cors = {
-- Default allowed origins for development
-- Override in production with CORS_ALLOWED_ORIGINS environment variable
allowed_origins = (function()
local env_origins = os.getenv("CORS_ALLOWED_ORIGINS")
if env_origins then
-- Parse comma-separated list from environment
local origins = {}
for origin in env_origins:gmatch("([^,]+)") do
table.insert(origins, origin:match("^%s*(.-)%s*$")) -- trim whitespace
table.insert(origins, origin:match("^%s*(.-)%s*$"))
end
return origins
else
@ -35,54 +40,40 @@ return {
},
-- Logging
log_level = "info",
log_requests = true,
log_level = config.server.log_level or "info",
log_requests = config.server.log_requests or true,
-- API-Key-Authentifizierung (PRODUCTION READY)
api_keys = {
-- Hugo Frontend API-Key (für Website-Formulare)
[os.getenv("HUGO_API_KEY") or "hugo-dev-key-change-in-production"] = {
name = "Hugo Frontend",
permissions = {"mail:send"},
allowed_ips = {
"127.0.0.1", -- Localhost
"10.0.0.0/8", -- Private network
"192.168.0.0/16", -- Private network
"172.16.0.0/12" -- Private network
}
},
-- API Keys (converted from nginx-style to old format for backward compatibility)
api_keys = config.api_keys,
-- Admin API-Key (für Testing und Management)
[os.getenv("ADMIN_API_KEY") or "admin-dev-key-change-in-production"] = {
name = "Admin Access",
permissions = {"*"}, -- All permissions
allowed_ips = {
"127.0.0.1", -- Local only for admin
"10.0.0.0/8" -- Internal network
}
},
-- Default SMTP config (for legacy compatibility)
mail = config.smtp_default,
-- Optional: Monitoring API-Key (nur Health-Checks)
[os.getenv("MONITORING_API_KEY") or "monitoring-dev-key"] = {
name = "Monitoring Service",
permissions = {"monitoring:health"},
allowed_ips = {
"127.0.0.1",
"10.0.0.0/8",
"172.16.0.0/12"
}
}
},
-- Multi-tenant mail configuration function
get_mail_config_for_api_key = function(api_key)
return ConfigParser.get_mail_config_for_api_key(config, api_key)
end,
-- Mail configuration (for SMTP integration)
mail = {
smtp_server = os.getenv("SMTP_HOST") or "mail.example.org",
smtp_port = tonumber(os.getenv("SMTP_PORT")) or 465,
use_ssl = true,
username = os.getenv("SMTP_USERNAME"),
password = os.getenv("SMTP_PASSWORD"),
from_address = os.getenv("SMTP_FROM") or "noreply@example.org",
to_address = os.getenv("SMTP_TO") or "admin@example.org"
}
-- Raw config access (for advanced usage)
raw_config = config
}
-- Print configuration summary on load
print("Furt Multi-Tenant Configuration Loaded:")
print(" Server: " .. server_config.host .. ":" .. server_config.port)
print(" Log Level: " .. server_config.log_level)
print(" Default SMTP: " .. (config.smtp_default.host or "not configured"))
local api_key_count = 0
for key_name, key_config in pairs(config.api_keys) do
api_key_count = api_key_count + 1
local smtp_info = ""
if key_config.mail_smtp_host then
smtp_info = " (custom SMTP: " .. key_config.mail_smtp_host .. ")"
end
print(" API Key: " .. key_config.name .. " -> " .. key_config.mail_to .. smtp_info)
end
print(" Total API Keys: " .. api_key_count)
return server_config