<p>I'm setting up an instance of ghost and I'm trying to secure the /ghost path with client cert verification. </p>

<p>I've got an initial ingress up and running that serves the site quite happily with the path specified as /. </p>

<p>I'm trying to add a second ingress (that's mostly the same) for the /ghost path. If I do this and add the annotations for basic auth, everything seems to work. i.e. If I browse to /ghost I am prompted for credentials in the basic-auth secret, if I browse to any other URL it is served without auth. </p>

<p>I then switched to client cert verification based on this example: <a href="https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/auth/client-certs" rel="nofollow noreferrer">https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/auth/client-certs</a></p>

<p>When I try this either the whole site or none of the site is secured, rather than the path-based separation, I got with basic-auth. Looking at the nginx.conf from the running pod the  <code>proxy_set_header ssl-client-verify</code>, <code>proxy_set_header ssl-client-subject-dn</code> &amp; <code>proxy_set_header ssl-client-issuer-dn</code> elements are added under the root / path and the /ghost path. I've tried removing those (from the root only) and copying the config directly back to the pod but not luck there either.</p>

<p>I'm pulling nginx-ingress (Chart version 0.23.0) in as a dependency via Helm</p>

<p>Ingress definition for <code>/</code> location - this one works</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    certmanager.k8s.io/cluster-issuer: letsencrypt-staging
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
  labels:
    app: my-app
    chart: my-app-0.1.1
    heritage: Tiller
    release: my-app
  name: my-app
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /
  tls:
  - hosts:
    - example.com
    secretName: mysite-tls
</code></pre>

<p>Ingress definition for <code>/ghost</code> location - this one doesn't work</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-secret: "default/auth-tls-chain"
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
    nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.example.com/error-cert.html"
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "false"
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: my-app
    chart: my-app-0.1.1
    heritage: Tiller
    release: my-app
  name: my-app-secure
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /ghost
  tls:
  - hosts:
    - example.com
    secretName: mysite-tls
</code></pre>

<p>You need a <code>'*'</code> on your path on your second ingress if you want to serve all the pages securely under <code>/ghost</code> and if you want just <code>/ghost</code> you need another rule. Something like this:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-secret: "default/auth-tls-chain"
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
    nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.example.com/error-cert.html"
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "false"
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: my-app
    chart: my-app-0.1.1
    heritage: Tiller
    release: my-app
  name: my-app-secure
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /ghost
      - backend:
          serviceName: my-app
          servicePort: http
        path: /ghost/*
  tls:
  - hosts:
    - example.com
    secretName: mysite-tls
</code></pre>

<p>However, if you want something like <code>/</code> unsecured and <code>/ghost</code> secured, I believe you won't be able to do it. For example, if you are using nginx, this is a limitation from nginx itself, when you configure a <a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#server" rel="nofollow noreferrer"><code>server {}</code></a> block with TLS in nginx it looks something like this:</p>

<pre><code>server {
    listen              443 ssl;
    server_name         example.com;
    ssl_certificate     example.com.crt;
    ssl_certificate_key example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}
</code></pre>

<p>The ingress controller creates paths like this:</p>

<pre><code>server {
    listen              443 ssl;
    server_name         example.com;
    ssl_certificate     example.com.crt;
    ssl_certificate_key example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...

    location / {
       ...
    }

    location /ghost {
       ...
    }

}
</code></pre>

<p>So when you configure another <code>server {}</code> block with the same hostname and with no SSL it will override the first one.</p>

<p>You could do it with different <code>- host:</code> rules in your ingress for example <code>ghost.example.com</code> with TLS and <code>main.example.com</code> without TLS. So in your nginx.conf you would have different <code>server {}</code> blocks.</p>

<p>You can always shell into the ingress controller pod to check the configs, for example:</p>

<pre><code>$ kubectl exec -it nginx-ingress-controller-xxxxxxxxx-xxxxx bash
www-data@nginx-ingress-controller-6bd7c597cb-8kzjh:/etc/nginx$ cat nginx.conf
</code></pre>
