Repository navigation
Proxy builder: clientCertificate(cert, key[, passphrase]) for mTLS upstreams (rift#1609) - #353
Merged
Conversation
rift 0.24.0 (rift#1609) sends a proxy's cert, key and passphrase to an upstream that asks for a client certificate, as Mountebank does. The typed builder had no way to set them; raw JSON could, but nothing enforced the pair, and an older engine drops all three silently, so the handshake fails at request time with no clue why. ProxySpec.clientCertificate(cert, key[, passphrase]) writes them as a pair, checks the PEM blocks up front, and creating such an imposter on an engine older than 0.24.0 is refused, for the raw wire keys too. The DSL already takes private keys this way (ImposterSpec.https). Closes #342
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #342
Why
From rift 0.24.0 (rift#1609), a
proxyresponse'scert,keyandpassphraseare presented to an upstream that requests a client certificate, as in Mountebank. The typed builder could not set them, and raw JSON had two gaps:The design decision (typed setters, following the
ImposterSpec.https(certPem, keyPem)precedent) is recorded in the triage comment on #342.What
ProxySpec.clientCertificate(certPem, keyPem)andclientCertificate(certPem, keyPem, passphrase):cert,keyandpassphrasethroughProxyResponse.extra, so there's no model or binary change, and read-back already round-trips;BEGIN CERTIFICATEblock and aBEGIN … PRIVATE KEYblock (PKCS#8, encrypted PKCS#8, PKCS#1 or SEC1), and refuse an empty passphrase and nulls;Key-to-cert matching and decryption stay with the engine (
400).Version gate:
PROXY_CLIENT_CERT_SINCE = "0.24.0".createandreplaceAllof a definition whose proxy carries any of the three wire keys fail withInvalidDefinitionon an older engine. The gate reads the wire keys, so a hand-built proxy is covered as well as the DSL setter. This is the same mechanism and the same modes as therequireClientCertificategate.Javadoc: the engine echoes these keys in
GET /impostersand--datadir(protect the admin API). Upstream trust is separate (upstreamTrust).Docs:
docs/design/sdk-api.md,ProxySpecblock.Fixtures:
tls/client.pem,tls/client-key.pemandtls/client-key-encrypted.pem(passphrasechangeit). These are the PEM forms of the existing throwawayclient.p12; the commands are intls/README.md.Tests
ProxyClientCertificateTest(9): literal wire JSON, key order, the passphrase, replacement, other chainers keep the certificate, PEM/passphrase/null refusals.ProxyClientCertificateGateTest(5): 0.23.0 refused before sending; the raw JSON path refused;replaceAllchecked; 0.24.0 accepted; a proxy without a certificate never asks for the version.ProxyClientCertificateIT(4, live, all lanes). The upstream is an https imposter requiring a client certificate fromtls/ca.pem, and the engine trusts that CA:clientCertificate→ not 200 (handshake refused);cert/keyback into the model.verifyon engine v0.24.0 passed on SPAWN and EMBEDDED.Downstream
rift-scala's
FacadeCoveragewill need entries for bothProxySpec.clientCertificatearities when it bumps.🤖 Generated with Claude Code