Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2b6a35b26 | ||
|
|
405524b036 | ||
|
|
7a58959869 | ||
|
|
0a5476793e | ||
|
|
389d4e5b13 | ||
|
|
bb8fdc64ba | ||
|
|
349adb2b95 | ||
|
|
cf81405a3f | ||
|
|
95dd642243 | ||
|
|
7df02cccdf | ||
|
|
05e1056a36 | ||
|
|
e91b993cad | ||
|
|
cab772403d | ||
|
|
0ded9c3a4d | ||
|
|
d24d0c194b | ||
|
|
8f3b7b3b2b |
@@ -1 +1,2 @@
|
||||
node_modules/
|
||||
/apps/.DS_Store
|
||||
|
||||
+74
-6
@@ -3,6 +3,7 @@ import { appInfoSchema, dynamicComposeSchema } from '@runtipi/common/schemas'
|
||||
import { fromError } from 'zod-validation-error';
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import YAML from 'yaml'
|
||||
|
||||
const getApps = async () => {
|
||||
const appsDir = await fs.promises.readdir(path.join(process.cwd(), 'apps'))
|
||||
@@ -29,7 +30,7 @@ describe("each app should have the required files", async () => {
|
||||
const apps = await getApps()
|
||||
|
||||
for (const app of apps) {
|
||||
const files = ['config.json', 'docker-compose.json', 'metadata/logo.jpg', 'metadata/description.md']
|
||||
const files = ['config.json', 'metadata/logo.jpg', 'metadata/description.md']
|
||||
|
||||
for (const file of files) {
|
||||
test(`app ${app} should have ${file}`, async () => {
|
||||
@@ -37,6 +38,12 @@ describe("each app should have the required files", async () => {
|
||||
expect(fileContent).not.toBeNull()
|
||||
})
|
||||
}
|
||||
|
||||
test(`app ${app} should have a compose file`, async () => {
|
||||
const legacyCompose = await getFile(app, 'docker-compose.json')
|
||||
const modernCompose = await getFile(app, 'docker-compose.yml')
|
||||
expect(legacyCompose || modernCompose).not.toBeNull()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -58,17 +65,78 @@ describe("each app should have a valid config.json", async () => {
|
||||
}
|
||||
})
|
||||
|
||||
describe("each app should have a valid docker-compose.json", async () => {
|
||||
describe("n8n-sandbox installation secrets", () => {
|
||||
test("exposes the shared API key as a password field", async () => {
|
||||
const fileContent = await getFile('n8n-sandbox', 'config.json')
|
||||
const config = JSON.parse(fileContent || '{}')
|
||||
const apiKey = config.form_fields?.find((field: { env_variable?: string }) => field.env_variable === 'SANDBOX_API_KEYS')
|
||||
|
||||
expect(apiKey?.type).toBe('password')
|
||||
expect(apiKey?.required).toBe(true)
|
||||
expect(apiKey?.min).toBeGreaterThanOrEqual(48)
|
||||
expect(config.port).toBeUndefined()
|
||||
expect(config.tipi_version).toBeGreaterThanOrEqual(5)
|
||||
})
|
||||
})
|
||||
|
||||
describe("n8n-sandbox post-install documentation", () => {
|
||||
test("documents the actual n8n override and optional SearXNG JSON setup", async () => {
|
||||
const description = await getFile('n8n-sandbox', 'metadata/description.md')
|
||||
|
||||
expect(description).toContain('services:\n n8n-2:\n environment:')
|
||||
expect(description).toContain('N8N_SANDBOX_SERVICE_URL=http://sandbox-api:8080')
|
||||
expect(description).toContain("Runtipi ne demande aucun port pour cette app")
|
||||
expect(description).not.toContain('sandbox-api:<PORT')
|
||||
expect(description).toContain('N8N_SANDBOX_SERVICE_API_KEY=<clé choisie lors de l’installation>')
|
||||
expect(description).toContain('/opt/runtipi/app-data/migrated/searxng/data/settings.yml')
|
||||
expect(description).toContain('- json')
|
||||
})
|
||||
})
|
||||
|
||||
describe("modern compose files preserve runtime semantics", () => {
|
||||
test("n8n-sandbox keeps its certificate bootstrap healthy for Runtipi", async () => {
|
||||
const fileContent = await getFile('n8n-sandbox', 'docker-compose.yml')
|
||||
expect(fileContent).not.toBeNull()
|
||||
|
||||
const parsed = YAML.parse(fileContent || '')
|
||||
const certs = parsed.services?.['sandbox-certs']
|
||||
const api = parsed.services?.['sandbox-api']
|
||||
|
||||
expect(parsed['x-runtipi']?.schema_version).toBe(2)
|
||||
const certCommand = certs?.command?.join(' ') || ''
|
||||
expect(certs?.restart).toBe('unless-stopped')
|
||||
expect(certCommand).toContain('rm -f /tmp/certs-ready')
|
||||
expect(certCommand).toContain('touch /tmp/certs-ready')
|
||||
expect(certCommand).toContain('tail -f /dev/null')
|
||||
expect(certCommand.indexOf('rm -f /tmp/certs-ready')).toBeLessThan(certCommand.indexOf('bootstrap-mtls.sh'))
|
||||
expect(certs?.healthcheck?.test).toContain('test -f /tmp/certs-ready')
|
||||
expect(api?.depends_on?.['sandbox-certs']?.condition).toBe('service_healthy')
|
||||
expect(api?.['x-runtipi']?.is_main).toBe(true)
|
||||
expect(parsed.services?.['sandbox-runner-1']?.environment?.SANDBOX_RUNNER_HTTP_BASE_URL).toBe('https://sandbox-runner-1:8080')
|
||||
expect(parsed.services?.['sandbox-runner-1']?.healthcheck?.test).toContain('https://localhost:8080/readyz')
|
||||
})
|
||||
})
|
||||
|
||||
describe("each app should have a valid compose file", async () => {
|
||||
const apps = await getApps()
|
||||
|
||||
for (const app of apps) {
|
||||
test(`app ${app} should have a valid docker-compose.json`, async () => {
|
||||
const fileContent = await getFile(app, 'docker-compose.json')
|
||||
const parsed = dynamicComposeSchema.safeParse(JSON.parse(fileContent || '{}'))
|
||||
test(`app ${app} should have a valid compose file`, async () => {
|
||||
const legacyCompose = await getFile(app, 'docker-compose.json')
|
||||
const modernCompose = await getFile(app, 'docker-compose.yml')
|
||||
|
||||
if (modernCompose) {
|
||||
const parsed = YAML.parse(modernCompose)
|
||||
expect(parsed['x-runtipi']?.schema_version).toBeTypeOf('number')
|
||||
expect(parsed.services).toBeTypeOf('object')
|
||||
return
|
||||
}
|
||||
|
||||
const parsed = dynamicComposeSchema.safeParse(JSON.parse(legacyCompose || '{}'))
|
||||
|
||||
if (!parsed.success) {
|
||||
const validationError = fromError(parsed.error);
|
||||
console.error(`Error parsing docker-compose.json for app ${app}:`, validationError.toString());
|
||||
console.error(`Error parsing compose file for app ${app}:`, validationError.toString());
|
||||
}
|
||||
|
||||
expect(parsed.success).toBe(true)
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -1,49 +0,0 @@
|
||||
# n8n Sandbox Service
|
||||
|
||||
Sandbox auto-hébergé pour l'**AI Assistant** de n8n (setup « Self-host the sandbox manually » de la doc n8n). L'app déploie les trois services de la stack officielle :
|
||||
|
||||
| Service | Rôle |
|
||||
|---|---|
|
||||
| `sandbox-certs` | Job one-shot : génère la CA privée et les certificats mTLS, puis s'arrête. |
|
||||
| `sandbox-api` | Point d'entrée HTTP (`:8080`) que n8n appelle pour exécuter du code. |
|
||||
| `sandbox-runner-1` | Docker-in-Docker **privileged** : crée et exécute les conteneurs sandbox. |
|
||||
|
||||
## Après l'installation
|
||||
|
||||
Dans l'app **n8n** (paramètres ou `app.env`), ajouter :
|
||||
|
||||
```
|
||||
N8N_ENABLED_MODULES=instance-ai
|
||||
N8N_INSTANCE_AI_SANDBOX_ENABLED=true
|
||||
N8N_INSTANCE_AI_SANDBOX_PROVIDER=n8n-sandbox
|
||||
N8N_INSTANCE_AI_SANDBOX_IMAGE=n8nio/n8n-sandbox-service-sandbox:1.3.0
|
||||
N8N_SANDBOX_SERVICE_URL=http://sandbox-api:8080
|
||||
N8N_SANDBOX_SERVICE_API_KEY=<valeur du champ « Clé API sandbox »>
|
||||
```
|
||||
|
||||
Puis redémarrer n8n et vérifier depuis son conteneur :
|
||||
|
||||
```
|
||||
wget -qO- http://sandbox-api:8080/healthz # {"status":"ok"}
|
||||
```
|
||||
|
||||
## Données persistantes
|
||||
|
||||
Tout est sous `app-data/<store>/n8n-sandbox/data/` :
|
||||
|
||||
- `tls/` : certificats mTLS (contient la clé de la CA, à traiter comme un secret)
|
||||
- `api/` : base SQLite de l'API
|
||||
- `runner-state/` : base SQLite du runner
|
||||
- `runner-docker/` : `/var/lib/docker` du DinD (cache de l'image sandbox, peut peser plusieurs Go ; vidable sans perte)
|
||||
|
||||
## Sécurité
|
||||
|
||||
- Aucun port n'est publié sur l'hôte. `sandbox-api:8080` est joignable par les autres apps Runtipi via `tipi_main_network`, protégé uniquement par la clé API.
|
||||
- Le runner est `privileged` : équivalent root sur l'hôte. Ne jamais l'exposer.
|
||||
- n8n recommande cette stack pour le développement/test et Daytona pour la production.
|
||||
|
||||
## Notes
|
||||
|
||||
- Les noms `sandbox-api` et `sandbox-runner-1` sont les SAN des certificats : ne pas les renommer.
|
||||
- Les certificats ne se renouvellent pas seuls. Pour les régénérer, supprimer `data/tls/` et redémarrer l'app.
|
||||
- L'image sandbox est téléchargée par le runner au premier usage.
|
||||
@@ -7,64 +7,22 @@
|
||||
"hostname": "mediamtx",
|
||||
"isMain": true,
|
||||
"internalPort": "8889",
|
||||
"environment": [
|
||||
{
|
||||
"key": "MTX_PROTOCOLS",
|
||||
"value": "tcp"
|
||||
},
|
||||
{
|
||||
"key": "MTX_LOGLEVEL",
|
||||
"value": "info"
|
||||
},
|
||||
{
|
||||
"key": "MTX_LOGDESTINATIONS",
|
||||
"value": "stdout"
|
||||
},
|
||||
{
|
||||
"key": "MTX_RTSPADDRESS",
|
||||
"value": ":8554"
|
||||
},
|
||||
{
|
||||
"key": "MTX_RTMPADDRESS",
|
||||
"value": ":1935"
|
||||
},
|
||||
{
|
||||
"key": "MTX_HLSADDRESS",
|
||||
"value": ":8888"
|
||||
},
|
||||
{
|
||||
"key": "MTX_WEBRTCADDRESS",
|
||||
"value": ":8889"
|
||||
},
|
||||
{
|
||||
"key": "MTX_SRTADDRESS",
|
||||
"value": ":8890"
|
||||
},
|
||||
{
|
||||
"key": "MTX_APIADDRESS",
|
||||
"value": ":9997"
|
||||
},
|
||||
{
|
||||
"key": "MTX_METRICSADDRESS",
|
||||
"value": ":9998"
|
||||
},
|
||||
{
|
||||
"key": "MTX_AUTHINTERNALUSERS",
|
||||
"value": "${MTX_API_USERNAME:+${MTX_API_USERNAME}:${MTX_API_PASSWORD}}"
|
||||
},
|
||||
{
|
||||
"key": "MTX_PATHDEFAULTS_RECORD",
|
||||
"value": "${MTX_RECORD_ENABLED:-false}"
|
||||
},
|
||||
{
|
||||
"key": "MTX_PATHDEFAULTS_RECORDPATH",
|
||||
"value": "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f"
|
||||
},
|
||||
{
|
||||
"key": "MTX_PATHDEFAULTS_RECORDFORMAT",
|
||||
"value": "fmp4"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"MTX_PROTOCOLS": "tcp",
|
||||
"MTX_LOGLEVEL": "info",
|
||||
"MTX_LOGDESTINATIONS": "stdout",
|
||||
"MTX_RTSPADDRESS": ":8554",
|
||||
"MTX_RTMPADDRESS": ":1935",
|
||||
"MTX_HLSADDRESS": ":8888",
|
||||
"MTX_WEBRTCADDRESS": ":8889",
|
||||
"MTX_SRTADDRESS": ":8890",
|
||||
"MTX_APIADDRESS": ":9997",
|
||||
"MTX_METRICSADDRESS": ":9998",
|
||||
"MTX_AUTHINTERNALUSERS": "${MTX_API_USERNAME:+${MTX_API_USERNAME}:${MTX_API_PASSWORD}}",
|
||||
"MTX_PATHDEFAULTS_RECORD": "${MTX_RECORD_ENABLED:-false}",
|
||||
"MTX_PATHDEFAULTS_RECORDPATH": "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f",
|
||||
"MTX_PATHDEFAULTS_RECORDFORMAT": "fmp4"
|
||||
},
|
||||
"addPorts": [
|
||||
{
|
||||
"containerPort": 8554,
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
"exposable": false,
|
||||
"no_gui": true,
|
||||
"dynamic_config": true,
|
||||
"port": 8080,
|
||||
"tipi_version": 1,
|
||||
"tipi_version": 5,
|
||||
"min_tipi_version": "4.7.0",
|
||||
"version": "1.3.0",
|
||||
"author": "n8n",
|
||||
@@ -18,11 +17,11 @@
|
||||
"supported_architectures": ["amd64", "arm64"],
|
||||
"form_fields": [
|
||||
{
|
||||
"type": "random",
|
||||
"encoding": "hex",
|
||||
"type": "password",
|
||||
"min": 48,
|
||||
"label": "Cle API sandbox (SANDBOX_API_KEYS)",
|
||||
"hint": "A recopier dans l'app n8n : N8N_SANDBOX_SERVICE_API_KEY. Plusieurs cles possibles, separees par des virgules.",
|
||||
"max": 128,
|
||||
"label": "Clé API partagée avec n8n (SANDBOX_API_KEYS)",
|
||||
"hint": "Choisir une clé forte, puis recopier cette même valeur dans N8N_SANDBOX_SERVICE_API_KEY dans les paramètres de l'app n8n officielle.",
|
||||
"required": true,
|
||||
"env_variable": "SANDBOX_API_KEYS"
|
||||
},
|
||||
@@ -32,24 +32,32 @@
|
||||
services:
|
||||
sandbox-certs:
|
||||
image: n8nio/n8n-sandbox-service-api:1.3.0
|
||||
# Obligatoire sous Runtipi : sans cette ligne le builder injecte
|
||||
# restart: unless-stopped et ce job one-shot boucle en redemarrage.
|
||||
restart: "no"
|
||||
# Runtipi considere l'app arretee si un seul de ses conteneurs est sorti.
|
||||
# Le bootstrap reste donc actif et sain apres la generation idempotente.
|
||||
restart: unless-stopped
|
||||
user: "0:0"
|
||||
entrypoint: ["sh", "-c"]
|
||||
# Genere les certs (idempotent) puis fixe les droits pour l'utilisateur
|
||||
# sandbox-api de l'image : /tls/api et le repertoire SQLite de l'API
|
||||
# (en bind mount, Docker cree le dossier en root sinon).
|
||||
# Genere les certs, fixe les droits pour sandbox-api, publie l'etat ready,
|
||||
# puis reste actif sans ouvrir de port ni lancer de service reseau.
|
||||
command:
|
||||
- >
|
||||
rm -f /tmp/certs-ready &&
|
||||
bootstrap-mtls.sh --out-dir /tls --api-san sandbox-api
|
||||
--control-san-prefix sandbox-runner &&
|
||||
chown -R sandbox-api:sandbox-api /tls/api /var/lib/n8n-sandbox-api
|
||||
chown -R sandbox-api:sandbox-api /tls/api /var/lib/n8n-sandbox-api &&
|
||||
touch /tmp/certs-ready &&
|
||||
exec tail -f /dev/null
|
||||
environment:
|
||||
NUM_RUNNERS: "1"
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/tls:/tls
|
||||
- ${APP_DATA_DIR}/data/api:/var/lib/n8n-sandbox-api
|
||||
healthcheck:
|
||||
test: "test -f /tmp/certs-ready"
|
||||
interval: 5s
|
||||
timeout: 2s
|
||||
retries: 12
|
||||
start_period: 5s
|
||||
|
||||
sandbox-api:
|
||||
image: n8nio/n8n-sandbox-service-api:1.3.0
|
||||
@@ -57,7 +65,7 @@ services:
|
||||
|
||||
depends_on:
|
||||
sandbox-certs:
|
||||
condition: service_completed_successfully
|
||||
condition: service_healthy
|
||||
|
||||
environment:
|
||||
SANDBOX_API_KEYS: "${SANDBOX_API_KEYS}"
|
||||
@@ -115,11 +123,10 @@ services:
|
||||
SANDBOX_RUNNER_REGISTRATION_TOKEN: "${SANDBOX_REGISTRATION_TOKEN}"
|
||||
|
||||
SANDBOX_RUNNER_API_GRPC_ADDR: sandbox-api:9090
|
||||
# http:// et non https:// : le mTLS ne couvre que le gRPC
|
||||
# (enregistrement + SandboxControl). Le trafic proxy exec/files de
|
||||
# l'API vers le runner reste en HTTP clair authentifie par X-Api-Key
|
||||
# (docs/configuration.md du depot et compose officiel n8n).
|
||||
SANDBOX_RUNNER_HTTP_BASE_URL: http://sandbox-runner-1:8080
|
||||
# Le listener HTTP du runner sert obligatoirement TLS avec le certificat
|
||||
# SandboxControl. Son SAN sandbox-runner-1 est genere par sandbox-certs.
|
||||
# HTTP est refuse depuis la version 1.3.0 pour ne pas exposer X-Api-Key.
|
||||
SANDBOX_RUNNER_HTTP_BASE_URL: https://sandbox-runner-1:8080
|
||||
|
||||
SANDBOX_RUNNER_CONTROL_GRPC_LISTEN_ADDR: ":9091"
|
||||
SANDBOX_RUNNER_CONTROL_GRPC_ADVERTISE_ADDR: sandbox-runner-1:9091
|
||||
@@ -148,8 +155,9 @@ services:
|
||||
|
||||
healthcheck:
|
||||
# /readyz passe au vert une fois le runner enregistre aupres de l'API
|
||||
# (meme check que le compose du depot upstream).
|
||||
test: "wget -qO- http://localhost:8080/readyz"
|
||||
# Le probe local ignore uniquement la verification du certificat ; le
|
||||
# trafic API -> runner reste verifie avec la CA et le SAN partages.
|
||||
test: "wget -qO- --no-check-certificate https://localhost:8080/readyz"
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 24
|
||||
@@ -0,0 +1,96 @@
|
||||
# n8n Sandbox Service
|
||||
|
||||
Sandbox auto-hébergé pour l'**AI Assistant** de n8n (configuration « Self-host the sandbox manually » de la documentation n8n). L'app déploie les trois services de la stack officielle :
|
||||
|
||||
| Service | Rôle |
|
||||
|---|---|
|
||||
| `sandbox-certs` | Initialise la CA privée et les certificats mTLS, puis reste inactif et sain pour que Runtipi conserve l'app au statut « Démarré ». |
|
||||
| `sandbox-api` | Point d'entrée HTTP interne (`:8080`) que n8n appelle pour exécuter du code. |
|
||||
| `sandbox-runner-1` | Docker-in-Docker **privileged** : crée et exécute les conteneurs sandbox. |
|
||||
|
||||
## Après l'installation
|
||||
|
||||
Pendant l'installation, choisir une clé forte dans le champ **Clé API partagée avec n8n** et la conserver dans un gestionnaire de mots de passe.
|
||||
|
||||
Dans l'application officielle **n8n**, activer la **configuration utilisateur Docker Compose**, puis ajouter :
|
||||
|
||||
```yaml
|
||||
# Add your docker-compose overrides here.
|
||||
# The overrides will be merged with the generated docker-compose.yml file.
|
||||
|
||||
# Heure de Paris
|
||||
services:
|
||||
n8n-2:
|
||||
environment:
|
||||
- GENERIC_TIMEZONE=Europe/Paris
|
||||
|
||||
# AI Assistant et Sandbox externe
|
||||
- N8N_ENABLED_MODULES=instance-ai
|
||||
- N8N_INSTANCE_AI_SANDBOX_ENABLED=true
|
||||
- N8N_INSTANCE_AI_SANDBOX_PROVIDER=n8n-sandbox
|
||||
- N8N_INSTANCE_AI_SANDBOX_IMAGE=n8nio/n8n-sandbox-service-sandbox:1.3.0
|
||||
- N8N_SANDBOX_SERVICE_URL=http://sandbox-api:8080
|
||||
- N8N_SANDBOX_SERVICE_API_KEY=<clé choisie lors de l’installation>
|
||||
```
|
||||
|
||||
Remplacer entièrement `<clé choisie lors de l’installation>` par la vraie clé, sans conserver les caractères `<` et `>`. Ne jamais publier cette valeur.
|
||||
|
||||
Le port de `N8N_SANDBOX_SERVICE_URL` reste `8080` : il s'agit du port interne du service Docker. Runtipi ne demande aucun port pour cette app, car elle n'en publie aucun sur l'hôte.
|
||||
|
||||
Enregistrer la configuration, puis redémarrer l'application **n8n**. Pour vérifier la communication depuis son conteneur :
|
||||
|
||||
```sh
|
||||
wget -qO- http://sandbox-api:8080/healthz
|
||||
```
|
||||
|
||||
La réponse attendue est `{"status":"ok"}`.
|
||||
|
||||
## Recherche web avec SearXNG (facultatif)
|
||||
|
||||
SearXNG est une application séparée et n'est pas nécessaire au fonctionnement du sandbox. L'installer seulement si les workflows ou outils IA de n8n doivent effectuer des recherches web.
|
||||
|
||||
Pour autoriser les réponses JSON de SearXNG, modifier :
|
||||
|
||||
```sh
|
||||
sudo nano /opt/runtipi/app-data/migrated/searxng/data/settings.yml
|
||||
```
|
||||
|
||||
Conserver les autres réglages existants et vérifier que le fichier contient :
|
||||
|
||||
```yaml
|
||||
use_default_settings: true
|
||||
|
||||
search:
|
||||
formats:
|
||||
- html
|
||||
- json
|
||||
```
|
||||
|
||||
Contrôle facultatif du contenu et des fins de ligne :
|
||||
|
||||
```sh
|
||||
sudo cat -A /opt/runtipi/app-data/migrated/searxng/data/settings.yml
|
||||
```
|
||||
|
||||
Redémarrer ensuite l'application **SearXNG**, puis redémarrer **n8n** si sa configuration a également été modifiée.
|
||||
|
||||
## Données persistantes
|
||||
|
||||
Tout est sous `app-data/<store>/n8n-sandbox/data/` :
|
||||
|
||||
- `tls/` : certificats mTLS (contient la clé de la CA, à traiter comme un secret)
|
||||
- `api/` : base SQLite de l'API
|
||||
- `runner-state/` : base SQLite du runner
|
||||
- `runner-docker/` : `/var/lib/docker` du DinD (cache de l'image sandbox, peut peser plusieurs Go ; vidable sans perte)
|
||||
|
||||
## Sécurité
|
||||
|
||||
- Aucun port n'est publié sur l'hôte. `sandbox-api:8080` est joignable par les autres apps Runtipi via `tipi_main_network`, protégé uniquement par la clé API.
|
||||
- Le runner est `privileged` : équivalent root sur l'hôte. Ne jamais l'exposer.
|
||||
- n8n recommande cette stack pour le développement/test et Daytona pour la production.
|
||||
|
||||
## Notes
|
||||
|
||||
- Les noms `sandbox-api` et `sandbox-runner-1` sont les SAN des certificats : ne pas les renommer.
|
||||
- Les certificats ne se renouvellent pas seuls. Pour les régénérer, supprimer `data/tls/` et redémarrer l'app.
|
||||
- L'image sandbox est téléchargée par le runner au premier usage.
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -29,16 +29,10 @@
|
||||
"readOnly": true
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
{
|
||||
"key": "NGINX_HOST",
|
||||
"value": "${NGINX_SERVER_NAME:-localhost}"
|
||||
},
|
||||
{
|
||||
"key": "TZ",
|
||||
"value": "${TZ:-Europe/Paris}"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"NGINX_HOST": "${NGINX_SERVER_NAME:-localhost}",
|
||||
"TZ": "${TZ:-Europe/Paris}"
|
||||
},
|
||||
"healthCheck": {
|
||||
"test": "curl --fail http://localhost:80 || exit 1",
|
||||
"interval": "30s",
|
||||
|
||||
@@ -9,12 +9,9 @@
|
||||
"sh",
|
||||
"/scripts/init-certs.sh"
|
||||
],
|
||||
"environment": [
|
||||
{
|
||||
"key": "CERT_TOOL_VERSION",
|
||||
"value": "4.14"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"CERT_TOOL_VERSION": "4.14"
|
||||
},
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/config",
|
||||
@@ -74,48 +71,18 @@
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"key": "OPENSEARCH_JAVA_OPTS",
|
||||
"value": "-Xms1g -Xmx1g -Dlog4j2.formatMsgNoLookups=true"
|
||||
},
|
||||
{
|
||||
"key": "DISABLE_INSTALL_DEMO_CONFIG",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "bootstrap.memory_lock",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "network.host",
|
||||
"value": "wazuh.indexer"
|
||||
},
|
||||
{
|
||||
"key": "node.name",
|
||||
"value": "wazuh.indexer"
|
||||
},
|
||||
{
|
||||
"key": "cluster.initial_cluster_manager_nodes",
|
||||
"value": "wazuh.indexer"
|
||||
},
|
||||
{
|
||||
"key": "node.max_local_storage_nodes",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "plugins.security.allow_default_init_securityindex",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "NODES_DN",
|
||||
"value": "CN=wazuh.indexer,OU=Wazuh,O=Wazuh,L=California,C=US"
|
||||
},
|
||||
{
|
||||
"key": "plugins.security.ssl.http.clientauth_mode",
|
||||
"value": "OPTIONAL"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"OPENSEARCH_JAVA_OPTS": "-Xms1g -Xmx1g -Dlog4j2.formatMsgNoLookups=true",
|
||||
"DISABLE_INSTALL_DEMO_CONFIG": "true",
|
||||
"bootstrap.memory_lock": "true",
|
||||
"network.host": "wazuh.indexer",
|
||||
"node.name": "wazuh.indexer",
|
||||
"cluster.initial_cluster_manager_nodes": "wazuh.indexer",
|
||||
"node.max_local_storage_nodes": "1",
|
||||
"plugins.security.allow_default_init_securityindex": "true",
|
||||
"NODES_DN": "CN=wazuh.indexer,OU=Wazuh,O=Wazuh,L=California,C=US",
|
||||
"plugins.security.ssl.http.clientauth_mode": "OPTIONAL"
|
||||
},
|
||||
"ulimits": {
|
||||
"memlock": {
|
||||
"soft": -1,
|
||||
@@ -209,64 +176,22 @@
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"key": "WAZUH_INDEXER_HOSTS",
|
||||
"value": "wazuh.indexer:9200"
|
||||
},
|
||||
{
|
||||
"key": "WAZUH_NODE_NAME",
|
||||
"value": "manager"
|
||||
},
|
||||
{
|
||||
"key": "WAZUH_NODE_TYPE",
|
||||
"value": "master"
|
||||
},
|
||||
{
|
||||
"key": "WAZUH_CLUSTER_NODES",
|
||||
"value": "wazuh.manager"
|
||||
},
|
||||
{
|
||||
"key": "WAZUH_CLUSTER_BIND_ADDR",
|
||||
"value": "wazuh.manager"
|
||||
},
|
||||
{
|
||||
"key": "INDEXER_URL",
|
||||
"value": "https://wazuh.indexer:9200"
|
||||
},
|
||||
{
|
||||
"key": "INDEXER_USERNAME",
|
||||
"value": "${INDEXER_USERNAME:-admin}"
|
||||
},
|
||||
{
|
||||
"key": "INDEXER_PASSWORD",
|
||||
"value": "${INDEXER_PASSWORD:-admin}"
|
||||
},
|
||||
{
|
||||
"key": "FILEBEAT_SSL_VERIFICATION_MODE",
|
||||
"value": "full"
|
||||
},
|
||||
{
|
||||
"key": "SSL_CERTIFICATE_AUTHORITIES",
|
||||
"value": "/var/ossec/etc/certs/root-ca.pem"
|
||||
},
|
||||
{
|
||||
"key": "SSL_CERTIFICATE",
|
||||
"value": "/var/ossec/etc/certs/server.pem"
|
||||
},
|
||||
{
|
||||
"key": "SSL_KEY",
|
||||
"value": "/var/ossec/etc/certs/server-key.pem"
|
||||
},
|
||||
{
|
||||
"key": "API_USERNAME",
|
||||
"value": "wazuh-wui"
|
||||
},
|
||||
{
|
||||
"key": "API_PASSWORD",
|
||||
"value": "${API_PASSWORD:-MyS3cr37P450r.*-}"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"WAZUH_INDEXER_HOSTS": "wazuh.indexer:9200",
|
||||
"WAZUH_NODE_NAME": "manager",
|
||||
"WAZUH_NODE_TYPE": "master",
|
||||
"WAZUH_CLUSTER_NODES": "wazuh.manager",
|
||||
"WAZUH_CLUSTER_BIND_ADDR": "wazuh.manager",
|
||||
"INDEXER_URL": "https://wazuh.indexer:9200",
|
||||
"INDEXER_USERNAME": "${INDEXER_USERNAME:-admin}",
|
||||
"INDEXER_PASSWORD": "${INDEXER_PASSWORD:-admin}",
|
||||
"FILEBEAT_SSL_VERIFICATION_MODE": "full",
|
||||
"SSL_CERTIFICATE_AUTHORITIES": "/var/ossec/etc/certs/root-ca.pem",
|
||||
"SSL_CERTIFICATE": "/var/ossec/etc/certs/server.pem",
|
||||
"SSL_KEY": "/var/ossec/etc/certs/server-key.pem",
|
||||
"API_USERNAME": "wazuh-wui",
|
||||
"API_PASSWORD": "${API_PASSWORD:-MyS3cr37P450r.*-}"
|
||||
},
|
||||
"ulimits": {
|
||||
"memlock": {
|
||||
"soft": -1,
|
||||
@@ -368,60 +293,21 @@
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"key": "SERVER_HOST",
|
||||
"value": "0.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "OPENSEARCH_HOSTS",
|
||||
"value": "https://wazuh.indexer:9200"
|
||||
},
|
||||
{
|
||||
"key": "SERVER_SSL_ENABLED",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "INDEXER_USERNAME",
|
||||
"value": "${INDEXER_USERNAME:-admin}"
|
||||
},
|
||||
{
|
||||
"key": "INDEXER_PASSWORD",
|
||||
"value": "${INDEXER_PASSWORD:-admin}"
|
||||
},
|
||||
{
|
||||
"key": "WAZUH_API_URL",
|
||||
"value": "https://wazuh.manager"
|
||||
},
|
||||
{
|
||||
"key": "DASHBOARD_USERNAME",
|
||||
"value": "${DASHBOARD_USERNAME:-kibanaserver}"
|
||||
},
|
||||
{
|
||||
"key": "DASHBOARD_PASSWORD",
|
||||
"value": "${DASHBOARD_PASSWORD:-kibanaserver}"
|
||||
},
|
||||
{
|
||||
"key": "API_USERNAME",
|
||||
"value": "wazuh-wui"
|
||||
},
|
||||
{
|
||||
"key": "API_PASSWORD",
|
||||
"value": "${API_PASSWORD:-MyS3cr37P450r.*-}"
|
||||
},
|
||||
{
|
||||
"key": "SERVER_SSL_CERTIFICATE",
|
||||
"value": "/usr/share/wazuh-dashboard/config/certs/dashboard.pem"
|
||||
},
|
||||
{
|
||||
"key": "SERVER_SSL_KEY",
|
||||
"value": "/usr/share/wazuh-dashboard/config/certs/dashboard-key.pem"
|
||||
},
|
||||
{
|
||||
"key": "OPENSEARCH_SSL_CERTIFICATE_AUTHORITIES",
|
||||
"value": "/usr/share/wazuh-dashboard/config/certs/root-ca.pem"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"SERVER_HOST": "0.0.0.0",
|
||||
"OPENSEARCH_HOSTS": "https://wazuh.indexer:9200",
|
||||
"SERVER_SSL_ENABLED": "true",
|
||||
"INDEXER_USERNAME": "${INDEXER_USERNAME:-admin}",
|
||||
"INDEXER_PASSWORD": "${INDEXER_PASSWORD:-admin}",
|
||||
"WAZUH_API_URL": "https://wazuh.manager",
|
||||
"DASHBOARD_USERNAME": "${DASHBOARD_USERNAME:-kibanaserver}",
|
||||
"DASHBOARD_PASSWORD": "${DASHBOARD_PASSWORD:-kibanaserver}",
|
||||
"API_USERNAME": "wazuh-wui",
|
||||
"API_PASSWORD": "${API_PASSWORD:-MyS3cr37P450r.*-}",
|
||||
"SERVER_SSL_CERTIFICATE": "/usr/share/wazuh-dashboard/config/certs/dashboard.pem",
|
||||
"SERVER_SSL_KEY": "/usr/share/wazuh-dashboard/config/certs/dashboard-key.pem",
|
||||
"OPENSEARCH_SSL_CERTIFICATE_AUTHORITIES": "/usr/share/wazuh-dashboard/config/certs/root-ca.pem"
|
||||
},
|
||||
"volumes": [
|
||||
{
|
||||
"hostPath": "${APP_DATA_DIR}/data/config/wazuh_ssl_certs",
|
||||
@@ -462,4 +348,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -12,7 +12,8 @@
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@types/node": "^22.14.1"
|
||||
"@types/node": "^22.14.1",
|
||||
"yaml": "2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@runtipi/common": "^0.8.0",
|
||||
|
||||
Reference in New Issue
Block a user