-
Notifications
You must be signed in to change notification settings - Fork 12
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
browZer support - 3rd party server certs for controller #159
Comments
Hi, I worked on 3rd party topics for controller edge services, in order to be able to run terraform using the restapi from anywhere (actually my utimate goad is to create a stack using aws service catalog and terraform runtime engine). Long story short, here are the things I have done and what must be changed in the current controller chart to get it working out of the box: I assme you have already generated a certificate for the edge url using for instance let's encrypt (In my case i am using the edge controller nginx ingress to trigger certifcate generation through certificate manager letsencrypt prod issuer, even though i will eventually use ssl passthough):
It would be great to propose a way to pass these path using helm values with a if block => Can this enhancement be made?
|
That sounds interesting, @qmugnier! Yes, let's improve this controller chart so that it works with browZer. The router chart, too, needs to support Is this an accurate recap of the customizations you needed to make to the controller chart?
This is pretty close to how it should work. The main difference from what's needed is that the public cert needs to be configured as an alternative certificate, not the main cert. The web listener named "client" in your sample has a binding for the client API. That's where the Ziti BrowZer Runtime (ZBR) connects when it's running inside the user's web browser. It needs a public cert because it's not pre-configured to trust any of Ziti's root CAs. Still, the client API normally presents a server cert from a private CA, e.g., the ziti-controllerweb-root-issuer (CM Issuer) provided by the chart. The public cert is normally configured as an alternative cert like this. web:
- name: client
bindPoints:
- interface: 0.0.0.0:1280
address: edge-controller.ziti.mypublicdomain.com:443
identity:
cert: /etc/ziti/web-identity/tls.crt
server_cert: /etc/ziti/web-identity/tls.crt
key: /etc/ziti/web-identity/tls.key
ca: /etc/ziti/web-identity/ca.crt
alt_server_certs:
- server_cert: /etc/ziti/web-identity-public/tls.crt
server_key: /etc/ziti/web-identity-public/tls.key This avoids the need to add the public CA root cert to the trust Bundle because alternative certs are presumed to be from a CA we don't control. Adding a root CA cert from a CA you don't control to the trust Bundle is a security risk. Anyone who can get a cert from that CA can bypass the outer TLS security layer of the Ziti network!
EDIT: YAML syntax error |
This sounds even better. To be clear, is it somethingto be integrated into the chart, or is the alt_server_certs already supported by the chart ? (I cannot see anything related to that in the template). |
It's a feature of the controller. The chart needs new template values to allow setting alt cert on the web identity, at least. |
We will also need the alt cert template value in router chart for wss: #114 |
Got it now, it does say in the doc that the web section is powered by Xweb (same in controller and router) and that there is a I tried that but now when I hit the swagger url (https://edge-controller.public.domain.org/edge/management/v1/swagger.json), I am back to the tls error (unkwown CA) and my terraform fails again: Are you sure this has to be done that way at the controller level? If I look at the old documentation (Not sure why it was taken down) from archive.org, it says that the certificate must be replaced in the identity section, https://web.archive.org/web/20230908193528/https://openziti.io/docs/guides/alt-server-certs/ and that the router web section must have the alt_server_certs section as you mentionned before. Any thougths ? |
I read your answer again I think I did not get this part right:
I then removed the public address from ziti-controller-web-identity-cert (this would have to be supported by the chart as well). Seems to be working for the swagger url, but when I use my terraform project I get an invalid tls/encrypt error. For now, I am using the archive.org method and it is working fine, but as soon as the public CA solution works I will migrate to it. |
The main problem with that archived approach was it creates a vulnerability in the network. The CA that issues the primary cert must be trusted by the entire Ziti network, so it's essential to control that CA (not use a public CA). That's why the alt_server_certs was invented, so we can present a cert from a CA we don't control, like LetsEncrypt. The controller and router charts still need to be updated to support this. I'm taking a look now to see if I can include the improvement in a batch of changes I'm working. I'll update this issue. |
For the TF provider, curl -sSkf https://localhost:1280/.well-known/est/cacerts \
| base64 -d \
| openssl pkcs7 -inform DER -outform PEM -print_certs |
Hi all ;) I've just studied your discussion and I have some thoughts on it as well. Regarding the alt-server / "Let's Encrypt cert": Alternative approach: Bye, |
Reloader seems the way to go. |
This is important and will be addressed soon. Here's a recap of the issues related to supporting Ziti BrowZer Runtime (ZBR) clients with K8s-deployed Ziti controllers. browZer's value proposition is agentless Ziti. This means the user can visit a Ziti-protected web app in a normal web browser without installing additional software. Therefore, any solution mustn't introduce any requirements for additional software or out-of-band configuration, such as adding a root CA to the browser's trust store. The Ziti controllers and routers must present trusted server certs wherever ZBR clients connect because a normal web browser cannot be configured to trust a different root CA from within the Javascript runtime sandbox. The Ziti controller and router configurations support The controller's trusted server certificate may or may not be bound directly to the |
Hi, quick update on the issue.
web:
- name: client
bindPoints:
- interface: 0.0.0.0:1280
address: edge-controller.ziti.mypublicdomain.com:443
identity:
cert: /etc/ziti/web-identity/tls.crt
server_cert: /etc/ziti/web-identity/tls.crt
key: /etc/ziti/web-identity/tls.key
ca: /etc/ziti/web-identity/ca.crt
alt_server_certs:
- server_cert: /etc/ziti/web-identity-public/tls.crt
server_key: /etc/ziti/web-identity-public/tls.key
At first, I thought everything worked fine until I tried to enroll a router. After looking for a root cause I ended up finding this issue that seems very similar: Just in case, I added edge-controller.ziti.mypublicdomain.com:443 to /etc/ziti/ctrl-identity/tls.crt (the certs identity block for the controller), but that did not help, same error. Am i missing something like an option in the enroll process? |
The token's signature couldn't be verified by the router during enrollment. It's signed by the key that's configured for the controller's web listener where You can inspect the router's enrollment token (type The token includes a signed claim Here's a Python script that automates this process. If you run it on the router host that's attempting to enroll you should see that signature verification failed. https://gist.github.com/qrkourier/b9cacf765b2d62817672bc7e6be6bdc3 ziti-jwt.py /tmp/router1.jwt
|
Hi, I got the things up & running. And for the controller, I just added an additional ingress rule: apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: ziti-controller-ingress-alt-client
namespace: openziti
spec:
ingressClassName: nginx
rules:
- host: clients.browzer.my.domain
http:
paths:
- backend:
service:
name: ziti-controller-client
port:
number: 443
path: /
pathType: Prefix
tls:
- hosts:
- clients.browzer.my.domain
secretName: default-nginx-cert Then I told browzer to use this name for the controller. The controller itself is not aware of it's additional name - but it seems work ;) |
Yes, it will work for BrowZer (ZBR) clients even if the controller is not aware of the DNS name those clients are using. It's because they never negotiate mTLS with the controller, only routers, so it's perfectly fine to reverse proxy the controller API. |
@marvkis: this is not exactly my use case. I need ssl passthrough at the ingress level. |
@qrkourier : I followed the procedure and here are the results. {
"header": {
"alg": "RS256",
"kid": "b5b45cec76ae94682d4bb5477caf1ea9012c664d",
"typ": "JWT"
},
"payload": {
"iss": "https://edge-controller.mypublicdomain.com:443",
"sub": "pmPbC0C30",
"aud": [
""
],
"exp": 1720080190,
"jti": "3c6ea49d-87ee-47dd-8d8c-35e7b6fb4c31",
"em": "erott",
"ctrls": null
},
"analysis": {
"signature_valid": false,
"enrollment_method": "one-time token for a router",
"expiration": "2024-07-04T17:03:10"
}
} => Invalid And then inspected the content of server_cert: /etc/ziti/web-identity/tls.crt (which does not have any reference to edge-controller.mypublicdomain.com as discussed before) to extract the public pem and reran the script: {
"header": {
"alg": "RS256",
"kid": "b5b45cec76ae94682d4bb5477caf1ea9012c664d",
"typ": "JWT"
},
"payload": {
"iss": "https://edge-controller.mypublicdomain.com:443",
"sub": "pmPbC0C30",
"aud": [
""
],
"exp": 1720080190,
"jti": "3c6ea49d-87ee-47dd-8d8c-35e7b6fb4c31",
"em": "erott",
"ctrls": null
},
"analysis": {
"signature_valid": true,
"enrollment_method": "one-time token for a router",
"expiration": "2024-07-04T17:03:10"
}
} => Valid |
You must configure the controller's client API advertisement to enrollers in The It may be a bug that the controller allowed this configuration because it will never succeed since the issuer URL in the claim always gets the wrong cert. Clarification: it's the correct cert by SNI selection, but it's not the cert signed by the key that also signed the enrollment token, so enrollment always fails. |
@qrkourier : makes perfectly sense, thank you. |
This enables the controller to handle edge requests from agentless browZer clients which are never pre-configured with a trust bundle, and only trust 3rd party server certs.
It's a feature of the controller to present an alternative server cert when the edge client is requested by a distinctive domain name (SNI selected).
This issue tracks progress on this piece of the browZer puzzle, and is only necessary because no one has yet used browZer with a Ziti network controller hosted in K8s.
Resolving this issue may be as simple as documenting a way to configure the controller's alt certs with Helm input values.
This is related to the router issue to support browZer.
The text was updated successfully, but these errors were encountered: