kubernetes ingress-nginx 忽略路径中的特殊字符

huangapple go评论45阅读模式
英文:

kubernetes ingress-nginx ignore special characters in path

问题

I'm trying to have a rule listening to a specific path containing a dollar sign like this:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: metadata-ingress
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "false"
spec:
  ingressClassName: public
  tls:
  - hosts:
    - mydomain.com
  rules:
  - host: mydomain.com
    http:
      paths:
      - path: /api/v2/$metadata
        pathType: Prefix
        backend:
          service:
            name: busybox
            port:
              number: 8280

I don't want any url rewrite or anything fancy, just want this specific path to be caught and forwarded to this service.

Without the "$" it works.

I thought disabling regex with use-regex: "false" would fix it, but no.

I also tried using the url encoded value for $ : %24metadata but it doesn't help either.

I also tried to use "exact" instead of "prefix" as the pathType but no.

英文:

I'm trying to have a rule listening to a specific path containing a dollar sign like this:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: metadata-ingress
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "false"
spec:
  ingressClassName: public
  tls:
  - hosts:
    - mydomain.com
  rules:
  - host: mydomain.com
    http:
      paths:
      - path: /api/v2/$metadata
        pathType: Prefix
        backend:
          service:
            name: busybox
            port:
              number: 8280

I don't want any url rewrite or anything fancy, just want this specific path to be caught and forwarded to this service.

Without the "$" it works.

I thought disabling regex with use-regex: "false" would fix it, but no.

I also tried using the url encoded value for $ : %24metadata but it doesn't help either.

I also tried to use "exact" instead of "prefix" as the pathType but no.

答案1

得分: 1

I can't reproduce your problem, but I thought I walk through my test setup and you can tell me if anything is different. For the purpose of testing different paths, I have two deployments using the traefik/whoami image (this just provides a useful endpoint that shows us -- among other things -- the hostname and path involved in the request).

That looks like:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: example
    component: app1
  name: example-app1
spec:
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: example
    component: app1

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: example
    component: app2
  name: example-app2
spec:
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: example
    component: app2

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: example
    component: app1
  name: example-app1
spec:
  selector:
    matchLabels:
      app: example
      component: app1
  template:
    metadata:
      labels:
        app: example
        component: app1
    spec:
      containers:
      - image: docker.io/traefik/whoami:latest
        name: whoami
        ports:
        - containerPort: 80
          name: http

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: example
    component: app2
  name: example-app2
spec:
  selector:
    matchLabels:
      app: example
      component: app2
  template:
    metadata:
      labels:
        app: example
        component: app2
    spec:
      containers:
      - image: docker.io/traefik/whoami:latest
        name: whoami
        ports:
        - containerPort: 80
          name: http

I've also deployed the following Ingress resource, which looks mostly like yours, except I've added a second paths config so that we can compare requests that match /api/v2/$metadata vs those that do not:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: house
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  name: example
spec:
  ingressClassName: nginx
  rules:
  - host: example.apps.infra.house
    http:
      paths:
      - backend:
          service:
            name: example-app1
            port:
              name: http
        path: /
        pathType: Prefix
      - backend:
          service:
            name: example-app2
            port:
              name: http
        path: /api/v2/$metadata
        pathType: Prefix
  tls:
  - hosts:
    - example.apps.infra.house
    secretName: example-cert

With these resources in place, a request to https://example.apps.infra.house/ goes to app1:

$ curl -s https://example.apps.infra.house/ | grep Hostname
Hostname: example-app1-596fcf48bd-dqhvc

Whereas a request to https://example.apps.infra.house/api/v2/$metadata goes to app2:

$ curl -s https://example.apps.infra.house/api/v2/\$metadata | grep Hostname
Hostname: example-app2-8675dc9b45-6hg7l

So that all seems to work.


We can, if we are so inclined, examine the nginx configuration that results from that Ingress. On my system, the nginx ingress controller runs in the nginx-ingress namespace:

$ kubectl -n nginx-ingress get deploy
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
ingress-nginx-controller   1/1     1            1           8d

The configuration lives in /etc/nginx/nginx.conf in the container. We can cat the file to stdout and look for the relevant directives:

$ kubectl -n nginx-ingress exec deploy/ingress-nginx-controller cat /etc/nginx/nginx.conf
...
                location /api/v2/$metadata/ {
                ...
                }
...

