sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #04422
[Merge] ~adam-collard/maas:3.3-vault-proxy into maas:3.3
Adam Collard has proposed merging ~adam-collard/maas:3.3-vault-proxy into maas:3.3.
Commit message:
LP:2002111 explicitly set proxies for hvac.Client
Cherry-pick 79bc358e2
Requested reviews:
Adam Collard (adam-collard)
Related bugs:
Bug #2002111 in MAAS: "Connection to local Vault fails if proxy is configured"
https://bugs.launchpad.net/maas/+bug/2002111
For more details, see:
https://code.launchpad.net/~adam-collard/maas/+git/maas/+merge/435596
--
Your team MAAS Committers is subscribed to branch maas:3.3.
diff --git a/src/maasserver/bootsources.py b/src/maasserver/bootsources.py
index 58c6cb7..5c2b081 100644
--- a/src/maasserver/bootsources.py
+++ b/src/maasserver/bootsources.py
@@ -378,6 +378,7 @@ def cache_boot_sources():
# FIXME: This modifies the environment of the entire process, which is Not
# Cool. We should integrate with simplestreams in a more Pythonic manner.
+ # See maasserver.vault._create_hvac_client - LP:2002111
pristine_env = yield deferToDatabase(set_simplestreams_env)
errors = []
diff --git a/src/maasserver/pytest_tests/test_vault.py b/src/maasserver/pytest_tests/test_vault.py
index 7277dbb..94db5ff 100644
--- a/src/maasserver/pytest_tests/test_vault.py
+++ b/src/maasserver/pytest_tests/test_vault.py
@@ -1,10 +1,11 @@
+from contextlib import suppress
from datetime import datetime, timedelta, timezone
-from os import environ
from unittest.mock import ANY, MagicMock
from django.core.exceptions import ImproperlyConfigured
from hvac.exceptions import VaultError as HVACVaultError
import pytest
+from requests.adapters import HTTPAdapter
from maasserver import vault
from maasserver.models import Config
@@ -143,25 +144,52 @@ class TestVaultClient:
ensure_auth.assert_called_once()
+@pytest.mark.parametrize("scheme", ["http", "https"])
class TestNoProxySettingForHVAC:
- def test_no_proxy_set(self, monkeypatch):
- url = "http://url.to.vault:8200"
- monkeypatch.delenv("no_proxy", raising=False)
- _create_hvac_client(url)
- assert environ.get("no_proxy") == url
-
- def test_no_proxy_appended(self, monkeypatch):
- url = "http://url.to.vault:8200"
- monkeypatch.setenv("no_proxy", "localhost,127.0.0.1")
- _create_hvac_client(url)
- assert environ.get("no_proxy") == f"localhost,127.0.0.1,{url}"
-
- def test_idempotency(self, monkeypatch):
- url = "http://url.to.vault:8200"
- monkeypatch.delenv("no_proxy", raising=False)
- _create_hvac_client(url)
- _create_hvac_client(url)
- assert environ.get("no_proxy") == url
+ def test_proxy_for_vault_scheme_set_to_None(self, scheme):
+ """HVAC client should be configured to not use a proxy."""
+ hvac_client = _create_hvac_client(f"{scheme}://url.to.vault:8200")
+ assert hvac_client.session.proxies == {scheme: None}
+
+ def test_proxy_for_with_env(self, scheme, monkeypatch):
+ """HVAC client should ignore standard proxy environment variables."""
+ monkeypatch.setenv("http_proxy", "http://squid.proxy:3128")
+ monkeypatch.setenv("https_proxy", "http://squid.proxy:3128")
+ monkeypatch.setenv("no_proxy", "127.0.0.1.localhost")
+
+ hvac_client = _create_hvac_client(f"{scheme}://url.to.vault:8200")
+ assert hvac_client.session.proxies == {scheme: None}
+
+ def test_request_honours_proxies(self, scheme, monkeypatch):
+ """Verify that the request made by requests follows the rules."""
+ monkeypatch.setenv("http_proxy", "http://squid.proxy:3128")
+ monkeypatch.setenv("https_proxy", "http://squid.proxy:3128")
+ monkeypatch.setenv("no_proxy", "127.0.0.1.localhost")
+ hvac_client = _create_hvac_client(f"{scheme}://url.to.vault:8200")
+
+ class ProxyRecordingAdapter(HTTPAdapter):
+ """
+ A basic subclass of the HTTPAdapter that records the arguments used to
+ ``send``.
+ """
+
+ def __init__(self2, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self2.proxies = []
+
+ def send(self2, request, **kwargs):
+ self2.proxies.append(kwargs.get("proxies"))
+ return
+
+ adapter = ProxyRecordingAdapter()
+ hvac_client.session.mount(f"{scheme}://", adapter)
+
+ # Since we return None from ProxyRecordingAdapter.send, it throws
+ # AttributeErrors, we just want to see the request that was
+ # attempted
+ with suppress(AttributeError):
+ hvac_client.seal_status
+ assert scheme not in adapter.proxies[0]
class TestGetRegionVaultClient:
diff --git a/src/maasserver/vault.py b/src/maasserver/vault.py
index 9ff213f..2b28a3d 100644
--- a/src/maasserver/vault.py
+++ b/src/maasserver/vault.py
@@ -1,8 +1,8 @@
from datetime import datetime, timedelta, timezone
from functools import cache, wraps
import logging
-import os
from typing import Any, Callable, NamedTuple, Optional
+from urllib.parse import urlparse
from dateutil.parser import isoparse
from django.core.exceptions import ImproperlyConfigured
@@ -48,13 +48,11 @@ def wrap_errors(func: Callable) -> Callable:
def _create_hvac_client(url: str, **kwargs) -> hvac.Client:
"""Create HVAC client for the given URL, with no proxies set."""
- # This is gross, and unfortunately necessary due to bootsources.get_simplestreams_env
- # and https://github.com/psf/requests/issues/2018
- if no_proxy := os.environ.get("no_proxy"):
- if url not in no_proxy.split(","):
- os.environ["no_proxy"] = f"{no_proxy},{url}"
- else:
- os.environ["no_proxy"] = url
+ # FIXME: This is gross, and unfortunately necessary due to
+ # bootsources.get_simplestreams_env and
+ # https://github.com/psf/requests/issues/2018
+ # LP:2002528
+ kwargs["proxies"] = {urlparse(url).scheme: None}
return hvac.Client(url=url, **kwargs)
References