Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

snippets are not always working with 2 Ingress controllers #10802

Closed
klauserber opened this issue Dec 24, 2023 · 6 comments
Closed

snippets are not always working with 2 Ingress controllers #10802

klauserber opened this issue Dec 24, 2023 · 6 comments
Labels
needs-kind Indicates a PR lacks a `kind/foo` label and requires one. needs-priority needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one.

Comments

@klauserber
Copy link

klauserber commented Dec 24, 2023

What happened:
Deployment of a simple Ingress with a server snippet leads to the error:

Failed to save resource: admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: nginx.ingress.kubernetes.io/server-snippet annotation cannot be used. Snippet directives are disabled by the Ingress administrator

See my next comment to reproduce it in kind -> #10802 (comment)

Solution -> #10802 (comment)

Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-app-public
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |-
      server_tokens off;
spec:
  ingressClassName: nginx-public
  rules:
    - host: hello-app.sw.isium.de
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: hello-app
                port:
                  number: 80

It is a fresh helm install, here are the values:

controller:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: swerk/node-type
            operator: In
            values:
            - edge
  allowSnippetAnnotations: true
  extraArgs:
    default-ssl-certificate: nginx-public/nginx-public-default-cert-tls
  hostPort:
    enabled: true
  ingressClass: nginx-public
  ingressClassResource:
    default: false
    name: nginx-public
  kind: DaemonSet
  resources:
    limits:
      memory: 200Mi
    requests:
      cpu: 25m
      memory: 90Mi
  service:
    enabled: false
    type: ClusterIP
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoSchedule
    key: swerk/edge-node
    operator: Exists

I have tried to set controller.config.allow-snippet-annotations: "true" with the same result.

What you expected to happen:

-snippet annotations are working as expected. This is a stripped down example. In reality I want to set the Annotation nginx.ingress.kubernetes.io/modsecurity-snippet

NGINX Ingress controller version (exec into the pod and run nginx-ingress-controller --version.):

-------------------------------------------------------------------------------
NGINX Ingress controller
  Release:       v1.9.5
  Build:         f503c4bb5fa7d857ad29e94970eb550c2bc00b7c
  Repository:    https://github.com/kubernetes/ingress-nginx
  nginx version: nginx/1.21.6

-------------------------------------------------------------------------------

Kubernetes version (use kubectl version):

kubectl version
Client Version: v1.28.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.27.8-gke.1067000

Environment:

  • Cloud provider or hardware configuration: Google gke
  • OS (e.g. from /etc/os-release): Container-Optimized OS
  • Kernel (e.g. uname -a): Linux gke-prod-edge-76c8d95c-1hm2 5.15.133+ Basic structure  #1 SMP Fri Dec 1 13:04:48 UTC 2023 x86_64 Intel(R) Xeon(R) CPU @ 2.20GHz GenuineIntel GNU/Linux
  • Install tools: OpenTofu/Google Terraform provider
    • Please mention how/where was the cluster created like kubeadm/kops/minikube/kind etc.
  • Basic cluster related info:
kubectl get no -o wide
NAME                          STATUS   ROLES    AGE   VERSION               INTERNAL-IP   EXTERNAL-IP     OS-IMAGE                             KERNEL-VERSION   CONTAINER-RUNTIME
gke-prod-base-00b0a819-15vt   Ready    <none>   26h   v1.27.8-gke.1067000   10.52.80.5    <none>          Container-Optimized OS from Google   5.15.133+        containerd://1.7.7
gke-prod-base-00b0a819-81dj   Ready    <none>   26h   v1.27.8-gke.1067000   10.52.80.6    <none>          Container-Optimized OS from Google   5.15.133+        containerd://1.7.7
gke-prod-edge-76c8d95c-1hm2   Ready    <none>   26h   v1.27.8-gke.1067000   10.52.80.4    34.141.110.41   Container-Optimized OS from Google   5.15.133+        containerd://1.7.7
  • How was the ingress-nginx-controller installed:
    • If helm was used then please show output of helm ls -A | grep -i ingress
