Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions conf/proxy.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# workdir = "./work"

# Experimental out-of-process Rust SQL dataplane. When enabled, set
# enable-traffic-replay = false and start tiproxy-rs with the same absolute
# control socket, allowed UID, and TLS allowlist roots.
# enable-traffic-replay = false
# Experimental out-of-process Rust SQL dataplane. The Go default
# enable-traffic-replay = true is accepted by tiproxy-rs and SQL serving
# starts. Capture and replay are not implemented: the traffic API answers
# "unsupported" while the flag is true and "disabled" while it is false.
# The Go process still rejects rust-dataplane.enabled together with
# enable-traffic-replay. Start tiproxy-rs with the same absolute control
# socket, allowed UID, and TLS allowlist roots.
# enable-traffic-replay = true
# [rust-dataplane]
# enabled = true
# control-socket = "/var/run/tiproxy/tiproxy-rust-control.sock"
Expand Down
4 changes: 2 additions & 2 deletions docs/design/rust-control-admin.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ drains instead of continuing without an operator surface (Go only logs the
| `DELETE /api/debug/health` | clears the override, `200 ""`. |
| `GET /metrics`, `/metrics/`, `/api/metrics`, `/api/metrics/` | the B0 native exposition, `text/plain; version=0.0.4; charset=utf-8; escaping=underscores`. |
| `GET /api/dataplane/status` | the Go key set in gin's sorted-map order; `desired_generation` and `sent_generation` are the latest composed generation (there is no transport hop in-process), `applied_generation`/`rejected_generation` come from SQL serving, `last_result_code` is `ERROR_CODE_INVALID_SNAPSHOT` when the latest rejection is newer than the latest apply, `ERROR_CODE_OK` after the first apply, `ERROR_CODE_UNSPECIFIED` before it. |
| `POST /api/traffic/{capture,replay,cancel}`, `GET /api/traffic/show` | `400 text/plain "traffic <verb> is disabled"`, the Go answer when `enable-traffic-replay = false`, which the Rust dataplane composition requires. |
| `POST /api/traffic/{capture,replay,cancel}`, `GET /api/traffic/show` | `400 text/plain`. The body is `traffic <verb> is unsupported` when `enable-traffic-replay` is true, and Go's `traffic <verb> is disabled` when it is false. The default is true and SQL serving still starts. |

Health inputs: `closing` is the runtime lifecycle leaving `Ready`; the
namespace-owner readiness is the config module's initial persistent view;
Expand Down Expand Up @@ -288,7 +288,7 @@ certificate.
every command's exit code and stdout: `health`, `config get`/`config set
--input`, `namespace list`/`put`/`get`/`import`/`commit`/`del` including
missing namespaces, and `traffic show`/`capture`/`replay`/`cancel`, which
both sides refuse with the disabled message while traffic replay is off.
both sides refuse. The evidence overlay sets `enable-traffic-replay = false`, so both answers are the disabled message. A default configuration answers `unsupported` on the native process.
`config get` and `health` are compared semantically (the TOML renderers
differ in layout and omitted zero fields); every other observation,
including the CLI's `namespace list` failure on an empty set (the Go server
Expand Down
34 changes: 21 additions & 13 deletions docs/design/rust-control-config-namespace.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ old reader/election, and campaign with the new transport; owner-fenced writes
remain unavailable throughout the handoff. Transport construction participates
in prospective candidate validation, so an unsupported replacement retains the
last-good source generation instead of publishing and then failing. In
particular, `cluster-tls.skip-ca = true` is rejected explicitly by the current
safe Rust etcd transport; it can never silently downgrade the owner connection
to plaintext.
particular, `cluster-tls.skip-ca = true` still opens a TLS connection and
does not require a CA. It does not downgrade the owner connection to
plaintext.

Binary/build/process facts are not configuration: the composition root passes
`TopologyRuntimeIdentity` directly to the CP-TOPO constructor. CP-TOPO combines
Expand Down Expand Up @@ -208,27 +208,30 @@ would activate the value is rejected by the serving validator.
| --- | --- | --- |
| `workdir` | Restart | Modeled and checksummed; process/filesystem ownership is fixed at startup. |
| `proxy.addr`, `proxy.advertise-addr`, `proxy.pd-addrs`, `proxy.port-range` | Restart | Modeled; SQL bind and topology identity are fixed at startup. |
| `api.addr`, `api.proxy-protocol` | Restart | Modeled; CP-ADMIN will own the HTTP listener. |
| `api.addr` | Restart | The native process binds it. `--admin-addr` overrides only that bind. |
| `log.encoder`, `log.simple` | Restart | Modeled; encoder construction is fixed at startup. |
| `balance.routing-rule` | Restart | Modeled; listener-group construction is fixed at startup. |
| `ha.virtual-ip`, `ha.interface`, `ha.garp-burst-count`, `ha.garp-refresh-count` | Restart | Modeled; CP-HA consumes them at startup. |
| `api.proxy-protocol` | Restart, `v2` unsupported | Retained for the checksum. `v2` is rejected because the native admin listener does not apply PROXY protocol. Any other value is inert. |
| `balance.routing-rule` | Dynamic | Accepted for routers created after the reload. An existing router keeps the rule it was built with, matching the Go process. |
| `ha.virtual-ip` | Restart, applied | Excluded when the process selects an advertise address. |
| `ha.interface`, `ha.garp-burst-count`, `ha.garp-refresh-count` | Restart, inert | Retained. VIP ownership and GARP are not implemented. |
| `ha.virtual-ip` with `ha.interface` | Restart, unsupported | Go binds the VIP only when both are set. That activation is rejected. |
| `metering.type`, `region`, `bucket`, `prefix`, `endpoint`, `shared-pool-id`; every field below `metering.aws`, `.oss`, `.cos`, `.azure`, `.localfs` | Restart | Modeled with secret-safe debug output; CP-METER consumes them at startup. |
| `rust-dataplane.enabled`, `.control-socket`, `.routing-shadow-socket`, `.allowed-uid`, `.tls-allowed-roots`, `.metrics-owner-port` | Restart | Modeled; process/transport, TLS trust roots, observer socket, and metrics-owner bind cannot change online. A nonzero metrics-owner port must differ from every SQL/API listener port. |
| `proxy.max-connections`, `proxy.high-memory-usage-reject-threshold`, `proxy.conn-buffer-size` | Dynamic | Applied by the Rust SQL serving snapshot. |
| all five fields `enabled`, `idle`, `cnt`, `intvl`, `timeout` below each of `proxy.frontend-keepalive`, `.backend-healthy-keepalive`, `.backend-unhealthy-keepalive` | Dynamic | Applied by the Rust SQL serving snapshot. |
| `proxy.proxy-protocol`, `.graceful-wait-before-shutdown`, `.graceful-close-conn-timeout`, `.public-endpoints` | Dynamic | Applied by the Rust SQL serving snapshot, including the latest graceful-close value at process drain. |
| every `name`, `pd-addrs`, `ns-servers` below `proxy.backend-clusters` | Dynamic | Projected in stable order for CP-TOPO. |
| `proxy.fail-backend-list`, `proxy.failover-timeout` | Dynamic | Retained for CP-ROUTE; no effect is claimed before #147. |
| `security.encryption-key-path` | Dynamic | Modeled and checksummed; CP-ADMIN consumes it. |
| `security.encryption-key-path` | Dynamic, inert | Retained, including a non-empty path, so a Go config still starts. Traffic capture is not implemented and does not read the key. |
| `security.require-backend-tls` | Dynamic | Applied by the Rust SQL serving snapshot. |
| `cert`, `key`, `ca`, `min-tls-version`, `cert-allowed-cn`, `skip-ca` below each of `security.server-tls`, `.server-http-tls`, `.cluster-tls`, `.sql-tls` | Dynamic | All material is validated and content-watched atomically. SQL front/back is applied now; HTTP and cluster projections are ready for CP-ADMIN/CP-TOPO. `cluster-tls.skip-ca = true` is an explicit unsupported candidate while the Rust config owner uses the safe etcd transport. |
| `cert`, `key`, `ca`, `min-tls-version`, `cert-allowed-cn`, `skip-ca` below each of `security.server-tls`, `.server-http-tls`, `.cluster-tls`, `.sql-tls` | Dynamic | `Config.Check` accepts every minimum version, a relative path, and a certificate without its key. The effective minimum version follows Go `GetMinTLSVer`; the native handshake floor is TLS 1.2, and only a `1.3` suffix selects TLS 1.3 alone. A relative path is resolved against the process working directory. A configured `--tls-root` or `tls-allowed-roots` still confines the read; an empty allowlist does not add a jail. A certificate and key are still required together when a server identity is built. `cluster-tls.skip-ca = true` keeps the etcd connection on TLS and does not require a CA. |
| `auto-certs` below global `server-tls` / `server-http-tls` and namespace `frontend.security` | Unsupported | Canonically round-tripped, then rejected explicitly because #146 does not generate server certificates. |
| `auto-certs` below global `cluster-tls` / `sql-tls` and namespace `backend.security` | Dynamic, inert | Canonically round-tripped; the legacy client-side shape has no serving meaning. |
| `rsa-key-size`, `autocert-expire-duration` below every global TLS block | Dynamic, inert unless auto-certs | Canonically round-tripped; because auto-certs is unsupported, these fields do not generate material in #146. |
| `log.level`, every `filename`, `max-size`, `max-days`, `max-backups` below `log.log-file` | Dynamic | Level is applied by CP-001; file sink changes are retained for CP-ADMIN/log ownership. |
| `balance.label-name`, `.policy`, `.routing-policy`; `migrations-per-second` below `.status`, `.health`, `.memory`, `.cpu`, `.location`, `.conn-count`; `.conn-count.count-ratio-threshold` | Dynamic | Validated and retained for CP-ROUTE. |
| every `labels.<key>` | Dynamic | Stable map projection for CP-TOPO/CP-ROUTE. |
| `enable-traffic-replay` | Dynamic, only `false` supported | Canonically modeled and reloadable, but enabling it is rejected by the serving validator because traffic capture remains M2 CP-CAPTURE #151. |
| `enable-traffic-replay` | Dynamic, inert | The Go default `true` is accepted and SQL serving starts. Capture and replay are not implemented: the traffic API answers `unsupported` when the flag is true and `disabled` when it is false. `rust-dataplane.enabled` together with this flag still fails `Config.Check`. |

Namespace values have a separate, equally exact classification:

Expand Down Expand Up @@ -320,12 +323,17 @@ where an unrelated first proxy update empties all namespaces.

## TLS rotation

TLS paths must be absolute and under configured allowed roots. Certificate and
key must be supplied together; minimum TLS is 1.2 or 1.3; allowed common names
are bounded and canonicalized. Candidate validation loads and parses every
A relative TLS path is resolved against the process working directory, the
same way Go `os.ReadFile` resolves it. When `--tls-root` or
`tls-allowed-roots` is non-empty, the canonical path must stay under one of
those roots. An empty allowlist has no extra jail. Minimum versions follow
Go `GetMinTLSVer`, with a native floor of TLS 1.2. A certificate without its
key is accepted by `Config.Check` and rejected when a server identity is
built, so it cannot become a plaintext listener. Allowed common names are
bounded and canonicalized. Candidate validation loads and parses every
complete cert/key/CA set before publishing a source generation; the serving
adapter then constructs and atomically swaps one complete immutable connection
factory. Partial, unreadable, invalid, or expired material is rejected without
factory. Unreadable, invalid, or expired material is rejected without
publishing a partial set. A generation advances for an accepted
config/namespace value change **or for a byte-level change to any referenced
TLS material file**, even when every source revision and canonical config
Expand Down
Loading