From 7f1a77602988eac286f05fc03ca6c8ae12ae1b3a Mon Sep 17 00:00:00 2001 From: mpabi Date: Sun, 12 Apr 2026 20:07:29 +0200 Subject: [PATCH] ops(sol): add public edge host preparation --- .gitea/workflows/prepare-sol-public-edge.yaml | 43 +++++++++++++++++ README.md | 11 +++++ sol/public-edge/README.md | 29 ++++++++++++ .../scripts/prepare-sol-public-edge.sh | 46 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 .gitea/workflows/prepare-sol-public-edge.yaml create mode 100644 README.md create mode 100644 sol/public-edge/README.md create mode 100755 sol/public-edge/scripts/prepare-sol-public-edge.sh diff --git a/.gitea/workflows/prepare-sol-public-edge.yaml b/.gitea/workflows/prepare-sol-public-edge.yaml new file mode 100644 index 0000000..99d0715 --- /dev/null +++ b/.gitea/workflows/prepare-sol-public-edge.yaml @@ -0,0 +1,43 @@ +name: prepare-sol-public-edge + +on: + push: + branches: + - main + paths: + - sol/public-edge/** + - .gitea/workflows/prepare-sol-public-edge.yaml + workflow_dispatch: + +jobs: + prepare: + runs-on: k3s-deploy + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install OpenSSH client + run: | + if ! command -v ssh >/dev/null 2>&1; then + apt-get update + apt-get install -y --no-install-recommends openssh-client + fi + + - name: Materialize sol SSH key + env: + SOL_SSH_PRIVATE_KEY_B64: ${{ secrets.SOL_SSH_PRIVATE_KEY_B64 }} + run: | + test -n "$SOL_SSH_PRIVATE_KEY_B64" + install -d -m 0700 "$HOME/.ssh" + printf '%s' "$SOL_SSH_PRIVATE_KEY_B64" | base64 -d >"$HOME/.ssh/sol_mevnode" + chmod 600 "$HOME/.ssh/sol_mevnode" + + - name: Prepare public edge firewall rules + env: + TARGET_HOST: 149.50.96.162 + TARGET_USER: user + PUBLIC_IFACE: enp6s0 + run: | + chmod +x ./sol/public-edge/scripts/prepare-sol-public-edge.sh + export SSH_IDENTITY_FILE="$HOME/.ssh/sol_mevnode" + ./sol/public-edge/scripts/prepare-sol-public-edge.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..7bea25e --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# trade-host-iac + +Host-level infrastructure and operator workflows for `trade-next`. + +## Current Modules + +- `sol/public-edge` - prepares public HTTP/HTTPS exposure for the trade stack on `sol` + +## Workflows + +- `.gitea/workflows/prepare-sol-public-edge.yaml` - opens `80/tcp` and `443/tcp` on `sol` from the `trade-next` runner using the org secret `SOL_SSH_PRIVATE_KEY_B64` diff --git a/sol/public-edge/README.md b/sol/public-edge/README.md new file mode 100644 index 0000000..48346ca --- /dev/null +++ b/sol/public-edge/README.md @@ -0,0 +1,29 @@ +# sol public edge + +Host preparation for public `HTTP` and `HTTPS` exposure on `sol`. + +## Purpose + +- reserve and open `80/tcp` and `443/tcp` on `sol` +- keep the host-side firewall state reproducible from Git +- support the cluster-side `public-edge` module in `trade-next/trade-gitops` + +## Operator Flow + +From the repository root: + +```bash +./sol/public-edge/scripts/prepare-sol-public-edge.sh +``` + +Or push to `main` and let `.gitea/workflows/prepare-sol-public-edge.yaml` execute the same step from the `trade-next` runner. + +This script: + +- verifies the target host is reachable over SSH +- opens `80/tcp` and `443/tcp` on `enp6s0` in `ufw` if the rules are missing +- prints the resulting `ufw` rules and current listeners on `80` and `443` + +## Workflow Prerequisite + +- organization secret `SOL_SSH_PRIVATE_KEY_B64` must contain the base64-encoded private key for `user@149.50.96.162` diff --git a/sol/public-edge/scripts/prepare-sol-public-edge.sh b/sol/public-edge/scripts/prepare-sol-public-edge.sh new file mode 100755 index 0000000..2daf937 --- /dev/null +++ b/sol/public-edge/scripts/prepare-sol-public-edge.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +TARGET_HOST="${TARGET_HOST:-149.50.96.162}" +TARGET_USER="${TARGET_USER:-user}" +SSH_PORT="${SSH_PORT:-22}" +SSH_IDENTITY_FILE="${SSH_IDENTITY_FILE:-}" +PUBLIC_IFACE="${PUBLIC_IFACE:-enp6s0}" + +ssh_target() { + local -a cmd=(ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p "$SSH_PORT") + if [ -n "$SSH_IDENTITY_FILE" ]; then + cmd+=(-i "$SSH_IDENTITY_FILE") + fi + cmd+=("${TARGET_USER}@${TARGET_HOST}") + cmd+=("$@") + "${cmd[@]}" +} + +remote_rule_present() { + local pattern="$1" + ssh_target "sudo ufw status numbered | grep -F -- $(printf '%q' "$pattern") >/dev/null" +} + +ensure_rule() { + local port="$1" + local comment="$2" + local pattern="${port}/tcp on ${PUBLIC_IFACE}" + if remote_rule_present "$pattern"; then + echo "ufw rule already present: ${pattern}" + else + ssh_target "sudo ufw allow in on ${PUBLIC_IFACE} to any port ${port} proto tcp comment '${comment}'" + echo "added ufw rule: ${pattern}" + fi +} + +ensure_rule 80 trade-public-http +ensure_rule 443 trade-public-https + +echo +echo "[ufw]" +ssh_target "sudo ufw status numbered" + +echo +echo "[listeners]" +ssh_target "sudo ss -ltn '( sport = :80 or sport = :443 )' || true"