nginx-public            nginx-public            3               2023-12-24 10:27:24.508810721 +0000 UTC deployed        ingress-nginx-4.9.0          1.9.5
  • If helm was used then please show output of helm -n <ingresscontrollernamespace> get values <helmreleasename>
  • If helm was not used, then copy/paste the complete precise command used to install the controller, along with the flags and options used
  • if you have more than one instance of the ingress-nginx-controller installed in the same cluster, please provide details for all the instances
USER-SUPPLIED VALUES:
controller:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: swerk/node-type
            operator: In
            values:
            - edge
  allowSnippetAnnotations: true
  extraArgs:
    default-ssl-certificate: nginx-public/nginx-public-default-cert-tls
  hostPort:
    enabled: true
  ingressClass: nginx-public
  ingressClassResource:
    default: false
    name: nginx-public
  kind: DaemonSet
  resources:
    limits:
      memory: 200Mi
    requests:
      cpu: 25m
      memory: 90Mi
  service:
    enabled: false
    type: ClusterIP
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoSchedule
    key: swerk/edge-node
    operator: Exists
  • Current State of the controller:
    • kubectl describe ingressclasses
Name:         nginx-internal
Labels:       app.kubernetes.io/component=controller
              app.kubernetes.io/instance=nginx-internal
              app.kubernetes.io/managed-by=Helm
              app.kubernetes.io/name=ingress-nginx
              app.kubernetes.io/part-of=ingress-nginx
              app.kubernetes.io/version=1.9.5
              helm.sh/chart=ingress-nginx-4.9.0
Annotations:  ingressclass.kubernetes.io/is-default-class: true
              meta.helm.sh/release-name: nginx-internal
              meta.helm.sh/release-namespace: nginx-internal
Controller:   k8s.io/ingress-nginx
Events:       <none>


Name:         nginx-public
Labels:       app.kubernetes.io/component=controller
              app.kubernetes.io/instance=nginx-public
              app.kubernetes.io/managed-by=Helm
              app.kubernetes.io/name=ingress-nginx
              app.kubernetes.io/part-of=ingress-nginx
              app.kubernetes.io/version=1.9.5
              helm.sh/chart=ingress-nginx-4.9.0
Annotations:  meta.helm.sh/release-name: nginx-public
              meta.helm.sh/release-namespace: nginx-public
Controller:   k8s.io/ingress-nginx
Events:       <none>
  • kubectl -n <ingresscontrollernamespace> get all -A -o wide -> to much Informations for now
  • kubectl -n <ingresscontrollernamespace> describe po <ingresscontrollerpodname>
kubectl -n nginx-public describe po nginx-public-ingress-nginx-controller-xfd62 
Name:             nginx-public-ingress-nginx-controller-xfd62
Namespace:        nginx-public
Priority:         0
Service Account:  nginx-public-ingress-nginx
Node:             gke-prod-edge-76c8d95c-1hm2/10.52.80.4
Start Time:       Sun, 24 Dec 2023 10:22:48 +0000
Labels:           app.kubernetes.io/component=controller
                  app.kubernetes.io/instance=nginx-public
                  app.kubernetes.io/managed-by=Helm
                  app.kubernetes.io/name=ingress-nginx
                  app.kubernetes.io/part-of=ingress-nginx
                  app.kubernetes.io/version=1.9.5
                  controller-revision-hash=675554f8c7
                  helm.sh/chart=ingress-nginx-4.9.0
                  pod-template-generation=1
Annotations:      cni.projectcalico.org/containerID: e8d5508d8f8a702e47411017e82da9c48fbd1e94d753c3df70c7d1ded826b10e
                  cni.projectcalico.org/podIP: 10.52.96.26/32
                  cni.projectcalico.org/podIPs: 10.52.96.26/32
Status:           Running
IP:               10.52.96.26
IPs:
  IP:           10.52.96.26
