We have a host of microservices all being served via a single api-gateway service, in Kubernetes, with an ingress to forward to the same that looks like below ->
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: beta-https
namespace: beta
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
tls:
- hosts:
- beta.xyz.com
secretName: beta-secret
rules:
- host: beta.xyz.com
http:
paths:
- path: /api/(.*)
backend:
serviceName: api-svc
servicePort: 8443
Now we have a new requirement, wherein a subset of the apis - /api/secure , must be IP restricted. Any ideas on how to achieve this?
I am assuming I can use nginx.ingress.kubernetes.io/whitelist-source-range
, in a new config to foroward traffic to /api/secure, but how do I ensure the above config does not server /api/secure?
From what I see you are trying to create two separate paths where /api/secure
will be accesible only for specific ip addresses.
I have replicated your problem, made some tests and found a solution.
When creating two ingress objects like yours, which differ on path
field e.g. one has path: /api/(.*)
and second has path: /api/secure
nginx will generate the following configuration (output is shortened):
server { server_name beta.xyz.com ;
listen 80 ;
listen 443 ssl http2 ;
...
location ~* "^/api/secure" {
...
}
location ~* "^/api/(.*)" {
...
}
and in nginx documentation you can read:
To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the
location with the longest matching prefix is selected and remembered
. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used.
meaning: NGINX always fulfills requests using the most specific match
Based on this information, creating two separate ingresses, just like you mentioned, should solve your problem, because /api/secure
will always be more specific path than /api/(.*)
.
Let me know if that helped.
so for someone looking into doing something similar, I was able to get this working by using nginx.ingress.kubernetes.io/server-snippet
to add a snippet and block the traffic
location ~ "^/api/secure/(.*)" {
deny all;
return 403;
}