Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 97cc6b5

Browse files
committed
Authenticate client with mtls
1 parent 4349b8e commit 97cc6b5

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

packages/jumpstarter/jumpstarter/client/client.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from jumpstarter_protocol import jumpstarter_pb2_grpc
1010

1111
from jumpstarter.client import DriverClient
12-
from jumpstarter.common.importlib import import_class
1312
from jumpstarter.common.grpc import aio_secure_channel
13+
from jumpstarter.common.importlib import import_class
1414

1515

1616
@asynccontextmanager
@@ -41,8 +41,12 @@ async def client_from_channel(
4141
if endpoint.certificate:
4242
attempted_channel = aio_secure_channel(
4343
endpoint.endpoint,
44-
grpc.ssl_channel_credentials(root_certificates=endpoint.certificate.encode()),
45-
) # TODO: set token
44+
grpc.ssl_channel_credentials(
45+
root_certificates=endpoint.certificate.encode(),
46+
private_key=endpoint.client_private_key.encode(),
47+
certificate_chain=endpoint.client_certificate.encode(),
48+
),
49+
)
4650
try:
4751
response = await jumpstarter_pb2_grpc.ExporterServiceStub(attempted_channel).GetReport(
4852
empty_pb2.Empty()

packages/jumpstarter/jumpstarter/exporter/tls.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def with_alternative_endpoints(server, endpoints: list[str]):
4141
sans.append(x509.IPAddress(host))
4242

4343
key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend())
44+
client_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend())
4445

4546
crt = (
4647
x509.CertificateBuilder()
@@ -53,6 +54,16 @@ def with_alternative_endpoints(server, endpoints: list[str]):
5354
.add_extension(x509.SubjectAlternativeName(sans), critical=False)
5455
.sign(private_key=key, algorithm=hashes.SHA256(), backend=default_backend())
5556
)
57+
client_crt = (
58+
x509.CertificateBuilder()
59+
.subject_name(x509.Name([]))
60+
.issuer_name(x509.Name([]))
61+
.public_key(client_key.public_key())
62+
.serial_number(x509.random_serial_number())
63+
.not_valid_before(datetime.now())
64+
.not_valid_after(datetime.now() + timedelta(days=365))
65+
.sign(private_key=client_key, algorithm=hashes.SHA256(), backend=default_backend())
66+
)
5667

5768
pem_crt = crt.public_bytes(serialization.Encoding.PEM)
5869
pem_key = key.private_bytes(
@@ -61,14 +72,27 @@ def with_alternative_endpoints(server, endpoints: list[str]):
6172
encryption_algorithm=serialization.NoEncryption(),
6273
)
6374

64-
server_credentials = grpc.ssl_server_credentials([(pem_key, pem_crt)])
75+
pem_client_crt = client_crt.public_bytes(serialization.Encoding.PEM)
76+
pem_client_key = client_key.private_bytes(
77+
encoding=serialization.Encoding.PEM,
78+
format=serialization.PrivateFormat.TraditionalOpenSSL,
79+
encryption_algorithm=serialization.NoEncryption(),
80+
)
81+
82+
server_credentials = grpc.ssl_server_credentials(
83+
[(pem_key, pem_crt)], root_certificates=pem_client_crt, require_client_auth=True
84+
)
6585

6686
endpoints_pb = []
6787
for endpoint in endpoints:
6888
server.add_secure_port(endpoint, server_credentials)
69-
# FIXME: generate and check token
7089
endpoints_pb.append(
71-
jumpstarter_pb2.Endpoint(endpoint=endpoint, token="", certificate=pem_crt),
90+
jumpstarter_pb2.Endpoint(
91+
endpoint=endpoint,
92+
certificate=pem_crt,
93+
client_certificate=pem_client_crt,
94+
client_private_key=pem_client_key,
95+
),
7296
)
7397

7498
return endpoints_pb

0 commit comments

Comments
 (0)