Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce ECSCredentialsProvider IP Rules #234

Closed
wants to merge 20 commits into from
Closed

Enforce ECSCredentialsProvider IP Rules #234

wants to merge 20 commits into from

Conversation

waahm7
Copy link
Contributor

@waahm7 waahm7 commented Apr 19, 2024

Description of changes:

  • The resolved ip address of ECSCredentials provider must follow certain limitations if it is HTTP. This PR enforces those limitations so that we don't make requests on potential malicious HTTP servers.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@codecov-commenter
Copy link

codecov-commenter commented Apr 19, 2024

Codecov Report

Attention: Patch coverage is 60.00000% with 14 lines in your changes are missing coverage. Please review.

Project coverage is 79.43%. Comparing base (277c8fb) to head (f99dce1).

Files Patch % Lines
source/credentials_provider_ecs.c 60.00% 14 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #234      +/-   ##
==========================================
- Coverage   79.54%   79.43%   -0.12%     
==========================================
  Files          33       33              
  Lines        5872     5907      +35     
==========================================
+ Hits         4671     4692      +21     
- Misses       1201     1215      +14     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@waahm7 waahm7 changed the title WIP | ECSCredentialsProvider IP Rules Enforce ECSCredentialsProvider IP Rules Enforce Apr 22, 2024
@waahm7 waahm7 changed the title ECSCredentialsProvider IP Rules Enforce Enforce ECSCredentialsProvider IP Rules Apr 22, 2024
@waahm7 waahm7 marked this pull request as ready for review April 22, 2024 20:24
source/credentials_provider_ecs.c Show resolved Hide resolved
result |= aws_byte_cursor_eq(&address, &ecs_container_host_address);
result |= aws_byte_cursor_eq(&address, &eks_container_host_address);
} else if (aws_host_utils_is_ipv6(address, false)) {
/* Check for both the short form and long form of an IPv6 address to be safe. */
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO: it would be cool if we had a function to convert these IP strings into their actual byte values

since there are even more ways to write these addresses (e.g. "0:0::1"), which are weird, but still legal

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are getting these IP strings from a system call, and we can convert them back to byte values using an OS dependent system call and memcmp them (at least that's what ChatGPT told me). I can add a function to common, but the fact that we are getting these IPs from system calls, we discussed that it should be good enough to just compare both the short form and the long form and ignore the weird ones.

Testing the OS behavior for n different platforms led to the addition of an actual mock server, but unfortunately, GitHub runners don't support IPv6.

Comment on lines +502 to +504
/* validate ip address if the connection manager is not mocked */
if (impl->function_table == g_aws_credentials_provider_http_function_table &&
!s_is_valid_remote_host_ip(ecs_user_data, connection)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

don't have the implementation skip functionality when it detects it's in a test

Do we need to add aws_http_connection_get_remote_endpoint() to the function_table?

@@ -57,6 +57,12 @@ add_test_case(credentials_provider_ecs_no_auth_token_success)
add_test_case(credentials_provider_ecs_success_multi_part_doc)
add_test_case(credentials_provider_ecs_real_new_destroy)

if(ENABLE_AUTH_MOCK_SERVER_TESTS)
# TODO: Add IPv6 tests when the Github runner support it. See: https://github.com/actions/runner-images/issues/668
Copy link
Contributor

Choose a reason for hiding this comment

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

You could add the test, and have it return AWS_OP_SKIP if it fails due to lack of IPv6 support

aws_credentials_provider_get_credentials(provider, s_get_credentials_callback, NULL);
s_aws_wait_for_credentials_result();
ASSERT_NULL(s_tester.credentials);
ASSERT_TRUE(s_tester.error_code == AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST);
Copy link
Contributor

Choose a reason for hiding this comment

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

trivial:

Suggested change
ASSERT_TRUE(s_tester.error_code == AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST);
ASSERT_INT_EQUALS(AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST, s_tester.error_code);

it gives a nice printf about what we got, vs what was expected

aws_credentials_provider_get_credentials(provider, s_get_credentials_callback, NULL);
s_aws_wait_for_credentials_result();
ASSERT_NOT_NULL(s_tester.credentials);
ASSERT_TRUE(s_tester.error_code == AWS_OP_SUCCESS);
Copy link
Contributor

Choose a reason for hiding this comment

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

likewise

@@ -536,6 +557,87 @@ static int s_credentials_provider_ecs_basic_success(struct aws_allocator *alloca

AWS_TEST_CASE(credentials_provider_ecs_basic_success, s_credentials_provider_ecs_basic_success);

static int s_credentials_provider_ecs_mocked_server_basic_ipv4_invalid(struct aws_allocator *allocator, void *ctx) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There's already a system for mocking HTTP calls in auth tests. Is there a really good reason for adding another?

bool result = false;

const struct aws_byte_cursor address =
aws_byte_cursor_from_c_str(aws_http_connection_get_remote_endpoint(connection)->address);
Copy link
Contributor

Choose a reason for hiding this comment

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

This technique won't work with many other HTTP clients. It's uncommon that you have a chance to inspect the IP before making the actual request.

just asking the host_resolver directly would be more portable

I get that you're trying to avoid additional calls to the resolver. You could do like the Rust SDK and only validate when full-uri is passed in by the user.

Is the fact that this relies on the HTTP client what's forcing you to add a 2nd way of mocking HTTP calls?

@waahm7
Copy link
Contributor Author

waahm7 commented May 13, 2024

Closing in favor of #238

@waahm7 waahm7 closed this May 13, 2024
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.

3 participants