package main import ( "context" "crypto/subtle" "encoding/json" "errors" "io" "net/http" "os" "path/filepath" "strings" "time" "git.cin.su/m/Assistant/contracts/authority" "git.cin.su/m/Assistant/contracts/identity" secretcontracts "git.cin.su/m/Assistant/contracts/secrets" authoritydomain "git.cin.su/m/Assistant/modules/authority/domain" "git.cin.su/m/Assistant/platform/ids" platformsecrets "git.cin.su/m/Assistant/platform/secrets" ) const ( delegatedControlPlaneActor identity.ActorID = "domovoy-control-plane-actor" delegatedControlPlanePrincipal identity.PrincipalID = "domovoy-control-plane-principal" delegatedControlPlaneTokenFile = "control_plane_service_token" ) type delegatedControlPlaneAuthoritySource interface { LoadDelegatedControlPlaneGrant(context.Context, authority.GrantID) (authority.DelegatedControlPlaneGrant, error) RecordDelegatedControlPlaneAudit(context.Context, authority.DelegatedControlPlaneAudit) error RevokeDelegatedControlPlaneGrant(context.Context, authority.GrantID, string) (bool, error) } type delegatedControlPlaneCore interface { Session(context.Context, string) (identity.CreatorSession, error) Binding(context.Context, identity.ActorID, identity.PrincipalID) (identity.PrincipalBinding, error) } type delegatedControlPlaneHandler struct { authority delegatedControlPlaneAuthoritySource core delegatedControlPlaneCore credential func() (string, error) now func() time.Time newID func() (ids.ID, error) } func registerDelegatedControlPlaneRoutes(mux *http.ServeMux, handler delegatedControlPlaneHandler) { mux.HandleFunc("POST /v1/internal/control-plane/authorize", handler.authorize) mux.HandleFunc("POST /v1/internal/control-plane/completions", handler.complete) mux.HandleFunc("POST /v1/creator/control-plane/grants/{grant}/revoke", handler.revoke) } func (h delegatedControlPlaneHandler) authorize(w http.ResponseWriter, r *http.Request) { if !h.serviceAuthenticated(r) { http.Error(w, "service principal denied", http.StatusUnauthorized) return } var request authority.DelegatedControlPlaneRequest decoder := json.NewDecoder(io.LimitReader(r.Body, 8<<10)) decoder.DisallowUnknownFields() if err := decoder.Decode(&request); err != nil { http.Error(w, "invalid delegated control-plane request", http.StatusBadRequest) return } grant, err := h.authority.LoadDelegatedControlPlaneGrant(r.Context(), request.GrantID) if err != nil { http.Error(w, "delegated authority denied", http.StatusForbidden) return } binding, err := h.core.Binding(r.Context(), delegatedControlPlaneActor, delegatedControlPlanePrincipal) if err != nil || authoritydomain.ValidateDelegatedControlPlaneGrant(h.now().UnixMilli(), binding, grant, request) != nil { _ = h.audit(r.Context(), grant, request, "DENY", "FAILED") http.Error(w, "delegated authority denied", http.StatusForbidden) return } if err := h.audit(r.Context(), grant, request, "ALLOW", "PENDING"); err != nil { http.Error(w, "delegated audit unavailable", http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusNoContent) } func (h delegatedControlPlaneHandler) complete(w http.ResponseWriter, r *http.Request) { if !h.serviceAuthenticated(r) { http.Error(w, "service principal denied", http.StatusUnauthorized) return } var value authority.DelegatedControlPlaneCompletion decoder := json.NewDecoder(io.LimitReader(r.Body, 8<<10)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil || (value.Outcome != "COMPLETED" && value.Outcome != "FAILED") { http.Error(w, "invalid delegated completion", http.StatusBadRequest) return } grant, err := h.authority.LoadDelegatedControlPlaneGrant(r.Context(), value.Request.GrantID) if err != nil { http.Error(w, "delegated authority unavailable", http.StatusServiceUnavailable) return } if !authoritydomain.RequestMatchesDelegatedControlPlaneGrant(grant, value.Request) { http.Error(w, "delegated completion denied", http.StatusForbidden) return } if err := h.audit(r.Context(), grant, value.Request, "ALLOW", value.Outcome); err != nil { http.Error(w, "delegated audit unavailable", http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusNoContent) } func (h delegatedControlPlaneHandler) revoke(w http.ResponseWriter, r *http.Request) { session, err := h.core.Session(r.Context(), r.Header.Get("Authorization")) if err != nil { http.Error(w, "creator session denied", http.StatusUnauthorized) return } grant, err := h.authority.LoadDelegatedControlPlaneGrant(r.Context(), authority.GrantID(r.PathValue("grant"))) if err != nil || !authoritydomain.CanIssuerRevokeDelegatedGrant(session.PrincipalID, grant) { http.Error(w, "delegated grant revoke denied", http.StatusForbidden) return } ok, err := h.authority.RevokeDelegatedControlPlaneGrant(r.Context(), grant.ID, string(session.PrincipalID)) if err != nil || !ok { http.Error(w, "delegated grant revoke denied", http.StatusConflict) return } request := authority.DelegatedControlPlaneRequest{GrantID: grant.ID, TaskID: grant.TaskID, TaskRevision: grant.TaskRevision, Operation: authority.DelegatedOperationRevokeControlPlaneGrant, Resource: grant.Resource} if err := h.audit(r.Context(), grant, request, "REVOKE", "REVOKED"); err != nil { http.Error(w, "delegated audit unavailable", http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusNoContent) } func (h delegatedControlPlaneHandler) serviceAuthenticated(r *http.Request) bool { if h.credential == nil { return false } expected, err := h.credential() presented := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") return err == nil && expected != "" && presented != "" && subtle.ConstantTimeCompare([]byte(expected), []byte(presented)) == 1 } func (h delegatedControlPlaneHandler) audit(ctx context.Context, grant authority.DelegatedControlPlaneGrant, request authority.DelegatedControlPlaneRequest, decision, outcome string) error { if h.newID == nil { return errors.New("delegated audit id unavailable") } id, err := h.newID() if err != nil { return err } return h.authority.RecordDelegatedControlPlaneAudit(ctx, authority.DelegatedControlPlaneAudit{AuditID: id, GrantID: grant.ID, ServiceActorID: delegatedControlPlaneActor, ServicePrincipalID: delegatedControlPlanePrincipal, TaskID: request.TaskID, TaskRevision: request.TaskRevision, Operation: request.Operation, Resource: request.Resource, Decision: decision, Outcome: outcome, RecordedAtUnixMillis: h.now().UnixMilli()}) } func delegatedControlPlaneCredential() (string, error) { ref := os.Getenv("CONTROL_PLANE_SERVICE_CREDENTIAL_REF") if ref == "" { return "", errors.New("control-plane service credential ref is required") } root := os.Getenv("CONTROL_PLANE_SERVICE_SECRET_ROOT") if root == "" { root = "/run/control-plane-secrets" } resolver, err := platformsecrets.NewFileResolver(root) if err != nil { return "", err } return resolver.ResolveFile(secretcontracts.SecretFileRef{CredentialRef: secretcontracts.CredentialRef(ref), Purpose: secretcontracts.SecretPurposeServiceAuthentication, Consumer: secretcontracts.RuntimeConsumerCommit, Path: filepath.Join(root, delegatedControlPlaneTokenFile)}) }