sources/curl: add org.osbuild.mtls secrets support

If `org.osbuild.mtls` is passed as a secret name, look for the mtls data
in the environment.
This commit is contained in:
Sanne Raymaekers 2024-03-06 14:36:02 +01:00 committed by Simon de Vlieger
parent c990c07f79
commit 29159189f1
2 changed files with 104 additions and 6 deletions

View file

@ -2,13 +2,19 @@
""" """
Source for downloading files from URLs. Source for downloading files from URLs.
The files are indexed by their content hash. Can download files The files are indexed by their content hash. It can download files
that require secrets. The only secret provider currently supported that require secrets. The secret providers currently supported are:
is `org.osbuild.rhsm` for downloading Red Hat content that requires
a subscriptions.
Internally use curl to download the files; the files are cached in - `org.osbuild.rhsm` for downloading Red Hat content that requires
an internal cache. Multiple parallel connections are used to speed a subscriptions.
- `org.osbuild.mtls` for downloading content that requires client
certificats. The paths to the key and cert should be set in the
environment in OSBUILD_SOURCES_CURL_SSL_CLIENT_KEY,
OSBUILD_SOURCES_CURL_SSL_CLIENT_CERT, and optionally
OSBUILD_SOURCES_CURL_SSL_CA_CERT.
It uses curl to download the files; the files are cached in an
internal cache. Multiple parallel connections are used to speed
up the download. up the download.
""" """
@ -107,6 +113,16 @@ class CurlSource(sources.SourceService):
if self.subscriptions is None: if self.subscriptions is None:
self.subscriptions = Subscriptions.from_host_system() self.subscriptions = Subscriptions.from_host_system()
url["secrets"] = self.subscriptions.get_secrets(url.get("url")) url["secrets"] = self.subscriptions.get_secrets(url.get("url"))
elif url.get("secrets", {}).get("name") == "org.osbuild.mtls":
key = os.getenv("OSBUILD_SOURCES_CURL_SSL_CLIENT_KEY")
cert = os.getenv("OSBUILD_SOURCES_CURL_SSL_CLIENT_CERT")
if not (key and cert):
raise RuntimeError(f"mtls secrets required but key ({key}) or cert ({cert}) not defined")
url["secrets"] = {
'ssl_ca_cert': os.getenv("OSBUILD_SOURCES_CURL_SSL_CA_CERT"),
'ssl_client_cert': cert,
'ssl_client_key': key,
}
return checksum, url return checksum, url

View file

@ -0,0 +1,82 @@
#!/usr/bin/python3
import contextlib
import os
import pathlib
import socket
import tempfile
import pytest
SOURCES_NAME = "org.osbuild.curl"
def test_curl_source_not_exists(sources_module):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
curl_source = sources_module.CurlSource.from_args(["--service-fd", str(sock.fileno())])
tmpdir = tempfile.TemporaryDirectory()
curl_source.cache = tmpdir.name
desc = {
"url": "http://localhost:80/a",
}
checksum = "sha256:1234567890123456789012345678901234567890909b14ffb032aa20fa23d9ad6"
assert not curl_source.exists(checksum, desc)
def test_curl_source_exists(sources_module):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
curl_source = sources_module.CurlSource.from_args(["--service-fd", str(sock.fileno())])
tmpdir = tempfile.TemporaryDirectory()
curl_source.cache = tmpdir.name
desc = {
"url": "http://localhost:80/a",
}
checksum = "sha256:1234567890123456789012345678901234567890909b14ffb032aa20fa23d9ad6"
pathlib.Path(os.path.join(tmpdir.name, checksum)).touch()
assert curl_source.exists(checksum, desc)
def test_curl_source_transform(sources_module):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
curl_source = sources_module.CurlSource.from_args(["--service-fd", str(sock.fileno())])
tmpdir = tempfile.TemporaryDirectory()
curl_source.cache = tmpdir.name
desc = {
"url": "http://localhost:80/a",
"secrets": {
"name": "org.osbuild.mtls",
},
}
with contextlib.ExitStack() as cm:
os.environ["OSBUILD_SOURCES_CURL_SSL_CLIENT_KEY"] = "key"
os.environ["OSBUILD_SOURCES_CURL_SSL_CLIENT_CERT"] = "cert"
def cb():
del os.environ["OSBUILD_SOURCES_CURL_SSL_CLIENT_KEY"]
del os.environ["OSBUILD_SOURCES_CURL_SSL_CLIENT_CERT"]
cm.callback(cb)
checksum = "sha256:1234567890123456789012345678901234567890909b14ffb032aa20fa23d9ad6"
pathlib.Path(os.path.join(tmpdir.name, checksum)).touch()
new_desc = curl_source.transform(checksum, desc)
assert new_desc[1]["secrets"]["ssl_client_key"] == "key"
assert new_desc[1]["secrets"]["ssl_client_cert"] == "cert"
assert new_desc[1]["secrets"]["ssl_ca_cert"] is None
def test_curl_source_transform_fail(sources_module):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
curl_source = sources_module.CurlSource.from_args(["--service-fd", str(sock.fileno())])
tmpdir = tempfile.TemporaryDirectory()
curl_source.cache = tmpdir.name
desc = {
"url": "http://localhost:80/a",
"secrets": {
"name": "org.osbuild.mtls",
},
}
checksum = "sha256:1234567890123456789012345678901234567890909b14ffb032aa20fa23d9ad6"
pathlib.Path(os.path.join(tmpdir.name, checksum)).touch()
with pytest.raises(RuntimeError) as exc:
curl_source.transform(checksum, desc)
assert "mtls secrets required" in str(exc)