From 9ac8f38821aea5515eb3bf49d95e7cb311b567cd Mon Sep 17 00:00:00 2001 From: Maxim Kondratenko Date: Fri, 1 Sep 2023 16:55:33 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=C3=8Dnitial=20integration=20with=20Zitadel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 39 ++++++++++++ Makefile | 2 +- api/everest.go | 8 +++ cmd/config/config.go | 8 ++- docker-compose.yml | 131 +++++++++++++++++++++++++++++++++++++++-- go.mod | 7 ++- go.sum | 14 ++++- traefik-dynamic.yml | 109 ++++++++++++++++++++++++++++++++++ zitadel-config.yml | 96 ++++++++++++++++++++++++++++++ zitadel-init-steps.yml | 9 +++ 10 files changed, 412 insertions(+), 11 deletions(-) create mode 100644 .env.example create mode 100644 traefik-dynamic.yml create mode 100644 zitadel-config.yml create mode 100644 zitadel-init-steps.yml diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..d110bde4 --- /dev/null +++ b/.env.example @@ -0,0 +1,39 @@ +# ======================= GENERAL CONTAINERS PARAMS ====================================== +# Domain name Everest is exposed. +# Default=127.0.0.1.nip.io - points to 127.0.0.1 +# Mandatory. +EVEREST_DOMAIN=127.0.0.1.nip.io + +# The prefix name for all Everest containers. +# Default=everest +# Optional. +EVEREST_CONTAINER_PREFIX=everest + +# ======================== TRAEFIK PARAMS ====================================================== +# Exposed secured port. +# Default 443 +# Optional. +TRAEFIK_SECURE_HOST_PORT=443 + +# Exposed incured port. +# Traefik is configured to redirect all requests to SECURE ENDPOINT. +# Default 80 +# Optional. +TRAEFIK_INSECURE_HOST_PORT=80 + +# ======================== ZITADEL PARAMS ========================================================== +# Master encryption key for Zitadel. +# Must be >=32 chars. +# Mandatory. +ZITADEL_MASTERKEY= + +# ======================== EVERST BACKEND PARAMS ==================================== +# Everest backend docker container tag. +# Default='dev-latest'. +# Optional. +#EVEREST_TAG=v0.1.0 + +# OAuth Everest client JWT key path. +# Mandatory. +OAUTH_CLIENT_KEY_PATH= + diff --git a/Makefile b/Makefile index c0c60687..0ead0720 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ local-env-down: ## Stop development environment cert: ## Install dev TLS certificates mkcert -install - mkcert -cert-file=dev-cert.pem -key-file=dev-key.pem percona-everest-backend percona-everest-backend.localhost 127.0.0.1 + mkcert -cert-file=dev-cert.pem -key-file=dev-key.pem percona-everest-backend percona-everest-backend.localhost account.127.0.0.1.nip.io 127.0.0.1.nip.io 127.0.0.1 k8s: ## Create a local minikube cluster minikube start --nodes=3 --cpus=4 --memory=4g --apiserver-names host.docker.internal diff --git a/api/everest.go b/api/everest.go index 5c994dcf..b8e18906 100644 --- a/api/everest.go +++ b/api/everest.go @@ -36,6 +36,7 @@ import ( "github.com/percona/percona-everest-backend/model" "github.com/percona/percona-everest-backend/pkg/kubernetes" "github.com/percona/percona-everest-backend/public" + zitadel_introspect "github.com/zitadel/zitadel-go/v2/pkg/api/middleware/http" ) const ( @@ -136,6 +137,13 @@ func (e *EverestServer) initHTTPServer() error { // Use our validation middleware to check all requests against the OpenAPI schema. apiGroup := e.echo.Group(basePath) + + introspection, err := zitadel_introspect.NewIntrospectionInterceptor(e.config.OAuthIssuerUrl, e.config.OAuthClientKeyPath) + if err != nil { + return errors.Wrap(err, "could not init auth middleware") + } + + apiGroup.Use(echo.WrapMiddleware(introspection.Handler)) apiGroup.Use(middleware.OapiRequestValidatorWithOptions(swagger, &middleware.Options{ SilenceServersWarning: true, })) diff --git a/cmd/config/config.go b/cmd/config/config.go index 6fa787a3..67c5b8e4 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -20,9 +20,11 @@ import "github.com/kelseyhightower/envconfig" // EverestConfig stores the configuration for the application. type EverestConfig struct { - DSN string `default:"postgres://admin:pwd@127.0.0.1:5432/postgres?sslmode=disable" envconfig:"DSN"` - HTTPPort int `default:"8080" envconfig:"HTTP_PORT"` - Verbose bool `default:"false" envconfig:"VERBOSE"` + DSN string `default:"postgres://admin:pwd@127.0.0.1:5432/postgres?sslmode=disable" envconfig:"DSN"` + HTTPPort int `default:"8080" envconfig:"HTTP_PORT"` + Verbose bool `default:"false" envconfig:"VERBOSE"` + OAuthIssuerUrl string `default:"" envconfig:"OAUTH_ISSUER_URL"` + OAuthClientKeyPath string `default:"" envconfig:"OAUTH_CLIENT_KEY_PATH"` } // ParseConfig parses env vars and fills EverestConfig. diff --git a/docker-compose.yml b/docker-compose.yml index d0bb20e8..8529e4f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,132 @@ -version: "3" +version: '3.8' + services: + traefik: + image: traefik:v2.10.1 + container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-traefik" + networks: + - everest + restart: unless-stopped + environment: + # static configuration: https://docs.traefik.io/reference/static-configuration/env/ + + TRAEFIK_ACCESSLOG: "info" + TRAEFIK_LOG_LEVEL: "info" + + TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: ":443" + # in case browser doesn't support TLS1.3 change the value below to "tls12" + TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_TLS_OPTIONS: "tls13" + + # setup traffic redirection to secured port. + TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80" + TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: "websecure" + TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_SCHEME: "https" + TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_PERMANENT: "true" + + TRAEFIK_PROVIDERS_FILE_FILENAME: "/etc/traefik/traefik-dynamic.yml" + + EVEREST_DOMAIN: "${EVEREST_DOMAIN}" + + ports: + - "${TRAEFIK_INSECURE_HOST_PORT:-80}:80" + - "${TRAEFIK_SECURE_HOST_PORT:-443}:443" + volumes: + - ./traefik-dynamic.yml:/etc/traefik/traefik-dynamic.yml + - ./dev-cert.pem:/etc/traefik-ssl-cert/tls.crt + - ./dev-key.pem:/etc/traefik-ssl-cert/tls.key + + zitadel: + image: ghcr.io/zitadel/zitadel:v2.35.0 + container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-zitadel" + restart: unless-stopped + networks: + - everest + command: + - start-from-init + - --config=/zitadel-config.yml + - --steps=/zitadel-init-steps.yml + - --masterkeyFromEnv + - --tlsMode=external + environment: + ZITADEL_MASTERKEY: "${ZITADEL_MASTERKEY}" + ZITADEL_EXTERNALDOMAIN: "account.${EVEREST_DOMAIN}" + ZITADEL_EXTERNALPORT: "${TRAEFIK_SECURE_HOST_PORT:-443}" + depends_on: + crdb: + condition: service_healthy + certs: + condition: service_completed_successfully + volumes: + - ./zitadel-config.yml:/zitadel-config.yml:ro + - ./zitadel-init-steps.yml:/zitadel-init-steps.yml:ro + - zitadel-certs:/crdb-certs:ro + + certs: + image: cockroachdb/cockroach:v22.2.2 + container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-certs" + entrypoint: [ '/bin/bash', '-c' ] + command: [ 'cp /certs/* /zitadel-certs/ && + cockroach cert create-client --overwrite --certs-dir /zitadel-certs/ --ca-key /zitadel-certs/ca.key zitadel_user && chown 1000:1000 /zitadel-certs/*' + ] + volumes: + - certs:/certs:ro + - zitadel-certs:/zitadel-certs:rw + depends_on: + crdb: + condition: service_healthy + + crdb: + image: cockroachdb/cockroach:v22.2.2 + container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-crdb" + restart: unless-stopped + networks: + - everest + command: + - start-single-node + - --advertise-addr=crdb + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"] + interval: 10s + timeout: 30s + retries: 5 + start_period: 10s + volumes: + - certs:/cockroach/certs:rw + - cockroach-data:/cockroach/cockroach-data:rw + pg: - image: postgres + image: postgres:15.4 + container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-pg" + networks: + - everest environment: - POSTGRES_USER=admin - POSTGRES_PASSWORD=pwd - ports: - - 5432:5432 + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U admin" ] + interval: 5s + timeout: 5s + retries: 5 + + everest: + image: perconalab/everest:${EVEREST_TAG:-dev-latest} + container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-backend" + networks: + - everest + depends_on: + pg: + condition: service_healthy + environment: + - DSN=postgres://admin:pwd@pg:5432/postgres?sslmode=disable + - OAUTH_ISSUER_URL=https://account.${EVEREST_DOMAIN} + - OAUTH_CLIENT_KEY_PATH=/oauth_client_key.json + volumes: + - ${OAUTH_CLIENT_KEY_PATH}:/oauth_client_key.json:rw + +networks: + everest: + +volumes: + certs: + zitadel-certs: + cockroach-data: \ No newline at end of file diff --git a/go.mod b/go.mod index a1e09790..c018161a 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/getkin/kin-openapi v0.118.0 github.com/go-logr/zapr v1.2.4 github.com/golang-migrate/migrate/v4 v4.16.2 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/jinzhu/gorm v1.9.16 github.com/kelseyhightower/envconfig v1.4.0 github.com/labstack/echo/v4 v4.11.1 @@ -17,6 +17,7 @@ require ( github.com/percona/everest-operator v0.0.9 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 + github.com/zitadel/zitadel-go/v2 v2.0.17 go.uber.org/zap v1.25.0 k8s.io/api v0.28.0 k8s.io/apimachinery v0.28.0 @@ -53,6 +54,8 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/schema v1.2.0 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect @@ -86,6 +89,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/xlab/treeprint v1.2.0 // indirect + github.com/zitadel/oidc v1.13.4 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -102,6 +106,7 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect diff --git a/go.sum b/go.sum index 21d6b213..537d24f7 100644 --- a/go.sum +++ b/go.sum @@ -140,10 +140,14 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -286,6 +290,10 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zitadel/oidc v1.13.4 h1:+k2GKqP9Ld9S2MSFlj+KaNsoZ3J9oy+Ezw51EzSFuC8= +github.com/zitadel/oidc v1.13.4/go.mod h1:3h2DhUcP02YV6q/CA/BG4yla0o6rXjK+DkJGK/dwJfw= +github.com/zitadel/zitadel-go/v2 v2.0.17 h1:MKsiKxJqE0o3IxKd0zg6NLAnWxvdze5nRrXk0kLEvKc= +github.com/zitadel/zitadel-go/v2 v2.0.17/go.mod h1:pCT8y65qnRqTDBFf7UT5+6NAsAdfjgQCfn4BQ6pMWZ0= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -433,6 +441,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/traefik-dynamic.yml b/traefik-dynamic.yml new file mode 100644 index 00000000..5700308e --- /dev/null +++ b/traefik-dynamic.yml @@ -0,0 +1,109 @@ +# "dynamic" configuration: https://docs.traefik.io/providers/file/ + +tls: + certificates: + - certFile: /etc/traefik-ssl-cert/tls.crt + keyFile: /etc/traefik-ssl-cert/tls.key + stores: + - default + stores: + default: + defaultCertificate: + certFile: /etc/traefik-ssl-cert/tls.crt + keyFile: /etc/traefik-ssl-cert/tls.key + options: + tls13: + minVersion: VersionTLS13 + # Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, + # and vice versa. (https://tools.ietf.org/html/rfc8446) + tls12: + minVersion: VersionTLS12 + preferServerCipherSuites: true + cipherSuites: + # see Percona's security baseline; no SHA-1, ECDHE before plain RSA, GCM before CBC + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + - TLS_RSA_WITH_AES_128_GCM_SHA256 + - TLS_RSA_WITH_AES_256_GCM_SHA384 + - TLS_RSA_WITH_AES_128_CBC_SHA256 + +http: + middlewares: + zitadel-headers: + headers: + isDevelopment: false + allowedHosts: + - "account.{{ env "EVEREST_DOMAIN" }}" + customRequestHeaders: + authority: "account.{{ env "EVEREST_DOMAIN" }}" + + routers: + zitadel: + entryPoints: ["websecure"] + rule: "HostRegexp(`account.{{ env "EVEREST_DOMAIN" }}`, `{subdomain:[a-z]+}.account.{{ env "EVEREST_DOMAIN" }}`)" + priority: 10 + middlewares: ["zitadel-headers"] + service: zitadel + tls: + domains: + - main: "account.{{ env "EVEREST_DOMAIN" }}" + + everest-backend: + entryPoints: [ "websecure" ] + rule: "Host(`{{ env "EVEREST_DOMAIN" }}`) && PathPrefix(`/v1`)" + priority: 50 + service: everest-backend + tls: + domains: + - main: "{{ env "EVEREST_DOMAIN" }}" + + everest-frontend: + entryPoints: [ "websecure" ] + priority: 40 + rule: "Host(`{{ env "EVEREST_DOMAIN" }}`)" + service: everest-frontend + tls: + domains: + - main: "{{ env "EVEREST_DOMAIN" }}" + + services: + zitadel: + loadBalancer: + healthCheck: + path: /debug/healthz + port: 8080 + interval: "10s" + timeout: "3s" + scheme: h2c + servers: + # h2c is the scheme for unencrypted HTTP/2 + - url: h2c://zitadel:8080 + passHostHeader: true + + everest-frontend: + loadBalancer: +# healthCheck: +# path: /debug/healthz +# port: 8080 +# interval: "10s" +# timeout: "3s" +# scheme: h2c + servers: + - url: http://everest:8080 + passHostHeader: true + + everest-backend: + loadBalancer: +# healthCheck: +# path: /debug/healthz +# port: 8080 +# interval: "10s" +# timeout: "3s" +# scheme: h2c + servers: + - url: http://everest:8080 + passHostHeader: true \ No newline at end of file diff --git a/zitadel-config.yml b/zitadel-config.yml new file mode 100644 index 00000000..7408e277 --- /dev/null +++ b/zitadel-config.yml @@ -0,0 +1,96 @@ +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml +Log: + Level: 'info' + +## Make ZITADEL accessible over HTTP, not HTTPS +ExternalSecure: true # ZITADEL_EXTERNALSECURE +#ExternalDomain: localhost # ZITADEL_EXTERNALDOMAIN +#ExternalPort: 443 # ZITADEL_EXTERNALPORT +## Header name of HTTP2 (incl. gRPC) calls from which the instance will be matched +HTTP2HostHeader: ":authority" # ZITADEL_HTTP2HOSTHEADER +## Header name of HTTP1 calls from which the instance will be matched +HTTP1HostHeader: "host" # ZITADEL_HTTP1HOSTHEADER +WebAuthNName: ZITADEL # ZITADEL_WEBAUTHN_NAME + +# If not using the docker compose example, adjust these values for connecting ZITADEL to your CockroachDB +Database: + cockroach: + Host: 'crdb' + User: + Username: 'zitadel_user' + SSL: + Mode: 'verify-full' + RootCert: "/crdb-certs/ca.crt" + Cert: "/crdb-certs/client.zitadel_user.crt" + Key: "/crdb-certs/client.zitadel_user.key" + Admin: + Username: 'root' + SSL: + Mode: 'verify-full' + RootCert: "/crdb-certs/ca.crt" + Cert: "/crdb-certs/client.root.crt" + Key: "/crdb-certs/client.root.key" + +LogStore: + Access: + Stdout: + Enabled: true + +# Storage for assets like user avatar, organization logo, icon, font, ... +AssetStorage: + Type: db # ZITADEL_ASSET_STORAGE_TYPE + # HTTP cache control settings for serving assets in the assets API and login UI + # the assets will also be served with an etag and last-modified header + Cache: + MaxAge: 5s # ZITADEL_ASSETSTORAGE_CACHE_MAXAGE + # 168h are 7 days + SharedMaxAge: 168h # ZITADEL_ASSETSTORAGE_CACHE_SHAREDMAXAGE + +OIDC: + # Sets the default values for lifetime and expiration for OIDC + # This default can be overwritten in the default instance configuration and for each instance during runtime + # !!! Changing this after the initial setup will have no impact without a restart !!! + DefaultAccessTokenLifetime: 1h # ZITADEL_OIDC_DEFAULTACCESSTOKENLIFETIME + DefaultIdTokenLifetime: 1h # ZITADEL_OIDC_DEFAULTIDTOKENLIFETIME + # 720h are 30 days, one month + DefaultRefreshTokenIdleExpiration: 720h # ZITADEL_OIDC_DEFAULTREFRESHTOKENIDLEEXPIRATION + # 2160h are 90 days, three months + DefaultRefreshTokenExpiration: 2160h # ZITADEL_OIDC_DEFAULTREFRESHTOKENEXPIRATION + +DefaultInstance: + LoginPolicy: + AllowUsernamePassword: true # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWUSERNAMEPASSWORD + AllowRegister: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWREGISTER + AllowExternalIDP: true # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWEXTERNALIDP + ForceMFA: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_FORCEMFA + HidePasswordReset: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_HIDEPASSWORDRESET + IgnoreUnknownUsernames: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_IGNOREUNKNOWNUSERNAMES + AllowDomainDiscovery: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWDOMAINDISCOVERY + PrivacyPolicy: + TOSLink: https://www.percona.com/legal/platform-terms-of-service # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_TOSLINK + PrivacyLink: https://www.percona.com/privacy-policy # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_PRIVACYLINK + HelpLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_HELPLINK + SupportEmail: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_SUPPORTEMAIL + # Sets the default values for lifetime and expiration for OIDC in each newly created instance + # This default can be overwritten for each instance during runtime + # Overwrites the system defaults + # If defined but not all durations are set it will result in an error + OIDCSettings: + AccessTokenLifetime: 1h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_ACCESSTOKENLIFETIME + IdTokenLifetime: 1h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_IDTOKENLIFETIME + # 720h are 30 days + RefreshTokenIdleExpiration: 720h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_REFRESHTOKENIDLEEXPIRATION + # 2160h are 90 days + RefreshTokenExpiration: 2160h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_REFRESHTOKENEXPIRATION + # this configuration sets the default email configuration + SMTPConfiguration: + # Configuration of the host + SMTP: + # must include the port, like smtp.mailtrap.io:2525. IPv6 is also supported, like [2001:db8::1]:2525 + Host: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST + User: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER + Password: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD + TLS: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_SSL + # If the host of the sender is different from ExternalDomain set DefaultInstance.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain to false + From: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROM + FromName: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROMNAME \ No newline at end of file diff --git a/zitadel-init-steps.yml b/zitadel-init-steps.yml new file mode 100644 index 00000000..a4a98464 --- /dev/null +++ b/zitadel-init-steps.yml @@ -0,0 +1,9 @@ +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml +FirstInstance: + Org: + Name: 'Percona' + Human: + # use the login admin@percona. + Username: 'admin' + Password: 'Password1!' + DisplayName: 'Admin' \ No newline at end of file From 3bad9dcd2f8974da42077bea7bd5933704493ecd Mon Sep 17 00:00:00 2001 From: Maxim Kondratenko Date: Thu, 7 Sep 2023 10:25:42 +0300 Subject: [PATCH 2/2] Adjust configuration --- .env.example | 12 ++++++++++++ Makefile | 7 ++++--- docker-compose.yml | 24 ++++++++++++++++++++---- zitadel-config.yml | 16 +++++++++------- zitadel-init-steps.yml | 6 ++++-- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/.env.example b/.env.example index d110bde4..4940444c 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,18 @@ TRAEFIK_INSECURE_HOST_PORT=80 # Mandatory. ZITADEL_MASTERKEY= +# Used for sending e-mail to users. +# Mandatory. +SMTP_HOST= + +# Used for sending e-mail to users. +# Mandatory. +SMTP_USER= + +# Used for sending e-mail to users. +# Mandatory. +SMTP_PASSWORD= + # ======================== EVERST BACKEND PARAMS ==================================== # Everest backend docker container tag. # Default='dev-latest'. diff --git a/Makefile b/Makefile index 0ead0720..044005b4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ FILES = $(shell find . -type f -name '*.go') +include .env default: help @@ -45,14 +46,14 @@ run-debug: build-debug ## Run binary bin/percona-everest-backend-debug local-env-up: ## Start development environment - docker-compose up --detach --remove-orphans + CAROOT_PATH="$(shell mkcert -CAROOT)" docker-compose up --detach --remove-orphans local-env-down: ## Stop development environment - docker-compose down --volumes --remove-orphans + CAROOT_PATH="$(shell mkcert -CAROOT)" docker-compose down --volumes --remove-orphans cert: ## Install dev TLS certificates mkcert -install - mkcert -cert-file=dev-cert.pem -key-file=dev-key.pem percona-everest-backend percona-everest-backend.localhost account.127.0.0.1.nip.io 127.0.0.1.nip.io 127.0.0.1 + mkcert -cert-file=dev-cert.pem -key-file=dev-key.pem percona-everest-backend percona-everest-backend.localhost *.${EVEREST_DOMAIN} ${EVEREST_DOMAIN} 127.0.0.1 k8s: ## Create a local minikube cluster minikube start --nodes=3 --cpus=4 --memory=4g --apiserver-names host.docker.internal diff --git a/docker-compose.yml b/docker-compose.yml index 8529e4f0..961a796a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,7 @@ services: traefik: image: traefik:v2.10.1 container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-traefik" + hostname: account.${EVEREST_DOMAIN} networks: - everest restart: unless-stopped @@ -48,14 +49,23 @@ services: - --masterkeyFromEnv - --tlsMode=external environment: - ZITADEL_MASTERKEY: "${ZITADEL_MASTERKEY}" - ZITADEL_EXTERNALDOMAIN: "account.${EVEREST_DOMAIN}" - ZITADEL_EXTERNALPORT: "${TRAEFIK_SECURE_HOST_PORT:-443}" + - ZITADEL_MASTERKEY=${ZITADEL_MASTERKEY} + - ZITADEL_EXTERNALDOMAIN=account.${EVEREST_DOMAIN} + - ZITADEL_EXTERNALPORT=${TRAEFIK_SECURE_HOST_PORT:-443} + - ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST=${SMTP_HOST} + - ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER=${SMTP_USER} + - ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD=${SMTP_PASSWORD} depends_on: crdb: condition: service_healthy certs: condition: service_completed_successfully + healthcheck: + test: [ "CMD", "/app/zitadel", "ready" ] + interval: 10s + timeout: 10s + retries: 5 + start_period: 20s volumes: - ./zitadel-config.yml:/zitadel-config.yml:ro - ./zitadel-init-steps.yml:/zitadel-init-steps.yml:ro @@ -97,6 +107,7 @@ services: pg: image: postgres:15.4 container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-pg" + restart: unless-stopped networks: - everest environment: @@ -111,17 +122,22 @@ services: everest: image: perconalab/everest:${EVEREST_TAG:-dev-latest} container_name: "${EVEREST_CONTAINER_PREFIX:-everest}-backend" + pull_policy: always + restart: unless-stopped networks: - everest depends_on: pg: condition: service_healthy + zitadel: + condition: service_healthy environment: - DSN=postgres://admin:pwd@pg:5432/postgres?sslmode=disable - OAUTH_ISSUER_URL=https://account.${EVEREST_DOMAIN} - OAUTH_CLIENT_KEY_PATH=/oauth_client_key.json volumes: - - ${OAUTH_CLIENT_KEY_PATH}:/oauth_client_key.json:rw + - ${OAUTH_CLIENT_KEY_PATH}:/oauth_client_key.json:ro + - ${CAROOT_PATH:-.}:/etc/ssl/certs:ro networks: everest: diff --git a/zitadel-config.yml b/zitadel-config.yml index 7408e277..5d788134 100644 --- a/zitadel-config.yml +++ b/zitadel-config.yml @@ -87,10 +87,12 @@ DefaultInstance: # Configuration of the host SMTP: # must include the port, like smtp.mailtrap.io:2525. IPv6 is also supported, like [2001:db8::1]:2525 - Host: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST - User: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER - Password: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD - TLS: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_SSL - # If the host of the sender is different from ExternalDomain set DefaultInstance.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain to false - From: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROM - FromName: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROMNAME \ No newline at end of file +# Host: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST +# User: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER +# Password: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD + TLS: true # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_SSL +# If the host of the sender is different from ExternalDomain set DefaultInstance.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain to false + From: Everest admin # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROM + FromName: Percona Everest Identity Provider # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROMNAME + DomainPolicy: + SMTPSenderAddressMatchesInstanceDomain: false \ No newline at end of file diff --git a/zitadel-init-steps.yml b/zitadel-init-steps.yml index a4a98464..4602c017 100644 --- a/zitadel-init-steps.yml +++ b/zitadel-init-steps.yml @@ -1,9 +1,11 @@ # All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml FirstInstance: + DefaultLanguage: en # ZITADEL_DEFAULTINSTANCE_DEFAULTLANGUAGE Org: Name: 'Percona' Human: - # use the login admin@percona. + # use the login admin@percona. Username: 'admin' Password: 'Password1!' - DisplayName: 'Admin' \ No newline at end of file + DisplayName: 'Admin' + PasswordChangeRequired: true # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED \ No newline at end of file