How to apply auth to specific path

I have the following paths:

/ - unauthenticated
/_healthcheck - unauthenticated
/.* - authenticated

Unfortunately I can’t seem to make Kong work with this. I’ve tried 2 Ingress resources, but they seem to compete. I’ve tried the following configurations:

new k8s.networking.v1beta1.Ingress(`${config.projectName}-unauthenticated`, {
  metadata: {
    namespace: namespace.metadata.name,
    annotations: {
      'kubernetes.io/tls-acme': 'true',
      'cert-manager.io/cluster-issuer': 'letsencrypt-http01',
      'acme.cert-manager.io/http01-ingress-class': 'kong-external',
      'kubernetes.io/ingress.class': 'kong-internal',
      'configuration.konghq.com': 'https-only'
    }
  },
  spec: {
    tls: [
      {
        secretName: `${config.projectName}-certificate`,
        hosts: [config.app.hostname]
      }
    ],
    rules: [
      {
        http: {
          paths: [
            {
              path: '/',
              backend: {
                serviceName: service.metadata.name,
                servicePort: service.spec.ports[0].port
              }
            }
          ]
        }
      }
    ]
  }
});

new k8s.networking.v1beta1.Ingress(`${config.projectName}-authenticated`, {
  metadata: {
    namespace: namespace.metadata.name,
    annotations: {
      'kubernetes.io/tls-acme': 'true',
      'cert-manager.io/cluster-issuer': 'letsencrypt-http01',
      'acme.cert-manager.io/http01-ingress-class': 'kong-external',
      'kubernetes.io/ingress.class': 'kong-internal',
      'configuration.konghq.com': 'https-only',
      'plugins.konghq.com': 'auth'
    }
  },
  spec: {
    tls: [
      {
        secretName: `${config.projectName}-certificate`,
        hosts: [config.app.hostname]
      }
    ],
    rules: [
      {
        http: {
          paths: [
            {
              path: '/',
              backend: {
                serviceName: service.metadata.name,
                servicePort: service.spec.ports[0].port
              }
            }
          ]
        }
      }
    ]
  }
});
new k8s.networking.v1beta1.Ingress(`${config.projectName}-unauthenticated`, {
  metadata: {
    namespace: namespace.metadata.name,
    annotations: {
      'kubernetes.io/tls-acme': 'true',
      'cert-manager.io/cluster-issuer': 'letsencrypt-http01',
      'acme.cert-manager.io/http01-ingress-class': 'kong-external',
      'kubernetes.io/ingress.class': 'kong-internal',
      'configuration.konghq.com': 'https-only'
    }
  },
  spec: {
    tls: [
      {
        secretName: `${config.projectName}-certificate`,
        hosts: [config.app.hostname]
      }
    ],
    rules: [
      {
        http: {
          paths: [
            {
              path: '/',
              backend: {
                serviceName: service.metadata.name,
                servicePort: service.spec.ports[0].port
              }
            },
            {
              path: '/_healthcheck',
              backend: {
                serviceName: service.metadata.name,
                servicePort: service.spec.ports[0].port
              }
            }
          ]
        }
      }
    ]
  }
});

new k8s.networking.v1beta1.Ingress(`${config.projectName}-authenticated`, {
  metadata: {
    namespace: namespace.metadata.name,
    annotations: {
      'kubernetes.io/tls-acme': 'true',
      'cert-manager.io/cluster-issuer': 'letsencrypt-http01',
      'acme.cert-manager.io/http01-ingress-class': 'kong-external',
      'kubernetes.io/ingress.class': 'kong-internal',
      'configuration.konghq.com': 'https-only',
      'plugins.konghq.com': 'auth'
    }
  },
  spec: {
    tls: [
      {
        secretName: `${config.projectName}-certificate`,
        hosts: [config.app.hostname]
      }
    ],
    rules: [
      {
        http: {
          paths: [
            {
              path: '/',
              backend: {
                serviceName: service.metadata.name,
                servicePort: service.spec.ports[0].port
              }
            }
          ]
        }
      }
    ]
  }
});

and a few more, but nothing seems to work.

I’ve only seen the ability to apply plugins via annotations (referencing a KongPlugin), but not vice versa. Ideally annotations would not be used at all, and instead Kong would read all resources of it’s CRDs. I’m actually not quite sure why it doesn’t work this way, as I think it would simplify configuration a ton.

Can you elaborate, maybe with an example? I’m not sure I understand you here.

In the above configuration you have, it seems that both the routes are exactly same, meaning, authenticated and unauthenticated ingress definitions both have path /. In the authenticated section you should add a path like /[a-z]+ to ensure that Kong can differentiate between different requests and execute plugins accordingly.

Using /[a-z]+ did solve this particular case, but what really should happen is that / should be treated literally, as in, only match /, with /.* or /* being required for matching all paths.

Regarding my idea about how I would like to see everything, it would be like this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: demo
spec:
  rules:
  - http:
      paths:
      - path: /foo
        backend:
          serviceName: httpbin
          servicePort: 80
      - path: /bar
        backend:
          serviceName: echo
          servicePort: 80
---
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: add-response-header
route:
  ingress: demo
  paths:
    - '/foo'
config:
  add:
    headers:
    - "demo: injected-by-kong"
plugin: response-transformer

And then add-response-header would be automatically parsed as kong would know when a new resource in the kong API version is created/modified. This way the configuration is always on the plugin, not on the ingress. As in, the ingress should not use annotations for configuration other than general annotations.

Also, having support for notPaths would also be really beneficial to allow for /foo/baz to match but not /foo/bar.

Also, how would I have been able to get /healthcheck to work? Because the only reason this worked is because /[a-z]+ doesn’t include _ in /_healthcheck so it doesn’t match.

Ideally, the ingresses should always apply specifically matched paths before using any defaults. So if 2 ingresses have /, but one has an exact match via a second path of /healthcheck, then it should use the ingress that has the exact match.

Correct.
You can create multiple rules in the same Ingress resource. More specific rules has higher priority.

The problem isn’t having this in a single Ingress, the issue is that / is in multiple Ingresss because of the limitation of configuration being done via annotations, and /healthcheck is only in one of the two, the one that is unauthenticated.

/healthcheck is only in one of the two, the one that is unauthenticated.

That’s how it should be. What concerns do you have?

the issue is that / is in multiple Ingress s because of the limitation of configuration being done via annotations

Can you elaborate? I don’t understand.