cloudbeaver/example/cloudbeaver.nomad.hcl

330 lines
8.1 KiB
HCL

job "cloudbeaver" {
datacenters = ["dc1"]
region = "global"
group "cloudbeaver" {
shutdown_delay = "6s"
network {
mode = "bridge"
}
volume "data" {
source = "cloudbeaver-data"
type = "csi"
access_mode = "single-node-writer"
attachment_mode = "file-system"
}
service {
name = "cloudbeaver"
port = 8978
meta {
alloc = "${NOMAD_ALLOC_INDEX}"
datacenter = "${NOMAD_DC}"
group = "${NOMAD_GROUP_NAME}"
job = "${NOMAD_JOB_NAME}"
namespace = "${NOMAD_NAMESPACE}"
node = "${node.unique.name}"
region = "${NOMAD_REGION}"
}
connect {
sidecar_service {
proxy {
upstreams {
destination_name = "postgres"
local_bind_port = 5432
# Work arround, see https://github.com/hashicorp/nomad/issues/18538
destination_type = "service"
}
}
}
sidecar_task {
config {
args = [
"-c",
"${NOMAD_SECRETS_DIR}/envoy_bootstrap.json",
"-l",
"${meta.connect.log_level}",
"--concurrency",
"${meta.connect.proxy_concurrency}",
"--disable-hot-restart"
]
}
resources {
cpu = 50
memory = 64
}
}
}
tags = [
"traefik.enable=true",
"traefik.http.routers.cloudbeaver.entrypoints=https",
"traefik.http.routers.cloudbeaver.rule=Host(`cloudbeaver.example.org`)",
"traefik.http.middlewares.csp-cloudbeaver.headers.contentsecuritypolicy=default-src 'self';font-src 'self' data:;img-src 'self' data:;script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';",
"traefik.http.routers.cloudbeaver.middlewares=security-headers@file,rate-limit-std@file,forward-proto@file,inflight-std@file,hsts@file,compression@file,csp-cloudbeaver",
]
}
# wait for required services tp be ready before starting the main task
task "wait-for" {
driver = "docker"
user = 1053
config {
image = "danielberteaud/wait-for:24.3-1"
readonly_rootfs = true
pids_limit = 20
}
lifecycle {
hook = "prestart"
}
env {
SERVICE_0 = "master.postgres.service.consul"
}
resources {
cpu = 10
memory = 10
memory_max = 30
}
}
task "cloudbeaver" {
driver = "docker"
config {
image = "danielberteaud/cloudbeaver:24.0.1-1"
pids_limit = 100
readonly_rootfs = true
mount {
type = "tmpfs"
target = "/tmp"
tmpfs_options {
size = 3000000
}
}
}
vault {
policies = ["cloudbeaver"]
env = false
disable_file = true
change_mode = "noop"
}
env {
CLOUDBEAVER_WEB_CONFIG = "/local/cloudbeaver.conf"
}
# Use a template block instead of env {} so we can fetch values from vault
template {
data = <<_EOT
LANG=fr_FR.utf8
TZ=Europe/Paris
_EOT
destination = "secrets/.env"
perms = 400
env = true
}
# Postgres DB config
template {
data = <<_EOT
PGDATABASE=cloudbeaver
PGHOST=127.0.0.1
PGPORT=5432
PGUSER={{ with secret "database/creds/cloudbeaver" }}{{ .Data.username }}{{ end }}
PGPASSWORD={{ with secret "database/creds/cloudbeaver" }}{{ .Data.password }}{{ end }}
_EOT
destination = "secrets/.db.env"
perms = 0400
env = true
}
# Main cloudbeaver configuration
template {
data = <<_EOT
{
"app": {
"adminCredentialsSaveEnabled": false,
"anonymousAccessAllowed": false,
"anonymousUserTeam": "user",
"authenticationEnabled": true,
"defaultNavigatorSettings": {
"hideFolders": false,
"hideSchemas": false,
"mergeEntities": false,
"showOnlyEntities": false,
"showSystemObjects": true,
"showUtilityObjects": false
},
"disabledDrivers": [
"sqlite:sqlite_jdbc",
"h2:h2_embedded",
"h2:h2_embedded_v2"
],
"enabledAuthProviders": [
"local"
],
"enabledDrivers": [],
"forwardProxy": true,
"plugins": {},
"publicCredentialsSaveEnabled": false,
"resourceManagerEnabled": true,
"resourceQuotas": {
"dataExportFileSizeLimit": 1000000000,
"resourceManagerFileSizeLimit": 500000,
"sqlBinaryPreviewMaxLength": 261120,
"sqlMaxRunningQueries": 100,
"sqlResultSetMemoryLimit": 2000000,
"sqlResultSetRowsLimit": 100000,
"sqlTextPreviewMaxLength": 4096
},
"supportsCustomConnections": true
},
"server": {
"contentRoot": "web",
"database": {
"driver": "postgres-jdbc",
"initialDataConfiguration": "/secrets/initial-data.conf",
"password": "$${PGPASSWORD}",
"pool": {
"maxConnections": 100,
"maxIdleConnections": 10,
"minIdleConnections": 4,
"validationQuery": "SELECT 1"
},
"url": "jdbc:postgresql://$${PGHOST}:$${PGPORT}/$${PGDATABASE}",
"user": "$${PGUSER}"
},
"develMode": false,
"driversLocation": "drivers",
"expireSessionAfterPeriod": 600000,
"productConfiguration": "conf/product.conf",
"rootURI": "/",
"serverHost": "127.0.0.1",
"serverName": "cloudbeaver",
"serverPort": 8978,
"serverURL": "https://cloudbeaver.example.org",
"serviceURI": "/api/",
"sm": {
"blockLoginPeriod": "$${CLOUDBEAVER_BLOCK_PERIOD:300}",
"enableBruteForceProtection": true,
"expiredAuthAttemptInfoTtl": 60,
"maxFailedLogin": "$${CLOUDBEAVER_MAX_FAILED_LOGINS:5}",
"minimumLoginTimeout": "$${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
"passwordPolicy": {
"minLength": "$${CLOUDBEAVER_POLICY_MIN_LENGTH:8}",
"minNumberCount": "$${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}",
"minSymbolCount": "$${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}",
"requireMixedCase": "$${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}"
}
},
"workspaceLocation": "/data"
}
}
_EOT
destination = "local/cloudbeaver.conf"
}
# Logback config
template {
data = <<_EOT
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{dd-MM-yyyy HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<!-- Disable logback status messages -->
<statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
<!--
<logger name="org.jkiss" level="INFO"/>
<logger name="io.cloudbeaver" level="INFO"/>
-->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
_EOT
destination = "local/logback.xml"
}
# Initial config (admin user and teams)
template {
data = <<_EOT
{
adminName: "cloudbeaver",
adminPassword: "{{ with secret "kv/service/cloudbeaver" }}{{ .Data.data.initial_admin_pwd }}{{ end }}",
teams: [
{
subjectId: "admin",
teamName: "Admin",
description: "Administrative access. Has all permissions.",
permissions: [ "admin" ]
},
{
subjectId: "user",
teamName: "User",
description: "All users, including anonymous.",
permissions: [ ]
}
]
}
_EOT
destination = "secrets/initial-data.conf"
uid = 100000
gid = 108978
perms = 440
}
# Mount persistent volume in /data
volume_mount {
volume = "data"
destination = "/data"
}
resources {
cpu = 100
memory = 384
}
}
}
}