SECURITY - TASKER: add staging env guard
This commit is contained in:
parent
854a596149
commit
6737138ab7
|
|
@ -30,6 +30,7 @@ x-proxy-env: &proxy-env
|
||||||
CERT_EMAIL: ${CERT_EMAIL:-}
|
CERT_EMAIL: ${CERT_EMAIL:-}
|
||||||
CERT_ACME_CA: ${CERT_ACME_CA:-https://acme-v02.api.letsencrypt.org/directory}
|
CERT_ACME_CA: ${CERT_ACME_CA:-https://acme-v02.api.letsencrypt.org/directory}
|
||||||
CERT_ACME_DNS: ${CERT_ACME_DNS:-}
|
CERT_ACME_DNS: ${CERT_ACME_DNS:-}
|
||||||
|
TRUSTED_PROXIES: ${TRUSTED_PROXIES:-0.0.0.0/0}
|
||||||
LISTEN_HTTP_PORT: ${LISTEN_HTTP_PORT:-8090}
|
LISTEN_HTTP_PORT: ${LISTEN_HTTP_PORT:-8090}
|
||||||
LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-8443}
|
LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-8443}
|
||||||
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
|
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
APP_DOMAIN=task.staging.nodedc.example
|
||||||
|
APP_RELEASE=v1.3.0
|
||||||
|
|
||||||
|
WEB_REPLICAS=1
|
||||||
|
SPACE_REPLICAS=1
|
||||||
|
ADMIN_REPLICAS=1
|
||||||
|
API_REPLICAS=1
|
||||||
|
WORKER_REPLICAS=1
|
||||||
|
BEAT_WORKER_REPLICAS=1
|
||||||
|
LIVE_REPLICAS=1
|
||||||
|
|
||||||
|
LISTEN_HTTP_PORT=8090
|
||||||
|
LISTEN_HTTPS_PORT=8443
|
||||||
|
|
||||||
|
WEB_URL=https://task.staging.nodedc.example
|
||||||
|
DEBUG=0
|
||||||
|
CORS_ALLOWED_ORIGINS=https://task.staging.nodedc.example,https://launcher.staging.nodedc.example
|
||||||
|
API_BASE_URL=http://api:8000
|
||||||
|
COOKIE_DOMAIN=.staging.nodedc.example
|
||||||
|
|
||||||
|
PGHOST=plane-db
|
||||||
|
PGDATABASE=plane
|
||||||
|
POSTGRES_USER=plane
|
||||||
|
POSTGRES_PASSWORD=replace-with-random-staging-secret
|
||||||
|
POSTGRES_DB=plane
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
PGDATA=/var/lib/postgresql/data
|
||||||
|
DATABASE_URL=
|
||||||
|
|
||||||
|
REDIS_HOST=plane-redis
|
||||||
|
REDIS_PORT=6379
|
||||||
|
REDIS_URL=
|
||||||
|
|
||||||
|
RABBITMQ_HOST=plane-mq
|
||||||
|
RABBITMQ_PORT=5672
|
||||||
|
RABBITMQ_USER=plane
|
||||||
|
RABBITMQ_PASSWORD=replace-with-random-staging-secret
|
||||||
|
RABBITMQ_VHOST=plane
|
||||||
|
AMQP_URL=
|
||||||
|
|
||||||
|
CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
TRUSTED_PROXIES=replace-with-platform-edge-proxy-cidr
|
||||||
|
SITE_ADDRESS=:80
|
||||||
|
CERT_EMAIL=admin@nodedc.example
|
||||||
|
CERT_ACME_DNS=
|
||||||
|
|
||||||
|
SECRET_KEY=replace-with-random-staging-secret
|
||||||
|
|
||||||
|
USE_MINIO=1
|
||||||
|
AWS_REGION=
|
||||||
|
AWS_ACCESS_KEY_ID=replace-with-random-staging-secret
|
||||||
|
AWS_SECRET_ACCESS_KEY=replace-with-random-staging-secret
|
||||||
|
AWS_S3_ENDPOINT_URL=http://plane-minio:9000
|
||||||
|
AWS_S3_BUCKET_NAME=uploads
|
||||||
|
FILE_SIZE_LIMIT=5242880
|
||||||
|
PROXY_BODY_SIZE_LIMIT=1073741824
|
||||||
|
POSTHOG_API_KEY=
|
||||||
|
POSTHOG_HOST=
|
||||||
|
INSTANCE_CHANGELOG_URL=
|
||||||
|
IS_INTERCOM_ENABLED=0
|
||||||
|
INTERCOM_APP_ID=
|
||||||
|
|
||||||
|
GUNICORN_WORKERS=1
|
||||||
|
MINIO_ENDPOINT_SSL=0
|
||||||
|
API_KEY_RATE_LIMIT=60/minute
|
||||||
|
LIVE_SERVER_SECRET_KEY=replace-with-random-staging-secret
|
||||||
|
DOCKERHUB_USER=makeplane
|
||||||
|
PULL_POLICY=if_not_present
|
||||||
|
CUSTOM_BUILD=false
|
||||||
|
|
||||||
|
ENABLE_SIGNUP=0
|
||||||
|
ENABLE_EMAIL_PASSWORD=0
|
||||||
|
ENABLE_MAGIC_LINK_LOGIN=0
|
||||||
|
PLANE_OIDC_ISSUER=https://auth.staging.nodedc.example/application/o/task-manager/
|
||||||
|
PLANE_OIDC_CLIENT_ID=nodedc-task-manager
|
||||||
|
PLANE_OIDC_CLIENT_SECRET=replace-with-random-staging-secret
|
||||||
|
PLANE_OIDC_REDIRECT_URI=https://task.staging.nodedc.example/auth/oidc/callback
|
||||||
|
PLANE_OIDC_SCOPE="openid email profile groups"
|
||||||
|
PLANE_OIDC_REQUIRED_GROUPS=nodedc:superadmin,nodedc:taskmanager:admin,nodedc:taskmanager:user
|
||||||
|
PLANE_OIDC_AUTO_LINK_EMAIL=1
|
||||||
|
PLANE_OIDC_AUTO_CREATE_USER=1
|
||||||
|
PLANE_NODEDC_SKIP_PROFILE_ONBOARDING=1
|
||||||
|
PLANE_NODEDC_ACCESS_ENFORCEMENT=1
|
||||||
|
PLANE_NODEDC_ACCESS_CHECK_URL=https://launcher.staging.nodedc.example/api/internal/access/check
|
||||||
|
PLANE_NODEDC_ACCESS_TOKEN=replace-with-same-value-as-NODEDC_INTERNAL_ACCESS_TOKEN
|
||||||
|
PLANE_NODEDC_ACCESS_SERVICE_SLUG=task-manager
|
||||||
|
PLANE_NODEDC_ACCESS_TIMEOUT_SECONDS=3
|
||||||
|
PLANE_NODEDC_ACCESS_CACHE_SECONDS=0
|
||||||
|
PLANE_NODEDC_ACCESS_ENFORCE_UNLINKED=1
|
||||||
|
PLANE_NODEDC_ACCESS_DENIED_REDIRECT_URL=https://launcher.staging.nodedc.example/
|
||||||
|
PLANE_NODEDC_GLOBAL_LOGOUT_URL="https://launcher.staging.nodedc.example/auth/logout?global=1&returnTo=/"
|
||||||
|
PLANE_NODEDC_LAUNCHER_PUBLIC_URL=https://launcher.staging.nodedc.example
|
||||||
|
PLANE_NODEDC_HANDOFF_URL=https://launcher.staging.nodedc.example/api/internal/handoff/consume
|
||||||
|
PLANE_NODEDC_HANDOFF_TIMEOUT_SECONDS=3
|
||||||
|
PLANE_NODEDC_WORKSPACE_POLICY_URL=https://launcher.staging.nodedc.example/api/internal/access/check
|
||||||
|
PLANE_NODEDC_WORKSPACE_POLICY_TIMEOUT_SECONDS=3
|
||||||
|
PLANE_NODEDC_WORKSPACE_CREATION_MODE=any_authorized_user
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${1:-"$ROOT_DIR/plane-app/plane.env.staging"}"
|
||||||
|
|
||||||
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
|
echo "Missing Tasker staging env file: $ENV_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$ENV_FILE"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
failures=0
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "FAIL: $*" >&2
|
||||||
|
failures=$((failures + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
require_value() {
|
||||||
|
local name="$1"
|
||||||
|
local value="${!name:-}"
|
||||||
|
|
||||||
|
if [[ -z "$value" ]]; then
|
||||||
|
fail "$name is required"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_secret() {
|
||||||
|
local name="$1"
|
||||||
|
local value="${!name:-}"
|
||||||
|
|
||||||
|
require_value "$name"
|
||||||
|
|
||||||
|
if [[ "$value" =~ change-me|local-dev|replace-with|example|plane|secret-key|access-key ]]; then
|
||||||
|
fail "$name uses a placeholder/dev value"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#value} -lt 32 ]]; then
|
||||||
|
fail "$name must be at least 32 characters"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_https_url() {
|
||||||
|
local name="$1"
|
||||||
|
local value="${!name:-}"
|
||||||
|
|
||||||
|
require_value "$name"
|
||||||
|
|
||||||
|
if [[ "$value" != https://* ]]; then
|
||||||
|
fail "$name must use https://"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_staging_domain() {
|
||||||
|
local name="$1"
|
||||||
|
local value="${!name:-}"
|
||||||
|
|
||||||
|
require_value "$name"
|
||||||
|
|
||||||
|
if [[ "$value" == *.local.nodedc || "$value" == "localhost" || "$value" == 127.* ]]; then
|
||||||
|
fail "$name must not use local/dev domain"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_staging_domain APP_DOMAIN
|
||||||
|
require_https_url WEB_URL
|
||||||
|
require_https_url PLANE_OIDC_ISSUER
|
||||||
|
require_https_url PLANE_OIDC_REDIRECT_URI
|
||||||
|
require_https_url PLANE_NODEDC_ACCESS_CHECK_URL
|
||||||
|
require_https_url PLANE_NODEDC_ACCESS_DENIED_REDIRECT_URL
|
||||||
|
require_https_url PLANE_NODEDC_GLOBAL_LOGOUT_URL
|
||||||
|
require_https_url PLANE_NODEDC_LAUNCHER_PUBLIC_URL
|
||||||
|
require_https_url PLANE_NODEDC_HANDOFF_URL
|
||||||
|
require_https_url PLANE_NODEDC_WORKSPACE_POLICY_URL
|
||||||
|
|
||||||
|
require_value CORS_ALLOWED_ORIGINS
|
||||||
|
IFS=',' read -ra cors_origins <<< "$CORS_ALLOWED_ORIGINS"
|
||||||
|
for origin in "${cors_origins[@]}"; do
|
||||||
|
origin="${origin//[[:space:]]/}"
|
||||||
|
if [[ "$origin" != https://* ]]; then
|
||||||
|
fail "CORS_ALLOWED_ORIGINS contains non-HTTPS origin: $origin"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
require_secret POSTGRES_PASSWORD
|
||||||
|
require_secret RABBITMQ_PASSWORD
|
||||||
|
require_secret SECRET_KEY
|
||||||
|
require_secret AWS_ACCESS_KEY_ID
|
||||||
|
require_secret AWS_SECRET_ACCESS_KEY
|
||||||
|
require_secret LIVE_SERVER_SECRET_KEY
|
||||||
|
require_secret PLANE_OIDC_CLIENT_SECRET
|
||||||
|
require_secret PLANE_NODEDC_ACCESS_TOKEN
|
||||||
|
|
||||||
|
if [[ "${COOKIE_DOMAIN:-}" == *.local.nodedc || "${COOKIE_DOMAIN:-}" == "localhost" ]]; then
|
||||||
|
fail "COOKIE_DOMAIN must not use local/dev domain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ENABLE_SIGNUP:-}" != "0" ]]; then
|
||||||
|
fail "ENABLE_SIGNUP must be 0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ENABLE_EMAIL_PASSWORD:-}" != "0" ]]; then
|
||||||
|
fail "ENABLE_EMAIL_PASSWORD must be 0 for staging OIDC-only access"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ENABLE_MAGIC_LINK_LOGIN:-}" != "0" ]]; then
|
||||||
|
fail "ENABLE_MAGIC_LINK_LOGIN must be 0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${PLANE_NODEDC_ACCESS_ENFORCEMENT:-}" != "1" ]]; then
|
||||||
|
fail "PLANE_NODEDC_ACCESS_ENFORCEMENT must be 1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${PLANE_NODEDC_ACCESS_ENFORCE_UNLINKED:-}" != "1" ]]; then
|
||||||
|
fail "PLANE_NODEDC_ACCESS_ENFORCE_UNLINKED must be 1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${TRUSTED_PROXIES:-}" =~ change-me|local-dev|replace-with|example ]]; then
|
||||||
|
fail "TRUSTED_PROXIES uses a placeholder/dev value"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${TRUSTED_PROXIES:-}" in
|
||||||
|
*"0.0.0.0/0"*|*"::/0"*|*"10.0.0.0/8"*|*"172.16.0.0/12"*|*"192.168.0.0/16"*|*"127.0.0.0/8"*)
|
||||||
|
fail "TRUSTED_PROXIES must be limited to the actual platform edge proxy or ingress subnet"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $failures -gt 0 ]]; then
|
||||||
|
echo "Tasker staging env check failed with $failures issue(s)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Tasker staging env check passed: $ENV_FILE"
|
||||||
Loading…
Reference in New Issue