added infisical integration

This commit is contained in:
2026-08-25 12:35:49 +02:00
parent 37710c8d6c
commit d5b9a534a5
+123 -10
View File
@@ -1,3 +1,18 @@
# ═══════════════════════════════════════════════════════════════════
# Secret richiesti (a livello repo/org, ereditati con `secrets: inherit`):
# DEPLOY_SSH_KEY, MAVEN_USERNAME, MAVEN_PASSWORD
# INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET, INFISICAL_PROJECT_ID
#
# INFISICAL: i secret applicativi vengono iniettati a runtime dalla CLI
# infisical installata SUL SERVER di deploy (nessun file di secret viene
# scritto su disco). L'environment Infisical coincide con il nome ambiente
# ricavato dai file (docker-compose-<env>.yml / .env_<env>).
# Il file .env_<env> del repo resta la base: le variabili iniettate da
# Infisical hanno precedenza, perché per docker compose l'ambiente della
# shell vince sui valori di --env-file.
# Se i secret INFISICAL_* non sono configurati il workflow si comporta
# esattamente come prima (nessuna iniezione).
# ═══════════════════════════════════════════════════════════════════
name: Deploy Environment (reusable)
on:
@@ -40,6 +55,7 @@ jobs:
DEPLOY_USER: ${{ vars.DEPLOY_USER }}
DEPLOY_BASE_PATH: ${{ vars.DEPLOY_BASE_PATH }}
TARGET_HOST: ${{ vars[inputs.host-var] }}
INFISICAL_DOMAIN: ${{ vars.INFISICAL_HOST }}
steps:
- uses: actions/checkout@v6
@@ -87,6 +103,57 @@ jobs:
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H "${{ vars[inputs.host-var] }}" >> ~/.ssh/known_hosts 2>/dev/null
# ─────────────────────────────────────────────────────────────
# INFISICAL: login con machine identity (universal auth) sul
# server di deploy, dove la CLI è installata. Il login restituisce
# un access token a vita breve: è l'UNICA credenziale che viaggia
# negli step successivi, mentre client id/secret non escono da qui.
# Le credenziali sono passate via stdin e non come argomenti, così
# non compaiono nella process list del server (`ps`).
# ─────────────────────────────────────────────────────────────
- name: Login Infisical
run: |
HOST="${{ vars[inputs.host-var] }}"
CID="${{ secrets.INFISICAL_CLIENT_ID }}"
CSEC="${{ secrets.INFISICAL_CLIENT_SECRET }}"
PID="${{ vars.INFISICAL_PROJECT_ID }}"
if [ -z "$CID" ] || [ -z "$CSEC" ] || [ -z "$PID" ]; then
echo "Secret INFISICAL_* non configurati: deploy senza iniezione dei secret (comportamento legacy)."
echo "IRUN_ENV=INFISICAL_TOKEN=" >> $GITHUB_ENV
exit 0
fi
if ! ssh ${DEPLOY_USER}@${HOST} "command -v infisical >/dev/null 2>&1"; then
echo "ERRORE: CLI 'infisical' non trovata su ${HOST}."
echo "Installala sul server oppure rimuovi i secret INFISICAL_* per tornare al deploy legacy."
exit 1
fi
TOKEN=$(printf '%s\n%s\n%s\n' "$CID" "$CSEC" "$INFISICAL_DOMAIN" | ssh ${DEPLOY_USER}@${HOST} '
read -r cid
read -r csec
read -r dom
export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID="$cid"
export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET="$csec"
export INFISICAL_DOMAIN="$dom"
export INFISICAL_DISABLE_UPDATE_CHECK=true
infisical login --method=universal-auth --silent --plain
')
TOKEN=$(echo "$TOKEN" | tr -d '\r' | tail -n 1)
if [ -z "$TOKEN" ]; then
echo "ERRORE: login Infisical fallito su ${INFISICAL_DOMAIN}."
exit 1
fi
echo "::add-mask::$TOKEN"
# Prefisso di ambiente riusato da tutti gli ssh successivi: viene
# letto da .irun.sh sul server per decidere se e come iniettare i
# secret. Il token è mascherato nei log.
echo "IRUN_ENV=INFISICAL_TOKEN='${TOKEN}' INFISICAL_PROJECT_ID='${PID}' INFISICAL_ENV='${ENV_NAME}' INFISICAL_DOMAIN='${INFISICAL_DOMAIN}' INFISICAL_DISABLE_UPDATE_CHECK=true" >> $GITHUB_ENV
echo "Login Infisical OK (${INFISICAL_DOMAIN}) - environment '${ENV_NAME}', path '/' ricorsivo."
- name: Docker login sul server
run: |
HOST="${{ vars[inputs.host-var] }}"
@@ -114,9 +181,51 @@ jobs:
ssh ${DEPLOY_USER}@${HOST} "mkdir -p ${REMOTE_PATH}"
# Wrapper unico per TUTTI i comandi che devono vedere i secret
# (docker compose pull/up/ps e gli script .wait-healthy.sh /
# .sync-fe-hosts.sh, che a loro volta invocano docker compose).
# Va copiato per primo: viene usato già dallo snapshot qui sotto
# e dallo step di rollback.
cat > /tmp/irun.sh << 'EOF'
#!/bin/sh
# Esegue il comando ricevuto iniettando i secret di Infisical come
# variabili d'ambiente del processo. Per docker compose l'ambiente
# della shell ha precedenza su --env-file: il file .env_<ambiente>
# del repo resta quindi la base e Infisical sovrascrive/integra.
# Se INFISICAL_TOKEN non e' valorizzato il comando viene eseguito
# tale e quale: comportamento legacy invariato.
set -e
CMD="$*"
if [ -z "${INFISICAL_TOKEN}" ]; then
exec sh -c "${CMD}"
fi
if ! command -v infisical >/dev/null 2>&1; then
echo "ERRORE: CLI 'infisical' non installata su questo server." >&2
exit 1
fi
# --recursive non e' presente su tutte le versioni della CLI: lo si
# usa solo se supportato, evitando un "unknown flag" in produzione.
RFLAG=""
if infisical run --help 2>/dev/null | grep -q -- "--recursive"; then
RFLAG="--recursive"
fi
exec infisical run \
--projectId="${INFISICAL_PROJECT_ID}" \
--env="${INFISICAL_ENV}" \
--path=/ \
$RFLAG \
--command="${CMD}"
EOF
scp /tmp/irun.sh ${DEPLOY_USER}@${HOST}:${REMOTE_PATH}/.irun.sh
# Snapshot dello stato corrente PRIMA di sovrascrivere i file
ssh ${DEPLOY_USER}@${HOST} "
set -e
export ${IRUN_ENV:-INFISICAL_TOKEN=}
cd ${REMOTE_PATH}
# Se esiste già uno .rollback, non cancellarlo: potrebbe essere l'unica
# traccia di un deploy precedente il cui rollback non è andato a buon
@@ -130,7 +239,7 @@ jobs:
if [ -f ${COMPOSE} ]; then
cp -f ${COMPOSE} .rollback/${COMPOSE}
[ -f ${ENV_FILE} ] && cp -f ${ENV_FILE} .rollback/${ENV_FILE} || true
ids=\$(docker compose -f ${COMPOSE} ${ENVFLAG} ps -q 2>/dev/null || true)
ids=\$(sh .irun.sh \"docker compose -f ${COMPOSE} ${ENVFLAG} ps -q\" 2>/dev/null || true)
if [ -n \"\$ids\" ]; then
echo 'services:' > .rollback/pin.yml
for cid in \$ids; do
@@ -329,8 +438,11 @@ jobs:
CBASE="cd ${REMOTE_PATH} && DOCKER_CONFIG=/tmp/.docker-ci docker compose -f ${COMPOSE}"
[ -f "$ENV_FILE" ] && CBASE="${CBASE} --env-file ${ENV_FILE}"
ssh ${DEPLOY_USER}@${HOST} "${CBASE} pull"
ssh ${DEPLOY_USER}@${HOST} "${CBASE} up -d ${{ inputs.compose-opts }}"
# I comandi passano da .irun.sh: i secret Infisical vengono iniettati
# nel processo docker compose (interpolazione ${VAR} nel compose file
# e blocchi "environment:"), senza mai finire su disco.
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV} sh ${REMOTE_PATH}/.irun.sh '${CBASE} pull'"
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV} sh ${REMOTE_PATH}/.irun.sh '${CBASE} up -d ${{ inputs.compose-opts }}'"
- name: Post-deploy
run: |
@@ -366,15 +478,15 @@ jobs:
[ -f "$ENV_FILE" ] && CBASE="${CBASE} --env-file ${ENV_FILE}"
echo "── Container status (iniziale) ──"
ssh ${DEPLOY_USER}@${HOST} "${CBASE} ps"
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV} sh ${REMOTE_PATH}/.irun.sh '${CBASE} ps'"
# Attende che tutti i container siano "running" e, se hanno un
# healthcheck definito, "healthy" (vedi .wait-healthy.sh, creato
# nello step "Prepara server" e condiviso con il rollback).
ssh ${DEPLOY_USER}@${HOST} "cd ${REMOTE_PATH} && sh .wait-healthy.sh ${COMPOSE} ${ENV_FILE} ${TIMEOUT}"
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV} sh ${REMOTE_PATH}/.irun.sh 'cd ${REMOTE_PATH} && sh .wait-healthy.sh ${COMPOSE} ${ENV_FILE} ${TIMEOUT}'"
echo "── Container status (finale) ──"
ssh ${DEPLOY_USER}@${HOST} "${CBASE} ps"
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV} sh ${REMOTE_PATH}/.irun.sh '${CBASE} ps'"
# ─────────────────────────────────────────────────────────────
# HOSTS: dopo un deploy riuscito, recuperiamo l'IP del container
@@ -393,7 +505,7 @@ jobs:
COMPOSE="docker-compose-${ENV_NAME}.yml"
ENV_FILE=".env_${ENV_NAME}"
ssh ${DEPLOY_USER}@${HOST} "cd ${REMOTE_PATH} && sh .sync-fe-hosts.sh ${COMPOSE} ${ENV_FILE}"
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV} sh ${REMOTE_PATH}/.irun.sh 'cd ${REMOTE_PATH} && sh .sync-fe-hosts.sh ${COMPOSE} ${ENV_FILE}'"
# ─────────────────────────────────────────────────────────────
# CLEANUP: eseguito SOLO se tutti gli step precedenti sono andati
@@ -479,6 +591,7 @@ jobs:
container_ok=0
ssh ${DEPLOY_USER}@${HOST} "
set -e
export ${IRUN_ENV:-INFISICAL_TOKEN=}
cd ${REMOTE_PATH}
if [ -f .rollback/${COMPOSE} ]; then
cp -f .rollback/${COMPOSE} ${COMPOSE}
@@ -486,9 +599,9 @@ jobs:
PIN=''
[ -f .rollback/pin.yml ] && PIN='-f .rollback/pin.yml'
echo 'Ripristino container alla versione precedente...'
DOCKER_CONFIG=/tmp/.docker-ci docker compose -f ${COMPOSE} \$PIN ${ENVFLAG} up -d
sh .irun.sh \"DOCKER_CONFIG=/tmp/.docker-ci docker compose -f ${COMPOSE} \$PIN ${ENVFLAG} up -d\"
echo 'Attendo che i container ripristinati siano running/healthy...'
sh .wait-healthy.sh ${COMPOSE} ${ENV_FILE} ${TIMEOUT}
sh .irun.sh \"sh .wait-healthy.sh ${COMPOSE} ${ENV_FILE} ${TIMEOUT}\"
else
echo 'Nessuno snapshot disponibile: nessun rollback container (probabile primo deploy).'
fi
@@ -503,7 +616,7 @@ jobs:
# deploy fallito (o, se prima non c'era una voce, nessuna voce),
# puntando a un container che non esiste più.
hosts_ok=0
ssh ${DEPLOY_USER}@${HOST} "cd ${REMOTE_PATH} && sh .sync-fe-hosts.sh ${COMPOSE} ${ENV_FILE}" || hosts_ok=1
ssh ${DEPLOY_USER}@${HOST} "${IRUN_ENV:-INFISICAL_TOKEN=} sh ${REMOTE_PATH}/.irun.sh 'cd ${REMOTE_PATH} && sh .sync-fe-hosts.sh ${COMPOSE} ${ENV_FILE}'" || hosts_ok=1
# Cleanup config temporaneo (best-effort, non deve mascherare l'esito del rollback)
ssh ${DEPLOY_USER}@${HOST} "rm -rf /tmp/.docker-ci" || true