Skip to content

rfc53: add message protocol v2 - #559

Open
garlick wants to merge 1 commit into
flux-framework:masterfrom
garlick:rfc53_message_2
Open

garlick wants to merge 1 commit into
flux-framework:masterfrom
garlick:rfc53_message_2

Conversation

@garlick

@garlick garlick commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Problem: message protocol v1 (RFC 3) does not support message signatures, multiple payloads, and is not extensible.

Introduce message format v2 to address these needs.

Assited-by: Claude:opus-5.5

@github-actions

Copy link
Copy Markdown

⚠️ linkcheck failed with status code 2

1 similar comment
@github-actions

Copy link
Copy Markdown

⚠️ linkcheck failed with status code 2

@garlick
garlick force-pushed the rfc53_message_2 branch 2 times, most recently from 96b921f to e5a9270 Compare October 12, 2026 16:18
@github-actions

Copy link
Copy Markdown

⚠️ linkcheck failed with status code 2

1 similar comment
@github-actions

Copy link
Copy Markdown

⚠️ linkcheck failed with status code 2

@grondo grondo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me!

Some high level comments after trying to digest most of this RFC. Note that you may have already considered and rejected some of this while drafting this first version, which appears very well designed! If so, then feel free to ignore comments.

Comment thread spec_53.rst
Comment on lines +395 to +407
The signature part SHALL be an RFC 39 signature of the *message* class whose
payload is the 32-byte message digest. The signing mechanism SHALL be
selected by the flux-security configuration, as for other RFC 39
signatures.

This specification relies on the following properties of the RFC 39
message class:

- A message-class signature has a limited lifetime, on the order of
minutes, after which verification fails.

- A message-class signature cannot be verified as a signature of another
class, nor a signature of another class as a message-class signature.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't 100% clear what is meant here by message "class" and message-class signature. Is the definition of "message class" coming from another RFC?

@garlick garlick Oct 13, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad! I meant to add to the PR description that this PR assumes that we'd enhance RFC 39 to have another type of signatures for messages with a tighter TTL and perhaps optional replay detection. Having those relaxed for jobspec is necessary but it would weaken message signatures unnecessarily.

Comment thread spec_53.rst
Comment on lines +377 to +387
The *message digest* SHALL be the SHA-256 digest of the concatenation of
the following items, in order. Each item SHALL be encoded as a 4-byte
length in network byte order followed by the item's bytes:

#. The topic part, including its terminating NUL, if *cflag-topic* is set.

#. The payload, if *cflag-payload* is set.

#. The attachment, if *cflag-attachment* is set.

#. The content header, including any extension fields.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the ability for a forwarder to substitute a response from another request or stream to the sender, it may be useful to encode something extra in the message digest (to be included in the signature) for responses. Claude suggests a random nonce that the sender then verifies. For streaming RPCs a sequence number could be included to ensure message order isn't tampered with either, though I'm not 100% sure how this would be implemented in the actual code. Just leaving the comment here for consideration.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting. Good thought, I will ponder that one.

Comment thread spec_53.rst Outdated
Comment on lines +459 to +462
A mechanism that rejects replays, such as MUNGE, would reject a
second verification of the same signature on the same host. Requests and
responses each have exactly one receiver, so verifying only at that
receiver, and only once, avoids rejecting legitimate messages.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This note contradicts RFC 39 which states that EMUNGE_CRED_REPLAYED and EMUNGE_CRED_EXPIRED SHALL be treated as success.

Comment thread spec_53.rst Outdated
Comment on lines +435 to +438
A receiver that requires authentication of a message SHALL:

#. Reject the message with EPERM if *cflag-signed* is clear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could get a bit confusing because "A receiver" here probably means a service receiving a response (reject with EPERM doesn't make sense otherwise), and a receiver of a response actually MUST accept unsigned error requests as noted below (for ENOSYS, EHOSTUNREACH type errors)

Claude had a good suggestion to add a Terminology section with the following definitions to more clearly separate the roles of general sender, receiver vs client, server.

  • sender: the component that creates a message.
  • forwarder: a broker, connector, or other component that relays a message without being its final recipient.
  • receiver: the final recipient of a message, request or response.
  • service: the receiver of a request.
  • client: the receiver of a response.

Comment thread spec_53.rst

A response rejected by verification SHALL be discarded and MAY be logged.
A client that discards a response in a streaming RPC MAY terminate the RPC.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Specifically require that an unsigned error response terminates a streaming RPC with an error. A client MUST NOT treat an unsigned ENODATA as the normal end of a stream, so a responder MUST sign an ENODATA response.

Comment thread spec_53.rst
Comment on lines +275 to +285
The content header contains only fields chosen by the sender. Forwarders
SHALL NOT modify it.

The *cflags* bit positions differ from those of the version 1 flags. The
correspondence between them is given in `Correspondence with Version 1`_.
Route presence is a transport flag in version 2.

Undefined *cflags* bits and the *cpad* field SHALL be zero. A receiver
SHALL reject a message with an undefined *cflags* bit set, or a nonzero
*cpad*, with EPROTO, because a content field may change the meaning of a
message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it also be specified that forwarders ignore unknown cflags, so an updated protocol with an added cflag can pass through an older instance (e.g. when launching a newer flux version within an older)

Comment thread spec_53.rst Outdated
Comment on lines +325 to +335
The *tpad* field and the undefined *tflags* bits are reserved. Senders SHALL
set them to zero, forwarders SHALL pass them through unchanged, and
receivers SHALL ignore them.

.. note::

These rules let future features be added without a new message version.
A new content flag makes older receivers reject messages that use it,
which is the safe outcome for anything that changes a message's meaning.
A new transport flag or transport extension field is carried through
older forwarders and ignored by older receivers.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is the right place for this comment, but Claude had this observation about the transport header extensions:

Transport header extensions need a layout rule:

The spec reserves the bytes after the fixed transport fields for future revisions, but it does not say how a receiver finds a field there. I suggest stating the rule now, before any extension is defined:

  • An extension field SHALL be present only if its tflags bit is set, unless its definition makes it always present.
  • Extension fields SHALL appear in the order in which they are defined.
  • The definition of each field SHALL fix its size, or SHALL define a length prefix for it.
  • A receiver SHALL ignore bytes after the last field that it knows.

This uses the same approach as the content header. It is compatible with v1 and with current v2 implementations, because senders cannot include extension bytes until a revision defines them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent refinement, thanks!

@mergify

mergify Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@garlick

garlick commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

That was some really excellent feedback, all of it. I'm preparing a new draft and will force push shorlty.

@github-actions

Copy link
Copy Markdown

⚠️ linkcheck failed with status code 2

Problem: message protocol v1 (RFC 3) does not support message signatures,
multiple payloads, and is not extensible.

Introduce message format v2 to address these needs.

Assisted-by: Claude:opus-5.5
@github-actions

Copy link
Copy Markdown

⚠️ linkcheck failed with status code 2

@garlick

garlick commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Just force pushed some edits. I went down a rabbit hole with signed responses. Responses can be generated by the transport (like ENOSYS or EHOSTUNREACH), live RPCs are tracked, a client can't safely recycle a matchtag until it knows the server will no longer use it, etc. Ultimately, since we don't have an immediate need for signed requests, I just dropped it and left it as a future enhancement. I think we can add it without a protocol revision later when the need arises, and the issues are easily resolved - it just seemed like investing too much energy in that right now was misplaced. LMK if you are OK with that.

I think I addressed your suggestions that were not response related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants