mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
Capture TLS fingerprints in report context
This commit is contained in:
94
docs/operations/tls-fingerprint-capture.md
Normal file
94
docs/operations/tls-fingerprint-capture.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# TLS Fingerprint Capture
|
||||
|
||||
Aether stores per-request TLS capture under `usage.request_metadata.tls_fingerprint`.
|
||||
|
||||
```json
|
||||
{
|
||||
"tls_fingerprint": {
|
||||
"incoming": {
|
||||
"source": "forwarded_header",
|
||||
"ja3": "...",
|
||||
"ja3_hash": "...",
|
||||
"ja4": "...",
|
||||
"protocol": "TLSv1.3",
|
||||
"cipher": "TLS_AES_128_GCM_SHA256",
|
||||
"sni": "api.example.com",
|
||||
"alpn": "h2"
|
||||
},
|
||||
"outgoing": {
|
||||
"source": "aether_transport_config",
|
||||
"observed": false,
|
||||
"transport_path": "direct",
|
||||
"backend": "reqwest_rustls",
|
||||
"http_mode": "auto",
|
||||
"tls_stack": "rustls",
|
||||
"tls_versions_offered": ["TLS1.3", "TLS1.2"],
|
||||
"alpn_offered": ["h2", "http/1.1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`incoming` is the client-to-Aether TLS fingerprint. It can be populated by Aether native TLS capture in direct deployments or by trusted reverse-proxy headers when TLS terminates before Aether.
|
||||
|
||||
`outgoing` is the Aether-to-provider TLS transport record. The current gateway records the exact transport configuration it controls. It sets `observed: false` because reqwest/rustls does not expose the emitted ClientHello bytes on the direct path. A future connector-level ClientHello capture or probe result can reuse the same object with `observed: true` plus `ja3`, `ja3_hash`, and `ja4`.
|
||||
|
||||
## Nginx TLS Termination
|
||||
|
||||
When nginx terminates HTTPS and proxies HTTP to Aether, Aether cannot see the original ClientHello. Configure nginx to forward the TLS fields it can observe:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name api.example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_set_header X-Aether-TLS-Source nginx;
|
||||
proxy_set_header X-Aether-TLS-Protocol $ssl_protocol;
|
||||
proxy_set_header X-Aether-TLS-Cipher $ssl_cipher;
|
||||
proxy_set_header X-Aether-TLS-SNI $ssl_server_name;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Stock nginx does not provide JA3/JA4 variables. The forwarded record is still useful, but it is not a complete TLS fingerprint. To forward JA3/JA4 through nginx, use an nginx build/module or edge layer that computes them and set:
|
||||
|
||||
```nginx
|
||||
proxy_set_header X-Aether-TLS-JA3 $ja3;
|
||||
proxy_set_header X-Aether-TLS-JA3-Hash $ja3_hash;
|
||||
proxy_set_header X-Aether-TLS-JA4 $ja4;
|
||||
```
|
||||
|
||||
Only accept these headers from trusted infrastructure. Do not expose Aether directly to public clients while also trusting client-supplied `X-Aether-TLS-*` headers.
|
||||
|
||||
## Nginx TCP Passthrough
|
||||
|
||||
If Aether terminates TLS itself, nginx can pass TCP through without decrypting:
|
||||
|
||||
```nginx
|
||||
stream {
|
||||
map $ssl_preread_server_name $aether_backend {
|
||||
api.example.com 127.0.0.1:3443;
|
||||
default 127.0.0.1:3443;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443;
|
||||
proxy_pass $aether_backend;
|
||||
ssl_preread on;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this mode nginx cannot inject HTTP headers because it never sees HTTP. Aether native TLS capture is responsible for populating `tls_fingerprint.incoming`.
|
||||
Reference in New Issue
Block a user