Skip to content
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

How to configure the helm chart include TLS termination (https) into OWUI pod #70

Open
brokedba opened this issue Sep 2, 2024 · 7 comments
Labels
enhancement New feature or request

Comments

@brokedba
Copy link

brokedba commented Sep 2, 2024

I want to expose my open web ui in the cloud using TLS termination (since the Ip address is not localhost it is not recognized as safe so no mic or device can accessed from the browser).

I have the below values for the OpnWebUI helm chart and I think I secrewed it up a bit between the ingress and the loadbalancer service. I want to add a tsl secret and get the https termination accessible. I assume I need to keep the service clusterIP and add a TLS secret to the ingress to forward http traffic to https but really benefit from your help.
My K8 is in Oracle cloud OCI btw.


# Open WebUI Helm values
nameOverride: ""

ollama:
  enabled: false

ollamaUrls:
  - "http://ollama.ollama.svc.cluster.local:11434"

pipelines:
  enabled: true

ingress:
  enabled: true
  class: "nginx"
  annotations:
    kubernetes.io/ingress.class: nginx
  hosts:
    - host: openwebui.domain
      paths:
        - path: /
          pathType: Prefix
  tls: false

persistence:
  enabled: true
  size: 2Gi

service:
  type: LoadBalancer  # Change service type to LoadBalancer
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"  # Specify the shape of the LB
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "100"
    service.beta.kubernetes.io/oci-load-balancer-internal: "false"  # Set to "false" if you need an external LB
  port: 80
  containerPort: 8080
  loadBalancerIP: ""  # You can leave this empty or specify a static IP if required
  labels: {}
  loadBalancerClass: ""

extraEnvVars:
  - name: OPENAI_API_KEY
    value: "0p3n-w3bu!"

podSecurityContext: {}
containerSecurityContext: {}
@0xThresh
Copy link
Collaborator

0xThresh commented Sep 2, 2024

Hey @brokedba, these are the relevant lines of the Helm chart for TLS: https://github.com/open-webui/helm-charts/blob/main/charts/open-webui/templates/ingress.yaml#L17-L21

If you have a TLS secret to use created on your cluster already, it looks like you need to set the tls value to true, and set the .Values.ingress.existingSecret value to the name of that secret in your K8s cluster. This should get your TLS termination working.

If you need to try a different approach, I see Oracle has a guide to set up an Nginx ingress controller on their Kubernetes service, so this might be worth the read: https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengsettingupingresscontroller.htm. I'm doing something similar to this approach on my clusters using the AWS ALB Ingress Controller.

Please let me know if you find a fix, or any further issues with the chart while trying to implement one!

@brokedba
Copy link
Author

brokedba commented Sep 2, 2024

Hi @0xThresh , the ingress controller was actually the default nginx.
https actually works already as by default the ingress class chosen is nginx . The ingress controller service is a loadbalancer and the ingress of the openwebui shares the same IP.

kubectl describe ingress -n open-webui
Name:             open-webui
Labels:           app.kubernetes.io/component=open-webui
                  app.kubernetes.io/instance=open-webui
                  app.kubernetes.io/managed-by=Helm
                  app.kubernetes.io/version=0.3.13
                  helm.sh/chart=open-webui-3.1.7
