Compare commits

..

22 Commits

Author SHA1 Message Date
7a62cebc92 🤖 ci(vault): declare dance-lessons-coach JWT role + ops policy
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 1m8s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Detect changed charts (pull_request) Successful in 1m5s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
2026-05-06 12:55:17 +02:00
2367bd6cd7 fix(crowdsec): use Recreate strategy for lapi to avoid RWO volume multi-attach
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 49s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
RollingUpdate with maxSurge>0 creates a new pod before terminating the old one,
causing a Multi-Attach error on the RWO PVCs (crowdsec-db-pvc, crowdsec-config-pvc).
Recreate terminates the old pod first, then starts the new one.
2026-04-16 10:25:10 +02:00
82a6eb0d85 configure grafana with prometheus
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 5m2s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-03-18 17:07:35 +01:00
a762c8f90f deploy prometheus
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 25s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-03-18 16:21:31 +01:00
1b2c325023 no clickhouse pod on pi2
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 25s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-01-03 19:17:04 +01:00
9f0adfe14d use self signed cert
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 1m2s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-01-02 19:07:46 +01:00
02322e9a24 use internal .lab instead of failing duckdns.org
Some checks failed
Helm Charts / Detect changed charts (push) Successful in 22s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Failing after 34s
2025-12-31 17:54:36 +01:00
2c8de3468a set IP_GEOLOCATION_DB to geoip lite city db
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m29s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-12 15:32:58 +01:00
87aac41959 plausible:geoip include free city database
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m38s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-11 13:09:56 +01:00
2f0bc7ab4a expose plausible event api
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m28s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-11 08:29:17 +01:00
3225c17b4a fix ingressroute service
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m44s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-11 07:51:06 +01:00
d91f8e2900 fix yaml indentation
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m38s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-11 07:39:55 +01:00
ec0f42676a fix: specify namespace in kustomization.yaml
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m31s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-11 07:28:58 +01:00
6822b53775 clickhouse: donne droit de lecture sur bd system
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 12s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 16:58:07 +01:00
5b13d0f679 plausible: fix clickhouse url
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m58s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 15:54:41 +01:00
dee0fed059 plausible: add reconnect config for orm
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 14s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 15:46:58 +01:00
09d7aa9b9e pgboucner: set server_idle_tiemout to 2h
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 15s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 15:35:28 +01:00
0b74c97a85 plausible: don't run db create
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m35s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 15:15:53 +01:00
0942171673 set crowdsec lapi deployment strategy
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m50s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 15:00:57 +01:00
a8c497a5da try plausible CE for web analytics 2025-12-10 15:00:47 +01:00
d7130b1635 create plausible clickhouse database
All checks were successful
Helm Charts / Detect changed charts (push) Successful in 3m9s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-10 13:19:56 +01:00
a5338ac6f7 TODO: 1 vault_database_secret_backend_connection per database 2025-12-09 12:58:59 +01:00
46 changed files with 2095 additions and 47 deletions

View File

@@ -16,10 +16,11 @@ concurrency:
.vault_step: &vault_step
name: read vault secret
uses: https://gitea.arcodange.duckdns.org/arcodange-org/vault-action.git@main
uses: https://gitea.arcodange.lab/arcodange-org/vault-action.git@main
id: vault-secrets
with:
url: https://vault.arcodange.duckdns.org
url: https://vault.arcodange.lab
caCertificate: ${{ secrets.HOMELAB_CA_CERT }}
jwtGiteaOIDC: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
role: gitea_cicd_crowdsec
method: jwt
@@ -49,12 +50,12 @@ jobs:
env:
OPENTOFU_VERSION: 1.8.2
TERRAFORM_VAULT_AUTH_JWT: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
VAULT_CACERT: "${{ github.workspace }}/homelab.pem"
steps:
- *vault_step
- uses: actions/checkout@v4
# - uses: dflook/terraform-plan@v1
# with:
# path: hashicorp-vault/iac
- name: prepare vault self signed cert
run: echo -n "${{ secrets.HOMELAB_CA_CERT }}" | base64 -d > $VAULT_CACERT
- name: terraform apply
uses: dflook/terraform-apply@v1
with:

View File