Controlled By:  DaemonSet/nginx-public-ingress-nginx-controller
Containers:
  controller:
    Container ID:    containerd://e3e7b35a32fece5b1115043da550e3f9c482bd7e752eddbe8aac8be980f4aece
    Image:           registry.k8s.io/ingress-nginx/controller:v1.9.5@sha256:b3aba22b1da80e7acfc52b115cae1d4c687172cbf2b742d5b502419c25ff340e
    Image ID:        registry.k8s.io/ingress-nginx/controller@sha256:b3aba22b1da80e7acfc52b115cae1d4c687172cbf2b742d5b502419c25ff340e
    Ports:           80/TCP, 443/TCP, 8443/TCP
    Host Ports:      80/TCP, 443/TCP, 0/TCP
    SeccompProfile:  RuntimeDefault
    Args:
      /nginx-ingress-controller
      --election-id=nginx-public-ingress-nginx-leader
      --controller-class=k8s.io/ingress-nginx
      --ingress-class=nginx-public
      --configmap=$(POD_NAMESPACE)/nginx-public-ingress-nginx-controller
      --validating-webhook=:8443
      --validating-webhook-certificate=/usr/local/certificates/cert
      --validating-webhook-key=/usr/local/certificates/key
      --default-ssl-certificate=nginx-public/nginx-public-default-cert-tls
    State:          Running
      Started:      Sun, 24 Dec 2023 10:22:49 +0000
    Ready:          True
    Restart Count:  0
    Limits:
      memory:  200Mi
    Requests:
      cpu:      25m
      memory:   90Mi
    Liveness:   http-get http://:10254/healthz delay=10s timeout=1s period=10s #success=1 #failure=5
    Readiness:  http-get http://:10254/healthz delay=10s timeout=1s period=10s #success=1 #failure=3
    Environment:
      POD_NAME:       nginx-public-ingress-nginx-controller-xfd62 (v1:metadata.name)
      POD_NAMESPACE:  nginx-public (v1:metadata.namespace)
      LD_PRELOAD:     /usr/local/lib/libmimalloc.so
    Mounts:
      /usr/local/certificates/ from webhook-cert (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jvrgw (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  webhook-cert:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  nginx-public-ingress-nginx-admission
    Optional:    false
  kube-api-access-jvrgw:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   Burstable
Node-Selectors:              kubernetes.io/os=linux
Tolerations:                 node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                             node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                             node.kubernetes.io/not-ready:NoExecute op=Exists
                             node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                             node.kubernetes.io/unreachable:NoExecute op=Exists
                             node.kubernetes.io/unschedulable:NoSchedule op=Exists
                             swerk/edge-node:NoSchedule op=Exists
Events:
  Type    Reason     Age                From                      Message
  ----    ------     ----               ----                      -------
  Normal  Scheduled  26m                default-scheduler         Successfully assigned nginx-public/nginx-public-ingress-nginx-controller-xfd62 to gke-prod-edge-76c8d95c-1hm2
  Normal  Pulled     26m                kubelet                   Container image "registry.k8s.io/ingress-nginx/controller:v1.9.5@sha256:b3aba22b1da80e7acfc52b115cae1d4c687172cbf2b742d5b502419c25ff340e" already present on machine
  Normal  Created    26m                kubelet                   Created container controller
  Normal  Started    26m                kubelet                   Started container controller
  Normal  RELOAD     24m (x2 over 26m)  nginx-ingress-controller  NGINX reload triggered due to a change in configuration
  • kubectl -n <ingresscontrollernamespace> describe svc <ingresscontrollerservicename> -> no Service hostPort is used

  • Current state of ingress object, if applicable:

    • kubectl -n <appnamespace> get all,ing -o wide
kubectl get all,ing -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP            NODE                          NOMINATED NODE   READINESS GATES
pod/hello-app-f764f5c6f-rbmvp   1/1     Running   0          25h   10.52.98.20   gke-prod-base-00b0a819-81dj   <none>           <none>

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/hello-app    ClusterIP   10.52.75.253   <none>        80/TCP    25h   app=hello-app
service/kubernetes   ClusterIP   10.52.64.1     <none>        443/TCP   27h   <none>

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES             SELECTOR
deployment.apps/hello-app   1/1     1            1           25h   hello-app    nginxdemos/hello   app=hello-app

NAME                                  DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES             SELECTOR
replicaset.apps/hello-app-f764f5c6f   1         1         1       25h   hello-app    nginxdemos/hello   app=hello-app,pod-template-hash=f764f5c6f

NAME                                         CLASS            HOSTS                       ADDRESS         PORTS   AGE
ingress.networking.k8s.io/hello-app          nginx-internal   hello-app.XXXXXXXXXXXXXXXX   34.141.110.41   80      25h
ingress.networking.k8s.io/hello-app-public   nginx-public     hello-app.XXXXXXXXXXXXXX       34.141.110.41   80      87m
  • kubectl -n <appnamespace> describe ing <ingressname>
 kubectl describe ing hello-app-public 
Name:             hello-app-public
Labels:           <none>
Namespace:        default
Address:          10.52.64.11
Ingress Class:    nginx-public
Default backend:  <default>
Rules:
  Host                   Path  Backends
  ----                   ----  --------
  hello-app.XXXXXXXXXXXXXXXXXXXXXX  
                         /   hello-app:80 (10.52.98.20:80)
Annotations:             nginx.ingress.kubernetes.io/enable-modsecurity: true
                         nginx.ingress.kubernetes.io/enable-owasp-core-rules: true
Events:
  Type    Reason  Age                    From                      Message
  ----    ------  ----                   ----                      -------
  Normal  Sync    60m (x27 over 72m)     nginx-ingress-controller  Scheduled for sync
  Normal  Sync    43m (x23 over 54m)     nginx-ingress-controller  Scheduled for sync
  Normal  Sync    34m (x16 over 42m)     nginx-ingress-controller  Scheduled for sync
  Normal  Sync    33m (x3 over 34m)      nginx-ingress-controller  Scheduled for sync
  Normal  Sync    4m49s (x159 over 89m)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    4m49s (x159 over 89m)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    2m6s (x61 over 32m)    nginx-ingress-controller  Scheduled for sync

  • If applicable, then, your complete and exact curl/grpcurl command (redacted if required) and the reponse to the curl/grpcurl command with the -v flag -> not applicable

  • Others:

    • Any other related information like ;
      • copy/paste of the snippet (if applicable)
      • kubectl describe ... of any custom configmap(s) created and in use
kubectl -n nginx-public describe cm nginx-public-ingress-nginx-controller 
Name:         nginx-public-ingress-nginx-controller
Namespace:    nginx-public
Labels:       app.kubernetes.io/component=controller
              app.kubernetes.io/instance=nginx-public
              app.kubernetes.io/managed-by=Helm
              app.kubernetes.io/name=ingress-nginx
              app.kubernetes.io/part-of=ingress-nginx
              app.kubernetes.io/version=1.9.5
              helm.sh/chart=ingress-nginx-4.9.0
Annotations:  meta.helm.sh/release-name: nginx-public
              meta.helm.sh/release-namespace: nginx-public

Data
====
allow-snippet-annotations:
----
true

BinaryData
====

Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  CREATE  35m   nginx-ingress-controller  ConfigMap nginx-public/nginx-public-ingress-nginx-controller
  Normal  UPDATE  32m   nginx-ingress-controller  ConfigMap nginx-public/nginx-public-ingress-nginx-controller
- Any other related information that may help

How to reproduce this issue:

I cannot reproduce is with a minimal kind based example. Still try it.

Anything else we need to know:

@klauserber klauserber added the kind/bug Categorizes issue or PR as related to a bug. label Dec 24, 2023
@k8s-ci-robot
Copy link
Contributor

This issue is currently awaiting triage.

If Ingress contributors determines this is a relevant issue, they will accept it by applying the triage/accepted label and provide further guidance.

The triage/accepted label can be added by org members by writing /triage accepted in a comment.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. needs-priority labels Dec 24, 2023
@klauserber
Copy link
Author

I have 2 Ingress Controllers installed. One has allowSnippetAnnotations: false and one has allowSnippetAnnotations: true. Apparently every Ingress Object is validated bei all Admission Controllers.

Reproduction in kind:

we need to values files:

values-1.yaml:

controller:
  allowSnippetAnnotations: false

  ingressClassResource:
    name: nginx-1

  ingressClass: nginx-1

values-2.yaml:

controller:
  allowSnippetAnnotations: true

  ingressClassResource:
    name: nginx-2

  ingressClass: nginx-2

and 2 Ingress objects:

ingress-1.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
spec:
  ingressClassName: nginx-1
  rules:
  - host: foo.bar
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: http-svc
            port:
              number: 80

ingress-2.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |-
      server_tokens off;
spec:
  ingressClassName: nginx-2
  rules:
  - host: foo.bar
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: http-svc
            port:
              number: 80

Try to install everything:

helm upgrade -i ingress-nginx-1 ingress-nginx/ingress-nginx --version 4.9.0 -f values-1.yaml
helm upgrade -i ingress-nginx-2 ingress-nginx/ingress-nginx --version 4.9.0 -f values-2.yaml

kubectl apply -f ingress-1.yaml
kubectl apply -f ingress-2.yaml

The last command produces the error:

kubectl apply -f ingress-2.yaml
Error from server (BadRequest): error when creating "ingress-2.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: nginx.ingress.kubernetes.io/server-snippet annotation cannot be used. Snippet directives are disabled by the Ingress administrator

I think this is a veto from the wrong admission controller (from ingress-1 Ingress controller)

@klauserber klauserber changed the title snippets are not working snippets are not always working with 2 Ingress controllers Dec 24, 2023
@longwuyuan
Copy link
Contributor

longwuyuan commented Dec 25, 2023

/remove-kind bug

Need data because test on minikube works
Can you kindly check if the 2 instances of the controller that you have installed, are meeting the uniqueness criteria described here https://kubernetes.github.io/ingress-nginx/user-guide/k8s-122-migration/#how-can-i-easily-install-multiple-instances-of-the-ingress-nginx-controller-in-the-same-cluster. If you have installed both instances of the controller in same namespace, can you put them in 2 different namespaces just for sanity sake.

@k8s-ci-robot k8s-ci-robot added needs-kind Indicates a PR lacks a `kind/foo` label and requires one. and removed kind/bug Categorizes issue or PR as related to a bug. labels Dec 25, 2023
@klauserber
Copy link
Author

ok, thank you @longwuyuan it is solved.

Key was indeed to follow the howto to deploy multiple ingress controllers: https://kubernetes.github.io/ingress-nginx/user-guide/k8s-122-migration/#how-can-i-easily-install-multiple-instances-of-the-ingress-nginx-controller-in-the-same-cluster

It was the missing controller.ingressClassResource.controllerValue in the helm releases.

Here is a full working example (testet in kind):

values-1.yaml

controller:
  allowSnippetAnnotations: false

  ingressClassResource:
    enabled: true
    name: nginx-1
    controllerValue: mydomain.org/ingress-1
  ingressClass: nginx-1
  ingressClassByName: true

values-2.yaml

controller:
  allowSnippetAnnotations: true

  ingressClassResource:
    enabled: true
    name: nginx-2
    controllerValue: mydomain.org/ingress-2
  ingressClass: nginx-2
  ingressClassByName: true

ingress-1.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
spec:
  ingressClassName: nginx-1
  rules:
  - host: foo.bar
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: http-svc
            port:
              number: 80

ingress-2.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |-
      server_tokens off;
spec:
  ingressClassName: nginx-2
  rules:
  - host: foo.bar
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: http-svc
            port:
              number: 80

create two namespaces

kubectl create ns ingress-1
kubectl create ns ingress-2

install ingress-nginx in both namespaces

helm upgrade -i -n ingress-1 ingress-nginx-1 ingress-nginx/ingress-nginx --version 4.9.0 -f values-1.yaml
helm upgrade -i -n ingress-2 ingress-nginx-2 ingress-nginx/ingress-nginx --version 4.9.0 -f values-2.yaml

create two ingress objects

kubectl -n ingress-1 apply -f ingress-1.yaml
kubectl -n ingress-2 apply -f ingress-2.yaml

@longwuyuan
Copy link
Contributor

awesome. Thanks 🙏

/close

@k8s-ci-robot
Copy link
Contributor

@longwuyuan: Closing this issue.

In response to this:

awesome. Thanks 🙏

/close

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-kind Indicates a PR lacks a `kind/foo` label and requires one. needs-priority needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one.
Projects
Archived in project
Development

No branches or pull requests

3 participants