Skip to content

Event stream initial-request messages are not signed #4429

@rcoh

Description

@rcoh

Problem

Event stream operations that include an initial-request message send that message unsigned, even when the operation requires SigV4 authentication and all subsequent messages are properly signed.

Root Cause

The issue is in the client codegen for event streams with initial requests:

https://github.com/smithy-lang/smithy-rs/blob/main/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt#L68-L79

The generated code creates the initial message and immediately serializes it to bytes:

let initial_message = initial_message(body);
let mut buffer = Vec::new();
write_message_to(&initial_message, &mut buffer)?;
let initial_message_stream = futures_util::stream::iter(vec![Ok(buffer.into())]);
let adapter = message_stream_adaptor;
initial_message_stream.chain(adapter)

The problem is that initial_message is written to bytes before being chained with the MessageStreamAdapter. The adapter is what signs messages in its poll_next() implementation, but the initial message bytes bypass this entirely.

For comparison, regular event messages flow through the adapter's signing pipeline:

  1. Poll stream for message
  2. Marshall message
  3. Sign message
  4. Write signed message to bytes

But the initial message is already bytes when chained, so step 3 never happens.

Impact

Any AWS service operation using event streams with initial-request messages will:

  • Send the initial message without a signature
  • Potentially fail authentication if the service validates initial message signatures
  • Have inconsistent behavior between the initial message and subsequent messages

Reproduction

The server-side tests show this is expected to work:
https://github.com/smithy-lang/smithy-rs/blob/main/codegen-server-test/integration-tests/eventstreams/tests/structured_eventstream_tests.rs#L701-L703

Server code handles signed initial messages correctly, but client codegen doesn't generate them.

Solution

The initial message needs to flow through the same marshalling/signing pipeline as regular events. This likely requires:

  1. Not serializing the initial message during request serialization
  2. Including it in the stream that goes through MessageStreamAdapter
  3. Ensuring the marshaller can handle initial-request message types

The challenge is that signing happens after HTTP request signing (which provides the signature for the first event stream message), so the initial message can't be signed during serialization - it needs to be deferred like other event messages.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions