|
| 1 | +package config |
| 2 | + |
| 3 | +// RedactedConfig is a public-safe view of Config, suitable for serving on the |
| 4 | +// log's HTML index page. It is built by an *allowlist*: only fields that are |
| 5 | +// neither secrets nor filesystem paths are copied across. A newly added field |
| 6 | +// is therefore excluded by default — it has to be added here explicitly to be |
| 7 | +// exposed — so a future secret can't leak by accident. Everything path-like is |
| 8 | +// intentionally absent: data_dir, ca_cosigner.seed_path, acme.tls_cert / |
| 9 | +// tls_key, every *.public_key_path / ca_cosigner_key_path, mirror.seed_path. |
| 10 | +// |
| 11 | +// Internal bind addresses (acme.listen, monitoring.listen, metrics.listen, |
| 12 | +// mirror.sign_subtree_listen) are also dropped; only the public external_url |
| 13 | +// values are exposed. sign_subtree_path is an HTTP route, not a bind address |
| 14 | +// or filesystem path, so it is kept. The metrics section has nothing left to |
| 15 | +// expose once its listen address is dropped, so it is omitted entirely. |
| 16 | +type RedactedConfig struct { |
| 17 | + Log LogConfig `json:"log"` |
| 18 | + CACosigner RedactedCosigner `json:"ca_cosigner"` |
| 19 | + CACosignerQuorum RedactedQuorum `json:"ca_cosigner_quorum"` |
| 20 | + ACME RedactedACME `json:"acme"` |
| 21 | + Monitoring RedactedListener `json:"monitoring"` |
| 22 | + Landmarks LandmarkConfig `json:"landmarks"` |
| 23 | + Mirror RedactedMirror `json:"mirror"` |
| 24 | + LogLevel string `json:"log_level"` |
| 25 | +} |
| 26 | + |
| 27 | +// RedactedCosigner drops CosignerConfig.SeedPath. |
| 28 | +type RedactedCosigner struct { |
| 29 | + ID string `json:"id"` |
| 30 | + Algorithm string `json:"algorithm"` |
| 31 | +} |
| 32 | + |
| 33 | +// RedactedACME drops ACMEConfig.TLSCert, TLSKey, and the internal Listen |
| 34 | +// address. |
| 35 | +type RedactedACME struct { |
| 36 | + ExternalURL string `json:"external_url"` |
| 37 | + ChallengeMode string `json:"challenge_mode"` |
| 38 | +} |
| 39 | + |
| 40 | +// RedactedListener drops ListenerConfig.Listen (the internal bind address). |
| 41 | +type RedactedListener struct { |
| 42 | + ExternalURL string `json:"external_url"` |
| 43 | +} |
| 44 | + |
| 45 | +// RedactedQuorum mirrors CACosignerQuorum but with redacted endpoints. |
| 46 | +type RedactedQuorum struct { |
| 47 | + Mirrors []RedactedMirrorEndpoint `json:"mirrors"` |
| 48 | + MinSignatures int `json:"min_signatures"` |
| 49 | + RequestTimeoutMS int `json:"request_timeout_ms"` |
| 50 | + BestEffortAfterMinimum bool `json:"best_effort_after_minimum"` |
| 51 | + MirrorRetryDeadlineMS int `json:"mirror_retry_deadline_ms"` |
| 52 | +} |
| 53 | + |
| 54 | +// RedactedMirrorEndpoint drops MirrorEndpointConfig.PublicKeyPath. |
| 55 | +type RedactedMirrorEndpoint struct { |
| 56 | + ID string `json:"id"` |
| 57 | + URL string `json:"url"` |
| 58 | + Algorithm string `json:"algorithm"` |
| 59 | +} |
| 60 | + |
| 61 | +// RedactedMirror drops MirrorConfig.SeedPath and the internal |
| 62 | +// SignSubtreeListen bind address. |
| 63 | +type RedactedMirror struct { |
| 64 | + Enabled bool `json:"enabled"` |
| 65 | + CosignerID string `json:"cosigner_id"` |
| 66 | + Algorithm string `json:"algorithm"` |
| 67 | + Upstream RedactedUpstream `json:"upstream"` |
| 68 | + SignSubtreePath string `json:"sign_subtree_path"` |
| 69 | + RequireCASignatureOnSubtree bool `json:"require_ca_signature_on_subtree"` |
| 70 | +} |
| 71 | + |
| 72 | +// RedactedUpstream drops UpstreamConfig.CACosignerKeyPath. |
| 73 | +type RedactedUpstream struct { |
| 74 | + TileURL string `json:"tile_url"` |
| 75 | + LogID string `json:"log_id"` |
| 76 | + CACosignerID string `json:"ca_cosigner_id"` |
| 77 | + PollIntervalMS int `json:"poll_interval_ms"` |
| 78 | +} |
| 79 | + |
| 80 | +// Redacted returns the public-safe view of c. See RedactedConfig. |
| 81 | +func (c Config) Redacted() RedactedConfig { |
| 82 | + rc := RedactedConfig{ |
| 83 | + Log: c.Log, |
| 84 | + CACosigner: RedactedCosigner{ID: c.CACosigner.ID, Algorithm: c.CACosigner.Algorithm}, |
| 85 | + CACosignerQuorum: RedactedQuorum{ |
| 86 | + MinSignatures: c.CACosignerQuorum.MinSignatures, |
| 87 | + RequestTimeoutMS: c.CACosignerQuorum.RequestTimeoutMS, |
| 88 | + BestEffortAfterMinimum: c.CACosignerQuorum.BestEffortAfterMinimum, |
| 89 | + MirrorRetryDeadlineMS: c.CACosignerQuorum.MirrorRetryDeadlineMS, |
| 90 | + }, |
| 91 | + ACME: RedactedACME{ |
| 92 | + ExternalURL: c.ACME.ExternalURL, |
| 93 | + ChallengeMode: c.ACME.ChallengeMode, |
| 94 | + }, |
| 95 | + Monitoring: RedactedListener{ExternalURL: c.Monitoring.ExternalURL}, |
| 96 | + Landmarks: c.Landmarks, |
| 97 | + Mirror: RedactedMirror{ |
| 98 | + Enabled: c.Mirror.Enabled, |
| 99 | + CosignerID: c.Mirror.CosignerID, |
| 100 | + Algorithm: c.Mirror.Algorithm, |
| 101 | + SignSubtreePath: c.Mirror.SignSubtreePath, |
| 102 | + RequireCASignatureOnSubtree: c.Mirror.RequireCASignatureOnSubtree, |
| 103 | + Upstream: RedactedUpstream{ |
| 104 | + TileURL: c.Mirror.Upstream.TileURL, |
| 105 | + LogID: c.Mirror.Upstream.LogID, |
| 106 | + CACosignerID: c.Mirror.Upstream.CACosignerID, |
| 107 | + PollIntervalMS: c.Mirror.Upstream.PollIntervalMS, |
| 108 | + }, |
| 109 | + }, |
| 110 | + LogLevel: c.LogLevel, |
| 111 | + } |
| 112 | + for _, m := range c.CACosignerQuorum.Mirrors { |
| 113 | + rc.CACosignerQuorum.Mirrors = append(rc.CACosignerQuorum.Mirrors, RedactedMirrorEndpoint{ |
| 114 | + ID: m.ID, |
| 115 | + URL: m.URL, |
| 116 | + Algorithm: m.Algorithm, |
| 117 | + }) |
| 118 | + } |
| 119 | + return rc |
| 120 | +} |
0 commit comments