@@ -165,7 +165,7 @@ jobs:
chart_package=${chart}-${chart_version}.tgz
# helm package ${chart}
tar -X ${chart}/.helmignore -czf ${chart_package} ${chart}
curl --user ${{ github.actor }}:${{ secrets.PACKAGES_TOKEN }} -X POST --upload-file ./${chart_package} https://gitea.arcodange.duckdns.org/api/packages/${{ github.repository_owner }}/helm/api/charts
curl --user ${{ github.actor }}:${{ secrets.PACKAGES_TOKEN }} -X POST --upload-file ./${chart_package} https://gitea.arcodange.lab/api/packages/${{ github.repository_owner }}/helm/api/charts
application-charts:
<<: *charts-matrix-job

View File

@@ -0,0 +1,63 @@
---
# template source: https://github.com/bretfisher/docker-build-workflow/blob/main/templates/call-docker-build.yaml
name: Plausible
on: #[push,pull_request]
workflow_dispatch: {}
push: &plausiblePaths
paths:
- 'plausible/**/*.tf'
pull_request: *plausiblePaths
# cancel any previously-started, yet still active runs of this workflow on the same branch
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
.vault_step: &vault_step
name: read vault secret
uses: https://gitea.arcodange.lab/arcodange-org/vault-action.git@main
id: vault-secrets
with:
url: https://vault.arcodange.lab
caCertificate: ${{ secrets.HOMELAB_CA_CERT }}
jwtGiteaOIDC: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
role: gitea_cicd_plausible
method: jwt
path: gitea_jwt
secrets: |
kvv1/google/credentials credentials | GOOGLE_BACKEND_CREDENTIALS ;
kvv1/gitea/tofu_module_reader ssh_private_key | TERRAFORM_SSH_KEY ;
jobs:
gitea_vault_auth:
name: Auth with gitea for vault
runs-on: ubuntu-latest
outputs:
gitea_vault_jwt: ${{steps.gitea_vault_jwt.outputs.id_token}}
steps:
- name: Auth with gitea for vault
id: gitea_vault_jwt
run: |
echo -n "${{ secrets.vault_oauth__sh_b64 }}" | base64 -d | bash
tofu:
name: Tofu - plausible IAC
needs:
- gitea_vault_auth
runs-on: ubuntu-latest
env:
OPENTOFU_VERSION: 1.8.2
TERRAFORM_VAULT_AUTH_JWT: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
VAULT_CACERT: "${{ github.workspace }}/homelab.pem"
steps:
- *vault_step
- uses: actions/checkout@v4
- name: prepare vault self signed cert
run: echo -n "${{ secrets.HOMELAB_CA_CERT }}" | base64 -d > $VAULT_CACERT
- name: terraform apply
uses: dflook/terraform-apply@v1
with:
path: plausible/iac
auto_approve: true

View File

@@ -16,10 +16,11 @@ concurrency:
.vault_step: &vault_step
name: read vault secret
uses: https://gitea.arcodange.duckdns.org/arcodange-org/vault-action.git@main
uses: https://gitea.arcodange.lab/arcodange-org/vault-action.git@main
id: vault-secrets
with:
url: https://vault.arcodange.duckdns.org
url: https://vault.arcodange.lab
caCertificate: ${{ secrets.HOMELAB_CA_CERT }}
jwtGiteaOIDC: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
role: gitea_cicd
method: jwt
@@ -50,12 +51,12 @@ jobs:
env:
OPENTOFU_VERSION: 1.8.2
TERRAFORM_VAULT_AUTH_JWT: ${{ needs.gitea_vault_auth.outputs.gitea_vault_jwt }}
VAULT_CACERT: "${{ github.workspace }}/homelab.pem"
steps:
- *vault_step
- uses: actions/checkout@v4
# - uses: dflook/terraform-plan@v1
# with:
# path: hashicorp-vault/iac
- name: prepare vault self signed cert
run: echo -n "${{ secrets.HOMELAB_CA_CERT }}" | base64 -d > $VAULT_CACERT
- name: terraform apply
uses: dflook/terraform-apply@v1
with:

View File

@@ -10,7 +10,7 @@ metadata:
spec:
project: tools
source:
repoURL: https://gitea.arcodange.duckdns.org/arcodange-org/tools
repoURL: https://gitea.arcodange.lab/arcodange-org/tools
targetRevision: HEAD
path: {{ $app_name }}
destination:

View File

@@ -10,7 +10,7 @@ metadata:
spec:
description: Arcodange tools (monitoring, cache, connection pool, secret management...)
sourceRepos:
- 'https://gitea.arcodange.duckdns.org/arcodange-org/tools'
- 'https://gitea.arcodange.lab/arcodange-org/tools'
# Only permit applications to deploy to the tools namespace in the same cluster
destinations:
- namespace: tools

View File

@@ -6,4 +6,6 @@ tools:
crowdsec: {}
redis: {}
clickhouse: {}
grafana: {}
grafana: {}
plausible: {}
prometheus: {}

2
clickhouse/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
charts/
!charts/databases/

View File

@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@@ -0,0 +1,24 @@
apiVersion: v2
name: clickhouse databases
description: declare clickhouse databases
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "24.12.6.70-alpine"

View File

@@ -0,0 +1,85 @@
apiVersion: batch/v1
kind: Job
metadata:
name: clickhouse-db-init
labels:
app.kubernetes.io/name: clickhouse-db-init
app.kubernetes.io/instance: {{ .Release.Name }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/init-sql-configmap.yaml") . | sha256sum }}
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: clickhouse-init
image: clickhouse/clickhouse-server:{{ .Chart.AppVersion }}
command: ["bash", "-c"]
args:
- |
echo "⏳ Waiting for ClickHouse..."
until clickhouse-client \
--host {{ .Values.clickhouse.host }} \
--port {{ .Values.clickhouse.port }} \
--user {{ .Values.clickhouse.adminUser }} \
--password "{{ .Values.clickhouse.adminPassword }}" \
-q "SELECT 1" >/dev/null 2>&1; do
sleep 2
done
echo "✅ ClickHouse ready"
{{- if .Values.databases }}
echo "➡️ Creating declared databases & users..."
clickhouse-client \
--host {{ .Values.clickhouse.host }} \
--port {{ .Values.clickhouse.port }} \
--user {{ .Values.clickhouse.adminUser }} \
--password "{{ .Values.clickhouse.adminPassword }}" \
--multiquery < /config/init.sql
{{- end }}
echo "➡️ Generating list of databases to drop..."
clickhouse-client \
--host {{ .Values.clickhouse.host }} \
--port {{ .Values.clickhouse.port }} \
--user {{ .Values.clickhouse.adminUser }} \
--password "{{ .Values.clickhouse.adminPassword }}" \
-q "
SELECT concat('DROP DATABASE IF EXISTS ', name, ';')
FROM system.databases
WHERE name NOT IN (
'system',
'information_schema',
'INFORMATION_SCHEMA',
'default'
{{- if .Values.databases }}
{{- range $db := .Values.databases }}
, '{{ $db }}'
{{- end }}
{{- end }}
);
" > /tmp/to_drop.sql
if [ -s /tmp/to_drop.sql ]; then
echo "➡️ Dropping leftover databases:"
cat /tmp/to_drop.sql
clickhouse-client \
--host {{ .Values.clickhouse.host }} \
--port {{ .Values.clickhouse.port }} \
--user {{ .Values.clickhouse.adminUser }} \
--password "{{ .Values.clickhouse.adminPassword }}" \
--multiquery < /tmp/to_drop.sql
else
echo "✔️ No databases to drop."
fi
echo "🎉 Initialization completed"
volumeMounts:
- name: init-sql
mountPath: /config
volumes:
- name: init-sql
configMap:
name: clickhouse-init-sql

View File

@@ -0,0 +1,26 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: clickhouse-init-sql
data:
init.sql: |
-- This file is auto-generated by Helm
-- Databases and users initialization
{{- range $db := .Values.databases }}
-- Database: {{ $db }}
CREATE DATABASE IF NOT EXISTS {{ $db }};
-- User: {{ $db }}
CREATE USER IF NOT EXISTS {{ $db }}
IDENTIFIED BY '{{ $db }}arcodange';
-- Privileges
GRANT CREATE, SELECT, INSERT, ALTER, DROP
ON {{ $db }}.*
TO {{ $db }};
GRANT SELECT ON system.* TO {{ $db }};
{{- end }}

View File

@@ -0,0 +1,8 @@
clickhouse:
host: clickhouse.tools
port: 9000
adminUser: arcodange
adminPassword: clickhousearcodange
databases:
- plausible

View File

@@ -158,15 +158,15 @@ resources: {}
# memory: 128Mi
# -- Pod-level affinity. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling).
affinity: {}
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: kubernetes.io/hostname
# operator: In
# values:
# - my-node-xyz
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- pi2
# -- Pod-level tolerations. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling).
tolerations: []

View File

@@ -1,5 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: tools
helmGlobals:
chartHome: charts
helmCharts:
- name: clickhouse
@@ -7,6 +11,8 @@ helmCharts:
version: 0.4.0
releaseName: clickhouse
valuesFile: clickhouseValues.yaml
- name: databases
releaseName: clickhouse-databases
patches:
- target:

View File

@@ -5,7 +5,7 @@ description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.duckdns.org/api/packages/arcodange-org/helm
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: crowdsec
version: 0.20.1
repository: https://crowdsecurity.github.io/helm-charts

View File

@@ -8,7 +8,7 @@ terraform {
}
provider "vault" {
address = "https://vault.arcodange.duckdns.org"
address = "https://vault.arcodange.lab"
auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable
mount = "gitea_jwt"
role = "gitea_cicd_crowdsec"

View File

@@ -23,6 +23,8 @@ crowdsec: &crowdsec_config
- name: TZ
value: Europe/Paris
lapi:
strategy:
type: Recreate
env:
- name: TZ
value: Europe/Paris
@@ -90,4 +92,4 @@ tool:
repo: https://crowdsecurity.github.io/helm-charts
chart: crowdsec
version: 0.20.1
values: *crowdsec_config
values: *crowdsec_config

View File

@@ -16,7 +16,7 @@ description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.duckdns.org/api/packages/arcodange-org/helm
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: grafana
version: 10.3.0
repository: https://grafana.github.io/helm-charts

View File

@@ -270,11 +270,11 @@ grafana: &grafana_config
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
traefik.ingress.kubernetes.io/router.tls.domains.0.main: arcodange.duckdns.org
traefik.ingress.kubernetes.io/router.tls.domains.0.sans: grafana.arcodange.duckdns.org
traefik.ingress.kubernetes.io/router.tls.domains.0.main: arcodange.lab
traefik.ingress.kubernetes.io/router.tls.domains.0.sans: grafana.arcodange.lab
traefik.ingress.kubernetes.io/router.middlewares: localIp@file
hosts:
- grafana.arcodange.duckdns.org
- grafana.arcodange.lab
resources:
limits:
@@ -553,11 +553,11 @@ grafana: &grafana_config
username: arcodange
secureJsonData:
password: clickhousearcodange
# - name: Prometheus
# type: prometheus
# url: http://prometheus-prometheus-server
# access: proxy
# isDefault: true
- name: Prometheus
type: prometheus
url: http://prometheus-server.tools.svc.cluster.local
access: proxy
isDefault: true
# - name: CloudWatch
# type: cloudwatch
# access: proxy
@@ -695,6 +695,15 @@ grafana: &grafana_config
disableDeletion: false
options:
path: /var/lib/grafana/dashboards/clickhouse
- name: 'grafana-dashboards-kubernetes'
orgId: 1
folder: 'Kubernetes'
type: file
disableDeletion: true
editable: true
options:
path: /var/lib/grafana/dashboards/grafana-dashboards-kubernetes
# - name: 'default'
# orgId: 1
# folder: ''
@@ -728,6 +737,26 @@ grafana: &grafana_config
url: "https://grafana.com/api/dashboards/23589/revisions/1/download"
curlOptions: "-sLf"
datasource: clickhouse
grafana-dashboards-kubernetes:
k8s-system-api-server:
url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-system-api-server.json
token: ''
k8s-system-coredns:
url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-system-coredns.json
token: ''
k8s-views-global:
url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-views-global.json
token: ''
k8s-views-namespaces:
url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-views-namespaces.json
token: ''
k8s-views-nodes:
url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-views-nodes.json
token: ''
k8s-views-pods:
url: https://raw.githubusercontent.com/dotdc/grafana-dashboards-kubernetes/master/dashboards/k8s-views-pods.json
token: ''
# default:
# some-dashboard:

View File

@@ -5,7 +5,7 @@ description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.duckdns.org/api/packages/arcodange-org/helm
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: vault
version: 0.28.1
repository: https://helm.releases.hashicorp.com

View File

@@ -1,8 +1,8 @@
# Vault
1. Les [playbooks ansible](https://gitea.arcodange.duckdns.org/arcodange-org/factory/src/branch/main/ansible/arcodange/factory/playbooks) configurent la base de données postgres et le minimum requis pour permetre au dépot "tools" d'appliquer via un workflow gitea action [une configuration vault via tofu](./iac/).
1. Les [playbooks ansible](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/ansible/arcodange/factory/playbooks) configurent la base de données postgres et le minimum requis pour permetre au dépot "tools" d'appliquer via un workflow gitea action [une configuration vault via tofu](./iac/).
2. Configuration des backend d'authentification et des roles pour postgres et kubernetes. Définition de rôles "${app}-ops" pour permettre au dépot d'une application de définir ses propres dépendances dans vault. Rotation de credentials postgres pour les applications.
3. [Le dépot de l'application webapp](https://gitea.arcodange.duckdns.org/arcodange-org/webapp) gère l'obtention de ses crédentials pour postgres.
3. [Le dépot de l'application webapp](https://gitea.arcodange.lab/arcodange-org/webapp) gère l'obtention de ses crédentials pour postgres.
```mermaid
flowchart LR

View File

@@ -27,8 +27,8 @@ resource "vault_database_secret_backend_role" "role" {
"GRANT ${local.name}_role TO \"{{name}}\";",
]
revocation_statements = [
"REASSIGN OWNED BY \"{{name}}\" TO ${local.name}_role;",
"REVOKE ALL ON DATABASE ${local.database} FROM \"{{name}}\";", # should we drop the role ?
"REASSIGN OWNED BY \"{{name}}\" TO ${local.name}_role;", # reassign must be executed in the database where the reassgined objects are - TODO (one connection per database/app)
"REVOKE ALL ON DATABASE ${local.database} FROM \"{{name}}\";", # should we drop the role ? -> YES after fixing reassign
]
renew_statements = []
rollback_statements = []

View File

@@ -8,7 +8,7 @@ terraform {
}
provider "vault" {
address = "https://vault.arcodange.duckdns.org"
address = "https://vault.arcodange.lab"
auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable
mount = "gitea_jwt"
role = "gitea_cicd"

View File

@@ -1,6 +1,7 @@
applications = [
{ name = "webapp" },
{ name = "erp" },
{ name = "dance-lessons-coach" },
{
name = "cms"
ops_policies = ["factory__cf_r2_arcodange_tf"]
@@ -10,4 +11,8 @@ applications = [
name = "crowdsec"
service_account_namespaces = ["tools"]
},
{
name = "plausible"
service_account_namespaces = ["tools"]
},
]

View File

@@ -15,11 +15,11 @@ vault: &vault_config
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
traefik.ingress.kubernetes.io/router.tls.domains.0.main: arcodange.duckdns.org
traefik.ingress.kubernetes.io/router.tls.domains.0.sans: vault.arcodange.duckdns.org
traefik.ingress.kubernetes.io/router.tls.domains.0.main: arcodange.lab
traefik.ingress.kubernetes.io/router.tls.domains.0.sans: vault.arcodange.lab
traefik.ingress.kubernetes.io/router.middlewares: localIp@file
hosts:
- host: vault.arcodange.duckdns.org
- host: vault.arcodange.lab
paths: []
postStart: [] # https://github.com/hashicorp/vault-helm/blob/main/values.yaml

View File

@@ -5,7 +5,7 @@ description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.duckdns.org/api/packages/arcodange-org/helm
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: pgbouncer
version: 2.3.1
repository: https://icoretech.github.io/helm

View File

@@ -15,6 +15,7 @@ pgbouncer: &pgbouncer_config
auth_query: SELECT uname, phash FROM user_lookup($1)
ignore_startup_parameters: extra_float_digits # unsupported jdbc extra_float_digits=2 argument
server_reset_query: DEALLOCATE ALL # fix prepared statement already exist (crowdsec)
server_idle_timeout: 7200
pgbouncerExporter:
enabled: false

View File

@@ -5,7 +5,7 @@ description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.duckdns.org/api/packages/arcodange-org/helm
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: pgcat
version: 0.1.0
repository: https://improwised.github.io/charts/

View File

@@ -0,0 +1,36 @@
- op: add
path: /spec/template/spec/containers/0/volumeMounts/-
value:
name: generated-secrets
mountPath: /run/secrets
- op: add
path: /spec/template/spec/initContainers/0/volumeMounts
value:
- name: generated-secrets
mountPath: /run/secrets
- op: add
path: /spec/template/spec/initContainers/0
value:
name: build-database-url
image: alpine:3.19
command: ["/bin/sh", "-c"]
args:
- |
echo "postgres://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}" > /run/secrets/DATABASE_URL
volumeMounts:
- name: generated-secrets
mountPath: /run/secrets
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: plausible-db-credentials
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: plausible-db-credentials
key: password
envFrom:
- configMapRef:
name: plausible-config

6
plausible/iac/backend.tf Normal file
View File

@@ -0,0 +1,6 @@
terraform {
backend "gcs" {
bucket = "arcodange-tf"
prefix = "tools/plausible/main"
}
}

30
plausible/iac/main.tf Normal file
View File

@@ -0,0 +1,30 @@
module "app_roles" {
source = "git::ssh://git@192.168.1.202:2222/arcodange-org/tools.git//hashicorp-vault/iac/modules/app_roles?depth=1&ref=main"
name = "plausible"
service_account_namespaces = ["tools"]
}
# https://github.com/plausible/community-edition/wiki/configuration#database
#SECRET_KEY_BASE (openssl rand -base64 48)
#
resource "random_password" "secret" {
for_each = toset(["48","32"])
length = tonumber(each.value)
special = false
}
locals {
config = {
SECRET_KEY_BASE = base64encode(random_password.secret["48"].result)
TOTP_VAULT_KEY = base64encode(random_password.secret["32"].result)
}
}
resource "vault_kv_secret_v2" "config" {
mount = "kvv2"
name = "plausible/config"
cas = 1
# delete_all_versions = true
data_json = jsonencode(local.config)
}

View File

@@ -0,0 +1,16 @@
terraform {
required_providers {
vault = {
source = "vault"
version = "4.4.0"
}
}
}
provider "vault" {
address = "https://vault.arcodange.lab"
auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable
mount = "gitea_jwt"
role = "gitea_cicd_plausible"
}
}

View File

@@ -0,0 +1,85 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: tools
# https://kubectl.docs.kubernetes.io/references/kustomize/builtins/#_helmchartinflationgenerator_
helmCharts:
- name: plausible
repo: https://charts.pascaliske.dev
version: 2.0.0
releaseName: plausible
valuesFile: plausibleValues.yaml
namespace: tools
patches:
- target:
kind: IngressRoute
name: plausible-route
patch: |-
- op: add
path: /spec/tls
value:
certResolver: letsencrypt
domains:
- main: arcodange.lab
sans:
- analytics.arcodange.lab
resources:
- resources/vaultauth.yaml
- resources/vaultdynamicsecret.yaml
- resources/vaultsecret.yaml
- resources/configmap.yaml
- resources/geoipsecret.yaml
- resources/ingressroute.yaml
patchesJson6902:
- target:
version: v1
kind: Deployment
name: plausible
patch: |-
- op: replace
path: /spec/template/spec/containers/1/env/2
value:
name: GEOIPUPDATE_LICENSE_KEY
valueFrom:
secretKeyRef:
name: plausible-geoip
key: LICENSE_KEY
- op: replace
path: /spec/template/spec/containers/1/env/4
value:
name: GEOIPUPDATE_EDITION_IDS
value: "GeoLite2-Country GeoLite2-City"
- op: add
path: /spec/template/spec/containers/0/env/2
value:
name: IP_GEOLOCATION_DB
value: /geoip/GeoLite2-City.mmdb
- op: add
path: /spec/template/spec/volumes/-
value:
name: generated-secrets
emptyDir:
medium: Memory
- op: add
path: /spec/template/spec/containers/0/envFrom
value:
- configMapRef:
name: plausible-config
- op: add
path: /spec/template/spec/initContainers/0/envFrom
value:
- configMapRef:
name: plausible-config
- op: replace
path: /spec/template/spec/initContainers/0/args
value:
- >-
sleep 10 && /entrypoint.sh db migrate
- target:
version: v1
kind: Deployment
name: plausible
path: add-initcontainer.yaml

View File

@@ -0,0 +1,180 @@
image:
# -- The registry to pull the image from.
registry: ghcr.io
# -- The repository to pull the image from.
repository: plausible/community-edition
# -- The docker tag, if left empty chart's appVersion will be used.
# @default -- `.Chart.AppVersion`
tag: ''
# -- The pull policy for the controller.
pullPolicy: IfNotPresent
nameOverride: ''
fullnameOverride: ''
controller:
# -- Create a workload for this chart.
enabled: true
# -- Type of the workload object.
kind: Deployment
# -- The number of replicas.
replicas: 1
# -- Additional annotations for the controller object.
annotations: {}
# -- Additional labels for the controller object.
labels: {}
service:
# -- Create a service for exposing this chart.
enabled: true
# -- The service type used.
type: ClusterIP
# -- ClusterIP used if service type is `ClusterIP`.
clusterIP: ''
# -- LoadBalancerIP if service type is `LoadBalancer`.
loadBalancerIP: ''
# -- Allowed addresses when service type is `LoadBalancer`.
loadBalancerSourceRanges: []
# -- Additional annotations for the service object.
annotations: {}
# -- Additional labels for the service object.
labels: {}
serviceMonitor:
# -- Create a service monitor for prometheus operator.
enabled: false
# -- How frequently the exporter should be scraped.
interval: 30s
# -- Timeout value for individual scrapes.
timeout: 10s
# -- Additional annotations for the service monitor object.
annotations: {}
# -- Additional labels for the service monitor object.
labels: {}
ingressRoute:
# -- Create an IngressRoute object for exposing this chart.
create: true
# -- List of [entry points](https://doc.traefik.io/traefik/routing/routers/#entrypoints) on which the ingress route will be available.
entryPoints: [websecure]
# -- [Matching rule](https://doc.traefik.io/traefik/routing/routers/#rule) for the underlying router.
rule: Host(`analytics.arcodange.lab`)
# -- List of [middleware objects](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-middleware) for the ingress route.
middlewares:
- name: localIp@file
# -- Use an existing secret containing the TLS certificate.
tlsSecretName: ''
# -- Additional annotations for the ingress route object.
annotations: {}
# -- Additional labels for the ingress route object.
labels: {}
certificate:
# -- Create an Certificate object for the exposed chart.
create: false
# -- List of subject alternative names for the certificate.
dnsNames: []
# -- Name of the secret in which the certificate will be stored. Defaults to the first item in dnsNames.
secretName: ''
issuerRef:
# -- Type of the referenced certificate issuer. Can be "Issuer" or "ClusterIssuer".
kind: ClusterIssuer
# -- Name of the referenced certificate issuer.
name: ''
# -- Additional annotations for the certificate object.
annotations: {}
# -- Additional labels for the certificate object.
labels: {}
env:
# -- Timezone for the container.
- name: TZ
value: Europe/Paris
ports:
http:
# -- Enable the port inside the `Deployment` and `Service` objects.
enabled: true
# -- The port used as internal port and cluster-wide port if `.service.type` == `ClusterIP`.
port: 8000
# -- The external port used if `.service.type` == `NodePort`.
nodePort: null
# -- The protocol used for the service.
protocol: TCP
secret:
# -- Create a new secret object.
create: false
# -- Use an existing secret object.
existingSecret: 'plausible-config'
# -- Secret values used when not using an existing secret. Helm templates are supported for values.
values:
# -- Secret key for session tokens.
SECRET_KEY_BASE: '{{ randAlphaNum 42 | b64enc }}'
# -- Encryption token for TOTP secrets.
TOTP_VAULT_KEY: '{{ randAlphaNum 32 | b64enc }}'
# -- Additional annotations for the secret object.
annotations: {}
# -- Additional labels for the secret object.
labels: {}
geoip:
# -- Enable support for MaxMinds GeoLite2 database.
enabled: true
image:
# -- The repository for the geoip image.
repository: ghcr.io/maxmind/geoipupdate
# -- The docker tag for the geoip image.
tag: v7.1.1
# -- Required. MaxMind account ID.
accountId: '1266329'
# -- Required. Case-sensitive MaxMind license key.
# licenseKey: 'kvv2/data/plausible/geoip LICENSE_KEY'
# -- Optional. Database update frequency. Defaults to "168" which equals 7 days.
frequency: 168
# -- Optional. Specify the database mount path inside the containers.
mountPath: /geoip
serviceAccount:
# -- Create a `ServiceAccount` object.
create: true
# -- Specify the service account used for the controller.
name: ''
# -- Additional annotations for the service account object.
annotations: {}
# -- Additional labels for the service account object.
labels: {}
# -- Pod-level security attributes. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context).
securityContext: {}
# fsGroup: 1000
# runAsNonRoot: true
# runAsGroup: 1000
# runAsUser: 1000
# -- Compute resources used by the container. More info [here](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# -- Pod-level affinity. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling).
affinity: {}
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: kubernetes.io/hostname
# operator: In
# values:
# - my-node-xyz
# -- Pod-level tolerations. More info [here](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling).
tolerations: []
# - key: node-role.kubernetes.io/control-plane
# operator: Exists
# effect: NoSchedule

View File

@@ -0,0 +1,21 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: plausible-config
namespace: tools
# Doc: https://github.com/plausible/community-edition/wiki/Configuration
data:
DB_HOST: pgbouncer.tools
DB_PORT: !!str 5432
DB_NAME: plausible
BASE_URL: https://analytics.arcodange.lab
CLICKHOUSE_DATABASE_URL: http://plausible:plausiblearcodange@clickhouse.tools:8123/plausible
DB_POOL_SIZE: "30"
DB_QUEUE_TARGET: "10000" # 10 secondes
DB_CONNECT_TIMEOUT: "30000" # 30 secondes
DB_RECONNECT_ATTEMPTS: "5"
DB_RECONNECT_DELAY: "5000"

View File

@@ -0,0 +1,24 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: plausible-geoip
namespace: tools
spec:
type: kv-v2
# mount path
mount: kvv2
# path of the secret
path: plausible/geoip
# dest k8s secret
destination:
name: plausible-geoip
create: true
# static secret refresh interval
refreshAfter: 30s
# Name of the CRD to authenticate to Vault
vaultAuthRef: plausible

View File

@@ -0,0 +1,20 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: plausible-external
labels:
app.kubernetes.io/instance: plausible
app.kubernetes.io/name: plausible
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host(`analytics.arcodange.fr`) && (PathPrefix(`/api/event`) || PathPrefix(`/js/`))
middlewares:
- name: kube-system-crowdsec@kubernetescrd
services:
- kind: Service
name: plausible-web
namespace: tools
port: 8000

View File

@@ -0,0 +1,14 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: plausible
namespace: tools
spec:
vaultConnectionRef: default
method: kubernetes
mount: kubernetes
kubernetes:
role: plausible
serviceAccount: plausible
audiences:
- vault

View File

@@ -0,0 +1,25 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: plausible-db-credentials
namespace: tools
spec:
# Mount path of the secrets backend
mount: postgres
# Path to the secret
path: creds/plausible
# Where to store the secrets, VSO will create the secret
destination:
create: true
name: plausible-db-credentials
# Restart these pods when secrets rotated
rolloutRestartTargets:
- kind: Deployment
name: plausible
# Name of the CRD to authenticate to Vault
vaultAuthRef: plausible

View File

@@ -0,0 +1,24 @@
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: plausible
namespace: tools
spec:
type: kv-v2
# mount path
mount: kvv2
# path of the secret
path: plausible/config
# dest k8s secret
destination:
name: plausible-config
create: true
# static secret refresh interval
refreshAfter: 30s
# Name of the CRD to authenticate to Vault
vaultAuthRef: plausible

23
prometheus/Chart.yaml Normal file
View File

@@ -0,0 +1,23 @@
apiVersion: v2
name: prometheus
description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: prometheus
version: 28.13.0
repository: https://prometheus-community.github.io/helm-charts
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
version: 0.1.0
appVersion: "v3.10.0"

View File

@@ -0,0 +1,3 @@
{{- if eq .Values.tool.kind "HelmChart" -}}
{{- include "tool.helm-chart-config.tpl" . -}}
{{- end -}}

View File

@@ -0,0 +1,3 @@
{{- if eq .Values.tool.kind "HelmChart" -}}
{{- include "tool.helm-chart.tpl" . -}}
{{- end -}}

1260
prometheus/values.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@ description: A Helm chart for Kubernetes
dependencies:
- name: tool
version: 0.1.0
repository: https://gitea.arcodange.duckdns.org/api/packages/arcodange-org/helm
repository: https://gitea.arcodange.lab/api/packages/arcodange-org/helm
- name: redis
version: 2.1.0
repository: https://charts.pascaliske.dev