carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package edge
2
3// The forwarded-for proof (internal/edgeproof): the edge signs the
4// X-Forwarded-For chain it sends upstream, so an app on this box can tell a
5// client address the edge saw from one a local process typed. The console's
6// per-IP login limits are the reason (discussion 214, item 5): every request
7// the edge proxies to it arrives from loopback, and so does every request a
8// tenant process on the same box makes to 127.0.0.1:8090 directly.
9
10import (
11 "context"
12 "net/http"
13 "net/http/httputil"
14 "strings"
15 "time"
16
17 "github.com/carlosframework/platform/internal/edgeproof"
18)
19
20type forwardKeyCtx struct{}
21
22// withForwardKey puts the current signing key on the request, read once per
23// request from the home map's cached pair, so the proxies' Rewrite funcs —
24// which have no Edge to ask — can sign what they send. No key (no store,
25// nothing minted yet) leaves the request as it is, and nothing is signed.
26func (e *Edge) withForwardKey(r *http.Request) *http.Request {
27 key := signingKey(e.homes.Load().meshKeys())
28 if len(key) == 0 {
29 return r
30 }
31 return r.WithContext(context.WithValue(r.Context(), forwardKeyCtx{}, key))
32}
33
34// signForwarded replaces whatever proof header the inbound request carried
35// with the edge's own signature over the outbound chain. The delete is
36// unconditional: a client-sent proof is at best a replay, and with no key to
37// sign, the honest outbound request carries none.
38func signForwarded(pr *httputil.ProxyRequest) {
39 pr.Out.Header.Del(edgeproof.Header)
40 key, _ := pr.In.Context().Value(forwardKeyCtx{}).([]byte)
41 if len(key) == 0 {
42 return
43 }
44 xff := strings.Join(pr.Out.Header.Values("X-Forwarded-For"), ", ")
45 if xff == "" {
46 return
47 }
48 // pr.In.Host, because every Rewrite here sends it on as pr.Out.Host
49 // (and runs setForwarded before it does): it is the Host the upstream
50 // will see and verify against.
51 pr.Out.Header.Set(edgeproof.Header, edgeproof.Sign(key, pr.In.Host, xff, time.Now()))
52}
53