Security improvements #2
Some checks are pending
CI/CD Pipeline with Secure Ephemeral PiP / test-backend (push) Waiting to run
CI/CD Pipeline with Secure Ephemeral PiP / test-frontend (push) Blocked by required conditions
CI/CD Pipeline with Secure Ephemeral PiP / build-backend (push) Blocked by required conditions
CI/CD Pipeline with Secure Ephemeral PiP / build-frontend (push) Blocked by required conditions
CI/CD Pipeline with Secure Ephemeral PiP / cleanup (push) Blocked by required conditions

This commit is contained in:
continuist 2025-09-04 22:38:49 -04:00
parent 6624c2a340
commit 6bff6a1ad7
2 changed files with 43 additions and 26 deletions

View file

@ -57,20 +57,22 @@ jobs:
- name: Run backend unit tests - name: Run backend unit tests
run: | run: |
podman exec ci-pip-$RUN_ID podman run --rm \ podman exec ci-pip-$RUN_ID sh -c \
-v $(pwd):/workspace \ 'cd /workspace && podman run --rm \
-v /workspace:/workspace \
-w /workspace \ -w /workspace \
rust:latest \ rust:latest \
sh -c "cargo test --lib -- --test-threads=1" sh -c "cargo test --lib -- --test-threads=1"'
- name: Run backend integration tests - name: Run backend integration tests
run: | run: |
podman exec ci-pip-$RUN_ID podman run --rm \ podman exec ci-pip-$RUN_ID sh -c \
-v $(pwd):/workspace \ 'cd /workspace && podman run --rm \
-v /workspace:/workspace \
-w /workspace \ -w /workspace \
-e DATABASE_URL=postgres://testuser:testpassword@test-postgres:5432/testdb \ -e DATABASE_URL=postgres://testuser:testpassword@test-postgres:5432/testdb \
rust:latest \ rust:latest \
sh -c "cargo test --test '*' -- --test-threads=1" sh -c "cargo test --test '*' -- --test-threads=1"'
- name: Cleanup test resources - name: Cleanup test resources
if: always() if: always()
@ -98,11 +100,12 @@ jobs:
- name: Run frontend tests in PiP - name: Run frontend tests in PiP
run: | run: |
podman exec ci-pip-$RUN_ID podman run --rm \ podman exec ci-pip-$RUN_ID sh -c \
-v $(pwd):/workspace \ 'cd /workspace && podman run --rm \
-v /workspace:/workspace \
-w /workspace \ -w /workspace \
node:20 \ node:20 \
sh -c "npm ci && npm run test" sh -c "npm ci && npm run test"'
build-backend: build-backend:
runs-on: [self-hosted, ci] runs-on: [self-hosted, ci]
@ -129,9 +132,9 @@ jobs:
- name: Build backend image - name: Build backend image
run: | run: |
podman exec ci-pip-$RUN_ID podman build \ podman exec ci-pip-$RUN_ID sh -c \
-t ${{ secrets.REGISTRY_HOST }}/${{ secrets.APP_NAME }}/backend:${{ github.sha }} \ 'cd /workspace/backend && podman build \
-f Dockerfile.backend . -t "$REGISTRY/$APP_NAME/backend:$IMAGE_TAG" .'
- name: Push backend image - name: Push backend image
run: | run: |
@ -163,9 +166,9 @@ jobs:
- name: Build frontend image - name: Build frontend image
run: | run: |
podman exec ci-pip-$RUN_ID podman build \ podman exec ci-pip-$RUN_ID sh -c \
-t ${{ secrets.REGISTRY_HOST }}/${{ secrets.APP_NAME }}/frontend:${{ github.sha }} \ 'cd /workspace/frontend && podman build \
-f Dockerfile.frontend . -t "$REGISTRY/$APP_NAME/frontend:$IMAGE_TAG" .'
- name: Push frontend image - name: Push frontend image
run: | run: |
@ -177,7 +180,11 @@ jobs:
needs: [build-backend, build-frontend] needs: [build-backend, build-frontend]
if: always() if: always()
steps: steps:
- name: Cleanup PiP container and socket - name: Cleanup PiP container and per-run socket
run: | run: |
podman rm -f ci-pip-$RUN_ID 2>/dev/null || true podman rm -f ci-pip-$RUN_ID 2>/dev/null || true
rm -f ${XDG_RUNTIME_DIR}/podman-host/podman.sock 2>/dev/null || true SOCKET_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/podman-host-${RUN_ID}"
if pgrep -u "$(id -u)" -fa 'podman system service' | grep -F "unix://${SOCKET_DIR}/podman.sock" >/dev/null; then
pgrep -u "$(id -u)" -fa 'podman system service' | grep -F "unix://${SOCKET_DIR}/podman.sock" | awk '{print $1}' | xargs -r kill || true
fi
rm -rf "${SOCKET_DIR}" 2>/dev/null || true

View file

@ -7,18 +7,26 @@ set -euo pipefail
# Configuration # Configuration
RUN_ID="${GITHUB_RUN_ID:-local}" RUN_ID="${GITHUB_RUN_ID:-local}"
PIP_CONTAINER_NAME="ci-pip-${RUN_ID}" PIP_CONTAINER_NAME="ci-pip-${RUN_ID}"
SOCKET_DIR="${XDG_RUNTIME_DIR}/podman-host" SOCKET_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/podman-host-${RUN_ID}"
SOCKET_PATH="${SOCKET_DIR}/podman.sock" SOCKET_PATH="${SOCKET_DIR}/podman.sock"
PODMAN_IMAGE="quay.io/podman/stable:latest" PODMAN_IMAGE="quay.io/podman/stable:latest"
WORKSPACE="${GITHUB_WORKSPACE:-$PWD}"
# Clean up any existing container and socket # Clean up any existing container and socket for this run
echo "🧹 Cleaning up any existing PiP container and socket..." echo "🧹 Cleaning up any existing PiP container and socket for run ${RUN_ID}..."
podman rm -f "${PIP_CONTAINER_NAME}" 2>/dev/null || true podman rm -f "${PIP_CONTAINER_NAME}" 2>/dev/null || true
rm -f "${SOCKET_PATH}"
rm -rf "${SOCKET_DIR}"
# Create secure socket directory # Kill any host service bound to this specific socket path
echo "📁 Creating secure socket directory..." if pgrep -u "$(id -u)" -fa 'podman system service' | grep -F "unix://${SOCKET_PATH}" >/dev/null; then
echo "🛑 Stopping existing host service for this socket..."
pgrep -u "$(id -u)" -fa 'podman system service' | grep -F "unix://${SOCKET_PATH}" | awk '{print $1}' | xargs -r kill || true
fi
# Remove existing socket directory
rm -rf "${SOCKET_DIR}" 2>/dev/null || true
# Create secure per-run socket directory
echo "📁 Creating per-run socket directory..."
mkdir -p "${SOCKET_DIR}" mkdir -p "${SOCKET_DIR}"
chmod 700 "${SOCKET_DIR}" chmod 700 "${SOCKET_DIR}"
@ -40,7 +48,7 @@ echo "🔒 Setting secure socket permissions..."
chmod 660 "${SOCKET_PATH}" chmod 660 "${SOCKET_PATH}"
# Create ephemeral PiP container as client only (no inner daemon) # Create ephemeral PiP container as client only (no inner daemon)
echo "🐳 Creating secure PiP client container..." echo "🐳 Creating secure PiP client container with workspace mount..."
podman run -d \ podman run -d \
--name "${PIP_CONTAINER_NAME}" \ --name "${PIP_CONTAINER_NAME}" \
--security-opt=no-new-privileges \ --security-opt=no-new-privileges \
@ -49,7 +57,8 @@ podman run -d \
--network=none \ --network=none \
--tmpfs /run:rw,size=64M \ --tmpfs /run:rw,size=64M \
--tmpfs /tmp:rw,size=256M \ --tmpfs /tmp:rw,size=256M \
-v "${SOCKET_PATH}:/var/run/podman.sock" \ -v "${SOCKET_PATH}:/var/run/podman.sock:z" \
-v "${WORKSPACE}:/workspace:rw,z" \
-e CONTAINER_HOST="unix:///var/run/podman.sock" \ -e CONTAINER_HOST="unix:///var/run/podman.sock" \
"${PODMAN_IMAGE}" \ "${PODMAN_IMAGE}" \
sleep infinity sleep infinity
@ -69,4 +78,5 @@ fi
echo "🎉 Secure PiP client container setup complete!" echo "🎉 Secure PiP client container setup complete!"
echo " Container: ${PIP_CONTAINER_NAME}" echo " Container: ${PIP_CONTAINER_NAME}"
echo " Socket: ${SOCKET_PATH}" echo " Socket: ${SOCKET_PATH}"
echo " Workspace: ${WORKSPACE} → /workspace"
echo " Security: No network, no capabilities, read-only rootfs, client-only" echo " Security: No network, no capabilities, read-only rootfs, client-only"