Skip to content

Support for canonicalizing URI properly for AWS SigV4 signer#17137

Merged
mattklein123 merged 6 commits intoenvoyproxy:mainfrom
Y0Username:fix-16918
Aug 2, 2021
Merged

Support for canonicalizing URI properly for AWS SigV4 signer#17137
mattklein123 merged 6 commits intoenvoyproxy:mainfrom
Y0Username:fix-16918

Conversation

@Y0Username
Copy link
Contributor

Support for canonicalizing URI properly for AWS SigV4 signer

  • Canonicalizing query string
  • Canonicalizing path string
  • Adding tests for canonical path and query

Ref: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
Issue: #16918

Signed-off-by: Yathish Gangolli yathishsg@gmail.com

Commit Message:
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]
[Optional API Considerations:]

@Y0Username Y0Username requested a review from mattklein123 as a code owner June 24, 2021 23:25
@repokitteh-read-only
Copy link

Hi @Y0Username, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #17137 was opened by Y0Username.

see: more, trace.

@yanavlasov
Copy link
Contributor

If I understand this correctly you now created possibility that Envoy and request signer will "observe" different URL path representations. I do not know this feature well enough to say if this important from security perspective or not. Specifically the signer might think that request goes to service A while Envoy ends up routing request to service B because of the differences in path.
In any case I think it would be quite important to clarify why Envoy's path normalization can not be used in this case. It could be a gotcha for users of this filter and at the very least should be documented.

@yanavlasov yanavlasov self-assigned this Jun 25, 2021
@yanavlasov
Copy link
Contributor

/wait-any

@Y0Username
Copy link
Contributor Author

Y0Username commented Jun 25, 2021

@yanavlasov thanks for looking at it. Yes the signer and Envoy can technically see different path representations due to differences in normalizing and encoding. However, this path representation being created here is being used create a hash.

This doc explains how to create and sign requests AWS that are not being made by CLI/SDK. The sigv4 algorithm includes a hash of the request payload as part of the request signature to protect against malicious spoofing of a request by using the credentials from a non-malicious request. So the client and server need to hash the request identically. For various reasons (both practical and historical) this is the algorithm that sigv4 uses. Hence the need for different representation of URL path, if we use Envoy's path representation, requests to AWS will fail with: The request signature we calculated does not match the signature you provided.

I can add documentation to clarify this behavior.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

It would be great to not have different URL canonicalizing if we don't need it. Does this follow a standard? Can we use the common code that we already have? cc @htuch @yanavlasov @tonya11en for more details.

/wait-any

Copy link
Contributor

Choose a reason for hiding this comment

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

Use StringUtil::CaseInsensitiveCompare

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used absl::EqualsIgnoreCase

Copy link
Contributor

Choose a reason for hiding this comment

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

I would just make all of these all into static constexpr absl::string_view in some places you are having to allocate strings for the chars which is unnecessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

couldn't you use absl::EndsWith here?

Copy link
Contributor

Choose a reason for hiding this comment

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

StringUtil::CaseInsensitiveCompare

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used absl::EqualsIgnoreCase

Copy link
Contributor

Choose a reason for hiding this comment

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

value.empty() ? EMPTY_STRING : value is redundant. Just pass value

Copy link
Contributor

Choose a reason for hiding this comment

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

You should use absl::StrSplit(query_fragment, absl::MaxSplits('=', 1)) instead.

@htuch
Copy link
Member

htuch commented Jun 29, 2021

Yeah, I would like to understand what is going on with this canonicalization logic and how it relates to other path normalization in Envoy. This seems another opportunity for GOLDPANDA-style fun.

@tonya11en
Copy link
Member

There are a lot of deviations in these AWS utilities from the standard way Envoy does things, cURL/AsyncClient being another example. Adding another one is just making folks uncomfortable, especially since there have been CVEs related to path normalization in the past. This could turn out to be another vector for similar bugs.

If you could provide more info on why the common Envoy utilities can't be used, it would help.

@Y0Username
Copy link
Contributor Author

To be clear, the canonicalized path here is not used for routing. It is just used for calculating the request hash. The hash calculated on the client should match the hash calculated on the server side, otherwise the request fails. So the client needs to canonicalize the path exactly like the server does. Unfortunately, Envoy canonicalizes the path little differently compared to AWS recommendation.

The AWS recommendation is also based on RFC 3986, but with little tweaks that are listed here: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

@mattklein123
Copy link
Member

If the canonicalization is not the same I'm not sure there is much we can do about it unfortunately.

@tonya11en can you do the initial review here and then we can do a final pass?

/wait-any

@yanavlasov
Copy link
Contributor

Thanks for the AWS spec reference. Looking into it more, I agree that there is nothing we can do with existing Envoy normalizations.
Also thinking more about it I think custom normalization is likely ok. The only problem would be if the signing server makes some decisions based on path, but it does not look to be the case.

You may also suggest that operators enable Envoy's normalize_path option as it will minimize the differences in path observed by the signing server an Envoy.

Copy link
Contributor

@yanavlasov yanavlasov left a comment

Choose a reason for hiding this comment

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

/wait

@tonya11en
Copy link
Member

@Y0Username in the future when updating patches, can you please avoid force-pushing? It makes it so we cannot just see what changed since our last review.

@tonya11en
Copy link
Member

@Y0Username you'll need to add a release note to docs/root/version_history/current.rst

@tonya11en
Copy link
Member

/wait

  - Canonicalizing query string
  - Canonicalizing path string
  - Adding tests for canonical path and query

Ref: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
Issue: envoyproxy#16918

Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
@tonya11en
Copy link
Member

@Y0Username not sure if you saw my earlier message, but can you please refrain from force-pushing commits to your PR branch? It makes it so we can't see the diffs between your various revisions.

@Y0Username
Copy link
Contributor Author

@Y0Username not sure if you saw my earlier message, but can you please refrain from force-pushing commits to your PR branch? It makes it so we can't see the diffs between your various revisions.

I have stopped amending existing commits. I force push because I rebase on upstream/main. However, discussed offline to use merge commits.

tonya11en
tonya11en previously approved these changes Jul 29, 2021
Copy link
Member

@tonya11en tonya11en left a comment

Choose a reason for hiding this comment

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

I think it's ready for others to sweep through now.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

LGTM with small release note comment, thanks.

/wait


* access log: fix `%UPSTREAM_CLUSTER%` when used in http upstream access logs. Previously, it was always logging as an unset value.
* cluster: delete pools when they're idle to fix unbounded memory use when using PROXY protocol upstream with tcp_proxy. This behavior can be temporarily reverted by setting the ``envoy.reloadable_features.conn_pool_delete_when_idle`` runtime guard to false.
* extensions: fix the AWS Request Signer extension to correctly normalize the path and query string to be signed according to AWS' guidelines, so that the hash on the server side matches. See `AWS SigV4 documentaion <https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html>`_.
Copy link
Member

Choose a reason for hiding this comment

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

nit: instead of "extensions" can you make this "aws request signer" or something?

Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks!

@mattklein123 mattklein123 merged commit 003ff42 into envoyproxy:main Aug 2, 2021
baojr added a commit to baojr/envoy that referenced this pull request Aug 4, 2021
…bridge-stream

* upstream/main: (32 commits)
  tls: move ssl connection info into SocketAddressProvider (envoyproxy#17334)
  conn pool: default enable runtime feature `conn_pool_delete_when_idle` (envoyproxy#17577)
  api: LEDS api introduction (envoyproxy#17419)
  kafka: add support for api versions request in mesh-filter (envoyproxy#17475)
  ext_proc: Implement BUFFERED_PARTIAL processing mode (envoyproxy#17531)
  tooling: Async/pathlib/mypy cleanups and utils (envoyproxy#17505)
  xds: restructure CertificateProvider fields (envoyproxy#17201)
  Refactor OverloadIntegrationTest breaking out a test base, and the fake resource monitors. (envoyproxy#17530)
  listener: move active connection collection out of active tcp listener (envoyproxy#16947)
  tools: format checks for backticks (envoyproxy#17566)
  coverage: set lower limit for common/quic and common (envoyproxy#17573)
  v2: final source removal (envoyproxy#17565)
  test: bumping coverage (envoyproxy#17564)
  quic: enforcing header size and contents (envoyproxy#17520)
  Support for canonicalizing URI properly for AWS SigV4 signer (envoyproxy#17137)
  listener: add a stat for transport socket connect timeout (envoyproxy#17458)
  listener: add listen() error handling (envoyproxy#17427)
  http: return per route config when direct response is set (envoyproxy#17449)
  removing most v2 references from source/ (envoyproxy#17415)
  bug fix: return bootstrap when validating config (envoyproxy#17499)
  ...

Signed-off-by: Garrett Bourg <bourg@squareup.com>
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
…oxy#17137)

  - Canonicalizing query string
  - Canonicalizing path string
  - Adding tests for canonical path and query

Ref: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
Issue: envoyproxy#16918

Signed-off-by: Yathish Gangolli <yathishsg@gmail.com>
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.

6 participants