330 lines
8.1 KiB
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
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|