Namespace:        open-webui
Address:          40.233.69.156     <------- ingress controller service => loadBalancer 
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /   open-webui:http (10.244.0.227:8080)
Annotations:  kubernetes.io/ingress.class: nginx
              meta.helm.sh/release-name: open-webui
              meta.helm.sh/release-namespace: open-webui
              ```
              

ingress-controller has the same external IP

kubectl describe svc ingress-nginx-controller -n cluster-tools
Name:                     ingress-nginx-controller
Namespace:                cluster-tools
Labels:                   app.kubernetes.io/component=controller
                          app.kubernetes.io/instance=ingress-nginx
                          app.kubernetes.io/managed-by=Helm
                          app.kubernetes.io/name=ingress-nginx
                          app.kubernetes.io/part-of=ingress-nginx
                          app.kubernetes.io/version=1.7.1
                          helm.sh/chart=ingress-nginx-4.6.1
Annotations:              meta.helm.sh/release-name: ingress-nginx
                          meta.helm.sh/release-namespace: cluster-tools
                          service.beta.kubernetes.io/oci-load-balancer-shape: flexible
                          service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: 100
                          service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: 10
Selector:                 app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.108.219
IPs:                      10.96.108.219
LoadBalancer Ingress:     40.233.69.156    <------------------- same with openwebUi ingress
Port:                     http  80/TCP
TargetPort:               http/TCP
NodePort:                 http  32224/TCP
Endpoints:                10.244.1.18:80
Port:                     https  443/TCP
TargetPort:               https/TCP
NodePort:                 https  30175/TCP
Endpoints:                10.244.1.18:443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

  • this is just by choosing the default nginx ingressclass in the helm chart.
    -I think it's probably the default ingress controller which creates a self signed certificate.

Regarding tls secret ingress cofig
when I tried to create a ingress with a tls existing secret , I had the below error . I'm probably clueless of FQDN tls fundamentals , I tried with both empty and random domain value so try resolving the HTTPS://ingress_IP, but RFC 1123 didn't like it.

...
ingress:
  enabled: true
  class: "nginx"
  annotations:
    kubernetes.io/ingress.class: nginx
  hosts:
    - host: openwebui.com
      paths:
        - path: /
          pathType: Prefix
  tls: true
  existingSecret: "openwebui-tls-secret"
...
Error: UPGRADE FAILED: cannot patch "open-webui" with kind Ingress: Ingress.networking.k8s.io "open-webui" is invalid: spec.tls[0].hosts[0]: Invalid value: "": a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')
-- both empty and full values had the same outcome

@0xThresh
Copy link
Collaborator

0xThresh commented Sep 3, 2024

If you check the chart's ingress.yaml file, you'll see that the host value is used to populate the TLS host and the typical routes host. You're trying to pass the whole hosts block which isn't a valid value for the chart, and that explains why you're getting an error stating that the hostname is "" since the host value isn't being set in the values you sent.

I think these values will work better:

ingress:
  enabled: true
  class: "nginx"
  annotations:
    kubernetes.io/ingress.class: "nginx"
  host: openwebui.domain
  tls: true
  existingSecret: "openwebui-tls-secret"

@brokedba
Copy link
Author

brokedba commented Sep 3, 2024

If you check the chart's ingress.yaml file, you'll see that the host value is used to populate the TLS host and the typical routes host. You're trying to pass the whole hosts block which isn't a valid value for the chart, and that explains why you're getting an error stating that the hostname is "" since the host value isn't being set in the values you sent.

I think these values will work better:

ingress:
  enabled: true
  class: "nginx"
  annotations:
    kubernetes.io/ingress.class: "nginx"
  host: openwebui.domain
  tls: true
  existingSecret: "openwebui-tls-secret"

You are right , somehow I use the syntax with hosts without knowing how it ended there . Probably a copy paste gone wrong (from another helm chart , ollama ?) .
However , even if the error is gone I now have conflict with the ingress IP with error 404.

I have to remove the tls config again and see if I can recover the TLS termination with that same IP.

kubectl get ingress -A
NAMESPACE       NAME         CLASS   HOSTS                    ADDRESS         PORTS     AGE
ollama          ollama       nginx   ollama.domain            40.233.69.156   80        46h
open-webui      open-webui   nginx   openwebui.com            40.233.69.156   80, 443   6h16m

kubectl get svc -A | grep ingress
NAMESPACE          NAME                                  TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE
cluster-tools      ingress-nginx-controller              LoadBalancer   10.96.108.219   40.233.69.156   80:32224/TCP,443:30175/TCP   53d

@brokedba
Copy link
Author

brokedba commented Sep 3, 2024

@0xThresh
the only way to avoid the nginx conflict (404 not found) in my K8 config on OCI is the remove the host value all together .

ingress:
  enabled: true
  class: "nginx"
  annotations:
  kubernetes.io/ingress.class: nginx
  host: ""
  tls: false
  existingSecret: ""

This fixed it and I could use the IP of the nginx controller to access openwebui service (via redirection).
I'll leave it like this . I'm sure every cloud has it's own particularity but on OCI , I don't need to define a tls cert or host if the class is the default nginx which is fine by me .

@0xThresh
Copy link
Collaborator

Thanks for reporting back. We can look at re-working the ingress in the template to only define the host if it's included as a value to help any future OCI users.

@0xThresh 0xThresh added the enhancement New feature or request label Sep 27, 2024
@brokedba
Copy link
Author

brokedba commented Nov 30, 2024

Thanks for reporting back. We can look at re-working the ingress in the template to only define the host if it's included as a value to help any future OCI users.

What I noticed in other addon helm based installation in OCI is that there if the microservice is expecting a path i.e /webui
the ingress can be created with a host matching it.

resource "helm_release" "grafana" {
 name       = "grafana"
 repository = local.helm_repository.grafana
 chart      = "grafana"
 version    = local.helm_repository.grafana_version
 namespace  = kubernetes_namespace.cluster_tools.0.id
 wait       = false

 set {
   name  = "grafana\\.ini.server.root_url"
   value = "%(protocol)s://%(domain)s:%(http_port)s/grafana" <------------------------ path
   type  = "string"
 }

I found this in their kubernetes terraform module.

  • You see they generated a host FQDN at some point and stored it in ingress_hosts variable. (i.e ="k8sapp.28e9459d.nip.io")
resource "kubernetes_ingress_v1" "grafana" {
 wait_for_load_balancer = true
 metadata {
   name        = "grafana"
   namespace   = kubernetes_namespace.cluster_tools.0.id
   annotations = local.ingress_nginx_annotations
 }
 spec {
   ingress_class_name = "nginx"
   rule {
     http {
       path {
         path      = "/grafana(/|$)(.*)"  <-------------path
         path_type = "Prefix"
         backend {
           service {
             name = "grafana"
             port {
               number = 80
             } }}}}
              }
      dynamic "rule" {
     for_each = local.ingress_hosts     <--------------the host FQDN k8sapp.28e9459d.nip.io
     content {
       host = rule.value
       http {
         path {
           path      = "/grafana(/|$)(.*)"
           path_type = "Prefix"
           backend {
             service {
               name = "grafana"
               port {
                 number = 80
               }  } } }  }  }  }
   tls {
     secret_name = "grafana-${var.ingress_cluster_issuer}-tls"
     hosts       = local.ingress_hosts     <---------------hotsname k8sapp.28e9459d.nip.io
   }
 }            

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants