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

Support https proxy servers #83089

Closed
wants to merge 1 commit into from
Closed

Conversation

sivel
Copy link
Member

@sivel sivel commented Apr 18, 2024

SUMMARY

This PR adds the ability to proxy over a proxy server that listens on https.

ISSUE TYPE
  • Feature Pull Request
ADDITIONAL INFORMATION

This will conflict with #83085


The fact that http.client.HTTPConnection.connect establishes the tunnel is the 1st reason
HTTPS proxies aren't supported, the 2nd is that there is no native TLS in TLS, see TLSinTLS
"""
Copy link
Member Author

Choose a reason for hiding this comment

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

Overriding _tunnel to not do anything, and then calling super()._tunnel() are probably the biggest concerns with fragility and supportability here, but urllib3 does it too, kind of:

https://github.com/urllib3/urllib3/blob/b7c2910a9f49ba0d58c8d4381500c208f9a24765/src/urllib3/connection.py#L242
https://github.com/urllib3/urllib3/blob/b7c2910a9f49ba0d58c8d4381500c208f9a24765/src/urllib3/connection.py#L631

Copy link
Member

Choose a reason for hiding this comment

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

This doesn't look like it should be a docstring but rather a comment. Could you change?

port = selector.port
if not port:
port = 443 if tls_in_tls else 80
req._tunnel_host = f'{selector.hostname}:{port}'
Copy link
Member Author

Choose a reason for hiding this comment

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

All of this weirdness is just related to the fact that the existing code never attempted this, but again we're poking a private attribute.

@ansibot ansibot added feature This issue/PR relates to a feature request. needs_triage Needs a first human triage before being processed. needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. labels Apr 18, 2024
@@ -0,0 +1,41 @@
- when: ansible_facts.distribution not in ['MacOSX']
Copy link
Member

Choose a reason for hiding this comment

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

It's possible to also test a TLS proxy by combining https://pypi.org/p/trustme and https://pypi.org/p/proxy.py. This is what I integrated into the aiohttp test suite back when @jborean93, Satellite folks and I were poking on how to implement TLS-in-TLS transport with aiohttp a few years back. Well, the trustme was pre-integrated earlier to test true TLS w/o disabling trust verification.

I also integrated trustme into the ansible-core integration tests in December: #82334. So we do have usage examples in our codebase.

Please, consider using it here as well to make it possible to run this integration test against macOS too.


- name: Generate cert for stunnel
command: >-
openssl req -new -x509 -days 365 -nodes -out stunnel.pem -keyout stunnel.pem \
Copy link
Member

Choose a reason for hiding this comment

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

Based on the low-level TLS management I see here I believe that my suggestion to use trustme might simplify the configuration and positively affect the maintainability: https://github.com/ansible/ansible/pull/83089/files#r1571440157.

Copy link
Contributor

@jborean93 jborean93 left a comment

Choose a reason for hiding this comment

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

I'll have to try out a few scenarios, this seemed like a fun one.

self.read = functools.partial(self._process, True, sslobj.read)
self.recv = functools.partial(self._process, True, sslobj.read)
self.send = functools.partial(self._process, False, sslobj.write)
self.sendall = functools.partial(self._process, False, sslobj.write)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to worry about something calling sendall for this when the payload exceeds 16KiB? Is that even something we can do, i.e. a POST request with a large file?

Copy link
Contributor

@jborean93 jborean93 Apr 19, 2024

Choose a reason for hiding this comment

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

Ah just realized this is for TLS in TLS so it should never be sending/receiving any packets larger than this anyway.

self.recv = functools.partial(self._process, True, sslobj.read)
self.send = functools.partial(self._process, False, sslobj.write)
self.sendall = functools.partial(self._process, False, sslobj.write)
self._decref_socketios = socket._decref_socketios
Copy link
Contributor

Choose a reason for hiding this comment

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

Is something in the http.client.HTTPSConnection calling this internally?

Copy link
Member Author

Choose a reason for hiding this comment

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

socket.SocketIO used in makefile uses it in the close method, which is called by http. I could possibly get around this by not using socket.SocketIO directly, or subclass it.

@webknjaz webknjaz added the ci_verified Changes made in this PR are causing tests to fail. label Apr 19, 2024
@sivel
Copy link
Member Author

sivel commented Apr 22, 2024

For the record, I'm not really in favor of merging this. It's touching too much that I just don't feel is supportable. And maybe with a further investment in time and code, it could maybe be made a little better, but I'm leary of the potential burden on future me and/or other devs to support this.

I'm open to being wrong about this, and just looking for feedback.

@jborean93
Copy link
Contributor

While I feel the chances of urllib/http.client changing the way things are called internally I definitely wouldn't want to be the person who has to debug this if something was to break. On the flip side I do see people having to use a TLS based proxy becoming a more common scenario as time goes on so this can be a useful feature to have. Unfortunately I don't see this really being fixed properly in CPython itself so I'm not sure what the best way forward would be.

@mkrizek mkrizek removed the needs_triage Needs a first human triage before being processed. label Apr 23, 2024
@sivel
Copy link
Member Author

sivel commented Apr 23, 2024

Closing this per above.

@sivel sivel closed this Apr 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci_verified Changes made in this PR are causing tests to fail. feature This issue/PR relates to a feature request. needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants