For reading and verification only. You may not copy, use, modify or redistribute this code. Full notice on the main page.
tunnel/backend_prod.go
| 1 | //go:build !testnode && !testcp |
| 2 | |
| 3 | package main |
| 4 | |
| 5 | import ( |
| 6 | "flag" |
| 7 | "fmt" |
| 8 | "io" |
| 9 | ) |
| 10 | |
| 11 | // The production backend: the node's real control-plane client, JWKS cache and feed. The node holds exactly one secret, its own Ed25519 signing key |
| 12 | // (-node-key-file, mode 0600); the control plane holds the public half in TUNNEL_NODE_KEYS and a node that is taken over is revoked by removing its |
| 13 | // kid there. There is no shared secret to configure, and the control plane's address is the issuer the policy pins unless an operator points a |
| 14 | // staging node somewhere else on purpose. |
| 15 | |
| 16 | func init() { |
| 17 | theBackend = &backend{flags: prodFlags} |
| 18 | defaultMetricsAddr = "127.0.0.1:9101" |
| 19 | defaultOpenAIPrefixesURL = "https://openai.com/chatgpt-connectors.json" |
| 20 | } |
| 21 | |
| 22 | func prodFlags(fs *flag.FlagSet, stdout io.Writer) func(*Config) error { |
| 23 | controlURL := fs.String("control-url", envStr("TUNNEL_CONTROL_URL", policyData.Identity.Issuer), "the control plane (https://host[:port]): authorize, the feed and the published keys come from here only [TUNNEL_CONTROL_URL]") |
| 24 | keyFile := fs.String("node-key-file", envStr("TUNNEL_NODE_KEY_FILE", ""), "this node's Ed25519 signing key (PKCS#8 PEM, mode 0600): the one credential this node has [TUNNEL_NODE_KEY_FILE]") |
| 25 | kid := fs.String("node-kid", envStr("TUNNEL_NODE_KID", ""), "the kid of this node's public key in the control plane's TUNNEL_NODE_KEYS [TUNNEL_NODE_KID]") |
| 26 | initKey := fs.Bool("node-key-init", false, "create the signing key at -node-key-file (never over an existing one), print the TUNNEL_NODE_KEYS entry that registers it, and exit") |
| 27 | printKey := fs.Bool("node-key-print", false, "print the TUNNEL_NODE_KEYS entry of the key at -node-key-file and exit") |
| 28 | return func(cfg *Config) error { |
| 29 | if *keyFile == "" { |
| 30 | return fmt.Errorf("the node needs its signing key: -node-key-file (create it once with -node-key-init)") |
| 31 | } |
| 32 | if (*initKey || *printKey) && (!reNodeID.MatchString(cfg.NodeID) || !reKID.MatchString(*kid)) { |
| 33 | return fmt.Errorf("the TUNNEL_NODE_KEYS entry needs -node-id and -node-kid") |
| 34 | } |
| 35 | if *initKey { |
| 36 | key, err := GenerateNodeKey(*keyFile) |
| 37 | if err != nil { |
| 38 | return err |
| 39 | } |
| 40 | fmt.Fprintln(stdout, NodeKeysEntry(cfg.NodeID, *kid, key)) |
| 41 | return errDone |
| 42 | } |
| 43 | key, err := LoadNodeKey(*keyFile) |
| 44 | if err != nil { |
| 45 | return err |
| 46 | } |
| 47 | if *printKey { |
| 48 | fmt.Fprintln(stdout, NodeKeysEntry(cfg.NodeID, *kid, key)) |
| 49 | return errDone |
| 50 | } |
| 51 | control, err := NewHTTPControl(HTTPControlConfig{BaseURL: *controlURL, NodeID: cfg.NodeID, KID: *kid, Key: key, Version: version}) |
| 52 | if err != nil { |
| 53 | return err |
| 54 | } |
| 55 | clk := newClock(cfg.Now, cfg.AfterFunc) |
| 56 | health := &cpHealth{} |
| 57 | jwks := NewJWKSCache(JWKSConfig{ |
| 58 | Fetch: control.FetchJWKS, Clock: clk, Log: cfg.Logger, |
| 59 | Observe: func(ok bool) { |
| 60 | if ok { |
| 61 | health.good(clk.Now()) |
| 62 | } else { |
| 63 | health.bad(clk.Now()) |
| 64 | } |
| 65 | }, |
| 66 | }) |
| 67 | cfg.Keys, cfg.Control, cfg.Feed, cfg.Health = jwks, control, control, health |
| 68 | cfg.Background = append(cfg.Background, jwks.Run) |
| 69 | return nil |
| 70 | } |
| 71 | } |