first commit

This commit is contained in:
2023-07-14 11:51:07 +02:00
commit 284dc650c4
101 changed files with 8629 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
locals {
sorted-group-names = reverse(distinct(sort([
for grp in var.user-groups: grp.name
])))
sorted-groups = flatten([
for name in local.sorted-group-names: [
for grp in var.user-groups:
grp if grp.name == name
]
])
}
data "authentik_group" "vynil-admin" {
name = "vynil-ldap-admins"
}
resource "authentik_group" "groups" {
count = length(local.sorted-groups)
name = local.sorted-groups[count.index].name
}
data "authentik_group" "readed_groups" {
depends_on = [ authentik_group.groups ]
count = length(local.sorted-groups)
name = local.sorted-groups[count.index].name
}
resource "authentik_application" "dolibarr_application_ldap" {
name = "${var.component}-${var.instance}-ldap"
slug = "${var.component}-${var.instance}-ldap"
protocol_provider = authentik_provider_ldap.dolibarr_provider_ldap.id
meta_launch_url = "blank://blank"
}
resource "authentik_policy_binding" "dolibarr_ldap_access_users" {
count = length(local.sorted-groups)
target = authentik_application.dolibarr_application_ldap.uuid
group = authentik_group.groups[count.index].id
order = count.index
}
resource "authentik_policy_binding" "dolibarr_ldap_access_ldap" {
target = authentik_application.dolibarr_application_ldap.uuid
group = authentik_group.dolibarr_ldapsearch.id
order = length(local.sorted-groups)+1
}
resource "authentik_policy_binding" "dolibarr_ldap_access_vynil" {
target = authentik_application.dolibarr_application_ldap.uuid
group = data.authentik_group.vynil-admin.id
order = length(local.sorted-groups)+2
}
resource "authentik_application" "dolibarr_application_saml" {
name = var.component==var.instance?var.component:"${var.component}-${var.instance}"
slug = "${var.component}-${var.instance}"
protocol_provider = authentik_provider_saml.dolibarr.id
meta_launch_url = format("https://%s.%s", var.sub-domain, var.domain-name)
meta_icon = format("https://%s.%s/%s", var.sub-domain, var.domain-name, "theme/dolibarr_256x256_color.png")
}
resource "authentik_policy_binding" "dolibarr_saml_access_users" {
count = length(local.sorted-groups)
target = authentik_application.dolibarr_application_saml.uuid
group = authentik_group.groups[count.index].id
order = count.index
}
resource "authentik_policy_binding" "dolibarr_saml_access_vynil" {
target = authentik_application.dolibarr_application_saml.uuid
group = data.authentik_group.vynil-admin.id
order = length(local.sorted-groups)+1
}

180
apps/dolibarr/configmap.tf Normal file
View File

