-
Notifications
You must be signed in to change notification settings - Fork 343
feat: MDS connections use mTLS #1856
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
base: main
Are you sure you want to change the base?
Conversation
076c937 to
0d550bc
Compare
0d550bc to
00c5fbd
Compare
00c5fbd to
d31d480
Compare
8947e48 to
3689ea7
Compare
daniel-sanche
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing major, but left a few suggestions to consider
| """Returns the metadata server IP root URL.""" | ||
| scheme = "https" if use_mtls else "http" | ||
| return "{}://{}".format( | ||
| scheme, os.getenv(environment_vars.GCE_METADATA_IP, "169.254.169.254") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems stange that this IP is hardcoded in multiple places. Can this be GCE_MDS_HOSTS[-1]? Or can we make a DEFAULT_GCE_METADATA_IP constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add a _DEFAULT_GCE_METADATA_IP constant
| Returns: | ||
| google.auth.transport.Request: Request | ||
| object to use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the line break seems unnecessary here
| Args: | ||
| request (google.auth.transport.Request): A callable used to make | ||
| HTTP requests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use_mtls isn't mentioned here
| bool: True if the metadata server is reachable, False otherwise. | ||
| """ | ||
| use_mtls = _mtls.should_use_mds_mtls() | ||
| request = _prepare_request_for_mds(request, use_mtls=use_mtls) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar with how requests work in this library, but I find it surprising the request passed in is completely replaced with a new one when mtls is enabled. Wouldn't it be cleaner to create a different request at the caller side, instead of accepting one and then overriding it here?
If you do keep this behaviour, do the docstrings need to be updated to make it clear that the input request might not be used?
request (google.auth.transport.Request): A callable used to make HTTP requests.
Or am I thinking about all this wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually did initially implement it the way you suggested here (which is: the caller passes in a different request).
The problem @sai-sunder-s pointed out is that people using this library will create their own request object and then pass it in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a private file? Do users call these functions directly?
| bool: True if the metadata server is reachable, False otherwise. | ||
| """ | ||
| use_mtls = _mtls.should_use_mds_mtls() | ||
| request = _prepare_request_for_mds(request, use_mtls=use_mtls) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is _prepare_request_for_mds really needed? It seems like this could just be a one-liner:
request = requests.Request(_mtls.create_session()) if use_mtls else request
| "C:\\", "ProgramData", "Google", "ComputeEngine", "mds-mtls-root.crt" | ||
| ) | ||
| else: | ||
| return os.path.join("/", "run", "google-mds-mtls", "root.crt") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These paths are a bit unweildy, especially since the directory is referenced multiple times in this file. I'd suggest doing something like:
WIN_BASE_PATH_COMPONENTS = ("C:\\", "ProgramData", "Google", "ComputeEngine")
BASE_PATH_COMPONENTS = ("/", "run", "google-mds-mtls")
def _get_mds_root_crt_path():
if os.name == "nt":
return os.path.join(*WIN_BASE_PATH_COMPONENTS, "mds-mtls-root.crt")
else:
return os.path.join(*BASE_PATH_COMPONENTS, "root.crt")
Or, preferably, consider using Path objects instead of strings. It could simplify some of the weirdness of paths on different platforms
from pathlib import Path
WIN_BASE_PATH = PATH("C:/ProgramData/Google/ComputeEngine")
BASE_PATH = PATH("/run/google-mds-mtls")
def _get_mds_root_crt_path():
if os.name == "nt":
return WIN_BASE_PATH / "mds-mtls-root.crt"
else:
return BASE_PATH / "root.crt"
|
|
||
|
|
||
| def _get_mds_root_crt_path(): | ||
| if os.name == "nt": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The "nt" string is used in a few places, and could be confusing if you're not familiar
Maybe consider making this a constant. Something like WINDOWS_OS_NAME="nt"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this a bit closer, it looks like this change would contradict the public API as it currently stands. Custom request objects constructed and passed in by users would be bypassed after the next release, which could break existing code. I think we need to consider that more before merging
Or let me know if I'm misunterstanding
Feature Gating
The
GCE_METADATA_MTLS_MODEenvironment variable is introduced, which can be set to strict, none, or default.The
should_use_mds_mtlsfunction determines whether to use mTLS based on the environment variable and the existence of the certificate files.Using MDS mTLS
A custom
MdsMtlsAdapterfor requests is implemented to handle the SSL context for mTLS.The
create_sessionfunction creates a requests.Session with the mTLS adapter.Integrating with existing code
compute_engine/_metadata.py: