[infra] vault + chsettle + aurora for dev

This commit is contained in:
Stephan D
2026-03-16 19:50:05 +01:00
parent 5b1aca86e7
commit 89edf33c2c
51 changed files with 1606 additions and 62 deletions

View File

@@ -0,0 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && set -x
trap 'echo "[deploy-aurora-gateway] error at line $LINENO" >&2' ERR
: "${REMOTE_BASE:?missing REMOTE_BASE}"
: "${SSH_USER:?missing SSH_USER}"
: "${SSH_HOST:?missing SSH_HOST}"
: "${AURORA_GATEWAY_DIR:?missing AURORA_GATEWAY_DIR}"
: "${AURORA_GATEWAY_COMPOSE_PROJECT:?missing AURORA_GATEWAY_COMPOSE_PROJECT}"
: "${AURORA_GATEWAY_SERVICE_NAME:?missing AURORA_GATEWAY_SERVICE_NAME}"
REMOTE_DIR="${REMOTE_BASE%/}/${AURORA_GATEWAY_DIR}"
REMOTE_TARGET="${SSH_USER}@${SSH_HOST}"
RUNTIME_ENV_FILE="${RUNTIME_ENV_FILE:-ci/prod/.env.runtime}"
COMPOSE_FILE="aurora_gateway.yml"
SERVICE_NAMES="${AURORA_GATEWAY_SERVICE_NAME}"
REQUIRED_SECRETS=(
AURORA_GATEWAY_MONGO_USER
AURORA_GATEWAY_MONGO_PASSWORD
NATS_USER
NATS_PASSWORD
NATS_URL
)
for var in "${REQUIRED_SECRETS[@]}"; do
if [[ -z "${!var:-}" ]]; then
echo "missing required secret env: ${var}" >&2
exit 65
fi
done
if [[ ! -s .env.version ]]; then
echo ".env.version is missing; run version step first" >&2
exit 66
fi
b64enc() {
printf '%s' "$1" | base64 | tr -d '\n'
}
AURORA_GATEWAY_MONGO_USER_B64="$(b64enc "${AURORA_GATEWAY_MONGO_USER}")"
AURORA_GATEWAY_MONGO_PASSWORD_B64="$(b64enc "${AURORA_GATEWAY_MONGO_PASSWORD}")"
NATS_USER_B64="$(b64enc "${NATS_USER}")"
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
NATS_URL_B64="$(b64enc "${NATS_URL}")"
SSH_OPTS=(
-i /root/.ssh/id_rsa
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o LogLevel=ERROR
-o BatchMode=yes
-o PreferredAuthentications=publickey
-o ConnectTimeout=10
-q
)
if [[ "${DEBUG_DEPLOY:-0}" = "1" ]]; then
SSH_OPTS=("${SSH_OPTS[@]/-q/}" -vv)
fi
RSYNC_FLAGS=(-az --delete)
[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && RSYNC_FLAGS=(-avz --delete)
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "mkdir -p ${REMOTE_DIR}/{compose,env}"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" ci/prod/compose/ "$REMOTE_TARGET:${REMOTE_DIR}/compose/"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" "${RUNTIME_ENV_FILE}" "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.runtime"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" .env.version "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.version"
SERVICES_LINE="${SERVICE_NAMES}"
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" \
REMOTE_DIR="$REMOTE_DIR" \
COMPOSE_FILE="$COMPOSE_FILE" \
COMPOSE_PROJECT="$AURORA_GATEWAY_COMPOSE_PROJECT" \
SERVICES_LINE="$SERVICES_LINE" \
AURORA_GATEWAY_MONGO_USER_B64="$AURORA_GATEWAY_MONGO_USER_B64" \
AURORA_GATEWAY_MONGO_PASSWORD_B64="$AURORA_GATEWAY_MONGO_PASSWORD_B64" \
NATS_USER_B64="$NATS_USER_B64" \
NATS_PASSWORD_B64="$NATS_PASSWORD_B64" \
NATS_URL_B64="$NATS_URL_B64" \
bash -s <<'EOSSH'
set -euo pipefail
cd "${REMOTE_DIR}/compose"
set -a
. ../env/.env.runtime
load_kv_file() {
local file="$1"
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
''|\#*) continue ;;
esac
if printf '%s' "$line" | grep -Eq '^[[:alpha:]_][[:alnum:]_]*='; then
local key="${line%%=*}"
local value="${line#*=}"
key="$(printf '%s' "$key" | tr -d '[:space:]')"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
if [[ -n "$key" ]]; then
export "$key=$value"
fi
fi
done <"$file"
}
load_kv_file ../env/.env.version
set +a
IMAGE_TAG="${IMAGE_TAG:-${APP_V}-${GIT_REV}}"
export IMAGE_TAG
if base64 -d >/dev/null 2>&1 <<<'AA=='; then
BASE64_DECODE_FLAG='-d'
else
BASE64_DECODE_FLAG='--decode'
fi
decode_b64() {
val="$1"
if [[ -z "$val" ]]; then
printf ''
return
fi
printf '%s' "$val" | base64 "${BASE64_DECODE_FLAG}"
}
AURORA_GATEWAY_MONGO_USER="$(decode_b64 "$AURORA_GATEWAY_MONGO_USER_B64")"
AURORA_GATEWAY_MONGO_PASSWORD="$(decode_b64 "$AURORA_GATEWAY_MONGO_PASSWORD_B64")"
NATS_USER="$(decode_b64 "$NATS_USER_B64")"
NATS_PASSWORD="$(decode_b64 "$NATS_PASSWORD_B64")"
NATS_URL="$(decode_b64 "$NATS_URL_B64")"
export AURORA_GATEWAY_MONGO_USER AURORA_GATEWAY_MONGO_PASSWORD
export NATS_USER NATS_PASSWORD NATS_URL
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME
read -r -a SERVICES <<<"${SERVICES_LINE}"
pull_cmd=(docker compose -f "$COMPOSE_FILE" pull)
up_cmd=(docker compose -f "$COMPOSE_FILE" up -d --remove-orphans)
ps_cmd=(docker compose -f "$COMPOSE_FILE" ps)
if [[ "${#SERVICES[@]}" -gt 0 ]]; then
pull_cmd+=("${SERVICES[@]}")
up_cmd+=("${SERVICES[@]}")
ps_cmd+=("${SERVICES[@]}")
fi
"${pull_cmd[@]}"
"${up_cmd[@]}"
"${ps_cmd[@]}"
date -Is > .last_deploy
logger -t "deploy-${COMPOSE_PROJECT_NAME}" "${COMPOSE_PROJECT_NAME} deployed at $(date -Is) in ${REMOTE_DIR}"
EOSSH

View File

@@ -20,8 +20,6 @@ REQUIRED_SECRETS=(
MONGO_USER
MONGO_PASSWORD
API_ENDPOINT_SECRET
BFF_VAULT_ROLE_ID
BFF_VAULT_SECRET_ID
NATS_USER
NATS_PASSWORD
NATS_URL
@@ -46,8 +44,8 @@ b64enc() {
MONGO_USER_B64="$(b64enc "${MONGO_USER}")"
MONGO_PASSWORD_B64="$(b64enc "${MONGO_PASSWORD}")"
API_ENDPOINT_SECRET_B64="$(b64enc "${API_ENDPOINT_SECRET}")"
BFF_VAULT_ROLE_ID_B64="$(b64enc "${BFF_VAULT_ROLE_ID}")"
BFF_VAULT_SECRET_ID_B64="$(b64enc "${BFF_VAULT_SECRET_ID}")"
BFF_VAULT_ROLE_ID_B64="$(b64enc "${BFF_VAULT_ROLE_ID:-}")"
BFF_VAULT_SECRET_ID_B64="$(b64enc "${BFF_VAULT_SECRET_ID:-}")"
NATS_USER_B64="$(b64enc "${NATS_USER}")"
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
NATS_URL_B64="$(b64enc "${NATS_URL}")"
@@ -114,6 +112,9 @@ load_kv_file() {
done <"$file"
}
load_kv_file ../env/.env.version
if [[ -f ../env/vault.env ]]; then
load_kv_file ../env/vault.env
fi
set +a
IMAGE_TAG="${IMAGE_TAG:-${APP_V}-${GIT_REV}}"
@@ -146,6 +147,10 @@ NATS_URL="$(decode_b64 "$NATS_URL_B64")"
export MONGO_USER MONGO_PASSWORD API_ENDPOINT_SECRET
export BFF_VAULT_ROLE_ID BFF_VAULT_SECRET_ID
export NATS_USER NATS_PASSWORD NATS_URL
if [[ -z "${BFF_VAULT_ROLE_ID:-}" || -z "${BFF_VAULT_SECRET_ID:-}" ]]; then
echo "missing required secret env: BFF_VAULT_ROLE_ID/BFF_VAULT_SECRET_ID" >&2
exit 65
fi
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME
read -r -a SERVICES <<<"${SERVICES_LINE}"

View File

@@ -19,8 +19,6 @@ SERVICE_NAMES="${CALLBACKS_SERVICE_NAME}"
REQUIRED_SECRETS=(
CALLBACKS_MONGO_USER
CALLBACKS_MONGO_PASSWORD
CALLBACKS_VAULT_ROLE_ID
CALLBACKS_VAULT_SECRET_ID
NATS_USER
NATS_PASSWORD
NATS_URL
@@ -44,8 +42,8 @@ b64enc() {
CALLBACKS_MONGO_USER_B64="$(b64enc "${CALLBACKS_MONGO_USER}")"
CALLBACKS_MONGO_PASSWORD_B64="$(b64enc "${CALLBACKS_MONGO_PASSWORD}")"
CALLBACKS_VAULT_ROLE_ID_B64="$(b64enc "${CALLBACKS_VAULT_ROLE_ID}")"
CALLBACKS_VAULT_SECRET_ID_B64="$(b64enc "${CALLBACKS_VAULT_SECRET_ID}")"
CALLBACKS_VAULT_ROLE_ID_B64="$(b64enc "${CALLBACKS_VAULT_ROLE_ID:-}")"
CALLBACKS_VAULT_SECRET_ID_B64="$(b64enc "${CALLBACKS_VAULT_SECRET_ID:-}")"
NATS_USER_B64="$(b64enc "${NATS_USER}")"
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
NATS_URL_B64="$(b64enc "${NATS_URL}")"
@@ -111,6 +109,9 @@ load_kv_file() {
done <"$file"
}
load_kv_file ../env/.env.version
if [[ -f ../env/vault.env ]]; then
load_kv_file ../env/vault.env
fi
set +a
IMAGE_TAG="${IMAGE_TAG:-${APP_V}-${GIT_REV}}"
@@ -142,6 +143,10 @@ NATS_URL="$(decode_b64 "$NATS_URL_B64")"
export CALLBACKS_MONGO_USER CALLBACKS_MONGO_PASSWORD
export CALLBACKS_VAULT_ROLE_ID CALLBACKS_VAULT_SECRET_ID
export NATS_USER NATS_PASSWORD NATS_URL
if [[ -z "${CALLBACKS_VAULT_ROLE_ID:-}" || -z "${CALLBACKS_VAULT_SECRET_ID:-}" ]]; then
echo "missing required secret env: CALLBACKS_VAULT_ROLE_ID/CALLBACKS_VAULT_SECRET_ID" >&2
exit 65
fi
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME
read -r -a SERVICES <<<"${SERVICES_LINE}"

View File

@@ -22,8 +22,6 @@ REQUIRED_SECRETS=(
CHAIN_GATEWAY_RPC_URL
CHAIN_GATEWAY_SERVICE_WALLET_KEY
CHAIN_GATEWAY_SERVICE_WALLET_ADDRESS
CHAIN_GATEWAY_VAULT_ROLE_ID
CHAIN_GATEWAY_VAULT_SECRET_ID
NATS_USER
NATS_PASSWORD
NATS_URL
@@ -50,8 +48,8 @@ CHAIN_GATEWAY_MONGO_PASSWORD_B64="$(b64enc "${CHAIN_GATEWAY_MONGO_PASSWORD}")"
CHAIN_GATEWAY_RPC_URL_B64="$(b64enc "${CHAIN_GATEWAY_RPC_URL}")"
CHAIN_GATEWAY_SERVICE_WALLET_KEY_B64="$(b64enc "${CHAIN_GATEWAY_SERVICE_WALLET_KEY}")"
CHAIN_GATEWAY_SERVICE_WALLET_ADDRESS_B64="$(b64enc "${CHAIN_GATEWAY_SERVICE_WALLET_ADDRESS}")"
CHAIN_GATEWAY_VAULT_ROLE_ID_B64="$(b64enc "${CHAIN_GATEWAY_VAULT_ROLE_ID}")"
CHAIN_GATEWAY_VAULT_SECRET_ID_B64="$(b64enc "${CHAIN_GATEWAY_VAULT_SECRET_ID}")"
CHAIN_GATEWAY_VAULT_ROLE_ID_B64="$(b64enc "${CHAIN_GATEWAY_VAULT_ROLE_ID:-}")"
CHAIN_GATEWAY_VAULT_SECRET_ID_B64="$(b64enc "${CHAIN_GATEWAY_VAULT_SECRET_ID:-}")"
NATS_USER_B64="$(b64enc "${NATS_USER}")"
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
NATS_URL_B64="$(b64enc "${NATS_URL}")"
@@ -120,6 +118,9 @@ load_kv_file() {
done <"$file"
}
load_kv_file ../env/.env.version
if [[ -f ../env/vault.env ]]; then
load_kv_file ../env/vault.env
fi
set +a
IMAGE_TAG="${IMAGE_TAG:-${APP_V}-${GIT_REV}}"
@@ -156,6 +157,10 @@ export CHAIN_GATEWAY_RPC_URL
export CHAIN_GATEWAY_SERVICE_WALLET_KEY CHAIN_GATEWAY_SERVICE_WALLET_ADDRESS
export CHAIN_GATEWAY_VAULT_ROLE_ID CHAIN_GATEWAY_VAULT_SECRET_ID
export NATS_USER NATS_PASSWORD NATS_URL
if [[ -z "${CHAIN_GATEWAY_VAULT_ROLE_ID:-}" || -z "${CHAIN_GATEWAY_VAULT_SECRET_ID:-}" ]]; then
echo "missing required secret env: CHAIN_GATEWAY_VAULT_ROLE_ID/CHAIN_GATEWAY_VAULT_SECRET_ID" >&2
exit 65
fi
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME

View File

@@ -0,0 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && set -x
trap 'echo "[deploy-chsettle-gateway] error at line $LINENO" >&2' ERR
: "${REMOTE_BASE:?missing REMOTE_BASE}"
: "${SSH_USER:?missing SSH_USER}"
: "${SSH_HOST:?missing SSH_HOST}"
: "${CHSETTLE_GATEWAY_DIR:?missing CHSETTLE_GATEWAY_DIR}"
: "${CHSETTLE_GATEWAY_COMPOSE_PROJECT:?missing CHSETTLE_GATEWAY_COMPOSE_PROJECT}"
: "${CHSETTLE_GATEWAY_SERVICE_NAME:?missing CHSETTLE_GATEWAY_SERVICE_NAME}"
REMOTE_DIR="${REMOTE_BASE%/}/${CHSETTLE_GATEWAY_DIR}"
REMOTE_TARGET="${SSH_USER}@${SSH_HOST}"
RUNTIME_ENV_FILE="${RUNTIME_ENV_FILE:-ci/prod/.env.runtime}"
COMPOSE_FILE="chsettle_gateway.yml"
SERVICE_NAMES="${CHSETTLE_GATEWAY_SERVICE_NAME}"
REQUIRED_SECRETS=(
CHSETTLE_GATEWAY_MONGO_USER
CHSETTLE_GATEWAY_MONGO_PASSWORD
NATS_USER
NATS_PASSWORD
NATS_URL
)
for var in "${REQUIRED_SECRETS[@]}"; do
if [[ -z "${!var:-}" ]]; then
echo "missing required secret env: ${var}" >&2
exit 65
fi
done
if [[ ! -s .env.version ]]; then
echo ".env.version is missing; run version step first" >&2
exit 66
fi
b64enc() {
printf '%s' "$1" | base64 | tr -d '\n'
}
CHSETTLE_GATEWAY_MONGO_USER_B64="$(b64enc "${CHSETTLE_GATEWAY_MONGO_USER}")"
CHSETTLE_GATEWAY_MONGO_PASSWORD_B64="$(b64enc "${CHSETTLE_GATEWAY_MONGO_PASSWORD}")"
NATS_USER_B64="$(b64enc "${NATS_USER}")"
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
NATS_URL_B64="$(b64enc "${NATS_URL}")"
SSH_OPTS=(
-i /root/.ssh/id_rsa
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o LogLevel=ERROR
-o BatchMode=yes
-o PreferredAuthentications=publickey
-o ConnectTimeout=10
-q
)
if [[ "${DEBUG_DEPLOY:-0}" = "1" ]]; then
SSH_OPTS=("${SSH_OPTS[@]/-q/}" -vv)
fi
RSYNC_FLAGS=(-az --delete)
[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && RSYNC_FLAGS=(-avz --delete)
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "mkdir -p ${REMOTE_DIR}/{compose,env}"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" ci/prod/compose/ "$REMOTE_TARGET:${REMOTE_DIR}/compose/"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" "${RUNTIME_ENV_FILE}" "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.runtime"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" .env.version "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.version"
SERVICES_LINE="${SERVICE_NAMES}"
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" \
REMOTE_DIR="$REMOTE_DIR" \
COMPOSE_FILE="$COMPOSE_FILE" \
COMPOSE_PROJECT="$CHSETTLE_GATEWAY_COMPOSE_PROJECT" \
SERVICES_LINE="$SERVICES_LINE" \
CHSETTLE_GATEWAY_MONGO_USER_B64="$CHSETTLE_GATEWAY_MONGO_USER_B64" \
CHSETTLE_GATEWAY_MONGO_PASSWORD_B64="$CHSETTLE_GATEWAY_MONGO_PASSWORD_B64" \
NATS_USER_B64="$NATS_USER_B64" \
NATS_PASSWORD_B64="$NATS_PASSWORD_B64" \
NATS_URL_B64="$NATS_URL_B64" \
bash -s <<'EOSSH'
set -euo pipefail
cd "${REMOTE_DIR}/compose"
set -a
. ../env/.env.runtime
load_kv_file() {
local file="$1"
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
''|\#*) continue ;;
esac
if printf '%s' "$line" | grep -Eq '^[[:alpha:]_][[:alnum:]_]*='; then
local key="${line%%=*}"
local value="${line#*=}"
key="$(printf '%s' "$key" | tr -d '[:space:]')"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
if [[ -n "$key" ]]; then
export "$key=$value"
fi
fi
done <"$file"
}
load_kv_file ../env/.env.version
set +a
IMAGE_TAG="${IMAGE_TAG:-${APP_V}-${GIT_REV}}"
export IMAGE_TAG
if base64 -d >/dev/null 2>&1 <<<'AA=='; then
BASE64_DECODE_FLAG='-d'
else
BASE64_DECODE_FLAG='--decode'
fi
decode_b64() {
val="$1"
if [[ -z "$val" ]]; then
printf ''
return
fi
printf '%s' "$val" | base64 "${BASE64_DECODE_FLAG}"
}
CHSETTLE_GATEWAY_MONGO_USER="$(decode_b64 "$CHSETTLE_GATEWAY_MONGO_USER_B64")"
CHSETTLE_GATEWAY_MONGO_PASSWORD="$(decode_b64 "$CHSETTLE_GATEWAY_MONGO_PASSWORD_B64")"
NATS_USER="$(decode_b64 "$NATS_USER_B64")"
NATS_PASSWORD="$(decode_b64 "$NATS_PASSWORD_B64")"
NATS_URL="$(decode_b64 "$NATS_URL_B64")"
export CHSETTLE_GATEWAY_MONGO_USER CHSETTLE_GATEWAY_MONGO_PASSWORD
export NATS_USER NATS_PASSWORD NATS_URL
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME
read -r -a SERVICES <<<"${SERVICES_LINE}"
pull_cmd=(docker compose -f "$COMPOSE_FILE" pull)
up_cmd=(docker compose -f "$COMPOSE_FILE" up -d --remove-orphans)
ps_cmd=(docker compose -f "$COMPOSE_FILE" ps)
if [[ "${#SERVICES[@]}" -gt 0 ]]; then
pull_cmd+=("${SERVICES[@]}")
up_cmd+=("${SERVICES[@]}")
ps_cmd+=("${SERVICES[@]}")
fi
"${pull_cmd[@]}"
"${up_cmd[@]}"
"${ps_cmd[@]}"
date -Is > .last_deploy
logger -t "deploy-${COMPOSE_PROJECT_NAME}" "${COMPOSE_PROJECT_NAME} deployed at $(date -Is) in ${REMOTE_DIR}"
EOSSH

View File

@@ -16,6 +16,7 @@ trap 'echo "[deploy-db] error at line $LINENO" >&2' ERR
REMOTE_DIR="${REMOTE_BASE%/}/${DB_DIR}"
REMOTE_TARGET="${SSH_USER}@${SSH_HOST}"
RUNTIME_ENV_FILE="${RUNTIME_ENV_FILE:-ci/prod/.env.runtime}"
COMPOSE_FILE="${DB_COMPOSE_FILE:-db.yml}"
# SSH options: quiet by default; add -vv in debug mode
SSH_OPTS=(
@@ -47,6 +48,7 @@ rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" "${RUNTIME_ENV_FILE}" "$REMOTE
# The vault-agent container writes them into tmpfs and unsets them internally.
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" \
REMOTE_DIR="$REMOTE_DIR" \
COMPOSE_FILE="$COMPOSE_FILE" \
VAULT_ROLE_ID="$VAULT_ROLE_ID" \
VAULT_SECRET_ID="$VAULT_SECRET_ID" \
bash -s <<'EOSSH'
@@ -56,12 +58,12 @@ set -a; . ../env/.env.runtime; set +a
COMPOSE_PROJECT_NAME="${DB_COMPOSE_PROJECT:-sendico-db}"
export COMPOSE_PROJECT_NAME
# Run with ephemeral AppRole env (scoped only to these commands)
VAULT_ROLE_ID="${VAULT_ROLE_ID}" VAULT_SECRET_ID="${VAULT_SECRET_ID}" docker compose -f db.yml pull --quiet 2>/dev/null || \
VAULT_ROLE_ID="${VAULT_ROLE_ID}" VAULT_SECRET_ID="${VAULT_SECRET_ID}" docker compose -f db.yml pull
VAULT_ROLE_ID="${VAULT_ROLE_ID}" VAULT_SECRET_ID="${VAULT_SECRET_ID}" docker compose -f "${COMPOSE_FILE}" pull --quiet 2>/dev/null || \
VAULT_ROLE_ID="${VAULT_ROLE_ID}" VAULT_SECRET_ID="${VAULT_SECRET_ID}" docker compose -f "${COMPOSE_FILE}" pull
VAULT_ROLE_ID="${VAULT_ROLE_ID}" VAULT_SECRET_ID="${VAULT_SECRET_ID}" docker compose -f db.yml up -d --remove-orphans
VAULT_ROLE_ID="${VAULT_ROLE_ID}" VAULT_SECRET_ID="${VAULT_SECRET_ID}" docker compose -f "${COMPOSE_FILE}" up -d --remove-orphans
docker compose -f db.yml ps
docker compose -f "${COMPOSE_FILE}" ps
date -Is > .last_deploy
logger -t deploy-db "db deployed at $(date -Is) in ${REMOTE_DIR}"
EOSSH

View File

@@ -22,8 +22,6 @@ REQUIRED_SECRETS=(
TRON_GATEWAY_RPC_URL
TRON_GATEWAY_SERVICE_WALLET_KEY
TRON_GATEWAY_SERVICE_WALLET_ADDRESS
TRON_GATEWAY_VAULT_ROLE_ID
TRON_GATEWAY_VAULT_SECRET_ID
NATS_USER
NATS_PASSWORD
NATS_URL
@@ -52,8 +50,8 @@ TRON_GATEWAY_GRPC_URL_B64="$(b64enc "${TRON_GATEWAY_GRPC_URL:-}")"
TRON_GATEWAY_GRPC_TOKEN_B64="$(b64enc "${TRON_GATEWAY_GRPC_TOKEN:-}")"
TRON_GATEWAY_SERVICE_WALLET_KEY_B64="$(b64enc "${TRON_GATEWAY_SERVICE_WALLET_KEY}")"
TRON_GATEWAY_SERVICE_WALLET_ADDRESS_B64="$(b64enc "${TRON_GATEWAY_SERVICE_WALLET_ADDRESS}")"
TRON_GATEWAY_VAULT_ROLE_ID_B64="$(b64enc "${TRON_GATEWAY_VAULT_ROLE_ID}")"
TRON_GATEWAY_VAULT_SECRET_ID_B64="$(b64enc "${TRON_GATEWAY_VAULT_SECRET_ID}")"
TRON_GATEWAY_VAULT_ROLE_ID_B64="$(b64enc "${TRON_GATEWAY_VAULT_ROLE_ID:-}")"
TRON_GATEWAY_VAULT_SECRET_ID_B64="$(b64enc "${TRON_GATEWAY_VAULT_SECRET_ID:-}")"
NATS_USER_B64="$(b64enc "${NATS_USER}")"
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
NATS_URL_B64="$(b64enc "${NATS_URL}")"
@@ -124,6 +122,9 @@ load_kv_file() {
done <"$file"
}
load_kv_file ../env/.env.version
if [[ -f ../env/vault.env ]]; then
load_kv_file ../env/vault.env
fi
set +a
IMAGE_TAG="${IMAGE_TAG:-${APP_V}-${GIT_REV}}"
@@ -162,6 +163,10 @@ export TRON_GATEWAY_RPC_URL TRON_GATEWAY_GRPC_URL TRON_GATEWAY_GRPC_TOKEN
export TRON_GATEWAY_SERVICE_WALLET_KEY TRON_GATEWAY_SERVICE_WALLET_ADDRESS
export TRON_GATEWAY_VAULT_ROLE_ID TRON_GATEWAY_VAULT_SECRET_ID
export NATS_USER NATS_PASSWORD NATS_URL
if [[ -z "${TRON_GATEWAY_VAULT_ROLE_ID:-}" || -z "${TRON_GATEWAY_VAULT_SECRET_ID:-}" ]]; then
echo "missing required secret env: TRON_GATEWAY_VAULT_ROLE_ID/TRON_GATEWAY_VAULT_SECRET_ID" >&2
exit 65
fi
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME

View File

@@ -0,0 +1,140 @@
#!/usr/bin/env bash
set -euo pipefail
[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && set -x
trap 'echo "[deploy-vault] error at line $LINENO" >&2' ERR
: "${REMOTE_BASE:?missing REMOTE_BASE}"
: "${SSH_USER:?missing SSH_USER}"
: "${SSH_HOST:?missing SSH_HOST}"
: "${VAULT_DIR:?missing VAULT_DIR}"
: "${VAULT_COMPOSE_PROJECT:?missing VAULT_COMPOSE_PROJECT}"
REMOTE_DIR="${REMOTE_BASE%/}/${VAULT_DIR}"
REMOTE_TARGET="${SSH_USER}@${SSH_HOST}"
RUNTIME_ENV_FILE="${RUNTIME_ENV_FILE:-ci/prod/.env.runtime}"
COMPOSE_FILE="vault.yml"
SSH_OPTS=(
-i /root/.ssh/id_rsa
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o LogLevel=ERROR
-o BatchMode=yes
-o PreferredAuthentications=publickey
-o ConnectTimeout=10
-q
)
if [[ "${DEBUG_DEPLOY:-0}" = "1" ]]; then
SSH_OPTS=("${SSH_OPTS[@]/-q/}" -vv)
fi
RSYNC_FLAGS=(-az --delete)
[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && RSYNC_FLAGS=(-avz --delete)
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "mkdir -p ${REMOTE_DIR}/{compose,env}"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" ci/prod/compose/ "$REMOTE_TARGET:${REMOTE_DIR}/compose/"
rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" "${RUNTIME_ENV_FILE}" "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.runtime"
ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" \
REMOTE_BASE="$REMOTE_BASE" \
REMOTE_DIR="$REMOTE_DIR" \
COMPOSE_FILE="$COMPOSE_FILE" \
COMPOSE_PROJECT="$VAULT_COMPOSE_PROJECT" \
bash -s <<'EOSSH'
set -euo pipefail
cd "${REMOTE_DIR}/compose"
set -a
. ../env/.env.runtime
set +a
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
export COMPOSE_PROJECT_NAME
docker compose -f "$COMPOSE_FILE" pull --quiet 2>/dev/null || docker compose -f "$COMPOSE_FILE" pull
docker compose -f "$COMPOSE_FILE" up -d --remove-orphans
status_json=""
for _ in $(seq 1 30); do
status_json="$(docker exec dev-vault sh -lc 'export VAULT_ADDR=http://127.0.0.1:8200; vault status -format=json' 2>/dev/null || true)"
if [[ -n "$status_json" ]]; then
break
fi
sleep 2
done
if [[ -z "$status_json" ]]; then
echo "vault status did not become available" >&2
exit 65
fi
INIT_FILE="../env/vault-init.json"
if printf '%s' "$status_json" | grep -Eq '"initialized"[[:space:]]*:[[:space:]]*false'; then
docker exec dev-vault sh -lc 'export VAULT_ADDR=http://127.0.0.1:8200; vault operator init -format=json -key-shares=1 -key-threshold=1' >"$INIT_FILE"
chmod 600 "$INIT_FILE"
status_json="$(docker exec dev-vault sh -lc 'export VAULT_ADDR=http://127.0.0.1:8200; vault status -format=json')"
fi
if [[ ! -s "$INIT_FILE" ]]; then
echo "vault init file is missing: $INIT_FILE" >&2
exit 66
fi
INIT_JSON_COMPACT="$(tr -d '\r\n\t ' <"$INIT_FILE")"
UNSEAL_KEY="$(printf '%s' "$INIT_JSON_COMPACT" | sed -n 's/.*"unseal_keys_b64":\["\([^"]*\)".*/\1/p')"
ROOT_TOKEN="$(printf '%s' "$INIT_JSON_COMPACT" | sed -n 's/.*"root_token":"\([^"]*\)".*/\1/p')"
if [[ -z "$UNSEAL_KEY" || -z "$ROOT_TOKEN" ]]; then
echo "failed to extract vault init credentials" >&2
exit 67
fi
if printf '%s' "$status_json" | grep -Eq '"sealed"[[:space:]]*:[[:space:]]*true'; then
docker exec dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200; vault operator unseal '${UNSEAL_KEY}' >/dev/null"
fi
docker exec dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='${ROOT_TOKEN}'; vault auth list -format=json | grep -q '\"approle/\"' || vault auth enable approle >/dev/null"
docker exec dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='${ROOT_TOKEN}'; vault secrets list -format=json | grep -q '\"kv/\"' || vault secrets enable -path=kv kv-v2 >/dev/null"
docker exec -i dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='${ROOT_TOKEN}'; vault policy write sendico-dev-apps -" <<'EOF'
path "kv/data/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "kv/metadata/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
EOF
docker exec dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='${ROOT_TOKEN}'; vault write auth/approle/role/sendico-dev-apps token_policies='sendico-dev-apps' token_ttl='24h' token_max_ttl='720h' >/dev/null"
APPROLE_ROLE_ID="$(docker exec dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='${ROOT_TOKEN}'; vault read -field=role_id auth/approle/role/sendico-dev-apps/role-id")"
APPROLE_SECRET_ID="$(docker exec dev-vault sh -lc "export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN='${ROOT_TOKEN}'; vault write -force -field=secret_id auth/approle/role/sendico-dev-apps/secret-id")"
if [[ -z "$APPROLE_ROLE_ID" || -z "$APPROLE_SECRET_ID" ]]; then
echo "failed to create dev approle credentials" >&2
exit 68
fi
write_vault_env() {
local service_dir="$1"
local role_var="$2"
local secret_var="$3"
local env_dir="${REMOTE_BASE%/}/${service_dir}/env"
mkdir -p "$env_dir"
cat >"${env_dir}/vault.env" <<EOF
${role_var}=${APPROLE_ROLE_ID}
${secret_var}=${APPROLE_SECRET_ID}
EOF
chmod 600 "${env_dir}/vault.env"
}
write_vault_env "${BFF_DIR}" "BFF_VAULT_ROLE_ID" "BFF_VAULT_SECRET_ID"
write_vault_env "${CALLBACKS_DIR}" "CALLBACKS_VAULT_ROLE_ID" "CALLBACKS_VAULT_SECRET_ID"
write_vault_env "${CHAIN_GATEWAY_DIR}" "CHAIN_GATEWAY_VAULT_ROLE_ID" "CHAIN_GATEWAY_VAULT_SECRET_ID"
write_vault_env "${TRON_GATEWAY_DIR}" "TRON_GATEWAY_VAULT_ROLE_ID" "TRON_GATEWAY_VAULT_SECRET_ID"
docker compose -f "$COMPOSE_FILE" ps
date -Is > .last_deploy
logger -t "deploy-${COMPOSE_PROJECT_NAME}" "${COMPOSE_PROJECT_NAME} deployed at $(date -Is) in ${REMOTE_DIR}"
EOSSH