name: Reusable OpenTofu Deploy Template on: workflow_call: inputs: proxmox_endpoint: description: "The URL endpoint for the Proxmox API" type: string default: "https://212.3.125.242:8006/" infisical_api_url: description: "Infisical API URL (for self-hosted instances)" type: string required: false default: "https://secrets.itlab-ffeks.dnu.edu.ua" infisical_env: description: "Infisical Environment" type: string required: false secrets: infisical_cicd_token: description: "Infisical Service Token for CI/CD secrets" required: true infisical_project_token: description: "Infisical Service Token for project-specific secrets" required: false jobs: deploy-to-proxmox: runs-on: ubuntu-latest env: # Proxmox Auth (Endpoint from inputs) PROXMOX_VE_ENDPOINT: ${{ inputs.proxmox_endpoint }} PROXMOX_VE_INSECURE: "true" # Gitea Remote State Backend (Dynamic per-repository package/workspace) TF_HTTP_ADDRESS: "https://git.itlab-ffeks.dnu.edu.ua/api/packages/${{ gitea.repository_owner }}/terraform/state/${{ gitea.event.repository.name }}-${{ gitea.ref_name }}" TF_HTTP_LOCK_ADDRESS: "https://git.itlab-ffeks.dnu.edu.ua/api/packages/${{ gitea.repository_owner }}/terraform/state/${{ gitea.event.repository.name }}-${{ gitea.ref_name }}/lock" TF_HTTP_UNLOCK_ADDRESS: "https://git.itlab-ffeks.dnu.edu.ua/api/packages/${{ gitea.repository_owner }}/terraform/state/${{ gitea.event.repository.name }}-${{ gitea.ref_name }}/lock" TF_HTTP_LOCK_METHOD: "POST" TF_HTTP_UNLOCK_METHOD: "DELETE" TF_HTTP_USERNAME: ${{ gitea.actor }} TF_VAR_environment: ${{ gitea.ref_name }} TF_VAR_infisical_project_token: ${{ secrets.infisical_project_token }} steps: - name: Checkout Code uses: actions/checkout@v4 - name: Install Infisical CLI run: | curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | sudo -E bash sudo apt-get update && sudo apt-get install -y infisical - name: Fetch secrets from Infisical run: | export INFISICAL_API_URL="${{ inputs.infisical_api_url || 'https://app.infisical.com' }}" export INFISICAL_DOMAIN="$INFISICAL_API_URL" export INFISICAL_DISABLE_UPDATE_CHECK=true INFISICAL_ENV="${{ inputs.infisical_env }}" if [ -z "$INFISICAL_ENV" ]; then INFISICAL_ENV="${{ gitea.ref_name }}" fi fetch_secrets() { local token="$1" if [ -z "$token" ]; then return 0 fi export INFISICAL_TOKEN="$token" echo "Exporting secrets from Infisical..." infisical export --env="$INFISICAL_ENV" --format=json > secrets.json if [ $? -ne 0 ]; then echo "Error: Failed to fetch secrets from Infisical." >&2 exit 1 fi # Mask and write all secrets to GITHUB_ENV while IFS= read -r -d '' key && IFS= read -r -d '' value; do # Mask each line of the value individually to ensure multiline values are fully masked in the logs while IFS= read -r line; do if [ -n "$line" ]; then echo "::add-mask::$line" fi done <<< "$value" # Use multi-line syntax to support keys like SSH keys which have newlines EOF_DELIMITER="EOF_${key}_${RANDOM}" echo "$key<<$EOF_DELIMITER" >> $GITHUB_ENV echo "$value" >> $GITHUB_ENV echo "$EOF_DELIMITER" >> $GITHUB_ENV case "$key" in TF_VAR_*) ;; *) LOWER_KEY=$(echo "$key" | tr '[:upper:]' '[:lower:]') echo "TF_VAR_${LOWER_KEY}<<$EOF_DELIMITER" >> $GITHUB_ENV echo "$value" >> $GITHUB_ENV echo "$EOF_DELIMITER" >> $GITHUB_ENV ;; esac if [ "$key" = "INFRASTRUCTURE_TOKEN" ]; then echo "TF_HTTP_PASSWORD<<$EOF_DELIMITER" >> $GITHUB_ENV echo "$value" >> $GITHUB_ENV echo "$EOF_DELIMITER" >> $GITHUB_ENV fi done < <(jq -j 'if type == "array" then .[] | (.key, "\u0000", .value, "\u0000") else to_entries[] | (.key, "\u0000", .value, "\u0000") end' secrets.json) rm -f secrets.json } # Fetch general CI/CD secrets first fetch_secrets "${{ secrets.infisical_cicd_token }}" # Optionally fetch project-specific secrets PROJECT_TOKEN="${{ secrets.infisical_project_token }}" if [ -n "$PROJECT_TOKEN" ]; then echo "Fetching project-specific secrets from Infisical..." fetch_secrets "$PROJECT_TOKEN" else echo "No project-specific secrets token provided. Skipping." fi - name: Verify Secrets run: | if [ -z "$PROXMOX_VE_API_TOKEN" ]; then echo "Error: PROXMOX_VE_API_TOKEN is not set or is empty." >&2 exit 1 fi if [ -z "$INFRASTRUCTURE_TOKEN" ]; then echo "Error: INFRASTRUCTURE_TOKEN is not set or is empty." >&2 exit 1 fi echo "Verification successful: both tokens are present." - name: Configure Git for private modules run: git config --global url."https://oauth2:$INFRASTRUCTURE_TOKEN@git.itlab-ffeks.dnu.edu.ua".insteadOf "https://git.itlab-ffeks.dnu.edu.ua" - name: Setup OpenTofu uses: opentofu/setup-opentofu@v1 - name: OpenTofu Init run: tofu init - name: OpenTofu Validate run: tofu validate - name: OpenTofu Plan run: tofu plan - name: OpenTofu Apply run: tofu apply -auto-approve