yumechi-no-kuni-proxy-worker/README.md
eternal-flame-AD 607eaae3a9
even more defensive programming on image handling
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2024-11-22 12:59:46 -06:00

108 lines
No EOL
7.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Yumechi-no-kuni-proxy-worker
This is a misskey proxy worker for ゆめちのくに (Yumechi-no-kuni) instance. Runs natively on both local and Cloudflare Workers environments!
Work in progress! Currently to do:
- [X] Content-Type sniffing
- [X] SVG rendering
- [ ] Font rendering (likely will not run on Cloudflare Workers Free plan)
- [X] Preset image resizing
- [X] Opportunistic Redirection on large video files
- [X] RFC9110 compliant proxy loop detection with defensive programming against known vulnerable proxies
- [X] HTTPs only mode and X-Forwarded-Proto reflection
- [X] Cache-Control header
- [X] Rate-limiting on local deployment
- [X] Read config from Cloudflare
- [X] Timing and Rate-limiting headers (some not available on Cloudflare Workers)
- [X] Tiered rate-limiting
- [ ] Lossy WebP on CF Workers (maybe already works?)
- [ ] Cache results
- [ ] Handle all possible panics reported by Clippy
- [X] Sandboxing the image rendering
- [X] Prometheus-format metrics
## Demo
### Avatar resizing
Preview at:
CF Worker: [https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/avatar.webp?url=https://media.misskeyusercontent.com/io/274cc4f7-4674-4db1-9439-9fac08a66aa1.png](https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/avatar.webp?url=https://media.misskeyusercontent.com/io/274cc4f7-4674-4db1-9439-9fac08a66aa1.png)
Local: [https://mproxy.mi.yumechi.jp/proxy/avatar.webp?url=https://media.misskeyusercontent.com/io/274cc4f7-4674-4db1-9439-9fac08a66aa1.png](https://mproxy.mi.yumechi.jp/proxy/avatar.webp?url=https://media.misskeyusercontent.com/io/274cc4f7-4674-4db1-9439-9fac08a66aa1.png)
Image:
![Syuilo Avatar resived.png](https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/avatar.webp?url=https://media.misskeyusercontent.com/io/274cc4f7-4674-4db1-9439-9fac08a66aa1.png)
![Syuilo Avatar resived.png](https://mproxy.mi.yumechi.jp/proxy/avatar.webp?url=https://media.misskeyusercontent.com/io/274cc4f7-4674-4db1-9439-9fac08a66aa1.png)
### SVG rendering
(font rendering disabled due to size restrictions)
CF Worker: [https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg](https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg)
Local: [https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg](https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg)
![AES-AddRoundKey.svg](https://yumechi-no-kuni-proxy-worker.eternal-flame-ad.workers.dev/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg)
![AES-AddRoundKey.svg](https://mproxy.mi.yumechi.jp/proxy/static.webp?url=https://upload.wikimedia.org/wikipedia/commons/a/ad/AES-AddRoundKey.svg)
## Setup and Deployment
1. Clone this repository. Load the submodules with `git submodule update --init`.
2. Install Rust and Cargo, using [rustup](https://rustup.rs/) is recommended.
If you do not plan on deploying to Cloudflare Workers, you can remove the `rust-toolchain` file intended to get around [cloudflare/worker-rs#668](https://github.com/cloudflare/workers-rs/issues/668). Otherwise you may need to install that specific version of Rust by `rustup install $(cat rust-toolchain)`.
3. IF deploying locally:
1. Edit `local.toml` to your liking. The documentations can be opened with `cargo doc --open`.
2. Test run with `cargo run --features env-local -- -c local.toml`. Additional features `apparmor` and `reuse-port` are available for Linux users.
If you do not use the `apparmor` feature, you need to remove the `apparmor` stanza from the configuration file or the program will refuse to start. The `reuse-port` feature is not necessary but may improve performance on Linux in high-traffic environments.
3. Build with `cargo build --features env-local --profile release-local`. The built binary will be in `target/release-local/yumechi-no-kuni-proxy-worker`. You can consider setting `RUSTFLAGS="-Ctarget-cpu=native"` for better performance. Be prepared for ~5 minutes of build time due to link time optimization.
4. The only flag understood is `-c` for the configuration file. The configuration file is in TOML format. However, the `RUST_LOG` environment variable will change the log level. The log level is `info` by default if the environment variable is not set.
IF deploying to Cloudflare Workers:
Firstly I don't recommend deploying using the free plan because there are much faster implementations that do not or almost do not perform any Image processing. I have this feature mainly because I don't want to pay for a Cloudflare Workers plan just to support this.
The reported CPU time by Cloudflare is consistently over the free plan limit (which is only 10ms! probably not even enough for decoding an image) and will likely be throttled or terminated once you deploy it to real workloads. The paid plan is recommended for this worker.
5. Add the wasm target with `rustup +$(cat rust-toolchain) target add wasm32-unknown-unknown`.
6. Have a working JS environment.
7. Install `wrangler` with you JS package manager of choice. See <https://developers.cloudflare.com/workers/wrangler/install-and-update>/. `npx` also works.
8. Edit `wrangler.toml` to your liking. Everything in the `[vars]` section maps directly into the `config` section of the TOML configuration file. There is a `cf-worker-paid` feature set which enable some additional features that will never fit in the free plan, mainly SVG font rendering and some debugging features.
9. Test locally with `wrangler dev`.
10. Deploy with `wrangler deploy --outdir bundled/`.
## AppArmor
AppArmor is a Mandatory Access Control Linux security module that can be used to heavily restrict the actions of tasks.
It is much more secure than Docker and I recommend using AppArmor instead of Docker for isolation, mainly because:
- Docker is not designed for security but for convenience.
- Docker only creates a new namespace but do not actually police the actions of the task.
- There is no dynamic privilege reduction in Docker, so if the image parsing is compromised at the very least your whole container is compromised.
- AFAIK there are no known bypasses for AppArmor, but there are known bypasses for Docker.
To use AppArmor, you need to have the apparmor LSM loaded into kernel (should be just a kernel parameter) and load the `mac/apparmor/yumechi-no-kuni-proxy-worker` profile into the system. You might want to adjust the path to your binary and configuration file, or alternatively use the systemd `AppArmorProfile` directive to confine the worker.
All major distros should have an easy-to-follow guide on how to do this. Typically add a kernel parameter and install a userspace tool package.
This will create a highly restrictive environment: try it yourself with `aa-exec -p yumechi-no-kuni-proxy-worker [initial_foothold]` and see if you can break out :). And that is just the first layer of defense, try the more restrictive subprofiles:
- `yumechi-no-kuni-proxy-worker//serve`: irreversibly dropped into before listening on the network begins. Restrict loading additional code and access to configuration files.
- `yumechi-no-kuni-proxy-worker//serve//image`: absolutely no file, network or capability access.