@@ -0,0 +1,180 @@
data "kubernetes_ingress_v1" "authentik" {
metadata {
name = "authentik"
namespace = "${var.domain}-auth"
}
}
locals {
authentik-metadata-url="${data.kubernetes_ingress_v1.authentik.spec[0].rule[0].host}/api/v3/providers/saml/${authentik_provider_saml.dolibarr.id}/metadata/?download"
module-list = [
"user",
"ldap",
"syslog"
]
json-config = {
groups = [ for index, g in local.sorted-groups: {
name = g.name
admin = contains([for k,v in g:k], "admin")?g.admin:false
users = data.authentik_group.readed_groups[index].users_obj
}]
parameters = merge(var.parameters, {
LDAP_FIELD_FULLNAME="sAMAccountName"
LDAP_FIELD_LOGIN_SAMBA="sAMAccountName"
LDAP_FIELD_MAIL="mail"
LDAP_FIELD_NAME="sn"
LDAP_GROUP_FIELD_DESCRIPTION="sAMAccountName"
LDAP_GROUP_FIELD_FULLNAME="cn"
LDAP_GROUP_FIELD_GROUPID="gidNumber"
LDAP_GROUP_FIELD_GROUPMEMBERS="member"
LDAP_GROUP_OBJECT_CLASS="group"
LDAP_KEY_GROUPS="cn"
LDAP_KEY_USERS="cn"
LDAP_PASSWORD_HASH_TYPE="md5"
LDAP_SERVER_HOST="ak-outpost-ldap.${var.domain}-auth.svc"
LDAP_SERVER_PORT="389"
LDAP_SERVER_PROTOCOLVERSION="3"
LDAP_SERVER_TYPE="openldap"
LDAP_SERVER_DN="${local.base-dn}"
LDAP_SERVER_USE_TLS="0"
LDAP_SYNCHRO_ACTIVE="2"
LDAP_USER_OBJECT_CLASS="person"
LDAP_USER_DN=local.base-user-dn
LDAP_GROUP_DN=local.base-group-dn
LDAP_GROUP_FILTER="&(&(objectClass=groupOfNames)(|${join("",[for g in local.sorted-groups: format("(cn=%s)",g.name)])}))"
LDAP_ADMIN_DN="cn=${var.instance}-${var.component}-ldapsearch,${local.base-user-dn}"
LDAP_FILTER_CONNECTION="&(&(objectClass=inetOrgPerson)(|${join("",[for g in local.sorted-groups: format("(memberof=cn=%s,%s)",g.name,local.base-group-dn)])}))"
SAMLCONNECTOR_CREATE_UNEXISTING_USER="1"
SAMLCONNECTOR_MAPPING_USER_EMAIL="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
SAMLCONNECTOR_MAPPING_USER_FIRSTNAME="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
SAMLCONNECTOR_MAPPING_USER_LASTNAME="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
SAMLCONNECTOR_UPDATE_USER_EVERYTIME="1"
SAMLCONNECTOR_DISABLE_IDP_DISCONNECTION="1"
SAMLCONNECTOR_IDP_DISPLAY_BUTTON="1"
SAMLCONNECTOR_IDP_METADATA_SOURCE="url"
SAMLCONNECTOR_MANAGE_MULTIPLE_IDP="0"
SAMLCONNECTOR_SP_CERT_PATH="/var/saml/tls.crt"
SAMLCONNECTOR_SP_PRIV_KEY_PATH="/var/saml/tls.key"
SAMLCONNECTOR_IDP_METADATA_URL=local.authentik-metadata-url
SAMLCONNECTOR_IDP_METADATA_XML_PATH=local.authentik-metadata-url
MAIN_MODULE_SAMLCONNECTOR="1"
MAIN_MODULE_SAMLCONNECTOR_CSS="[\"\\/samlconnector\\/css\\/samlconnector.css.php\"]"
MAIN_MODULE_SAMLCONNECTOR_HOOKS="[\"mainloginpage\",\"logout\",\"samlconnectorsetup\"]"
MAIN_MODULE_SAMLCONNECTOR_JS="[\"\\/samlconnector\\/js\\/samlconnector.js.php\"]"
MAIN_MODULE_SAMLCONNECTOR_LOGIN="1"
MAIN_MODULE_SAMLCONNECTOR_MODULEFOREXTERNAL="1"
MAIN_MODULE_SAMLCONNECTOR_SUBSTITUTIONS="1"
MAIN_MODULE_SAMLCONNECTOR_TRIGGERS="1"
SYSLOG_LEVEL="${var.log-level}"
SYSLOG_FILE="/var/logs/dolibarr.log"
SYSLOG_HANDLERS="[\"mod_syslog_file\"]"
})
modules=join(",",[for i in concat(var.modules, local.module-list): format("MAIN_MODULE_%s",upper(i))])
}
}
resource "kubectl_manifest" "config-json" {
yaml_body = <<-EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: "${var.instance}-json"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
data:
"docker-php-ext-redis.ini": |-
extension = redis.so
session.save_handler = redis
session.save_path = "tcp://${var.instance}-${var.component}-redis.${var.namespace}.svc:6379/?prefix=SESSION_${var.component}_${var.instance}:"
"vynil-configurator.sh": |-
#!/bin/ash
pgsqlRun() { PGPASSWORD="$${DOLI_DB_PASSWORD:="dolibarr"}" psql -h "$${DOLI_DB_HOST:="postgres"}" -p "$${DOLI_DB_PORT}" -U "$${DOLI_DB_USER}" -w "$DOLI_DB_NAME" "$@"; }
setDBconf() { pgsqlRun -c "insert into llx_const(entity, name, type, value, visible) VALUES (1, '$1', 'chaine', '$2', 0) ON CONFLICT(entity, name) DO UPDATE SET value='$2';"; }
createUser() { pgsqlRun -c "INSERT INTO llx_user(entity, admin, employee, fk_establishment, datec, login, lastname, email, statut, fk_barcode_type, nb_holiday) VALUES (1, 0, 1, 0, NOW(), '$1', '$2', '$3', 1, 0, 0) ON CONFLICT(entity, login) DO UPDATE SET admin=0;"; }
createAdmin() { pgsqlRun -c "INSERT INTO llx_user(entity, admin, employee, fk_establishment, datec, login, lastname, email, statut, fk_barcode_type, nb_holiday) VALUES (1, 1, 0, 0, NOW(), '$1', '$2', '$3', 1, 0, 0) ON CONFLICT(entity, login) DO UPDATE SET admin=1;"; }
createGroup() { pgsqlRun -c "INSERT INTO llx_usergroup(entity, nom, datec) VALUES (1, '$1', NOW()) ON CONFLICT(entity, nom) DO NOTHING;"; }
setGroupPerm() { pgsqlRun -c "insert into llx_usergroup_rights(fk_id,fk_usergroup,entity) select d.id as fk_id, g.rowid as fk_usergroup, 1 as entity from llx_rights_def d, llx_usergroup g where d.id is not null and d.module<>'user' and g.nom='$1' ON CONFLICT(fk_id,fk_usergroup,entity) DO NOTHING;"; }
setGroupUser() { pgsqlRun -c "insert into llx_usergroup_user(entity, fk_user, fk_usergroup) select 1, u.rowid, g.rowid from llx_usergroup g, llx_user u where g.nom='$1' and u.login='$2' ON CONFLICT(entity, fk_user, fk_usergroup) DO NOTHING;"; }
configquery() { jq -r "$1" </etc/config/config.json; }
installMod() { cd /var/www/htdocs/install;php upgrade2.php 0.0.0 0.0.0 "$@"; }
groupq() { configquery ".groups[$1].$2"; }
userq() { configquery ".groups[$1].users[$2].$3"; }
dolEncrypt() {
{ php <<ENDphp
<?php
require_once "/app/htdocs/core/lib/security.lib.php";
print_r(dolEncrypt("$1"));
ENDphp
} |tail -1
}
# Set parameters
pcnt=$(configquery ".parameters|keys|length")
for i in $(seq 0 $(( $pcnt - 1)) );do
k=$(configquery ".parameters|keys[$i]")
v=$(configquery ".parameters.$k")
setDBconf "$k" "$v"
done
setDBconf LDAP_ADMIN_PASS "$(dolEncrypt $${DOLI_LDAP_ADMIN_PASS})"
setDBconf SAMLCONNECTOR_MAPPING_USER_SEARCH_KEY "$(dolEncrypt SAMLCONNECTOR_MAPPING_USER_LASTNAME)"
rm -f /var/documents/install.lock
installMod $(configquery ".modules")
touch /var/documents/install.lock
chmod 400 /var/documents/install.lock
# Create groups and users
gcnt=$(configquery ".groups | length")
for i in $(seq 0 $(( $gcnt - 1)) );do
gname=$(groupq $i name)
echo ' *** '"Creating group: $${gname}"
createGroup "$${gname}"
admin=$(groupq $i admin)
if [[ $${admin} != "true" ]];then
setGroupPerm "$${gname}"
fi
ucnt=$(groupq $i "users | length")
for j in $(seq 0 $(( $ucnt - 1)) );do
email=$(userq $i $j email)
name=$(userq $i $j name)
username=$(userq $i $j username)
if [[ $${admin} == "true" ]];then
echo ' *** '"Creating admin: $${name}"
createAdmin "$${username}" "$${name}" "$${email}"
else
echo ' *** '"Creating user: $${name}"
createUser "$${username}" "$${name}" "$${email}"
fi
setGroupUser "$${gname}" "$${username}"
done
done
>/var/logs/dolibarr.log
"config.json": |-
${jsonencode(local.json-config)}
EOF
}
resource "kubectl_manifest" "config" {
yaml_body = <<-EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: "${var.instance}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
data:
DOLI_DB_HOST: "${var.instance}-${var.component}.${var.namespace}.svc"
DOLI_DB_USER: "${var.component}"
DOLI_DB_NAME: "${var.component}"
DOLI_DB_PORT: "5432"
DOLI_DB_TYPE: "pgsql"
DOLI_ADMIN_LOGIN: "admin_${var.instance}"
DOLI_MODULES: "modSociete,modBlockedLog,modSamlConnector,modLdap"
DOLI_AUTH: "dolibarr"
DOLI_URL_ROOT: "https://${var.sub-domain}.${var.domain-name}"
DOLI_LDAP_PORT: "389"
DOLI_LDAP_VERSION: "3"
DOLI_LDAP_SERVERTYPE: "openldap"
DOLI_LDAP_LOGIN_ATTRIBUTE: "sAMAccountName"
DOLI_LDAP_FILTER: "(&(|${join("",[for g in local.sorted-groups: format("(memberof=cn=%s,%s)",g.name,local.base-group-dn)])})(|(uid=%1%)(mail=%1%)))"
DOLI_LDAP_ADMIN_LOGIN: "cn=${var.instance}-${var.component}-ldapsearch,${local.base-user-dn}"
DOLI_LDAP_DN: "${local.base-dn}"
DOLI_LDAP_HOST: "ak-outpost-ldap.${var.domain}-auth.svc"
EOF
}

185
apps/dolibarr/deploy.tf Normal file
View File

@@ -0,0 +1,185 @@
locals {
deploy-labels = merge(local.common-labels, {
"app.kubernetes.io/component" = "dolibarr"
})
}
resource "kubectl_manifest" "hpa" {
yaml_body = <<-EOF
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ${var.instance}
namespace: ${var.namespace}
labels: ${jsonencode(local.deploy-labels)}
spec:
minReplicas: ${var.hpa.min-replicas}
maxReplicas: ${var.hpa.max-replicas}
metrics:
- resource:
name: cpu
target:
averageUtilization: ${var.hpa.avg-cpu}
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ${var.instance}
EOF
}
resource "kubectl_manifest" "deploy" {
yaml_body = <<-EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${var.instance}
namespace: ${var.namespace}
labels: ${jsonencode(local.deploy-labels)}
spec:
selector:
matchLabels: ${jsonencode(local.deploy-labels)}
template:
metadata:
labels: ${jsonencode(local.deploy-labels)}
spec:
securityContext:
runAsGroup: 82
runAsUser: 82
fsGroup: 82
volumes:
- name: config-json
configMap:
name: ${kubectl_manifest.config-json.name}
- name: documents
persistentVolumeClaim:
claimName: ${kubectl_manifest.pvc.name}
- name: nginx-run
emptyDir: {}
- name: nginx-cache
emptyDir: {}
- name: shared-files
emptyDir: {}
- name: shared-logs
emptyDir: {}
- name: nginx-config
configMap:
name: ${kubectl_manifest.nginx-config.name}
- name: saml-cert
secret:
secretName: "${kubectl_manifest.saml_certificate.name}"
initContainers:
- name: configure
args:
- echo
- SUCCESS
image: "${var.images.dolibarr.registry}/${var.images.dolibarr.repository}:${var.images.dolibarr.tag}"
imagePullPolicy: "${var.images.dolibarr.pullPolicy}"
volumeMounts:
- name: shared-files
mountPath: /var/www/
- name: shared-logs
mountPath: /var/logs/
- name: documents
mountPath: /var/documents
- name: config-json
mountPath: /etc/config/config.json
subPath: config.json
- name: config-json
mountPath: /docker-entrypoint.d/vynil-configurator.sh
subPath: vynil-configurator.sh
securityContext:
runAsNonRoot: true
env:
- name: DOLI_DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: "${var.component}.${var.instance}-${var.component}.credentials.postgresql.acid.zalan.do"
envFrom:
- configMapRef:
name: "${kubectl_manifest.config.name}"
- secretRef:
name: "${kubectl_manifest.dolibarr_ldap.name}"
containers:
- name: dolibarr
command:
- "/usr/local/sbin/php-fpm"
image: "${var.images.dolibarr.registry}/${var.images.dolibarr.repository}:${var.images.dolibarr.tag}"
imagePullPolicy: "${var.images.dolibarr.pullPolicy}"
resources: ${jsonencode(var.resources)}
readinessProbe:
httpGet:
path: /index.php
port: 3000
scheme: HTTP
periodSeconds: 10
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
path: /index.php
port: 3000
scheme: HTTP
periodSeconds: 10
timeoutSeconds: 1
failureThreshold: 3
successThreshold: 1
volumeMounts:
- name: shared-logs
mountPath: /var/logs/
- name: shared-files
mountPath: /var/www/
- name: documents
mountPath: /var/documents
- name: saml-cert
mountPath: /var/saml
- name: config-json
mountPath: /usr/local/etc/php/conf.d/docker-php-ext-redis.ini
subPath: docker-php-ext-redis.ini
securityContext:
runAsNonRoot: true
env:
- name: DOLI_DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: "${var.component}.${var.instance}-${var.component}.credentials.postgresql.acid.zalan.do"
envFrom:
- configMapRef:
name: "${kubectl_manifest.config.name}"
- secretRef:
name: "${kubectl_manifest.dolibarr_ldap.name}"
- name: dolibarr-logs
command:
- "tail"
- "-f"
- "/var/logs/dolibarr.log"
image: "${var.images.dolibarr.registry}/${var.images.dolibarr.repository}:${var.images.dolibarr.tag}"
imagePullPolicy: "${var.images.dolibarr.pullPolicy}"
volumeMounts:
- name: shared-logs
mountPath: /var/logs/
- name: nginx
image: "${var.images.nginx.registry}/${var.images.nginx.repository}:${var.images.nginx.tag}"
imagePullPolicy: "${var.images.nginx.pullPolicy}"
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
ports:
- name: http
containerPort: 3000
protocol: TCP
volumeMounts:
- name: nginx-run
mountPath: /var/run
- name: nginx-cache
mountPath: /var/cache/nginx
- name: shared-files
mountPath: /var/www/
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
EOF
}

300
apps/dolibarr/index.yaml Normal file
View File

@@ -0,0 +1,300 @@
---
apiVersion: vinyl.solidite.fr/v1beta1
kind: Component
category: apps
metadata:
name: dolibarr
description: null
options:
domain-name:
default: your_company.com
examples:
- your_company.com
type: string
redis:
default:
exporter:
enabled: true
image: quay.io/opstree/redis-exporter:v1.44.0
image: quay.io/opstree/redis:v7.0.5
storage: 2Gi
examples:
- exporter:
enabled: true
image: quay.io/opstree/redis-exporter:v1.44.0
image: quay.io/opstree/redis:v7.0.5
storage: 2Gi
properties:
exporter:
default:
enabled: true
image: quay.io/opstree/redis-exporter:v1.44.0
properties:
enabled:
default: true
type: boolean
image:
default: quay.io/opstree/redis-exporter:v1.44.0
type: string
type: object
image:
default: quay.io/opstree/redis:v7.0.5
type: string
storage:
default: 2Gi
type: string
type: object
domain:
default: your-company
examples:
- your-company
type: string
ingress-class:
default: traefik
examples:
- traefik
type: string
parameters:
default:
MAIN_LANG_DEFAULT: auto
examples:
- MAIN_LANG_DEFAULT: auto
properties:
MAIN_LANG_DEFAULT:
default: auto
type: string
type: object
storage:
default:
accessMode: ReadWriteOnce
size: 10Gi
type: Filesystem
examples:
- accessMode: ReadWriteOnce
size: 10Gi
type: Filesystem
properties:
accessMode:
default: ReadWriteOnce
enum:
- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
type: string
size:
default: 10Gi
type: string
type:
default: Filesystem
enum:
- Filesystem
- block
type: string
type: object
issuer:
default: letsencrypt-prod
examples:
- letsencrypt-prod
type: string
modules:
default:
- societe
examples:
- - societe
items:
type: string
type: array
sub-domain:
default: erp
examples:
- erp
type: string
user-groups:
default:
- admin: true
name: dolibarr-admin
examples:
- - admin: true
name: dolibarr-admin
items:
properties:
admin:
type: boolean
name:
type: string
type: object
type: array
hpa:
default:
avg-cpu: 50
max-replicas: 5
min-replicas: 1
examples:
- avg-cpu: 50
max-replicas: 5
min-replicas: 1
properties:
avg-cpu:
default: 50
type: integer
max-replicas:
default: 5
type: integer
min-replicas:
default: 1
type: integer
type: object
images:
default:
dolibarr:
pullPolicy: IfNotPresent
registry: docker.io
repository: sebt3/dolibarr
tag: 17.0.1
nginx:
pullPolicy: IfNotPresent
registry: docker.io
repository: nginx
tag: alpine
examples:
- dolibarr:
pullPolicy: IfNotPresent
registry: docker.io
repository: sebt3/dolibarr
tag: 17.0.1
nginx:
pullPolicy: IfNotPresent
registry: docker.io
repository: nginx
tag: alpine
properties:
dolibarr:
default:
pullPolicy: IfNotPresent
registry: docker.io
repository: sebt3/dolibarr
tag: 17.0.1
properties:
pullPolicy:
default: IfNotPresent
type: string
registry:
default: docker.io
type: string
repository:
default: sebt3/dolibarr
type: string
tag:
default: 17.0.1
type: string
type: object
nginx:
default:
pullPolicy: IfNotPresent
registry: docker.io
repository: nginx
tag: alpine
properties:
pullPolicy:
default: IfNotPresent
type: string
registry:
default: docker.io
type: string
repository:
default: nginx
type: string
tag:
default: alpine
type: string
type: object
type: object
log-level:
default: 5
examples:
- 5
type: integer
postgres:
default:
replicas: 1
storage: 5Gi
version: '14'
examples:
- replicas: 1
storage: 5Gi
version: '14'
properties:
replicas:
default: 1
type: integer
storage:
default: 5Gi
type: string
version:
default: '14'
type: string
type: object
resources:
default:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 50m
memory: 100Mi
examples:
- limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 50m
memory: 100Mi
properties:
limits:
default:
cpu: 200m
memory: 256Mi
properties:
cpu:
default: 200m
type: string
memory:
default: 256Mi
type: string
type: object
requests:
default:
cpu: 50m
memory: 100Mi
properties:
cpu:
default: 50m
type: string
memory:
default: 100Mi
type: string
type: object
type: object
dependencies:
- dist: null
category: share
component: authentik-ldap
- dist: null
category: core
component: secret-generator
- dist: null
category: core
component: cert-manager-self-sign
- dist: null
category: dbo
component: postgresql
- dist: null
category: dbo
component: redis
providers:
kubernetes: true
authentik: true
kubectl: true
postgresql: null
restapi: true
http: true

75
apps/dolibarr/ingress.tf Normal file
View File

@@ -0,0 +1,75 @@
locals {
dns-names = ["${var.sub-domain}.${var.domain-name}"]
middlewares = ["${var.instance}-https"]
service = {
"name" = "${var.instance}"
"port" = {
"number" = 80
}
}
rules = [ for v in local.dns-names : {
"host" = "${v}"
"http" = {
"paths" = [{
"backend" = {
"service" = local.service
}
"path" = "/"
"pathType" = "Prefix"
}]
}
}]
}
resource "kubectl_manifest" "prj_certificate" {
yaml_body = <<-EOF
apiVersion: "cert-manager.io/v1"
kind: "Certificate"
metadata:
name: "${var.instance}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
secretName: "${var.instance}-cert"
dnsNames: ${jsonencode(local.dns-names)}
issuerRef:
name: "${var.issuer}"
kind: "ClusterIssuer"
group: "cert-manager.io"
EOF
}
resource "kubectl_manifest" "prj_https_redirect" {
yaml_body = <<-EOF
apiVersion: "traefik.containo.us/v1alpha1"
kind: "Middleware"
metadata:
name: "${var.instance}-https"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
redirectScheme:
scheme: "https"
permanent: true
EOF
}
resource "kubectl_manifest" "prj_ingress" {
force_conflicts = true
yaml_body = <<-EOF
apiVersion: "networking.k8s.io/v1"
kind: "Ingress"
metadata:
name: "${var.instance}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
annotations:
"traefik.ingress.kubernetes.io/router.middlewares": "${join(",", [for m in local.middlewares : format("%s-%s@kubernetescrd", var.namespace, m)])}"
spec:
ingressClassName: "${var.ingress-class}"
rules: ${jsonencode(local.rules)}
tls:
- hosts: ${jsonencode(local.dns-names)}
secretName: "${var.instance}-cert"
EOF
}

