12 stable releases

1.2.2 Oct 21, 2024
1.2.1 Sep 26, 2024
1.2.0 Aug 24, 2024
1.1.6 Jul 19, 2024
0.5.2 Jun 28, 2024

#103 in Web programming

MIT/Apache

54KB
1K SLoC

Idempotent Proxy

Reverse proxy server with build-in idempotency support written in Rust.

Overview

The idempotent-proxy is a reverse proxy service written in Rust with built-in idempotency support.

When multiple requests with the same idempotency-key arrive within a specific timeframe, only the first request is forwarded to the target service. The response is cached in Redis, and subsequent requests poll Redis to retrieve and return the first request's response.

This service can be used to proxy HTTPS outcalls for ICP canisters, enabling integration with any Web2 http service. It supports hiding secret information, access control, returning only the necessary headers and, for JSON or CBOR data, allows response filtering based on JSON Mask to return only required fields, thus saving cycles consumption in ICP canisters.

Idempotent Proxy

Features

  • Reverse proxy with build-in idempotency support
  • JSON response filtering
  • Access control
  • Response headers filtering
  • HTTPS support
  • Running as Cloudflare Worker
  • Docker image

Deploy

Run proxy in development mode

Run proxy:

# docker run --name redis -d -p 6379:6379 redis:latest # optional redis
cargo run -p idempotent-proxy-server

Building and running AWS Nitro Enclave image

Setup host machine

https://docs.marlin.org/learn/oyster/core-concepts/networking/outgoing

wget -O vsock-to-ip-transparent http://public.artifacts.marlin.pro/projects/enclaves/vsock-to-ip-transparent_v1.0.0_linux_amd64
chmod +x vsock-to-ip-transparent
./vsock-to-ip-transparent --vsock-addr 3:1200

https://docs.marlin.org/learn/oyster/core-concepts/networking/incoming

iptables rules:

# route incoming packets on port 80 to the transparent proxy
iptables -A PREROUTING -t nat -p tcp --dport 80 -i ens5 -j REDIRECT --to-port 1200
# route incoming packets on port 443 to the transparent proxy
iptables -A PREROUTING -t nat -p tcp --dport 443 -i ens5 -j REDIRECT --to-port 1200
# route incoming packets on port 1025:65535 to the transparent proxy
iptables -A PREROUTING -t nat -p tcp --dport 1025:65535 -i ens5 -j REDIRECT --to-port 1200
wget -O port-to-vsock-transparent http://public.artifacts.marlin.pro/projects/enclaves/port-to-vsock-transparent_v1.0.0_linux_amd64
chmod +x port-to-vsock-transparent
./port-to-vsock-transparent --vsock 88 --ip-addr 0.0.0.0:1200

Build and run enclave

The following steps should be run in AWS Nitro-based instances.

https://docs.aws.amazon.com/enclaves/latest/user/getting-started.html

sudo nitro-cli build-enclave --docker-uri ghcr.io/ldclabs/idempotent-proxy_enclave_amd64:latest --output-file idempotent-proxy_enclave_amd64.eif
# Start building the Enclave Image...
# Using the locally available Docker image...
# Enclave Image successfully created.
# {
#   "Measurements": {
#     "HashAlgorithm": "Sha384 { ... }",
#     "PCR0": "bbfe317cdaba604e1364fbd254150ce25516d83e31a87f8b3d8acb163286f57f51d8b3f6b2a482ac209b758334d996d9",
#     "PCR1": "4b4d5b3661b3efc12920900c80e126e4ce783c522de6c02a2a5bf7af3a2b9327b86776f188e4be1c1c404a129dbda493",
#     "PCR2": "9ea2080d6e6bd61f03a62357a1cbbae278b070db5df6b1fe5c57821ff249b77add0f95dab0a5beec7aa6ef6735f27b14"
#   }
# }
sudo nitro-cli run-enclave --cpu-count 2 --memory 512 --enclave-cid 88 --eif-path idempotent-proxy_enclave_amd64.eif --debug-mode
# Started enclave with enclave-cid: 88, memory: 512 MiB, cpu-ids: [1, 3]
# {
#   "EnclaveName": "idempotent-proxy_enclave_amd64",
#   "EnclaveID": "i-056e1ab9a31cd77a0-enc190ca7263013fd3",
#   "ProcessID": 21493,
#   "EnclaveCID": 88,
#   "NumberOfCPUs": 2,
#   "CPUIDs": [
#     1,
#     3
#   ],
#   "MemoryMiB": 512
# }
sudo nitro-cli describe-enclaves
sudo nitro-cli console --enclave-id i-056e1ab9a31cd77a0-enc190ca7263013fd3
sudo nitro-cli terminate-enclave --enclave-id i-056e1ab9a31cd77a0-enc190ca7263013fd3

Make a request

curl -v -X POST \
  --url http://YOUR_HOST/ \
  --header 'content-type: application/json' \
  --header 'x-forwarded-host: cloudflare-eth.com' \
  --header 'idempotency-key: key_001' \
  --data '{
	  "id": 1,
    "jsonrpc": "2.0",
    "method": "eth_getBlockByNumber",
    "params": ["latest", false]
}'

License

Copyright © 2024 LDC Labs.

ldclabs/idempotent-proxy is licensed under the MIT License. See LICENSE for the full license text.

Dependencies

~26–40MB
~724K SLoC