From dac4852e3283e3c37cfced66e6f98c86514cda6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Huss?= Date: Tue, 28 May 2024 17:01:16 +0200 Subject: [PATCH] fix --- apps/openproject/check.rhai | 13 + apps/openproject/index.yaml | 423 +++++++++++++ apps/openproject/openproject_Ingress.tf | 28 + apps/openproject/openproject_Job.tf | 124 ++++ apps/openproject/openproject_NetworkPolicy.tf | 28 + .../openproject_PersistentVolumeClaim.tf | 18 + apps/openproject/openproject_Pod.tf | 26 + apps/openproject/openproject_Secret.tf | 79 +++ apps/openproject/openproject_Service.tf | 99 +++ apps/openproject/openproject_rbac.tf | 25 + apps/openproject/openproject_workload.tf | 564 ++++++++++++++++++ apps/openproject/template.rhai | 6 + apps/taiga/taiga_ConfigMap.tf | 295 ++++++++- apps/taiga/taiga_workload.tf | 3 + 14 files changed, 1720 insertions(+), 11 deletions(-) create mode 100644 apps/openproject/check.rhai create mode 100644 apps/openproject/index.yaml create mode 100644 apps/openproject/openproject_Ingress.tf create mode 100644 apps/openproject/openproject_Job.tf create mode 100644 apps/openproject/openproject_NetworkPolicy.tf create mode 100644 apps/openproject/openproject_PersistentVolumeClaim.tf create mode 100644 apps/openproject/openproject_Pod.tf create mode 100644 apps/openproject/openproject_Secret.tf create mode 100644 apps/openproject/openproject_Service.tf create mode 100644 apps/openproject/openproject_rbac.tf create mode 100644 apps/openproject/openproject_workload.tf create mode 100644 apps/openproject/template.rhai diff --git a/apps/openproject/check.rhai b/apps/openproject/check.rhai new file mode 100644 index 0000000..1d67ecd --- /dev/null +++ b/apps/openproject/check.rhai @@ -0,0 +1,13 @@ +const DOMAIN = config.domain; +fn check_domain() { + assert(have_namespace(`${global::DOMAIN}`), `There is no ${global::DOMAIN} namespace`); +} +fn check_authentik() { + assert(have_namespace(`${global::DOMAIN}-auth`), `There is no ${global::DOMAIN}-auth namespace`); + assert(have_install(`${global::DOMAIN}-auth`, "authentik"), `No authentik installation in ${global::DOMAIN}-auth`); + assert(have_secret(`${global::DOMAIN}-auth`, "authentik"), `No authentik secret in ${global::DOMAIN}-auth`); +} +fn pre_check() { + check_domain(); + check_authentik(); +} diff --git a/apps/openproject/index.yaml b/apps/openproject/index.yaml new file mode 100644 index 0000000..368988c --- /dev/null +++ b/apps/openproject/index.yaml @@ -0,0 +1,423 @@ +--- +apiVersion: vinyl.solidite.fr/v1beta1 +kind: Component +category: apps +metadata: + name: openproject + description: null +options: + app_group: + default: apps + examples: + - apps + type: string + backups: + default: + enable: false + endpoint: '' + key_id_key: s3-id + restic_key: bck-password + retention: + db: 30d + keepDaily: 14 + keepMonthly: 12 + keepWeekly: 6 + keepYearly: 12 + schedule: + backup: 10 3 * * * + check: 10 5 * * 1 + db: 10 3 * * * + prune: 10 1 * * 0 + secret_key: s3-secret + secret_name: backup-settings + use_barman: false + examples: + - enable: false + endpoint: '' + key_id_key: s3-id + restic_key: bck-password + retention: + db: 30d + keepDaily: 14 + keepMonthly: 12 + keepWeekly: 6 + keepYearly: 12 + schedule: + backup: 10 3 * * * + check: 10 5 * * 1 + db: 10 3 * * * + prune: 10 1 * * 0 + secret_key: s3-secret + secret_name: backup-settings + use_barman: false + properties: + enable: + default: false + type: boolean + endpoint: + default: '' + type: string + key_id_key: + default: s3-id + type: string + restic_key: + default: bck-password + type: string + retention: + default: + db: 30d + keepDaily: 14 + keepMonthly: 12 + keepWeekly: 6 + keepYearly: 12 + properties: + db: + default: 30d + type: string + keepDaily: + default: 14 + type: integer + keepMonthly: + default: 12 + type: integer + keepWeekly: + default: 6 + type: integer + keepYearly: + default: 12 + type: integer + type: object + schedule: + default: + backup: 10 3 * * * + check: 10 5 * * 1 + db: 10 3 * * * + prune: 10 1 * * 0 + properties: + backup: + default: 10 3 * * * + type: string + check: + default: 10 5 * * 1 + type: string + db: + default: 10 3 * * * + type: string + prune: + default: 10 1 * * 0 + type: string + type: object + secret_key: + default: s3-secret + type: string + secret_name: + default: backup-settings + type: string + use_barman: + default: false + type: boolean + type: object + domain: + default: your-company + examples: + - your-company + type: string + domain_name: + default: your-company.com + examples: + - your-company.com + type: string + 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: + app: + pullPolicy: IfNotPresent + registry: docker.io + repository: to-be/defined + tag: v1.0.0 + postgresql: + registry: ghcr.io + repository: cloudnative-pg/postgresql + tag: 15.3 + redis: + pullPolicy: IfNotPresent + registry: quay.io + repository: opstree/redis + tag: v7.0.12 + redis_exporter: + pullPolicy: IfNotPresent + registry: quay.io + repository: opstree/redis-exporter + tag: v1.44.0 + examples: + - app: + pullPolicy: IfNotPresent + registry: docker.io + repository: to-be/defined + tag: v1.0.0 + postgresql: + registry: ghcr.io + repository: cloudnative-pg/postgresql + tag: 15.3 + redis: + pullPolicy: IfNotPresent + registry: quay.io + repository: opstree/redis + tag: v7.0.12 + redis_exporter: + pullPolicy: IfNotPresent + registry: quay.io + repository: opstree/redis-exporter + tag: v1.44.0 + properties: + app: + default: + pullPolicy: IfNotPresent + registry: docker.io + repository: to-be/defined + tag: v1.0.0 + properties: + pullPolicy: + default: IfNotPresent + enum: + - Always + - Never + - IfNotPresent + type: string + registry: + default: docker.io + type: string + repository: + default: to-be/defined + type: string + tag: + default: v1.0.0 + type: string + type: object + postgresql: + default: + registry: ghcr.io + repository: cloudnative-pg/postgresql + tag: 15.3 + properties: + registry: + default: ghcr.io + type: string + repository: + default: cloudnative-pg/postgresql + type: string + tag: + default: 15.3 + type: number + type: object + redis: + default: + pullPolicy: IfNotPresent + registry: quay.io + repository: opstree/redis + tag: v7.0.12 + properties: + pullPolicy: + default: IfNotPresent + enum: + - Always + - Never + - IfNotPresent + type: string + registry: + default: quay.io + type: string + repository: + default: opstree/redis + type: string + tag: + default: v7.0.12 + type: string + type: object + redis_exporter: + default: + pullPolicy: IfNotPresent + registry: quay.io + repository: opstree/redis-exporter + tag: v1.44.0 + properties: + pullPolicy: + default: IfNotPresent + enum: + - Always + - Never + - IfNotPresent + type: string + registry: + default: quay.io + type: string + repository: + default: opstree/redis-exporter + type: string + tag: + default: v1.44.0 + type: string + type: object + type: object + ingress_class: + default: traefik + examples: + - traefik + type: string + issuer: + default: letsencrypt-prod + examples: + - letsencrypt-prod + type: string + language: + default: fr_FR + examples: + - fr_FR + type: string + postgres: + default: + replicas: 1 + examples: + - replicas: 1 + properties: + replicas: + default: 1 + type: integer + type: object + redis: + default: + exporter: + enabled: true + examples: + - exporter: + enabled: true + properties: + exporter: + default: + enabled: true + properties: + enabled: + default: true + type: boolean + type: object + type: object + replicas: + default: 1 + examples: + - 1 + type: integer + sso_vynil: + default: true + examples: + - true + type: boolean + storage: + default: + postgres: + size: 10Gi + redis: + size: 2Gi + volume: + accessMode: ReadWriteOnce + class: '' + size: 1Gi + type: Filesystem + description: Configure this app storage + examples: + - postgres: + size: 10Gi + redis: + size: 2Gi + volume: + accessMode: ReadWriteOnce + class: '' + size: 1Gi + type: Filesystem + properties: + postgres: + default: + size: 10Gi + properties: + size: + default: 10Gi + type: string + type: object + redis: + default: + size: 2Gi + properties: + size: + default: 2Gi + type: string + type: object + volume: + default: + accessMode: ReadWriteOnce + class: '' + size: 1Gi + type: Filesystem + properties: + accessMode: + default: ReadWriteOnce + enum: + - ReadWriteOnce + - ReadOnlyMany + - ReadWriteMany + type: string + class: + default: '' + type: string + size: + default: 1Gi + type: string + type: + default: Filesystem + enum: + - Filesystem + - Block + type: string + type: object + type: object + sub_domain: + default: to-be-set + examples: + - to-be-set + type: string + timezone: + default: Europe/Paris + examples: + - Europe/Paris + type: string +dependencies: +- dist: null + category: dbo + component: pg +providers: + kubernetes: true + authentik: true + kubectl: true + postgresql: null + mysql: null + restapi: null + http: null + gitea: null +tfaddtype: null diff --git a/apps/openproject/openproject_Ingress.tf b/apps/openproject/openproject_Ingress.tf new file mode 100644 index 0000000..4a445c0 --- /dev/null +++ b/apps/openproject/openproject_Ingress.tf @@ -0,0 +1,28 @@ +resource "kubectl_manifest" "Ingress_openproject" { + yaml_body = <<-EOF + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: openproject + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + tls: + - hosts: + - openproject.example.com + secretName: '' + rules: + - host: openproject.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: openproject + port: + name: http +EOF +} + diff --git a/apps/openproject/openproject_Job.tf b/apps/openproject/openproject_Job.tf new file mode 100644 index 0000000..437254a --- /dev/null +++ b/apps/openproject/openproject_Job.tf @@ -0,0 +1,124 @@ +resource "kubectl_manifest" "Job_openproject-seeder-20240528164127" { + yaml_body = <<-EOF + apiVersion: batch/v1 + kind: Job + metadata: + name: openproject-seeder-20240528164127 + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + ttlSecondsAfterFinished: 6000 + template: + metadata: + labels: + app.kubernetes.io/name: openproject + helm.sh/chart: openproject-5.1.4 + app.kubernetes.io/instance: openproject + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: '14' + openproject/process: seeder + spec: + securityContext: + fsGroup: 1000 + volumes: + - name: tmp + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + - name: app-tmp + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + - name: data + persistentVolumeClaim: + claimName: openproject + initContainers: + - name: check-db-ready + image: docker.io/postgres:13 + imagePullPolicy: Always + command: + - sh + - -c + - until pg_isready -h $DATABASE_HOST -p $DATABASE_PORT -U openproject; do echo "waiting for database $DATABASE_HOST:$DATABASE_PORT"; sleep 2; done; + envFrom: + - secretRef: + name: openproject-core + - secretRef: + name: openproject-oidc + - secretRef: + name: openproject-memcached + env: + - name: OPENPROJECT_DB_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + resources: + limits: + memory: 200Mi + requests: + memory: 200Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + containers: + - name: seeder + image: docker.io/openproject/openproject:14-slim + imagePullPolicy: IfNotPresent + args: + - bash + - /app/docker/prod/seeder + envFrom: + - secretRef: + name: openproject-core + - secretRef: + name: openproject-oidc + - secretRef: + name: openproject-memcached + env: + - name: OPENPROJECT_DB_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + volumeMounts: + - mountPath: /tmp + name: tmp + - mountPath: /app/tmp + name: app-tmp + - name: data + mountPath: /var/openproject/assets + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + restartPolicy: OnFailure +EOF +} + diff --git a/apps/openproject/openproject_NetworkPolicy.tf b/apps/openproject/openproject_NetworkPolicy.tf new file mode 100644 index 0000000..19c8d85 --- /dev/null +++ b/apps/openproject/openproject_NetworkPolicy.tf @@ -0,0 +1,28 @@ +resource "kubectl_manifest" "NetworkPolicy_openproject-memcached" { + yaml_body = <<-EOF + kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + metadata: + name: openproject-memcached + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + podSelector: + matchLabels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: memcached + app.kubernetes.io/version: 1.6.24 + helm.sh/chart: memcached-6.14.0 + policyTypes: + - Ingress + - Egress + egress: + - {} + ingress: + - ports: + - port: 11211 +EOF +} + diff --git a/apps/openproject/openproject_PersistentVolumeClaim.tf b/apps/openproject/openproject_PersistentVolumeClaim.tf new file mode 100644 index 0000000..78cabdf --- /dev/null +++ b/apps/openproject/openproject_PersistentVolumeClaim.tf @@ -0,0 +1,18 @@ +resource "kubectl_manifest" "PersistentVolumeClaim_openproject" { + yaml_body = <<-EOF + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: openproject + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +EOF +} + diff --git a/apps/openproject/openproject_Pod.tf b/apps/openproject/openproject_Pod.tf new file mode 100644 index 0000000..a618c1f --- /dev/null +++ b/apps/openproject/openproject_Pod.tf @@ -0,0 +1,26 @@ +resource "kubectl_manifest" "Pod_openproject-test-connection" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Pod + metadata: + name: openproject-test-connection + labels: ${jsonencode(local.common-labels)} + annotations: + helm.sh/hook: test + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + containers: + - name: wget + image: busybox + command: + - wget + args: + - --no-verbose + - --tries=1 + - --spider + - openproject:8080/health_check + restartPolicy: Never +EOF +} + diff --git a/apps/openproject/openproject_Secret.tf b/apps/openproject/openproject_Secret.tf new file mode 100644 index 0000000..870702b --- /dev/null +++ b/apps/openproject/openproject_Secret.tf @@ -0,0 +1,79 @@ +resource "kubectl_manifest" "Secret_openproject-postgresql" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Secret + metadata: + name: openproject-postgresql + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} + type: Opaque + data: + postgres-password: VDQxbmpqeEVnYg== + password: cEhqbUkyQjVYVw== +EOF +} + +resource "kubectl_manifest" "Secret_openproject-core" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Secret + metadata: + name: openproject-core + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + stringData: + DATABASE_HOST: openproject-postgresql.vynil-ci.svc.cluster.local + DATABASE_PORT: '5432' + DATABASE_URL: postgresql://openproject@openproject-postgresql:5432/openproject + OPENPROJECT_SEED_ADMIN_USER_PASSWORD: admin + OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: 'true' + OPENPROJECT_SEED_ADMIN_USER_NAME: OpenProject Admin + OPENPROJECT_SEED_ADMIN_USER_MAIL: admin@example.net + OPENPROJECT_HTTPS: 'true' + OPENPROJECT_SEED_LOCALE: en + OPENPROJECT_HOST__NAME: openproject.example.com + OPENPROJECT_HSTS: 'true' + OPENPROJECT_RAILS__CACHE__STORE: memcache + OPENPROJECT_RAILS__RELATIVE__URL__ROOT: '' + POSTGRES_STATEMENT_TIMEOUT: 120s +EOF +} + +resource "kubectl_manifest" "Secret_openproject-oidc" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Secret + metadata: + name: openproject-oidc + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + stringData: + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_DISPLAY__NAME: Keycloak + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST: oidc.host + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER: oidc.identifier + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET: oidc.secret + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_AUTHORIZATION__ENDPOINT: oidc.authorizationEndpoint + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_TOKEN__ENDPOINT: oidc.tokenEndpoint + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_USERINFO__ENDPOINT: oidc.userinfoEndpoint + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT: oidc.endSessionEndpoint + OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SCOPE: '[openid email profile]' +EOF +} + +resource "kubectl_manifest" "Secret_openproject-memcached" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Secret + metadata: + name: openproject-memcached + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + stringData: + OPENPROJECT_CACHE__MEMCACHE__SERVER: openproject-memcached:11211 +EOF +} + diff --git a/apps/openproject/openproject_Service.tf b/apps/openproject/openproject_Service.tf new file mode 100644 index 0000000..808d502 --- /dev/null +++ b/apps/openproject/openproject_Service.tf @@ -0,0 +1,99 @@ +resource "kubectl_manifest" "Service_openproject-memcached" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Service + metadata: + name: openproject-memcached + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + type: ClusterIP + ports: + - name: memcache + port: 11211 + targetPort: memcache + nodePort: null + selector: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: memcached +EOF +} + +resource "kubectl_manifest" "Service_openproject-postgresql" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Service + metadata: + name: openproject-postgresql + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + type: ClusterIP + sessionAffinity: None + ports: + - name: tcp-postgresql + port: 5432 + targetPort: tcp-postgresql + nodePort: null + selector: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: primary +EOF +} + +resource "kubectl_manifest" "Service_openproject" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Service + metadata: + name: openproject + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + type: ClusterIP + sessionAffinity: ClientIP + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + ports: + - port: 8080 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: openproject + app.kubernetes.io/instance: openproject + openproject/process: web +EOF +} + +resource "kubectl_manifest" "Service_openproject-postgresql-hl" { + yaml_body = <<-EOF + apiVersion: v1 + kind: Service + metadata: + name: openproject-postgresql-hl + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + annotations: + service.alpha.kubernetes.io/tolerate-unready-endpoints: 'true' + ownerReferences: ${jsonencode(var.install_owner)} + spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: tcp-postgresql + port: 5432 + targetPort: tcp-postgresql + selector: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: primary +EOF +} + diff --git a/apps/openproject/openproject_rbac.tf b/apps/openproject/openproject_rbac.tf new file mode 100644 index 0000000..b408a64 --- /dev/null +++ b/apps/openproject/openproject_rbac.tf @@ -0,0 +1,25 @@ +resource "kubectl_manifest" "ServiceAccount_openproject" { + yaml_body = <<-EOF + apiVersion: v1 + kind: ServiceAccount + metadata: + name: openproject + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} +EOF +} + +resource "kubectl_manifest" "ServiceAccount_openproject-memcached" { + yaml_body = <<-EOF + apiVersion: v1 + kind: ServiceAccount + automountServiceAccountToken: false + metadata: + name: openproject-memcached + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} +EOF +} + diff --git a/apps/openproject/openproject_workload.tf b/apps/openproject/openproject_workload.tf new file mode 100644 index 0000000..c53376b --- /dev/null +++ b/apps/openproject/openproject_workload.tf @@ -0,0 +1,564 @@ +resource "kubectl_manifest" "Deployment_openproject-worker-default" { + yaml_body = <<-EOF + apiVersion: apps/v1 + kind: Deployment + metadata: + name: openproject-worker-default + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: openproject + app.kubernetes.io/instance: openproject + openproject/process: worker-default + template: + metadata: + annotations: + checksum/env-core: a4294db8b065a4d77e098d233e1b73e5ad4557890fd69436ba8fc7c2daf7a181 + checksum/env-memcached: f4f558dde2e4422edc31e686317ce225beea60a136cbb9459cfca7d1f5548be6 + checksum/env-oidc: 2a3d493b7fac498a180683454c58815e0a3bc6319adaf87d6e1eb459db3a8c04 + checksum/env-s3: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b + checksum/env-environment: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b + labels: + app.kubernetes.io/name: openproject + helm.sh/chart: openproject-5.1.4 + app.kubernetes.io/instance: openproject + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: '14' + openproject/process: worker-default + spec: + securityContext: + fsGroup: 1000 + serviceAccountName: openproject + volumes: + - name: tmp + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + - name: app-tmp + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + - name: data + persistentVolumeClaim: + claimName: openproject + initContainers: + - name: wait-for-db + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + image: docker.io/openproject/openproject:14-slim + imagePullPolicy: IfNotPresent + envFrom: + - secretRef: + name: openproject-core + - secretRef: + name: openproject-oidc + - secretRef: + name: openproject-memcached + env: + - name: OPENPROJECT_DB_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + command: + - bash + - /app/docker/prod/wait-for-db + containers: + - name: openproject + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + image: docker.io/openproject/openproject:14-slim + imagePullPolicy: IfNotPresent + envFrom: + - secretRef: + name: openproject-core + - secretRef: + name: openproject-oidc + - secretRef: + name: openproject-memcached + command: + - bash + - /app/docker/prod/worker + env: + - name: OPENPROJECT_DB_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + - name: QUEUE + value: '' + volumeMounts: + - mountPath: /tmp + name: tmp + - mountPath: /app/tmp + name: app-tmp + - name: data + mountPath: /var/openproject/assets + resources: + limits: + cpu: '4' + memory: 4Gi + requests: + cpu: 250m + memory: 512Mi +EOF +} + +resource "kubectl_manifest" "Deployment_openproject-web" { + yaml_body = <<-EOF + apiVersion: apps/v1 + kind: Deployment + metadata: + name: openproject-web + labels: ${jsonencode(local.common-labels)} + namespace: ${var.namespace} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: openproject + app.kubernetes.io/instance: openproject + openproject/process: web + template: + metadata: + annotations: + checksum/env-core: a4294db8b065a4d77e098d233e1b73e5ad4557890fd69436ba8fc7c2daf7a181 + checksum/env-memcached: f4f558dde2e4422edc31e686317ce225beea60a136cbb9459cfca7d1f5548be6 + checksum/env-oidc: 2a3d493b7fac498a180683454c58815e0a3bc6319adaf87d6e1eb459db3a8c04 + checksum/env-s3: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b + checksum/env-environment: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b + labels: + app.kubernetes.io/name: openproject + helm.sh/chart: openproject-5.1.4 + app.kubernetes.io/instance: openproject + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: '14' + openproject/process: web + spec: + securityContext: + fsGroup: 1000 + serviceAccountName: openproject + volumes: + - name: tmp + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + - name: app-tmp + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + - name: data + persistentVolumeClaim: + claimName: openproject + initContainers: + - name: wait-for-db + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + image: docker.io/openproject/openproject:14-slim + imagePullPolicy: IfNotPresent + envFrom: + - secretRef: + name: openproject-core + - secretRef: + name: openproject-oidc + - secretRef: + name: openproject-memcached + env: + - name: OPENPROJECT_DB_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + command: + - bash + - /app/docker/prod/wait-for-db + containers: + - name: openproject + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + image: docker.io/openproject/openproject:14-slim + imagePullPolicy: IfNotPresent + envFrom: + - secretRef: + name: openproject-core + - secretRef: + name: openproject-oidc + - secretRef: + name: openproject-memcached + env: + - name: OPENPROJECT_DB_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + command: + - bash + - /app/docker/prod/web + volumeMounts: + - mountPath: /tmp + name: tmp + - mountPath: /app/tmp + name: app-tmp + - name: data + mountPath: /var/openproject/assets + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: /health_checks/default + port: 8080 + httpHeaders: + - name: Host + value: localhost + initialDelaySeconds: 120 + timeoutSeconds: 3 + periodSeconds: 30 + failureThreshold: 3 + successThreshold: 1 + readinessProbe: + httpGet: + path: /health_checks/default + port: 8080 + httpHeaders: + - name: Host + value: localhost + initialDelaySeconds: 30 + timeoutSeconds: 3 + periodSeconds: 15 + failureThreshold: 30 + successThreshold: 1 + resources: + limits: + cpu: '4' + memory: 4Gi + requests: + cpu: 250m + memory: 512Mi +EOF +} + +resource "kubectl_manifest" "StatefulSet_openproject-postgresql" { + yaml_body = <<-EOF + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: openproject-postgresql + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + replicas: 1 + serviceName: openproject-postgresql-hl + updateStrategy: + rollingUpdate: {} + type: RollingUpdate + selector: + matchLabels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: primary + template: + metadata: + name: openproject-postgresql + labels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: postgresql + app.kubernetes.io/version: 15.4.0 + helm.sh/chart: postgresql-12.12.10 + app.kubernetes.io/component: primary + spec: + serviceAccountName: default + affinity: + podAffinity: null + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: primary + topologyKey: kubernetes.io/hostname + weight: 1 + nodeAffinity: null + securityContext: + fsGroup: 1001 + hostNetwork: false + hostIPC: false + containers: + - name: postgresql + image: docker.io/bitnami/postgresql:15.4.0-debian-11-r45 + imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsGroup: 0 + runAsNonRoot: true + runAsUser: 1001 + seccompProfile: + type: RuntimeDefault + env: + - name: BITNAMI_DEBUG + value: 'false' + - name: POSTGRESQL_PORT_NUMBER + value: '5432' + - name: POSTGRESQL_VOLUME_DIR + value: /bitnami/postgresql + - name: PGDATA + value: /bitnami/postgresql/data + - name: POSTGRES_USER + value: openproject + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: password + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: openproject-postgresql + key: postgres-password + - name: POSTGRES_DATABASE + value: openproject + - name: POSTGRESQL_ENABLE_LDAP + value: no + - name: POSTGRESQL_ENABLE_TLS + value: no + - name: POSTGRESQL_LOG_HOSTNAME + value: 'false' + - name: POSTGRESQL_LOG_CONNECTIONS + value: 'false' + - name: POSTGRESQL_LOG_DISCONNECTIONS + value: 'false' + - name: POSTGRESQL_PGAUDIT_LOG_CATALOG + value: off + - name: POSTGRESQL_CLIENT_MIN_MESSAGES + value: error + - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES + value: pgaudit + ports: + - name: tcp-postgresql + containerPort: 5432 + livenessProbe: + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U "openproject" -d "dbname=openproject" -h 127.0.0.1 -p 5432 + readinessProbe: + failureThreshold: 6 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + exec: + command: + - /bin/sh + - -c + - -e + - | + exec pg_isready -U "openproject" -d "dbname=openproject" -h 127.0.0.1 -p 5432 + [ -f /opt/bitnami/postgresql/tmp/.initialized ] || [ -f /bitnami/postgresql/.initialized ] + resources: + limits: {} + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - name: dshm + mountPath: /dev/shm + - name: data + mountPath: /bitnami/postgresql + volumes: + - name: dshm + emptyDir: + medium: Memory + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 8Gi +EOF +} + +resource "kubectl_manifest" "Deployment_openproject-memcached" { + yaml_body = <<-EOF + apiVersion: apps/v1 + kind: Deployment + metadata: + name: openproject-memcached + namespace: ${var.namespace} + labels: ${jsonencode(local.common-labels)} + ownerReferences: ${jsonencode(var.install_owner)} + spec: + selector: + matchLabels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: memcached + replicas: 1 + strategy: + rollingUpdate: {} + type: RollingUpdate + template: + metadata: + labels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: memcached + app.kubernetes.io/version: 1.6.24 + helm.sh/chart: memcached-6.14.0 + annotations: null + spec: + automountServiceAccountToken: false + affinity: + podAffinity: null + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/instance: openproject + app.kubernetes.io/name: memcached + topologyKey: kubernetes.io/hostname + weight: 1 + nodeAffinity: null + securityContext: + fsGroup: 1001 + fsGroupChangePolicy: Always + supplementalGroups: [] + sysctls: [] + serviceAccountName: openproject-memcached + containers: + - name: memcached + image: docker.io/bitnami/memcached:1.6.24-debian-12-r0 + imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsGroup: 1001 + runAsNonRoot: true + runAsUser: 1001 + seccompProfile: + type: RuntimeDefault + env: + - name: BITNAMI_DEBUG + value: 'false' + - name: MEMCACHED_PORT_NUMBER + value: '11211' + ports: + - name: memcache + containerPort: 11211 + livenessProbe: + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + tcpSocket: + port: memcache + readinessProbe: + failureThreshold: 6 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + tcpSocket: + port: memcache + volumeMounts: + - name: empty-dir + mountPath: /opt/bitnami/memcached/conf + subPath: app-conf-dir + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + volumes: + - name: empty-dir + emptyDir: {} +EOF +} + diff --git a/apps/openproject/template.rhai b/apps/openproject/template.rhai new file mode 100644 index 0000000..9ddda00 --- /dev/null +++ b/apps/openproject/template.rhai @@ -0,0 +1,6 @@ +const DEST=dest; +fn post_template() { + save_to_tf(`${global::DEST}/conditions.tf`, "conditions", #{ + have_podmonitors: have_crd("podmonitors.monitoring.coreos.com"), + }); +} diff --git a/apps/taiga/taiga_ConfigMap.tf b/apps/taiga/taiga_ConfigMap.tf index 6d7ddcc..3a585fb 100644 --- a/apps/taiga/taiga_ConfigMap.tf +++ b/apps/taiga/taiga_ConfigMap.tf @@ -15,21 +15,13 @@ resource "kubectl_manifest" "cm_env_back" { TAIGA_SITES_SCHEME: https TAIGA_ASYNC_RABBITMQ_HOST: ${kubectl_manifest.rabbit.name} TAIGA_EVENTS_RABBITMQ_HOST: ${kubectl_manifest.rabbit.name} - SESSION_COOKIE_SECURE: "True" - CSRF_COOKIE_SECURE: "True" ENABLE_TELEMETRY: "False" - PUBLIC_REGISTER_ENABLED: "True" - ENABLE_GITHUB_AUTH: "False" - ENABLE_GITLAB_AUTH: "False" - ENABLE_SLACK: "False" - ENABLE_GITHUB_IMPORTER: "False" - ENABLE_JIRA_IMPORTER: "False" - ENABLE_TRELLO_IMPORTER: "False" - ENABLE_OIDC_AUTH: "False" + PUBLIC_REGISTER_ENABLED: "False" ENABLE_OPENID_AUTH: "True" OPENID_SCOPE: "openid email profile" OPENID_TOKEN_URL: "${module.oauth2.sso_token_url}" OPENID_USER_URL: "${module.oauth2.sso_userinfo_url}" + DEBUG: "True" EOF } @@ -57,7 +49,7 @@ resource "kubectl_manifest" "cm_env_front" { ENABLE_TRELLO_IMPORTER: "false" ENABLE_OIDC_AUTH: "false" ENABLE_OPENID_AUTH: "true" - OPENID_URL: "${module.oauth2.sso_configuration_url}" + OPENID_URL: "${module.oauth2.sso_authorize_url}" OPENID_SCOPE: "openid email profile" OPENID_NAME: "${var.domain}" EOF @@ -77,6 +69,287 @@ resource "kubectl_manifest" "cm_scripts" { labels: ${jsonencode(local.postcfg_all_labels)} namespace: ${var.namespace} data: + config.py: |- + # -*- coding: utf-8 -*- + # This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # Copyright (c) 2021-present Kaleidos INC + + from .common import * + from ldap3 import Tls + import os, sys, ssl + + + ######################################### + ## GENERIC + ######################################### + + DEBUG = os.getenv('DEBUG', 'False') == 'True' + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': os.getenv('POSTGRES_DB'), + 'USER': os.getenv('POSTGRES_USER'), + 'PASSWORD': os.getenv('POSTGRES_PASSWORD'), + 'HOST': os.getenv('POSTGRES_HOST'), + 'PORT': os.getenv('POSTGRES_PORT','5432'), + 'OPTIONS': {'sslmode': os.getenv('POSTGRES_SSLMODE','disable')}, + 'DISABLE_SERVER_SIDE_CURSORS': os.getenv('POSTGRES_DISABLE_SERVER_SIDE_CURSORS', 'False') == 'True', + } + } + SECRET_KEY = os.getenv('TAIGA_SECRET_KEY') + + TAIGA_SITES_SCHEME = os.getenv('TAIGA_SITES_SCHEME', "http") + TAIGA_SITES_DOMAIN = os.getenv('TAIGA_SITES_DOMAIN', "localhost") + FORCE_SCRIPT_NAME = os.getenv('TAIGA_SUBPATH', '') + + TAIGA_URL = f"{ TAIGA_SITES_SCHEME }://{ TAIGA_SITES_DOMAIN }{ FORCE_SCRIPT_NAME }" + SITES = { + "api": { "name": "api", "scheme": TAIGA_SITES_SCHEME, "domain": TAIGA_SITES_DOMAIN }, + "front": { "name": "front", "scheme": TAIGA_SITES_SCHEME, "domain": f"{ TAIGA_SITES_DOMAIN }{ FORCE_SCRIPT_NAME }" } + } + + LANGUAGE_CODE = os.getenv("LANGUAGE_CODE", "en-us") + + INSTANCE_TYPE = "D" + + WEBHOOKS_ENABLED = os.getenv('WEBHOOKS_ENABLED', 'True') == 'True' + WEBHOOKS_ALLOW_PRIVATE_ADDRESS = os.getenv('WEBHOOKS_ALLOW_PRIVATE_ADDRESS', 'False') == 'True' + WEBHOOKS_ALLOW_REDIRECTS = os.getenv('WEBHOOKS_ALLOW_REDIRECTS', 'False') == 'True' + + # Setting DEFAULT_PROJECT_SLUG_PREFIX to false + # removes the username from project slug + DEFAULT_PROJECT_SLUG_PREFIX = os.getenv('DEFAULT_PROJECT_SLUG_PREFIX', 'False') == 'True' + + ######################################### + ## MEDIA + ######################################### + MEDIA_URL = f"{ TAIGA_URL }/media/" + DEFAULT_FILE_STORAGE = "taiga_contrib_protected.storage.ProtectedFileSystemStorage" + THUMBNAIL_DEFAULT_STORAGE = DEFAULT_FILE_STORAGE + + STATIC_URL = f"{ TAIGA_URL }/static/" + + + ######################################### + ## EMAIL + ######################################### + # https://docs.djangoproject.com/en/3.1/topics/email/ + EMAIL_BACKEND = os.getenv('EMAIL_BACKEND', 'django.core.mail.backends.console.EmailBackend') + CHANGE_NOTIFICATIONS_MIN_INTERVAL = 120 # seconds + + DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'system@taiga.io') + EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS', 'False') == 'True' + EMAIL_USE_SSL = os.getenv('EMAIL_USE_SSL', 'False') == 'True' + EMAIL_HOST = os.getenv('EMAIL_HOST', 'localhost') + EMAIL_PORT = os.getenv('EMAIL_PORT', 587) + EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', 'user') + EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', 'password') + + + ######################################### + ## SESSION + ######################################### + SESSION_COOKIE_SECURE = os.getenv('SESSION_COOKIE_SECURE', 'True') == 'True' + CSRF_COOKIE_SECURE = os.getenv('CSRF_COOKIE_SECURE', 'True') == 'True' + + + ######################################### + ## EVENTS + ######################################### + EVENTS_PUSH_BACKEND = "taiga.events.backends.rabbitmq.EventsPushBackend" + + EVENTS_PUSH_BACKEND_URL = os.getenv('EVENTS_PUSH_BACKEND_URL') + if not EVENTS_PUSH_BACKEND_URL: + EVENTS_PUSH_BACKEND_URL = f"amqp://{ os.getenv('RABBITMQ_USER') }:{ os.getenv('RABBITMQ_PASS') }@{ os.getenv('TAIGA_EVENTS_RABBITMQ_HOST', 'taiga-events-rabbitmq') }:5672/taiga" + + EVENTS_PUSH_BACKEND_OPTIONS = { + "url": EVENTS_PUSH_BACKEND_URL + } + + + ######################################### + ## TAIGA ASYNC + ######################################### + CELERY_ENABLED = os.getenv('CELERY_ENABLED', 'True') == 'True' + from kombu import Queue # noqa + + CELERY_BROKER_URL = os.getenv('CELERY_BROKER_URL') + if not CELERY_BROKER_URL: + CELERY_BROKER_URL = f"amqp://{ os.getenv('RABBITMQ_USER') }:{ os.getenv('RABBITMQ_PASS') }@{ os.getenv('TAIGA_ASYNC_RABBITMQ_HOST', 'taiga-async-rabbitmq') }:5672/taiga" + + CELERY_RESULT_BACKEND = None # for a general installation, we don't need to store the results + CELERY_ACCEPT_CONTENT = ['pickle', ] # Values are 'pickle', 'json', 'msgpack' and 'yaml' + CELERY_TASK_SERIALIZER = "pickle" + CELERY_RESULT_SERIALIZER = "pickle" + CELERY_TIMEZONE = os.getenv('CELERY_TIMEZONE', 'Europe/Madrid') + CELERY_TASK_DEFAULT_QUEUE = 'tasks' + CELERY_QUEUES = ( + Queue('tasks', routing_key='task.#'), + Queue('transient', routing_key='transient.#', delivery_mode=1) + ) + CELERY_TASK_DEFAULT_EXCHANGE = 'tasks' + CELERY_TASK_DEFAULT_EXCHANGE_TYPE = 'topic' + CELERY_TASK_DEFAULT_ROUTING_KEY = 'task.default' + + + ######################################### + ## REGISTRATION + ######################################### + PUBLIC_REGISTER_ENABLED = os.getenv('PUBLIC_REGISTER_ENABLED', 'False') == 'True' + + + ######################################### + ## CONTRIBS + ######################################### + + # SLACK + ENABLE_SLACK = os.getenv('ENABLE_SLACK', 'False') == 'True' + if ENABLE_SLACK: + INSTALLED_APPS += [ + "taiga_contrib_slack" + ] + + # GITHUB AUTH + # WARNING: If PUBLIC_REGISTER_ENABLED == False, currently Taiga by default prevents the OAuth + # buttons to appear for both login and register + ENABLE_GITHUB_AUTH = os.getenv('ENABLE_GITHUB_AUTH', 'False') == 'True' + if PUBLIC_REGISTER_ENABLED and ENABLE_GITHUB_AUTH: + INSTALLED_APPS += [ + "taiga_contrib_github_auth" + ] + GITHUB_API_CLIENT_ID = os.getenv('GITHUB_API_CLIENT_ID') + GITHUB_API_CLIENT_SECRET = os.getenv('GITHUB_API_CLIENT_SECRET') + + # GITLAB AUTH + # WARNING: If PUBLIC_REGISTER_ENABLED == False, currently Taiga by default prevents the OAuth + # buttons to appear for both login and register + ENABLE_GITLAB_AUTH = os.getenv('ENABLE_GITLAB_AUTH', 'False') == 'True' + if PUBLIC_REGISTER_ENABLED and ENABLE_GITLAB_AUTH: + INSTALLED_APPS += [ + "taiga_contrib_gitlab_auth" + ] + GITLAB_API_CLIENT_ID = os.getenv('GITLAB_API_CLIENT_ID') + GITLAB_API_CLIENT_SECRET = os.getenv('GITLAB_API_CLIENT_SECRET') + GITLAB_URL = os.getenv('GITLAB_URL') + + # OIDC AUTH + ENABLE_OIDC_AUTH = os.getenv('ENABLE_OIDC_AUTH', 'False') == 'True' + if ENABLE_OIDC_AUTH: + INSTALLED_APPS += [ + "mozilla_django_oidc", + "taiga_contrib_oidc_auth", + ] + AUTHENTICATION_BACKENDS = list(AUTHENTICATION_BACKENDS) + [ + "taiga_contrib_oidc_auth.oidc.TaigaOIDCAuthenticationBackend", + ] + ROOT_URLCONF = "settings.urls" + OIDC_CALLBACK_CLASS = "taiga_contrib_oidc_auth.views.TaigaOIDCAuthenticationCallbackView" + OIDC_BASE_URL = os.getenv("OIDC_BASE_URL", "https://id.fedoraproject.org/openidc") + OIDC_RP_SCOPES = os.getenv("OIDC_RP_SCOPES", "openid profile email") + OIDC_RP_SIGN_ALGO = os.getenv("OIDC_RP_SIGN_ALGO", "RS256") + OIDC_OP_JWKS_ENDPOINT = os.getenv("OIDC_OP_JWKS_ENDPOINT", OIDC_BASE_URL + "/Jwks") + OIDC_OP_AUTHORIZATION_ENDPOINT = os.getenv("OIDC_OP_AUTHORIZATION_ENDPOINT", OIDC_BASE_URL + "/Authorization") + OIDC_OP_TOKEN_ENDPOINT = os.getenv("OIDC_OP_TOKEN_ENDPOINT", OIDC_BASE_URL + "/Token") + OIDC_OP_USER_ENDPOINT = os.getenv("OIDC_OP_USER_ENDPOINT", OIDC_BASE_URL + "/UserInfo") + OIDC_RP_CLIENT_ID = os.getenv("OIDC_RP_CLIENT_ID") + OIDC_RP_CLIENT_SECRET = os.getenv("OIDC_RP_CLIENT_SECRET") + + if os.getenv('TAIGA_ENABLE_OPENID_AUTH', os.getenv('ENABLE_OPENID', 'False')).lower() == 'true': + print("ENABLE_OPENID") + INSTALLED_APPS += ["taiga_contrib_openid_auth"] + OPENID_USER_URL = os.getenv('TAIGA_OPENID_AUTH_USER_URL', os.getenv('OPENID_USER_URL')) + OPENID_TOKEN_URL = os.getenv('TAIGA_OPENID_AUTH_TOKEN_URL', os.getenv('OPENID_TOKEN_URL')) + OPENID_CLIENT_ID = os.getenv('TAIGA_OPENID_AUTH_CLIENT_ID', os.getenv('OPENID_CLIENT_ID')) + OPENID_CLIENT_SECRET = os.getenv('TAIGA_OPENID_AUTH_CLIENT_SECRET', os.getenv('OPENID_CLIENT_SECRET')) + OPENID_SCOPE = os.getenv('TAIGA_OPENID_SCOPE', os.getenv('OPENID_SCOPE')) + + if os.getenv('TAIGA_ENABLE_LDAP', os.getenv('ENABLE_LDAP', 'False')).lower() == 'true': + INSTALLED_APPS += ["taiga_contrib_ldap_auth_ext"] + + if os.getenv('TAIGA_LDAP_USE_TLS', os.getenv('LDAP_START_TLS', 'False')).lower() == 'true': + # Flag to enable LDAP with STARTTLS before bind + LDAP_START_TLS = True + LDAP_TLS_CERTS = Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1, ciphers='RSA+3DES') + else: + LDAP_START_TLS = False + + LDAP_SERVER = os.getenv('TAIGA_LDAP_SERVER', os.getenv('LDAP_SERVER')) + LDAP_PORT = int(os.getenv('TAIGA_LDAP_PORT', os.getenv('LDAP_PORT', '389'))) + + # Full DN of the service account use to connect to LDAP server and search for login user's account entry + # If LDAP_BIND_DN is not specified, or is blank, then an anonymous bind is attempated + LDAP_BIND_DN = os.getenv('TAIGA_LDAP_BIND_DN', os.getenv('LDAP_BIND_DN')) + LDAP_BIND_PASSWORD = os.getenv('TAIGA_LDAP_BIND_PASSWORD', os.getenv('LDAP_BIND_PASSWORD')) + + # Starting point within LDAP structure to search for login user + # Something like 'ou=People,dc=company,dc=com' + LDAP_SEARCH_BASE = os.getenv('TAIGA_LDAP_BASE_DN', os.getenv('LDAP_SEARCH_BASE')) + + # Additional search criteria to the filter (will be ANDed) + #LDAP_SEARCH_FILTER_ADDITIONAL = '(mail=*)' + + # Names of attributes to get username, e-mail and full name values from + # These fields need to have a value in LDAP + LDAP_USERNAME_ATTRIBUTE = os.getenv('TAIGA_LDAP_USERNAME_ATTRIBUTE', os.getenv('LDAP_USERNAME_ATTRIBUTE')) + LDAP_EMAIL_ATTRIBUTE = os.getenv('TAIGA_LDAP_EMAIL_ATTRIBUTE', os.getenv('LDAP_EMAIL_ATTRIBUTE')) + LDAP_FULL_NAME_ATTRIBUTE = os.getenv('TAIGA_LDAP_FULL_NAME_ATTRIBUTE', os.getenv('LDAP_FULL_NAME_ATTRIBUTE')) + + # Option to not store the passwords in the local db + if os.getenv('TAIGA_LDAP_SAVE_LOGIN_PASSWORD', os.getenv('LDAP_SAVE_LOGIN_PASSWORD', 'False')).lower() == 'false': + LDAP_SAVE_LOGIN_PASSWORD = False + + # Fallback on normal authentication method if this LDAP auth fails. Uncomment to enable. + LDAP_FALLBACK = os.getenv('TAIGA_LDAP_FALLBACK', os.getenv('LDAP_FALLBACK', 'normal')) + + # Function to map LDAP username to local DB user unique identifier. + # Upon successful LDAP bind, will override returned username attribute + # value. May result in unexpected failures if changed after the database + # has been populated. + def _ldap_slugify(uid: str) -> str: + # example: force lower-case + uid = uid.lower() + return uid + + LDAP_MAP_USERNAME_TO_UID = _ldap_slugify + + + ######################################### + ## TELEMETRY + ######################################### + ENABLE_TELEMETRY = os.getenv('ENABLE_TELEMETRY', 'True') == 'True' + + + ######################################### + ## IMPORTERS + ######################################### + ENABLE_GITHUB_IMPORTER = os.getenv('ENABLE_GITHUB_IMPORTER', 'False') == 'True' + if ENABLE_GITHUB_IMPORTER: + IMPORTERS["github"] = { + "active": True, + "client_id": os.getenv('GITHUB_IMPORTER_CLIENT_ID'), + "client_secret": os.getenv('GITHUB_IMPORTER_CLIENT_SECRET') + } + + ENABLE_JIRA_IMPORTER = os.getenv('ENABLE_JIRA_IMPORTER', 'False') == 'True' + if ENABLE_JIRA_IMPORTER: + IMPORTERS["jira"] = { + "active": True, + "consumer_key": os.getenv('JIRA_IMPORTER_CONSUMER_KEY'), + "cert": os.getenv('JIRA_IMPORTER_CERT'), + "pub_cert": os.getenv('JIRA_IMPORTER_PUB_CERT') + } + + ENABLE_TRELLO_IMPORTER = os.getenv('ENABLE_TRELLO_IMPORTER', 'False') == 'True' + if ENABLE_TRELLO_IMPORTER: + IMPORTERS["trello"] = { + "active": True, + "api_key": os.getenv('TRELLO_IMPORTER_API_KEY'), + "secret_key": os.getenv('TRELLO_IMPORTER_SECRET_KEY') + } certs.sh: |- #!/usr/bin/env bash if [ -f /etc/local-ca/ca.crt ];then diff --git a/apps/taiga/taiga_workload.tf b/apps/taiga/taiga_workload.tf index 2c65c94..4e45126 100644 --- a/apps/taiga/taiga_workload.tf +++ b/apps/taiga/taiga_workload.tf @@ -316,6 +316,9 @@ resource "kubectl_manifest" "Deployment_taiga-back" { - name: scripts mountPath: /docker-entrypoint.d/certs.sh subPath: certs.sh + - name: scripts + mountPath: /taiga-back/settings/config.py + subPath: config.py.sh - name: data mountPath: /taiga-back/static subPath: static