400 Bad Request The plain HTTP request was sent to HTTPS port

Installing passbolt Helm chart in a kubernetes cluster with ingress enabled throwing: “The plain HTTP request was sent to HTTPS port” when trying to access passbolt URL.

This issue is due to NGINX trying to reach backend passbolt service in HTTP instead of HTTPS which passbolt don’t like.

Adding "nginx.ingress.kubernetes.io/backend-protocol: “HTTPS” to passbolt ingress annotations resolved the issue.

1 Like

Hello, can you send some snippet? It hasn’t worked for me… This is my extra-values.yaml

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
  hosts:
    - host: passbolt.my.custom.domain   
      paths:
        - path: /
          pathType: ImplementationSpecific   
  tls:
    - secretName: passbolt-tls
      hosts:
        - passbolt.my.custom.domain

passboltEnv:
  plain:
    APP_FULL_BASE_URL: https://passbolt.my.custom.domain

Thanks in advance

Hello, I had the same issue.
It happens because the backend is using HTTPS and the client sends traffic via HTTP. Here you can find a deeper explanation about this topic: ssl - How NGINX Ingress controller back-end protocol annotation works in path based routing? - Stack Overflow

If the annotation suggested by @said678 doesn’t solve, check the tls secret created during the installation. Your nginx-ingress-controller expects SSL certificate but probably the original request is plain http.

In the tls secret you should see the cert-manager annotations, for example:

cert-manager.io/certificate-name
cert-manager.io/issuer-name

If not, you can try these configurations:

ingress:
  enabled: true
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: nginx
    external-dns.alpha.kubernetes.io/hostname: passbolt.my.custom.domain 
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
  hosts:
    - host: passbolt.my.custom.domain 
      paths:
        - path: /
          pathType: Prefix
          backend: 
            service:
              name: my-release-passbolt
              port: 
                number: 433
  tls:
    - secretName: my-release-passbolt-sec-tls
      hosts:
        - passbolt.my.custom.domain

Finally, be sure to inherit by the chart this value:

tls:
  autogenerate: true

I am still having this issue,

I am using rancher on k3s and nginx controller installed + cert manager.
Below is my yaml for ingress :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    field.cattle.io/publicEndpoints: >-
      [{"addresses":["172.10.100.11"],"port":443,"protocol":"HTTPS","serviceName":"default:my-release-passbolt","ingressName":"default:main-ing","hostname":"passbolt.ridhoswasta.com","path":"/","allNodes":false}]
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
  creationTimestamp: '2024-03-20T15:48:20Z'
  generation: 2
  managedFields:
    - apiVersion: networking.k8s.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        f:status:
          f:loadBalancer:
            f:ingress: {}
      manager: nginx-ingress
      operation: Update
      subresource: status
      time: '2024-03-20T15:48:21Z'
    - apiVersion: networking.k8s.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:annotations:
            .: {}
            f:field.cattle.io/publicEndpoints: {}
            f:kubernetes.io/ingress.class: {}
            f:nginx.ingress.kubernetes.io/backend-protocol: {}
        f:spec:
          f:rules: {}
          f:tls: {}
      manager: agent
      operation: Update
      time: '2024-03-20T15:53:00Z'
  name: main-ing
  namespace: default
  resourceVersion: '43437392'
  uid: 7d6f120e-b7f2-4850-97a6-386ec8f41bd6
spec:
  rules:
    - host: passbolt.ridhoswasta.com
      http:
        paths:
          - backend:
              service:
                name: my-release-passbolt
                port:
                  number: 443
            path: /
            pathType: Prefix
  tls:
    - hosts:
        - passbolt.ridhoswasta.com
      secretName: tls-secret
status:
  loadBalancer:
    ingress:
      - ip: 172.10.100.11

I have tried everything suggestion on the online but nothing can fix this now.

below is the nginx logs :

125.165.104.162 - - [20/Mar/2024:15:53:07 +0000] "GET /auth/is-authenticated.json HTTP/1.1" 400 650 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" "-"
125.165.104.162 - - [20/Mar/2024:15:54:07 +0000] "GET /users/me.json?api-version=v2 HTTP/1.1" 400 650 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" "-"

I want to share my experience on this topic.
I have a Kubernetes cluster with multiple ingress resources managed by a single NGINX ingress controller, deployed using the Bitnami Helm chart.
The ingress controller serves multiple backend applications and uses a wildcard certificate for HTTPS termination.
Passbolt is managed by Flux2 and deployed using the official Helm chart.
When adding Passbolt to the cluster, I ran into a significant issue.
Due to company policy, the wildcard certificate could only be used by the NGINX ingress controller for terminating HTTPS. Passbolt was required to handle its own certificates internally.
I needed to keep tls autogenerate: “true” enabled, so Passbolt would generate a self-signed certificate for its internal service communication.
I started with the following values.yaml snippet for Passbolt’s ingress configuration:

ingress:
  enabled: true
  className: nginx
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"    
  hosts:
    - host: passbolt.truedomain.com
      paths:
        - path: /
          port: https
          pathType: ImplementationSpecific

  tls:
    - autogenerate: true
      hosts:
        - passbolt.truedomain.com

and of course:

APP_FULL_BASE_URL: https://passbolt.truedomain.com

Using this configuration, when I browsed the application at

https://passbolt.truedomain.com

, the self-signed certificate generated by Passbolt was presented instead of the wildcard certificate configured on the NGINX ingress controller. This made the application almost unusable in modern browsers due to certificate errors like ERR_CERT_AUTHORITY_INVALID.
I tried several approaches, including configuring Passbolt to communicate over HTTP instead of HTTPS, but these attempts failed to meet the requirements and resulted in other issues.

After multiple iterations, I arrived at a working configuration by ensuring the certificates had different Common Names (CNs) to avoid conflicts between the wildcard certificate (handled by NGINX) and the self-signed certificate (generated by Passbolt). The key change was to bind the self-signed certificate to an internal domain (passbolt.local) while using the wildcard certificate for the public domain (passbolt.truedomain.com).

Here’s the final working values.yaml snippet:

  tls:
    - autogenerate: true
      hosts:
        - passbolt.local

It’s crucial to have the wildcard certificate (used by NGINX ingress) and the self-signed certificate (used by Passbolt) associated with different Common Names (CNs). This ensures that each certificate is used in its intended context without conflicts.
Let the ingress controller terminate TLS for public-facing domains while using internal certificates for backend communication.
The annotation nginx.ingress.kubernetes.io/backend-protocol: "HTTP" was critical in ensuring proper communication between the NGINX ingress controller and Passbolt.

Regards