Based on your comment, the following seems to work:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: "/$2"
    cert-manager.io/cluster-issuer: house
spec:
  ingressClassName: nginx
  tls:
    - hosts:
      - example.apps.infra.house
      secretName: example-cert
  rules:
  - host: example.apps.infra.house
    http:
      paths:
      - path: /app1(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: example-app1
            port:
              name: http

      # Note the use of single quotes (') here; this is
      # important; using double quotes we would need to
      # write `\\$` instead of `\$`.
      - path: '/api/v2/\$metadata'
        pathType: Prefix
        backend:
          service:
            name: example-app2
            port:
              name: http

The resulting location directives look like:

location ~* "^/api/v2/\$metadata" {
...
}
location ~* "^/app1(/|$)(.*)" {
...
}

And a request for the $metadata path succeeds.

英文:

I can't reproduce your problem, but I thought I walk through my test setup and you can tell me if anything is different. For the purpose of testing different paths, I have two deployments using the traefik/whoami image (this just provides a useful endpoint that shows us -- among other things -- the hostname and path involved in the request).

That looks like:

apiVersion: v1
kind: Service
metadata:
labels:
app: example
component: app1
name: example-app1
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: example
component: app1
---
apiVersion: v1
kind: Service
metadata:
labels:
app: example
component: app2
name: example-app2
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: example
component: app2
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: example
component: app1
name: example-app1
spec:
selector:
matchLabels:
app: example
component: app1
template:
metadata:
labels:
app: example
component: app1
spec:
containers:
- image: docker.io/traefik/whoami:latest
name: whoami
ports:
- containerPort: 80
name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: example
component: app2
name: example-app2
spec:
selector:
matchLabels:
app: example
component: app2
template:
metadata:
labels:
app: example
component: app2
spec:
containers:
- image: docker.io/traefik/whoami:latest
name: whoami
ports:
- containerPort: 80
name: http

I've also deployed the following Ingress resource, which looks mostly like yours, except I've added a second paths config so that we can compare requests that match /api/v2/$metadata vs those that do not:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: house
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: example
spec:
ingressClassName: nginx
rules:
- host: example.apps.infra.house
http:
paths:
- backend:
service:
name: example-app1
port:
name: http
path: /
pathType: Prefix
- backend:
service:
name: example-app2
port:
name: http
path: /api/v2/$metadata
pathType: Prefix
tls:
- hosts:
- example.apps.infra.house
secretName: example-cert

With these resources in place, a request to https://example.apps.infra.house/ goes to app1:

$ curl -s https://example.apps.infra.house/ | grep Hostname
Hostname: example-app1-596fcf48bd-dqhvc

Whereas a request to https://example.apps.infra.house/api/v2/$metadata goes to app2:

$ curl -s https://example.apps.infra.house/api/v2/\$metadata | grep Hostname
Hostname: example-app2-8675dc9b45-6hg7l

So that all seems to work.


We can, if we are so inclined, examine the nginx configuration that results from that Ingress. On my system, the nginx ingress controller runs in the nginx-ingress namespace:

$ kubectl -n nginx-ingress get deploy
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
ingress-nginx-controller   1/1     1            1           8d

The configuration lives in /etc/nginx/nginx.conf in the container. We can cat the file to stdout and look for the relevant directives:

$ kubectl -n nginx-ingress exec deploy/ingress-nginx-controller cat /etc/nginx/nginx.conf
...
location /api/v2/$metadata/ {
...
}
...

Based on your comment, the following seems to work:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: "/$2"
cert-manager.io/cluster-issuer: house
spec:
ingressClassName: nginx
tls:
- hosts:
- example.apps.infra.house
secretName: example-cert
rules:
- host: example.apps.infra.house
http:
paths:
- path: /app1(/|$)(.*)
pathType: Prefix
backend:
service:
name: example-app1
port:
name: http
# Note the use of single quotes (') here; this is
# important; using double quotes we would need to
# write `\\$` instead of `\$`.
- path: '/api/v2/\$metadata'
pathType: Prefix
backend:
service:
name: example-app2
port:
name: http

The resulting location directives look like:

location ~* "^/api/v2/\$metadata" {
...
}
location ~* "^/app1(/|$)(.*)" {
...
}

And a request for the $metadata path succeeds.

huangapple
  • 本文由 发表于 2023年2月10日 07:19:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75405465.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定