115
apps/dolibarr/ldap.tf Normal file
View File

@@ -0,0 +1,115 @@
data "kubernetes_secret_v1" "authentik" {
metadata {
name = "authentik"
namespace = "${var.domain}-auth"
}
}
locals {
base-dn = format("dc=%s", join(",dc=", split(".", format("%s.%s", var.sub-domain, var.domain-name))))
base-group-dn = format("ou=groups,%s", local.base-dn)
base-user-dn = format("ou=users,%s", local.base-dn)
authentik-token = data.kubernetes_secret_v1.authentik.data["AUTHENTIK_BOOTSTRAP_TOKEN"]
request_headers = {
"Content-Type" = "application/json"
Authorization = "Bearer ${local.authentik-token}"
}
ldap-outpost-providers = jsondecode(data.http.get_ldap_outpost.response_body).results[0].providers
ldap-outpost-pk = jsondecode(data.http.get_ldap_outpost.response_body).results[0].pk
}
resource "kubectl_manifest" "dolibarr_ldap" {
ignore_fields = ["metadata.annotations"]
yaml_body = <<-EOF
apiVersion: "secretgenerator.mittwald.de/v1alpha1"
kind: "StringSecret"
metadata:
name: "${var.instance}-${var.component}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
forceRegenerate: false
fields:
- fieldName: "DOLI_LDAP_ADMIN_PASS"
length: "32"
- fieldName: "DOLI_ADMIN_PASSWORD"
length: "32"
- fieldName: "DOLI_COOKIE_CRYPTKEY"
length: "32"
EOF
}
data "kubernetes_secret_v1" "dolibarr_ldap_password" {
depends_on = [kubectl_manifest.dolibarr_ldap]
metadata {
name = kubectl_manifest.dolibarr_ldap.name
namespace = var.namespace
}
}
resource "authentik_user" "dolibarr_ldapsearch" {
username = "${var.instance}-${var.component}-ldapsearch"
name = "${var.instance}-${var.component}-ldapsearch"
}
resource "authentik_group" "dolibarr_ldapsearch" {
name = "${var.instance}-${var.component}-ldapsearch"
users = [authentik_user.dolibarr_ldapsearch.id]
is_superuser = true
}
data "http" "dolibarr_ldapsearch_password" {
url = "http://authentik.${var.domain}-auth.svc/api/v3/core/users/${authentik_user.dolibarr_ldapsearch.id}/set_password/"
method = "POST"
request_headers = local.request_headers
request_body = jsonencode({password=data.kubernetes_secret_v1.dolibarr_ldap_password.data["DOLI_LDAP_ADMIN_PASS"]})
lifecycle {
postcondition {
condition = contains([201, 204], self.status_code)
error_message = "Status code invalid"
}
}
}
data "authentik_flow" "ldap-authentication-flow" {
slug = "ldap-authentication-flow"
}
resource "authentik_provider_ldap" "dolibarr_provider_ldap" {
name = "dolibarr-${var.instance}-ldap"
base_dn = local.base-dn
search_group = authentik_group.dolibarr_ldapsearch.id
bind_flow = data.authentik_flow.ldap-authentication-flow.id
}
data "http" "get_ldap_outpost" {
depends_on = [authentik_policy_binding.dolibarr_ldap_access_users] # fake dependency so it is not evaluated at plan stage
url = "http://authentik.${var.domain}-auth.svc/api/v3/outposts/instances/?name__iexact=ldap"
method = "GET"
request_headers = local.request_headers
lifecycle {
postcondition {
condition = contains([200], self.status_code)
error_message = "Status code invalid"
}
}
}
provider "restapi" {
uri = "http://authentik.${var.domain}-auth.svc/api/v3/"
headers = local.request_headers
create_method = "PATCH"
update_method = "PATCH"
destroy_method = "PATCH"
write_returns_object = true
id_attribute = "name"
}
resource "restapi_object" "ldap_outpost_binding" {
path = "/outposts/instances/${local.ldap-outpost-pk}/"
data = jsonencode({
name = "ldap"
providers = contains(local.ldap-outpost-providers, authentik_provider_ldap.dolibarr_provider_ldap.id) ? local.ldap-outpost-providers : concat(local.ldap-outpost-providers, [authentik_provider_ldap.dolibarr_provider_ldap.id])
})
}

View File

@@ -0,0 +1,44 @@
resource "kubectl_manifest" "nginx-config" {
yaml_body = <<-EOF
kind: ConfigMap
apiVersion: v1
metadata:
name: ${var.instance}-nginx
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
data:
nginx.conf: |
worker_processes 5;
events {
}
http {
include /etc/nginx/mime.types;
server {
listen 3000;
server_name $${NGINX_HOST};
root /var/www/htdocs;
index index.php;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location ~ [^/]\.php(/|$) {
# try_files $uri =404;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ index.php;
}
location /api {
if ( !-e $request_filename) {
rewrite ^.* /api/index.php last;
}
}
}
}
EOF
}

View File

@@ -0,0 +1,31 @@
locals {
pg-labels = merge(local.common-labels, {
"app.kubernetes.io/component" = "postgresql"
})
}
resource "kubectl_manifest" "dolibarr_postgresql" {
yaml_body = <<-EOF
apiVersion: "acid.zalan.do/v1"
kind: "postgresql"
metadata:
name: "${var.instance}-${var.component}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.pg-labels)}
spec:
databases:
${var.component}: "${var.component}"
numberOfInstances: ${var.postgres.replicas}
podAnnotations:
"k8up.io/backupcommand": "pg_dump -U postgres -d ${var.component} --clean"
"k8up.io/file-extension": ".sql"
postgresql:
version: "${var.postgres.version}"
teamId: "${var.instance}"
users:
${var.component}:
- "superuser"
- "createdb"
volume:
size: "${var.postgres.storage}"
EOF
}

