Infra
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
-- ==========================================
|
||||
-- GardenPlan – PostgreSQL Init Script
|
||||
-- Erstellt Keycloak-Datenbank & -Benutzer
|
||||
-- ==========================================
|
||||
|
||||
CREATE DATABASE keycloak_db;
|
||||
CREATE USER keycloak WITH PASSWORD 'keycloak_secret';
|
||||
GRANT ALL PRIVILEGES ON DATABASE keycloak_db TO keycloak;
|
||||
ALTER USER keycloak CREATEDB;
|
||||
@@ -0,0 +1,377 @@
|
||||
{
|
||||
"id": "gardenplan-realm",
|
||||
"realm": "gardenplan",
|
||||
"displayName": "GardenPlan",
|
||||
"displayNameHtml": "<div class=\"kc-logo-text\"><span>GardenPlan</span></div>",
|
||||
"notBefore": 0,
|
||||
"defaultSignatureAlgorithm": "RS256",
|
||||
"revokeRefreshToken": false,
|
||||
"refreshTokenMaxReuse": 0,
|
||||
"accessTokenLifespan": 3600,
|
||||
"accessTokenLifespanForImplicitFlow": 900,
|
||||
"ssoSessionIdleTimeout": 3600,
|
||||
"ssoSessionMaxLifespan": 86400,
|
||||
"ssoSessionIdleTimeoutRememberMe": 0,
|
||||
"ssoSessionMaxLifespanRememberMe": 0,
|
||||
"offlineSessionIdleTimeout": 2592000,
|
||||
"offlineSessionMaxLifespanEnabled": false,
|
||||
"offlineSessionMaxLifespan": 5184000,
|
||||
"clientSessionIdleTimeout": 0,
|
||||
"clientSessionMaxLifespan": 0,
|
||||
"clientOfflineSessionIdleTimeout": 0,
|
||||
"clientOfflineSessionMaxLifespan": 0,
|
||||
"accessCodeLifespan": 60,
|
||||
"accessCodeLifespanUserAction": 300,
|
||||
"accessCodeLifespanLogin": 1800,
|
||||
"actionTokenGeneratedByAdminLifespan": 43200,
|
||||
"actionTokenGeneratedByUserLifespan": 3600,
|
||||
"oauth2DeviceCodeLifespan": 600,
|
||||
"oauth2DevicePollingInterval": 5,
|
||||
"enabled": true,
|
||||
"sslRequired": "external",
|
||||
"registrationAllowed": true,
|
||||
"registrationEmailAsUsername": false,
|
||||
"rememberMe": false,
|
||||
"verifyEmail": false,
|
||||
"loginWithEmailAllowed": true,
|
||||
"duplicateEmailsAllowed": false,
|
||||
"resetPasswordAllowed": false,
|
||||
"editUsernameAllowed": false,
|
||||
"bruteForceProtected": false,
|
||||
"permanentLockout": false,
|
||||
"maxTemporaryLockouts": 0,
|
||||
"maxFailureWaitSeconds": 900,
|
||||
"minimumQuickLoginWaitSeconds": 60,
|
||||
"waitIncrementSeconds": 60,
|
||||
"quickLoginCheckMilliSlots": 144,
|
||||
"quickLoginCheckMilliDetails": 200,
|
||||
"bruteForceStrategy": "MULTI_USER",
|
||||
"resetPasswordTimeout": 0,
|
||||
"defaultRole": {
|
||||
"id": "gardenplan-default-role",
|
||||
"name": "default-roles-gardenplan",
|
||||
"description": "${role_default-roles}",
|
||||
"type": "DEFAULT",
|
||||
"scope": "GLOBAL"
|
||||
},
|
||||
"requiredCredentials": [
|
||||
"password"
|
||||
],
|
||||
"otpPolicyType": "totp",
|
||||
"otpPolicyAlgorithm": "HmacSHA1",
|
||||
"otpPolicyInitialCounter": 0,
|
||||
"otpPolicyDigits": 6,
|
||||
"otpPolicyLookAheadWindow": 1,
|
||||
"otpPolicyPeriod": 30,
|
||||
"otpSupportedApplications": [
|
||||
"FreeOTP",
|
||||
"Google Authenticator"
|
||||
],
|
||||
"localizationTexts": {},
|
||||
"webAuthnChallengeUsage": "per-session",
|
||||
"identityProviderAliases": {},
|
||||
"users": [
|
||||
{
|
||||
"id": "test-user-001",
|
||||
"username": "testuser",
|
||||
"enabled": true,
|
||||
"emailVerified": true,
|
||||
"email": "testuser@gardenplan.local",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "testpassword123!",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"roles": {
|
||||
"client": {
|
||||
"symfony-app": [
|
||||
"uma_authorization"
|
||||
]
|
||||
},
|
||||
"realm": [
|
||||
"default-roles-gardenplan",
|
||||
"offline_access",
|
||||
"uma_authorization"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"id": "symfony-app-client",
|
||||
"clientId": "symfony-app",
|
||||
"name": "Symfony GardenPlan API",
|
||||
"description": "Backend REST-API Client für GardenPlan",
|
||||
"enabled": true,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "changeme_client_secret",
|
||||
"baseUrl": "http://localhost/",
|
||||
"redirectUris": [
|
||||
"http://localhost/*",
|
||||
"http://127.0.0.1/*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"+"
|
||||
],
|
||||
"grantTypes": [
|
||||
"authorization_code",
|
||||
"refresh_token",
|
||||
"client_credentials",
|
||||
"implicit"
|
||||
],
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": true,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"serviceAccountsEnabled": true,
|
||||
"publicClient": false,
|
||||
"frontchannelLogout": true,
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"client.secret.creation.time": "1700000000",
|
||||
"oauth2.device.authorization.grant.enabled": "false",
|
||||
"backchannel.logout.revoke.offline.tokens": "false",
|
||||
"backchannel.logout.session.required": "true",
|
||||
"client_credentials.use_refresh_token": "false",
|
||||
"login.jansendata": "{}"
|
||||
},
|
||||
"authenticationFlowBindingOverrides": {},
|
||||
"fullScopeAllowed": true,
|
||||
"nodeReRegistrationTimeout": -1,
|
||||
"defaultClientScopes": [
|
||||
"web-origins",
|
||||
"roles",
|
||||
"profile",
|
||||
"email"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"address",
|
||||
"phone",
|
||||
"offline_access",
|
||||
"microprofile-jwt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "frontend-client",
|
||||
"clientId": "gardenplan-frontend",
|
||||
"name": "GardenPlan Frontend (React/Vue)",
|
||||
"description": "Frontend SPA Client für GardenPlan",
|
||||
"enabled": true,
|
||||
"publicClient": true,
|
||||
"baseUrl": "http://localhost:3000/",
|
||||
"redirectUris": [
|
||||
"http://localhost:3000/*",
|
||||
"http://127.0.0.1:3000/*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000"
|
||||
],
|
||||
"grantTypes": [
|
||||
"authorization_code",
|
||||
"implicit"
|
||||
],
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": false,
|
||||
"serviceAccountsEnabled": false,
|
||||
"frontchannelLogout": true,
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"oidc.ciba.grant.enabled": "false",
|
||||
"oauth2.device.authorization.grant.enabled": "false",
|
||||
"backchannel.logout.revoke.offline.tokens": "false",
|
||||
"backchannel.logout.session.required": "true"
|
||||
},
|
||||
"authenticationFlowBindingOverrides": {},
|
||||
"fullScopeAllowed": true,
|
||||
"defaultClientScopes": [
|
||||
"web-origins",
|
||||
"roles",
|
||||
"profile",
|
||||
"email"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"address",
|
||||
"phone",
|
||||
"offline_access",
|
||||
"microprofile-jwt"
|
||||
]
|
||||
}
|
||||
],
|
||||
"clientScopes": [
|
||||
{
|
||||
"id": "scope-email",
|
||||
"name": "email",
|
||||
"description": "OpenID Connect built-in scope: email",
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"include.in.token.scope": "true",
|
||||
"consent.screen.text": "${emailScopeConsentText}",
|
||||
"display.on.consent.screen": "true"
|
||||
},
|
||||
"icons": {},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"id": "mapper-email",
|
||||
"name": "email",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"userinfo.token.claim": "true",
|
||||
"user.attribute": "email",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "email",
|
||||
"jsonType.label": "String",
|
||||
"multivalued": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "mapper-email-verified",
|
||||
"name": "email verified",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"userinfo.token.claim": "true",
|
||||
"user.attribute": "emailVerified",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "email_verified",
|
||||
"jsonType.label": "boolean",
|
||||
"multivalued": "false"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "scope-profile",
|
||||
"name": "profile",
|
||||
"description": "OpenID Connect built-in scope: profile",
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"include.in.token.scope": "true",
|
||||
"consent.screen.text": "${profileScopeConsentText}",
|
||||
"display.on.consent.screen": "true"
|
||||
},
|
||||
"icons": {},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"id": "mapper-profile-name",
|
||||
"name": "full name",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-full-name-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "mapper-username",
|
||||
"name": "username",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-attribute-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "username",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "preferred_username",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "scope-roles",
|
||||
"name": "roles",
|
||||
"description": "OpenID Connect scope for role mapping",
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"include.in.token.scope": "false",
|
||||
"display.on.consent.screen": "false"
|
||||
},
|
||||
"icons": {},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"id": "mapper-client-roles",
|
||||
"name": "client roles",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-client-role-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"multivalued": "true",
|
||||
"user.attribute": "foo",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "resource_access.${client_id}.roles",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "mapper-realm-roles",
|
||||
"name": "realm roles",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-realm-role-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"multivalued": "true",
|
||||
"user.attribute": "foo",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "realm_access.roles",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "scope-web-origins",
|
||||
"name": "web-origins",
|
||||
"description": "OpenID Connect scope for web origins",
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"include.in.token.scope": "false",
|
||||
"consent.screen.text": "",
|
||||
"display.on.consent.screen": "false"
|
||||
},
|
||||
"icons": {},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"id": "mapper-web-origins",
|
||||
"name": "allowed web origins",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-allowed-origins-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "scope-offline-access",
|
||||
"name": "offline_access",
|
||||
"description": "OpenID Connect built-in scope: offline_access",
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"consent.screen.text": "${offlineAccessScopeConsentText}",
|
||||
"display.on.consent.screen": "true"
|
||||
},
|
||||
"icons": {}
|
||||
}
|
||||
],
|
||||
"defaultDefaultClientScopes": [
|
||||
"role_list",
|
||||
"profile",
|
||||
"email",
|
||||
"roles",
|
||||
"web-origins"
|
||||
],
|
||||
"defaultOptionalClientScopes": [
|
||||
"offline_access",
|
||||
"address",
|
||||
"phone"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
# ==========================================
|
||||
# GardenPlan – Nginx Konfiguration
|
||||
# Symfony Reverse Proxy + API Endpoint
|
||||
# ==========================================
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /var/www/html/public;
|
||||
|
||||
# Performance-Settings
|
||||
client_max_body_size 50M;
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
# Security Headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Default – Symfony Backend (REST API)
|
||||
location / {
|
||||
try_files $uri /index.php$is_args$args;
|
||||
}
|
||||
|
||||
# PHP-FPM Verbindung
|
||||
location ~ ^/index\.php(/|$) {
|
||||
fastcgi_pass php-fpm:9000;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param HTTPS off;
|
||||
|
||||
# PHP-FPM Timeout-Settings
|
||||
fastcgi_connect_timeout 600;
|
||||
fastcgi_send_timeout 600;
|
||||
fastcgi_read_timeout 600;
|
||||
}
|
||||
|
||||
# Verzeichnis-Zugriffe blockieren
|
||||
location ~ /^.ht {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# Assets Cache-Control
|
||||
location ~* \.(jpg|jpeg|gif|png|webp|svg|css|js|woff2?|ico)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Error Pages (optional)
|
||||
error_page 404 /error.html;
|
||||
error_page 500 502 503 504 /error.html;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
# ==========================================
|
||||
# GardenPlan – PHP-FPM Dockerfile
|
||||
# Symfony 7 / PHP 8.2 + erforderliche Extensions
|
||||
# ==========================================
|
||||
|
||||
FROM php:8.3-fpm-bookworm AS base
|
||||
|
||||
# System-Abhängigkeiten installieren
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
curl \
|
||||
libpng-dev \
|
||||
libonig-dev \
|
||||
libxml2-dev \
|
||||
libpq-dev \
|
||||
libzip-dev \
|
||||
zip \
|
||||
unzip \
|
||||
libfreetype6-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libwebp-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# PHP Extensions kompilieren & installieren
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
|
||||
&& docker-php-ext-install -j$(nproc) gd \
|
||||
&& docker-php-ext-install pdo pdo_pgsql xml zip mbstring opcache
|
||||
|
||||
# Composer installieren
|
||||
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
|
||||
RUN install-php-extensions intl apcu
|
||||
|
||||
# Node.js & npm für Frontend-Build (optional in Backend)
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npm install -g pnpm
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Symfony CLI installieren (optional, nützlich für Local-Tunnel etc.)
|
||||
RUN curl -sS https://get.symfony.com/cli/installer | bash \
|
||||
&& mv /root/.symfony5/bin/symfony /usr/local/bin/symfony
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
CMD ["php-fpm"]
|
||||
Reference in New Issue
Block a user