From 3c7657b8a773d2bee0dce57192e95de388be702a Mon Sep 17 00:00:00 2001 From: Volara Date: Sun, 8 Dec 2024 18:50:46 -0500 Subject: [PATCH] Migrate validator to use TDX --- .github/workflows/build-and-release.yml | 169 ++++++++---------------- Dockerfile | 2 - README.md | 113 +++++----------- config.yaml | 55 -------- volara-proof.manifest.template | 34 ----- volara_proof/__main__.py | 3 +- 6 files changed, 93 insertions(+), 283 deletions(-) delete mode 100644 config.yaml delete mode 100644 volara-proof.manifest.template diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 7df365a..8f47b65 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -1,112 +1,57 @@ -name: Build and Release - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - contents: write - -jobs: - build-and-release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build Docker image - uses: docker/build-push-action@v4 - with: - context: . - load: true - tags: | - volara-proof:${{ github.run_number }} - volara-proof:latest - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Clone and set up GSC - run: | - git clone https://github.com/gramineproject/gsc.git - cd gsc - python3 -m pip install --no-cache-dir 'docker>=7.1.0' 'jinja2>=3.1.4' 'tomli>=2.0.1' 'tomli-w>=1.0.0' 'pyyaml>=6.0.2' - - - name: Create signing key - run: | - echo "${{ secrets.SIGNING_KEY }}" > signing_key.pem - chmod 600 signing_key.pem - - - name: Build GSC image - run: | - cd gsc - ./gsc build volara-proof ../volara-proof.manifest.template -c ../config.yaml - - - name: Sign GSC image - run: | - cd gsc - ./gsc sign-image volara-proof ../signing_key.pem -c ../config.yaml - - - name: Export GSC image to file - run: | - docker save gsc-volara-proof:latest | gzip > gsc-volara-proof-${{ github.run_number }}.tar.gz - - - name: Generate verification data - run: | - cd gsc - ./gsc info-image gsc-volara-proof > ../sigstruct.txt - - - name: Upload image - uses: actions/upload-artifact@v3 - with: - name: gsc-volara-proof-image - path: gsc-volara-proof-${{ github.run_number }}.tar.gz - - - name: Upload verification data - uses: actions/upload-artifact@v3 - with: - name: gsc-volara-proof-sigstruct - path: sigstruct.txt - - - name: Generate release body - run: | - echo "MRSIGNER: $(grep -oP 'mr_signer = "\K[^"]*' sigstruct.txt)" >> release_body.txt - echo "MRENCLAVE: $(grep -oP 'mr_enclave = "\K[^"]*' sigstruct.txt)" >> release_body.txt - echo "Image SHA256: $(sha256sum gsc-volara-proof-${{ github.run_number }}.tar.gz | cut -d' ' -f1)" >> release_body.txt - - - name: Create Release and Upload Assets - uses: softprops/action-gh-release@v1 - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ github.run_number }} - name: Release v${{ github.run_number }} - body_path: release_body.txt - draft: false - prerelease: false - files: | - ./gsc-volara-proof-${{ github.run_number }}.tar.gz - ./sigstruct.txt - - - name: Cleanup signing key - if: always() - run: | - rm -f signing_key.pem - - - name: Log build result - if: always() - run: | - if [ ${{ job.status }} == "success" ]; then - echo "Build and release completed successfully" - else - echo "Build and release failed" - fi +build-and-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build Docker image + uses: docker/build-push-action@v4 + with: + context: . + load: true + tags: | + volara-proof:${{ github.run_number }} + volara-proof:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Export image to file + run: | + docker save volara-proof:latest | gzip > volara-proof-${{ github.run_number }}.tar.gz + - name: Generate release body + run: | + echo "Image SHA256: $(sha256sum volara-proof-${{ github.run_number }}.tar.gz | cut -d' ' -f1)" >> release_body.txt + - name: Upload image + uses: actions/upload-artifact@v3 + with: + name: volara-proof-image + path: volara-proof-${{ github.run_number }}.tar.gz + + - name: Create Release and Upload Assets + uses: softprops/action-gh-release@v1 + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ github.run_number }} + name: Release v${{ github.run_number }} + body_path: release_body.txt + draft: false + prerelease: false + files: | + ./volara-proof-${{ github.run_number }}.tar.gz + - name: Log build result + if: always() + run: | + if [ ${{ job.status }} == "success" ]; then + echo "Build and release completed successfully" + else + echo "Build and release failed" + fi diff --git a/Dockerfile b/Dockerfile index 7d84536..209838e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,6 @@ FROM python:3.12-slim # Install any Python dependencies your application needs, e.g.: RUN pip install --no-cache-dir requests -RUN mkdir /sealed && chmod 777 /sealed - WORKDIR /app COPY . /app diff --git a/README.md b/README.md index 279cb8e..d61a59e 100644 --- a/README.md +++ b/README.md @@ -28,110 +28,64 @@ This template provides a basic structure for building proof tasks that: } ``` -The project is designed to work with [Gramine](https://gramine.readthedocs.io/en/latest/), a lightweight library OS that enables running unmodified applications in secure enclaves, such as Intel SGX (Software Guard Extensions). This allows the code to run in a trusted execution environment, ensuring confidentiality and integrity of the computation. +The project is designed to work with Intel TDX (Trust Domain Extensions), providing hardware-level isolation and security guarantees for confidential computing workloads. ## Project Structure -- `volara_proof/`: Contains the main proof logic +- `my_proof/`: Contains the main proof logic - `proof.py`: Implements the proof generation logic - `__main__.py`: Entry point for the proof execution + - `models/`: Data models for the proof system - `demo/`: Contains sample input and output for testing -- `.github/workflows/`: CI/CD pipeline for building and releasing - `Dockerfile`: Defines the container image for the proof task -- `volara-proof.manifest.template`: Gramine manifest template for running securely in an Intel SGX enclave -- `config.yaml`: Configuration file for Gramine Shielded Containers (GSC) +- `requirements.txt`: Python package dependencies ## Getting Started To use this template: 1. Fork this repository -2. Modify the `volara_proof/proof.py` file to implement your specific proof logic -3. Update the `volara-proof.manifest.template` if you need to add any additional files or change the configuration +2. Modify the `my_proof/proof.py` file to implement your specific proof logic +3. Update the project dependencies in `requirements.txt` if needed 4. Commit your changes and push to your repository ## Customizing the Proof Logic -The main proof logic is implemented in `volara_proof/proof.py`. To customize it, update the `Proof.generate()` function to change how input files are processed. +The main proof logic is implemented in `my_proof/proof.py`. To customize it, update the `Proof.generate()` function to change how input files are processed. -The proof can be configured using environment variables. When running in an enclave, the environment variables must be defined in the `volara-proof.manifest.template` file as well. The following environment variables are used for this demo proof: +The proof can be configured using environment variables: -- `COOKIES`: The cookies for the data contributor +- `USER_EMAIL`: The email address of the data contributor, to verify data ownership + +If you want to use a language other than Python, you can modify the Dockerfile to install the necessary dependencies and build the proof task in the desired language. ## Local Development -To run the proof locally, without Gramine, you can use Docker: +To run the proof locally for testing, you can use Docker: -``` -docker build -t volara-proof . +```bash +docker build -t my-proof . docker run \ ---rm \ ---volume $(pwd)/demo/sealed:/sealed \ ---volume $(pwd)/demo/input:/input \ ---volume $(pwd)/demo/output:/output \ ---env USER_EMAIL=user123@gmail.com \ -volara-proof + --rm \ + --volume $(pwd)/input:/input \ + --volume $(pwd)/output:/output \ + --env USER_EMAIL=user123@gmail.com \ + my-proof ``` -## Building and Releasing - -This template includes a GitHub Actions workflow that automatically: - -1. Builds a Docker image with your code -2. Creates a Gramine-shielded container (GSC) image -3. Publishes the GSC image as a GitHub release - -**Important:** To use this workflow, you must generate a signing key and add it to your GitHub secrets. Follow these steps: - -1. Generate a signing key (see instructions below) -2. Add the key as a GitHub secret named `SIGNING_KEY` -3. Push your changes to the `main` branch or create a pull request - -### Generating the Gramine Signing Key (Required) - -Before building and signing your graminized Docker image, you must generate a signing key. This key is crucial for creating secure SGX enclaves. Here's how to generate it: - -1. If you have Gramine installed: - - ``` - gramine-sgx-gen-private-key enclave-key.pem - ``` - -2. If you don't have Gramine, use OpenSSL: - - ``` - openssl genrsa -3 -out enclave-key.pem 3072 - ``` +## Running with Intel TDX -After generating the key: +Intel TDX (Trust Domain Extensions) provides hardware-based memory encryption and integrity protection for virtual machines. To run this container in a TDX-enabled environment, follow your infrastructure provider's specific instructions for deploying confidential containers. -1. Keep this key secure, as it will be used to sign your enclaves. -2. Add the contents of `enclave-key.pem` as a GitHub secret named `SIGNING_KEY`. +Common volume mounts and environment variables: -This key is essential for the `gsc sign-image` step in the GSC workflow. - -## Running with SGX - -Intel SGX (Software Guard Extensions) is a set of security-related instruction codes built into modern Intel CPUs. It allows parts of a program to be executed in a secure enclave, isolated from the rest of the system. - -To load a released image with docker, copy the URL from the release and run: - -``` -curl -L https://address/of/gsc-volara-proof.tar.gz | docker load -``` - -To run the image: - -``` +```bash docker run \ ---rm \ ---volume /gsc-volara-proof/input:/input \ ---volume /gsc-volara-proof/output:/output \ ---device /dev/sgx_enclave:/dev/sgx_enclave \ ---volume /var/run/aesmd:/var/run/aesmd \ ---volume /mnt/gsc-volara-proof/sealed:/sealed \ ---env USER_EMAIL=user123@gmail.com \ -gsc-volara-proof + --rm \ + --volume /path/to/input:/input \ + --volume /path/to/output:/output \ + --env USER_EMAIL=user123@gmail.com \ + my-proof ``` Remember to populate the `/input` directory with the files you want to process. @@ -140,10 +94,13 @@ Remember to populate the `/input` directory with the files you want to process. This template leverages several security features: -1. **Secure Enclaves**: The proof runs inside an SGX enclave, isolating it from the rest of the system. -2. **Encrypted Storage**: The `/sealed` directory is automatically encrypted/decrypted by Gramine, providing secure storage for sensitive data. -3. **Input/Output Isolation**: Input and output directories are mounted separately, ensuring clear data flow boundaries. -4. **Minimal Attack Surface**: The Gramine manifest limits the files and resources accessible to the enclave, reducing potential vulnerabilities. +1. **Hardware-based Isolation**: The proof runs inside a TDX-protected environment, isolating it from the rest of the system +2. **Input/Output Isolation**: Input and output directories are mounted separately, ensuring clear data flow boundaries +3. **Minimal Container**: Uses a minimal Python base image to reduce attack surface + +## Customization + +Feel free to modify any part of this template to fit your specific needs. The goal is to provide a starting point that can be easily adapted to various proof tasks. ## Contributing diff --git a/config.yaml b/config.yaml deleted file mode 100644 index 04270db..0000000 --- a/config.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# NOTE: This file was copied from https://github.com/gramineproject/gsc/blob/fcf96546f4a23a4e6bcc6a14d80cf1521c018fc9/config.yaml.template - -# -# Specify the OS distro that is used to build Gramine, i.e., the distro from where the Gramine build -# gets all tools and dependencies from. This distro should match the distro underlying the -# application's Docker image; otherwise the results may be unpredictable (if you specify `"auto"`, -# which is recommended, you don't need to worry about the mismatch). -# -# Currently supported distros are: -# - ubuntu:20.04, ubuntu:21.04, ubuntu:22.04, ubuntu:23.04 -# - debian:10, debian:11, debian:12 -# - centos:8 -# - quay.io/centos/centos:stream9 -# - redhat/ubi8:8.8, redhat/ubi9:9.4 -# - redhat/ubi8-minimal:8.8, redhat/ubi9-minimal:9.4 - -# If Distro is set to "auto", GSC detects the distro automatically by examining the supplied -# Docker image. Alternatively, Distro can be set to one of the supported distros mentioned above. -Distro: "auto" - -# If the image has a specific registry, define it here. -# Empty by default; example value: "registry.access.redhat.com/ubi8". -Registry: "" - -# If you're using your own fork and branch of Gramine, specify the GitHub link and the branch name -# below; typically, you want to keep the default values though. -# -# It is also possible to specify the prebuilt Gramine Docker image (that was built previously via -# the `gsc build-gramine` command). For this, remove Repository and Branch and instead write: -# Image: "" -# -# GSC releases are guaranteed to work with corresponding Gramine releases (and GSC `master` -# branch is guaranteed to work with current Gramine `master` branch). -Gramine: - Repository: "https://github.com/gramineproject/gramine.git" - Branch: "master" - -# Specify the Intel SGX driver installed on your machine (more specifically, on the machine where -# the graminized Docker container will run); there are several variants of the SGX driver: -# -# - upstream (in-kernel) driver: use empty values like below -# Repository: "" -# Branch: "" -# -# - DCAP out-of-tree driver: same as above, use empty values -# Repository: "" -# Branch: "" -# -# - legacy out-of-tree driver: use something like the below values, but adjust the branch name -# Repository: "https://github.com/01org/linux-sgx-driver.git" -# Branch: "sgx_driver_1.9" -# -SGXDriver: - Repository: "" - Branch: "" \ No newline at end of file diff --git a/volara-proof.manifest.template b/volara-proof.manifest.template deleted file mode 100644 index dd24bd6..0000000 --- a/volara-proof.manifest.template +++ /dev/null @@ -1,34 +0,0 @@ -# Adjust this as needed. -sgx.enclave_size = "256M" - -# Increase this as needed, e.g., if you run a web server. -sgx.max_threads = 8 - -# Whitelist ENV variables that get passed to the enclave -# Using { passthrough = true } allows values to be passed in from the Satya node's /RunProof endpoint -loader.env.COOKIES = { passthrough = true } -loader.env.VOLARA_API_KEY = { passthrough = true } -loader.env.FILE_ID = { passthrough = true } -loader.env.MINER_ADDRESS = { passthrough = true } - -# Gramine gives a warning that allowed_files is not safe in production, but it -# should generally be fine for our use case which inherently assumes that input -# files are untrusted until proven otherwise. -sgx.allowed_files = [ - "file:/input/", - "file:/output/", - # Required for internet access from inside the enclave - "file:/etc/hosts", - "file:/etc/resolv.conf", -] - -# These directories are mounted from the host, which will be a temporary directory from the Satya node that's running the proof. -fs.mounts = [ - { type = "encrypted", path = "/sealed", uri = "file:/sealed", key_name = "_sgx_mrenclave" }, - { path = "/input", uri = "file:/input" }, - { path = "/output", uri = "file:/output" }, -] - -# You can add other Gramine-manifest-compatible options as needed, see the -# Gramine documentation for more details: https://gramine.readthedocs.io. Note -# that gsc defines a number of manifest settings by default. diff --git a/volara_proof/__main__.py b/volara_proof/__main__.py index e67e72e..438a978 100644 --- a/volara_proof/__main__.py +++ b/volara_proof/__main__.py @@ -8,7 +8,7 @@ from volara_proof.proof import Proof -INPUT_DIR, OUTPUT_DIR, SEALED_DIR = "/input", "/output", "/sealed" +INPUT_DIR, OUTPUT_DIR = "./demo/input", "./demo/output" logging.basicConfig(level=logging.INFO, format="%(message)s") @@ -17,7 +17,6 @@ def load_config() -> Dict[str, Any]: """Load proof configuration from environment variables.""" config = { "dlp_id": 19, # Set your own DLP ID here - "use_sealing": os.path.isdir(SEALED_DIR), "input_dir": INPUT_DIR, "cookies": os.environ.get("COOKIES", None), "volara_api_key": os.environ.get("VOLARA_API_KEY", None),