19
apps/dolibarr/pvc.tf Normal file
View File

@@ -0,0 +1,19 @@
resource "kubectl_manifest" "pvc" {
yaml_body = <<-EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ${var.instance}
namespace: "${var.namespace}"
annotations:
k8up.io/backup: "true"
labels: ${jsonencode(local.common-labels)}
spec:
accessModes:
- "${var.storage.accessMode}"
resources:
requests:
storage: "${var.storage.size}"
volumeMode: "${var.storage.type}"
EOF
}

32
apps/dolibarr/redis.tf Normal file
View File

@@ -0,0 +1,32 @@
locals {
redis-labels = merge(local.common-labels, {
"app.kubernetes.io/component" = "redis"
})
}
resource "kubectl_manifest" "dolibarr_redis" {
yaml_body = <<-EOF
apiVersion: "redis.redis.opstreelabs.in/v1beta1"
kind: "Redis"
metadata:
name: "${var.instance}-${var.component}-redis"
namespace: "${var.namespace}"
labels: ${jsonencode(local.redis-labels)}
spec:
kubernetesConfig:
image: "${var.redis.image}"
imagePullPolicy: "IfNotPresent"
storage:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: "${var.redis.storage}"
redisExporter:
enabled: ${var.redis.exporter.enabled}
image: "${var.redis.exporter.image}"
securityContext:
runAsUser: 1000
fsGroup: 1000
EOF
}

56
apps/dolibarr/saml.tf Normal file
View File

@@ -0,0 +1,56 @@
data "authentik_flow" "default-authorization-flow" {
slug = "default-provider-authorization-implicit-consent"
}
data "authentik_flow" "default-authentication-flow" {
slug = "default-authentication-flow"
}
data "authentik_property_mapping_saml" "saml_maps" {
managed_list = [
"goauthentik.io/providers/saml/email",
"goauthentik.io/providers/saml/groups",
"goauthentik.io/providers/saml/name",
"goauthentik.io/providers/saml/upn",
"goauthentik.io/providers/saml/uid",
"goauthentik.io/providers/saml/username",
"goauthentik.io/providers/saml/ms-windowsaccountname",
]
}
data "authentik_property_mapping_saml" "saml_name" {
managed = "goauthentik.io/providers/saml/username"
}
data "authentik_certificate_key_pair" "generated" {
name = "authentik Self-signed Certificate"
}
resource "kubectl_manifest" "saml_certificate" {
yaml_body = <<-EOF
apiVersion: "cert-manager.io/v1"
kind: "Certificate"
metadata:
name: "${var.instance}-${var.component}-saml"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
secretName: "${var.instance}-${var.component}-saml"
dnsNames: ${jsonencode(local.dns-names)}
issuerRef:
name: "self-sign"
kind: "ClusterIssuer"
group: "cert-manager.io"
EOF
}
resource "authentik_provider_saml" "dolibarr" {
name = "dolibarr-${var.instance}-saml"
authentication_flow = data.authentik_flow.default-authentication-flow.id
authorization_flow = data.authentik_flow.default-authorization-flow.id
acs_url = "https://${var.sub-domain}.${var.domain-name}/custom/samlconnector/acs.php?entity=1&fk_idp=0"
property_mappings = data.authentik_property_mapping_saml.saml_maps.ids
name_id_mapping = data.authentik_property_mapping_saml.saml_name.id
signing_kp = data.authentik_certificate_key_pair.generated.id
sp_binding = "post"
}

18
apps/dolibarr/svc.tf Normal file
View File

@@ -0,0 +1,18 @@
resource "kubectl_manifest" "svc" {
yaml_body = <<-EOF
apiVersion: v1
kind: Service
metadata:
name: ${var.instance}
namespace: "${var.namespace}"
labels: ${jsonencode(local.deploy-labels)}
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 3000
selector: ${jsonencode(local.deploy-labels)}
type: ClusterIP
EOF
}