[refactor](maestro): retire the PKI and federation identity layer
Contract rev 9 removes the instance CA, client certificates, the peer listener and the trust store fleet-wide. Internal traffic is plaintext HTTP on each service single :8080 listener, so there is no peer identity left to authorize: delete lib/pki, lib/federation, devboot, the per-service database role model and the /api/peers* and /api/instances surfaces, and drop the console Trusted services UI. Config delivery now rides a dedicated ES256 token from lib/configsign rather than mTLS, and the instance fingerprint is derived from a persisted random key and is informational only. main.go also wires the surfaces introduced by the later commits, which this change is what makes possible.
This commit is contained in:
@@ -16,12 +16,13 @@
|
||||
// Package containers implements Maestro's runtime write-back delivery for the
|
||||
// Service Config & Secrets theme (D6). When the operator sets or clears a
|
||||
// config value via the Settings panel, Maestro delivers it to the running
|
||||
// service's POST /config endpoint over an ALWAYS-mTLS edge: Maestro's own
|
||||
// identity (CN=maestro) and plain "https" regardless of dev mode, targeted at
|
||||
// the service's dedicated peer listener port (label org.dcntrlized.peer_port,
|
||||
// default 9443), which the service gates to CN=maestro. A set carries
|
||||
// {field, value, type}; a clear carries {field, action:"clear"} — the service
|
||||
// owns the schema and branches on what it receives.
|
||||
// service's POST /config endpoint on the service's single plaintext :8080
|
||||
// listener, authenticated with a short-lived, single-use ES256 config token
|
||||
// minted from Maestro's dedicated config-signing keypair (contract rev 9 §17).
|
||||
// There is no mTLS and no peer port: the fleet-wide internal transport is
|
||||
// plaintext HTTP. A set carries {field, value, type}; a clear carries
|
||||
// {field, action:"clear"} — the service owns the schema and branches on what it
|
||||
// receives.
|
||||
//
|
||||
// Delivery is best-effort: failures are logged (with the field name, never
|
||||
// the value) and do not prevent the panel write from succeeding. Values always
|
||||
@@ -42,32 +43,16 @@ import (
|
||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/logger"
|
||||
)
|
||||
|
||||
// peerPortLabel is the compose label a service declares to advertise the
|
||||
// internal port of its always-mTLS Maestro peer listener.
|
||||
const peerPortLabel = "org.dcntrlized.peer_port"
|
||||
|
||||
// defaultPeerPort is the fleet-wide default for that listener. Services keep/ve
|
||||
// to it unless the label overrides it.
|
||||
const defaultPeerPort = "9443"
|
||||
|
||||
// peerPort resolves the configured {peer listener port} from a container's
|
||||
// compose labels, falling back to the fleet default.
|
||||
func peerPort(labels map[string]string) string {
|
||||
if labels == nil {
|
||||
return defaultPeerPort
|
||||
}
|
||||
if p := labels[peerPortLabel]; p != "" {
|
||||
return p
|
||||
}
|
||||
return defaultPeerPort
|
||||
}
|
||||
// configPort is the single port every service serves its API, /config and web
|
||||
// app on after rev 9. There is no peer listener and no compose label.
|
||||
const configPort = "8080"
|
||||
|
||||
// ConfigDelivery is one key-value pair to deliver to a running service.
|
||||
type ConfigDelivery struct {
|
||||
Field string // manifest config field name
|
||||
Key string // container env var name
|
||||
Type string // "cleartext" | "password"
|
||||
Value string // the operator-entered value (sent over mTLS; never logged)
|
||||
Value string // the operator-entered value (never logged)
|
||||
}
|
||||
|
||||
// configRequest is the JSON body POSTed to the service's /config endpoint.
|
||||
@@ -79,10 +64,9 @@ type configRequest struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
}
|
||||
|
||||
// DeliverConfigValues delivers the given config pairs to the running service
|
||||
// over the mTLS peer edge. If the service is not running or unreachable, the
|
||||
// error is logged but not returned — the values will take effect at next start
|
||||
// via injectConfigSecrets.
|
||||
// DeliverConfigValues delivers the given config pairs to the running service.
|
||||
// If the service is not running or unreachable, the error is logged but not
|
||||
// returned — the values will take effect at next start via injectConfigSecrets.
|
||||
func DeliverConfigValues(ctx context.Context, serviceName string, items []ConfigDelivery) {
|
||||
if len(items) == 0 {
|
||||
return
|
||||
@@ -114,9 +98,10 @@ func DeliverConfigClear(ctx context.Context, serviceName, field string) {
|
||||
}
|
||||
|
||||
// postConfig performs one best-effort POST of body to the running service's
|
||||
// /config endpoint. NotFound/unreachable cases are logged at debug (the write
|
||||
// still applies at next start); transport errors carry the field name only,
|
||||
// never a value.
|
||||
// /config endpoint on the single :8080 listener, authenticated with a freshly
|
||||
// minted ES256 config token. NotFound/unreachable cases are logged at debug
|
||||
// (the write still applies at next start); transport errors carry the field
|
||||
// name only, never a value.
|
||||
func postConfig(ctx context.Context, serviceName, field, verb string, body []byte) {
|
||||
dc, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
@@ -137,30 +122,22 @@ func postConfig(ctx context.Context, serviceName, field, verb string, body []byt
|
||||
return
|
||||
}
|
||||
|
||||
// /config is served on the service's dedicated Maestro peer listener
|
||||
// (always mTLS, gated to CN=maestro), NOT the RN-facing flat edge. Maestro
|
||||
// presents its own identity and targets the peer port; dev mode does not
|
||||
// downgrade this edge.
|
||||
port := peerPort(inspectData.Config.Labels)
|
||||
|
||||
transport, err := authmgmt.MaestroTransport()
|
||||
token, err := authmgmt.ConfigToken(serviceName)
|
||||
if err != nil {
|
||||
logger.Warn("Config delivery to %s/%s: cannot build Maestro peer transport: %v", serviceName, field, err)
|
||||
logger.Warn("Config delivery to %s/%s: cannot mint config token: %v", serviceName, field, err)
|
||||
return
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
|
||||
url := fmt.Sprintf("https://%s:%s/config", network.IPAddress.Address, port)
|
||||
url := fmt.Sprintf("http://%s:%s/config", network.IPAddress.Address, configPort)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
logger.Warn("Config delivery to %s/%s: request build failed: %v", serviceName, field, err)
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
@@ -174,4 +151,4 @@ func postConfig(ctx context.Context, serviceName, field, verb string, body []byt
|
||||
} else {
|
||||
logger.Debug("Config delivery to %s/%s: service responded %d; will apply at next start", serviceName, field, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user