diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 07770e47c..e15a2cd2b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -37,7 +37,7 @@ This questions are the first thing we need to know to understand the context. -**NGINX Ingress controller version** (exec into the pod and run `/nginx-ingress-controller --version`): +**NGINX Ingress controller version** (exec into the pod and run nginx-ingress-controller --version.): ## Quick start @@ -67,19 +67,14 @@ helm show values ingress-nginx --repo https://kubernetes.github.io/ingress-nginx !!! attention "Helm install on AWS/GCP/Azure/Other providers" The *ingress-nginx-controller helm-chart is a generic install out of the box*. The default set of helm values is **not** configured for installation on any infra provider. The annotations that are applicable to the cloud provider must be customized by the users.
- See [AWS LB Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/).
- Examples of some annotations recommended (healthecheck ones are required for target-type IP) for the service resource of `--type LoadBalancer` on AWS are below: + See [AWS LB Constroller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/).
+ Examples of some annotations needed for the service resource of `--type LoadBalancer` on AWS are below: ```yaml annotations: - service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: deregistration_delay.timeout_seconds=270 - service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip - service.beta.kubernetes.io/aws-load-balancer-healthcheck-path: /healthz - service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "10254" - service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: http - service.beta.kubernetes.io/aws-load-balancer-healthcheck-success-codes: 200-299 service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing" service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" + service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" service.beta.kubernetes.io/aws-load-balancer-type: nlb service.beta.kubernetes.io/aws-load-balancer-manage-backend-security-group-rules: "true" service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true" @@ -92,7 +87,7 @@ helm show values ingress-nginx --repo https://kubernetes.github.io/ingress-nginx **If you don't have Helm** or if you prefer to use a YAML manifest, you can run the following command instead: ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/cloud/deploy.yaml ``` !!! info @@ -271,10 +266,11 @@ In AWS, we use a Network load balancer (NLB) to expose the Ingress-Nginx Control [Network load balancing on Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html) with [AWS Load Balancer Controller](https://github.com/kubernetes-sigs/aws-load-balancer-controller). + ##### Network Load Balancer (NLB) ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/aws/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/aws/deploy.yaml ``` ##### TLS termination in AWS Load Balancer (NLB) @@ -282,10 +278,10 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/cont By default, TLS is terminated in the ingress controller. But it is also possible to terminate TLS in the Load Balancer. This section explains how to do that on AWS using an NLB. -1. Download the [deploy.yaml](https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml) template +1. Download the [deploy.yaml](https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml) template ```console - wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml + wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml ``` 2. Edit the file and change the VPC CIDR in use for the Kubernetes cluster: @@ -333,7 +329,7 @@ kubectl create clusterrolebinding cluster-admin-binding \ Then, the ingress controller can be installed like this: ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/cloud/deploy.yaml ``` !!! warning @@ -342,7 +338,7 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/cont `10254/tcp` to also allow access to port `8443/tcp`. More information can be found in the [Official GCP Documentation](https://cloud.google.com/load-balancing/docs/tcp/setting-up-tcp#config-hc-firewall). - See the [GKE documentation](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules) + See the [GKE documentation](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules) on adding rules and the [Kubernetes issue](https://github.com/kubernetes/kubernetes/issues/79739) for more detail. Proxy-protocol is supported in GCE check the [Official Documentations on how to enable.](https://cloud.google.com/load-balancing/docs/tcp/setting-up-tcp#proxy-protocol) @@ -350,7 +346,7 @@ Proxy-protocol is supported in GCE check the [Official Documentations on how to #### Azure ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/cloud/deploy.yaml ``` More information with regard to Azure annotations for ingress controller can be found in the [official AKS documentation](https://docs.microsoft.com/en-us/azure/aks/ingress-internal-ip#create-an-ingress-controller). @@ -358,7 +354,7 @@ More information with regard to Azure annotations for ingress controller can be #### Digital Ocean ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/do/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/do/deploy.yaml ``` - By default the service object of the ingress-nginx-controller for Digital-Ocean, only configures one annotation. Its this one `service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true"`. While this makes the service functional, it was reported that the Digital-Ocean LoadBalancer graphs shows `no data`, unless a few other annotations are also configured. Some of these other annotations require values that can not be generic and hence not forced in a out-of-the-box installation. These annotations and a discussion on them is well documented in [this issue](https://github.com/kubernetes/ingress-nginx/issues/8965). Please refer to the issue to add annotations, with values specific to user, to get graphs of the DO-LB populated with data. @@ -366,11 +362,11 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/cont #### Scaleway ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/scw/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/scw/deploy.yaml ``` - Refer to the [dedicated tutorial](https://www.scaleway.com/en/docs/tutorials/proxy-protocol-v2-load-balancer/#configuring-proxy-protocol-for-ingress-nginx) in the Scaleway documentation for configuring the proxy protocol for ingress-nginx with the Scaleway load balancer. + #### Exoscale ```console @@ -383,7 +379,7 @@ The full list of annotations supported by Exoscale is available in the Exoscale #### Oracle Cloud Infrastructure ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/cloud/deploy.yaml ``` A @@ -410,7 +406,7 @@ For quick testing, you can use a This should work on almost every cluster, but it will typically use a port in the range 30000-32767. ```console -kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/baremetal/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.3/deploy/static/provider/baremetal/deploy.yaml ``` For more information about bare metal deployments (and how to use port 80 instead of a random port in the 30000-32767 range), @@ -432,7 +428,7 @@ kubectl exec $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version By default, the controller watches Ingress objects from all namespaces. If you want to change this behavior, use the flag `--watch-namespace` or check the Helm chart value `controller.scope` to limit the controller to a single -namespace. Although the use of this flag is not popular, one important fact to note is that the secret containing the default-ssl-certificate needs to also be present in the watched namespace(s). +namespace. See also [“How to easily install multiple instances of the Ingress NGINX controller in the same cluster”](https://kubernetes.github.io/ingress-nginx/#how-to-easily-install-multiple-instances-of-the-ingress-nginx-controller-in-the-same-cluster) diff --git a/docs/e2e-tests.md b/docs/e2e-tests.md index 43726f5a1..666d40ae3 100644 --- a/docs/e2e-tests.md +++ b/docs/e2e-tests.md @@ -7,17 +7,18 @@ Do not try to edit it manually. ### [[Admission] admission controller](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L39) -- [should not allow overlaps of host and paths without canary annotations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L47) -- [should allow overlaps of host and paths with canary annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L64) -- [should block ingress with invalid path](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L85) -- [should return an error if there is an error validating the ingress definition](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L102) -- [should return an error if there is an invalid value in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L116) -- [should return an error if there is a forbidden value in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L130) -- [should return an error if there is an invalid path and wrong pathType is set](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L144) -- [should not return an error if the Ingress V1 definition is valid with Ingress Class](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L178) -- [should not return an error if the Ingress V1 definition is valid with IngressClass annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L194) -- [should return an error if the Ingress V1 definition contains invalid annotations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L210) -- [should not return an error for an invalid Ingress when it has unknown class](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L224) +- [reject ingress with global-rate-limit annotations when memcached is not configured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L47) +- [should not allow overlaps of host and paths without canary annotations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L74) +- [should allow overlaps of host and paths with canary annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L91) +- [should block ingress with invalid path](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L112) +- [should return an error if there is an error validating the ingress definition](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L129) +- [should return an error if there is an invalid value in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L149) +- [should return an error if there is a forbidden value in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L163) +- [should return an error if there is an invalid path and wrong pathType is set](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L177) +- [should not return an error if the Ingress V1 definition is valid with Ingress Class](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L211) +- [should not return an error if the Ingress V1 definition is valid with IngressClass annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L227) +- [should return an error if the Ingress V1 definition contains invalid annotations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L243) +- [should not return an error for an invalid Ingress when it has unknown class](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/admission/admission.go#L263) ### [affinity session-cookie-name](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/affinity.go#L43) - [should set sticky cookie SERVERID](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/affinity.go#L50) - [should change cookie name on ingress definition change](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/affinity.go#L72) @@ -53,24 +54,24 @@ Do not try to edit it manually. - [should return status code 200 when authentication is configured with a map and Authorization header is sent](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L205) - [should return status code 401 when authentication is configured with invalid content and Authorization header is sent](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L233) - [proxy_set_header My-Custom-Header 42;](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L272) -- [proxy_set_header My-Custom-Header 42;](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L292) -- [proxy_set_header 'My-Custom-Header' '42';](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L311) -- [user retains cookie by default](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L420) -- [user does not retain cookie if upstream returns error status code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L431) -- [user with annotated ingress retains cookie if upstream returns error status code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L442) -- [should return status code 200 when signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L481) -- [should redirect to signin url when not signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L490) -- [keeps processing new ingresses even if one of the existing ingresses is misconfigured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L501) -- [should overwrite Foo header with auth response](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L525) -- [should return status code 200 when signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L701) -- [should redirect to signin url when not signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L710) -- [keeps processing new ingresses even if one of the existing ingresses is misconfigured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L721) -- [should return status code 200 when signed in after auth backend is deleted ](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L780) -- [should deny login for different location on same server](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L800) -- [should deny login for different servers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L828) -- [should redirect to signin url when not signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L857) -- [should return 503 (location was denied)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L887) -- [should add error to the config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L895) +- [proxy_set_header My-Custom-Header 42;](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L298) +- [proxy_set_header 'My-Custom-Header' '42';](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L324) +- [user retains cookie by default](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L433) +- [user does not retain cookie if upstream returns error status code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L444) +- [user with annotated ingress retains cookie if upstream returns error status code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L455) +- [should return status code 200 when signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L494) +- [should redirect to signin url when not signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L503) +- [keeps processing new ingresses even if one of the existing ingresses is misconfigured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L514) +- [should overwrite Foo header with auth response](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L538) +- [should return status code 200 when signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L714) +- [should redirect to signin url when not signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L723) +- [keeps processing new ingresses even if one of the existing ingresses is misconfigured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L734) +- [should return status code 200 when signed in after auth backend is deleted ](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L793) +- [should deny login for different location on same server](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L813) +- [should deny login for different servers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L841) +- [should redirect to signin url when not signed in](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L870) +- [should return 503 (location was denied)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L900) +- [should add error to the config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/auth.go#L908) ### [auth-tls-*](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/authtls.go#L31) - [should set sslClientCertificate, sslVerifyClient and sslVerifyDepth with auth-tls-secret](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/authtls.go#L38) - [should set valid auth-tls-secret, sslVerify to off, and sslVerifyDepth to 2](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/authtls.go#L86) @@ -148,11 +149,6 @@ Do not try to edit it manually. - [should allow correct origins - missing subdomain + origin with wildcard origin and correct origin](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/cors.go#L540) - [should allow - missing origins (should allow all origins)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/cors.go#L576) - [should allow correct origin but not others - cors allow origin annotations contain trailing comma](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/cors.go#L636) -- [should allow - origins with non-http[s] protocols](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/cors.go#L673) -### [custom-headers-*](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/customheaders.go#L33) -- [should return status code 200 when no custom-headers is configured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/customheaders.go#L40) -- [should return status code 503 when custom-headers is configured with an invalid secret](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/customheaders.go#L57) -- [more_set_headers 'My-Custom-Header' '42';](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/customheaders.go#L78) ### [custom-http-errors](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/customhttperrors.go#L34) - [configures Nginx correctly](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/customhttperrors.go#L41) ### [default-backend](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/default_backend.go#L29) @@ -173,13 +169,13 @@ Do not try to edit it manually. ### [from-to-www-redirect](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/fromtowwwredirect.go#L31) - [should redirect from www HTTP to HTTP](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/fromtowwwredirect.go#L38) - [should redirect from www HTTPS to HTTPS](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/fromtowwwredirect.go#L64) -### [backend-protocol - GRPC](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L45) -- [should use grpc_pass in the configuration file](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L48) -- [should return OK for service with backend protocol GRPC](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L71) -- [authorization metadata should be overwritten by external auth response headers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L132) -- [should return OK for service with backend protocol GRPCS](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L193) -- [should return OK when request not exceed timeout](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L260) -- [should return Error when request exceed timeout](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L303) +### [annotation-global-rate-limit](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/globalratelimit.go#L30) +- [generates correct configuration](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/globalratelimit.go#L38) +### [backend-protocol - GRPC](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L40) +- [should use grpc_pass in the configuration file](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L43) +- [should return OK for service with backend protocol GRPC](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L68) +- [authorization metadata should be overwritten by external auth response headers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L129) +- [should return OK for service with backend protocol GRPCS](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/grpc.go#L190) ### [http2-push-preload](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/http2pushpreload.go#L27) - [enable the http2-push-preload directive](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/http2pushpreload.go#L34) ### [allowlist-source-range](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/ipallowlist.go#L27) @@ -203,14 +199,14 @@ Do not try to edit it manually. - [should enable modsecurity with transaction ID and OWASP rules](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L64) - [should disable modsecurity](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L85) - [should enable modsecurity with snippet](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L102) -- [should enable modsecurity without using 'modsecurity on;'](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L124) -- [should disable modsecurity using 'modsecurity off;'](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L147) -- [should enable modsecurity with snippet and block requests](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L169) -- [should enable modsecurity globally and with modsecurity-snippet block requests](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L202) -- [should enable modsecurity when enable-owasp-modsecurity-crs is set to true](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L235) -- [should enable modsecurity through the config map](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L269) -- [should enable modsecurity through the config map but ignore snippet as disabled by admin](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L309) -- [should disable default modsecurity conf setting when modsecurity-snippet is specified](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L354) +- [should enable modsecurity without using 'modsecurity on;'](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L130) +- [should disable modsecurity using 'modsecurity off;'](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L153) +- [should enable modsecurity with snippet and block requests](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L175) +- [should enable modsecurity globally and with modsecurity-snippet block requests](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L214) +- [should enable modsecurity when enable-owasp-modsecurity-crs is set to true](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L253) +- [should enable modsecurity through the config map](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L292) +- [should enable modsecurity through the config map but ignore snippet as disabled by admin](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L338) +- [should disable default modsecurity conf setting when modsecurity-snippet is specified](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/modsecurity/modsecurity.go#L380) ### [preserve-trailing-slash](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/preservetrailingslash.go#L27) - [should allow preservation of trailing slashes](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/preservetrailingslash.go#L34) ### [proxy-*](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L30) @@ -222,10 +218,10 @@ Do not try to edit it manually. - [should set valid proxy timeouts](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L117) - [should not set invalid proxy timeouts](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L138) - [should turn on proxy-buffering](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L159) -- [should turn off proxy-request-buffering](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L184) -- [should build proxy next upstream](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L199) -- [should setup proxy cookies](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L220) -- [should change the default proxy HTTP version](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L238) +- [should turn off proxy-request-buffering](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L181) +- [should build proxy next upstream](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L196) +- [should setup proxy cookies](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L217) +- [should change the default proxy HTTP version](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxy.go#L235) ### [proxy-ssl-*](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxyssl.go#L32) - [should set valid proxy-ssl-secret](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxyssl.go#L39) - [should set valid proxy-ssl-secret, proxy-ssl-verify to on, proxy-ssl-verify-depth to 2, and proxy-ssl-server-name to on](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/proxyssl.go#L66) @@ -235,10 +231,6 @@ Do not try to edit it manually. ### [permanent-redirect permanent-redirect-code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/redirect.go#L30) - [should respond with a standard redirect code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/redirect.go#L33) - [should respond with a custom redirect code](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/redirect.go#L61) -### [relative-redirects](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/relativeredirects.go#L35) -- [configures Nginx correctly](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/relativeredirects.go#L43) -- [should respond with absolute URL in Location](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/relativeredirects.go#L61) -- [should respond with relative URL in Location](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/relativeredirects.go#L85) ### [rewrite-target use-regex enable-rewrite-log](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/rewrite.go#L32) - [should write rewrite logs](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/rewrite.go#L39) - [should use correct longest path match](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/rewrite.go#L68) @@ -255,13 +247,13 @@ Do not try to edit it manually. - [should not use the Service Cluster IP and Port](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/serviceupstream.go#L97) ### [configuration-snippet](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/snippet.go#L28) - [set snippet more_set_headers in all locations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/snippet.go#L34) -- [drops snippet more_set_header in all locations if disabled by admin](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/snippet.go#L66) +- [drops snippet more_set_header in all locations if disabled by admin](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/snippet.go#L73) ### [ssl-ciphers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/sslciphers.go#L28) - [should change ssl ciphers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/sslciphers.go#L35) - [should keep ssl ciphers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/sslciphers.go#L58) ### [stream-snippet](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/streamsnippet.go#L34) - [should add value of stream-snippet to nginx config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/streamsnippet.go#L41) -- [should add stream-snippet and drop annotations per admin config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/streamsnippet.go#L88) +- [should add stream-snippet and drop annotations per admin config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/streamsnippet.go#L94) ### [upstream-hash-by-*](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/upstreamhashby.go#L79) - [should connect to the same pod](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/upstreamhashby.go#L86) - [should connect to the same subset of pods](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/upstreamhashby.go#L95) @@ -270,9 +262,6 @@ Do not try to edit it manually. ### [x-forwarded-prefix](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/xforwardedprefix.go#L28) - [should set the X-Forwarded-Prefix to the annotation value](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/xforwardedprefix.go#L35) - [should not add X-Forwarded-Prefix if the annotation value is empty](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/annotations/xforwardedprefix.go#L57) -### [[CGroups] cgroups](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/cgroups/cgroups.go#L32) -- [detects cgroups version v1](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/cgroups/cgroups.go#L40) -- [detect cgroups version v2](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/cgroups/cgroups.go#L83) ### [Debug CLI](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/dbg/main.go#L29) - [should list the backend servers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/dbg/main.go#L37) - [should get information for a specific backend server](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/dbg/main.go#L56) @@ -287,8 +276,6 @@ Do not try to edit it manually. - [should return a self generated SSL certificate](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/defaultbackend/ssl.go#L29) ### [[Default Backend] change default settings](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/defaultbackend/with_hosts.go#L30) - [should apply the annotation to the default backend](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/defaultbackend/with_hosts.go#L38) -### [[Disable Leader] Routing works when leader election was disabled](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/disableleaderelection/disable_leader.go#L28) -- [should create multiple ingress routings rules when leader election has disabled](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/disableleaderelection/disable_leader.go#L35) ### [[Endpointslices] long service name](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/endpointslices/longname.go#L29) - [should return 200 when service name has max allowed number of characters 63](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/endpointslices/longname.go#L38) ### [[TopologyHints] topology aware routing](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/endpointslices/topology.go#L34) @@ -296,7 +283,7 @@ Do not try to edit it manually. ### [[Shutdown] Grace period shutdown](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/grace_period.go#L32) - [/healthz should return status code 500 during shutdown grace period](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/grace_period.go#L35) ### [[Shutdown] ingress controller](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/shutdown.go#L30) -- [should shutdown in less than 60 seconds without pending connections](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/shutdown.go#L40) +- [should shutdown in less than 60 secons without pending connections](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/shutdown.go#L40) ### [[Shutdown] Graceful shutdown with pending request](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/slow_requests.go#L25) - [should let slow requests finish before shutting down](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/gracefulshutdown/slow_requests.go#L33) ### [[Ingress] DeepInspection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/ingress/deep_inspection.go#L27) @@ -334,15 +321,13 @@ Do not try to edit it manually. - [removes HTTPS configuration when we delete TLS spec](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_certificates.go#L233) ### [[Lua] dynamic configuration](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L41) - [configures balancer Lua middleware correctly](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L49) -- [handles endpoints only changes](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L56) -- [handles endpoints only changes (down scaling of replicas)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L81) -- [handles endpoints only changes consistently (down scaling of replicas vs. empty service)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L119) -- [handles an annotation change](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L165) +- [handles endpoints only changes](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L61) +- [handles endpoints only changes (down scaling of replicas)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L86) +- [handles endpoints only changes consistently (down scaling of replicas vs. empty service)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L124) +- [handles an annotation change](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/lua/dynamic_configuration.go#L170) ### [[metrics] exported prometheus metrics](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L36) -- [exclude socket request metrics are absent](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L51) -- [exclude socket request metrics are present](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L73) -- [request metrics per undefined host are present when flag is set](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L95) -- [request metrics per undefined host are not present when flag is not set](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L128) +- [exclude socket request metrics are absent](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L50) +- [exclude socket request metrics are present](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/metrics/metrics.go#L72) ### [nginx-configuration](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/nginx/nginx.go#L99) - [start nginx with default configuration](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/nginx/nginx.go#L102) - [fails when using alias directive](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/nginx/nginx.go#L114) @@ -375,9 +360,9 @@ Do not try to edit it manually. - [should be disabled when setting is false](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/aio_write.go#L46) ### [Bad annotation values](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L29) - [[BAD_ANNOTATIONS] should drop an ingress if there is an invalid character in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L36) -- [[BAD_ANNOTATIONS] should drop an ingress if there is a forbidden word in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L68) -- [[BAD_ANNOTATIONS] should allow an ingress if there is a default blocklist config in place](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L105) -- [[BAD_ANNOTATIONS] should drop an ingress if there is a custom blocklist config in place and allow others to pass](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L138) +- [[BAD_ANNOTATIONS] should drop an ingress if there is a forbidden word in some annotation](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L75) +- [[BAD_ANNOTATIONS] should allow an ingress if there is a default blocklist config in place](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L119) +- [[BAD_ANNOTATIONS] should drop an ingress if there is a custom blocklist config in place and allow others to pass](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/badannotationvalues.go#L157) ### [brotli](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/brotli.go#L30) - [should only compress responses that meet the `brotli-min-length` condition](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/brotli.go#L38) ### [Configmap change](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/configmap_change.go#L29) @@ -408,7 +393,6 @@ Do not try to edit it manually. ### [Geoip2](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/geoip2.go#L36) - [should include geoip2 line in config when enabled and db file exists](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/geoip2.go#L45) - [should only allow requests from specific countries](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/geoip2.go#L69) -- [should up and running nginx controller using autoreload flag](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/geoip2.go#L122) ### [[Security] block-*](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/global_access_block.go#L28) - [should block CIDRs defined in the ConfigMap](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/global_access_block.go#L38) - [should block User-Agents defined in the ConfigMap](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/global_access_block.go#L55) @@ -424,8 +408,8 @@ Do not try to edit it manually. ### [global-options](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/global_options.go#L28) - [should have worker_rlimit_nofile option](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/global_options.go#L31) - [should have worker_rlimit_nofile option and be independent on amount of worker processes](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/global_options.go#L37) -### [GRPC](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/grpc.go#L39) -- [should set the correct GRPC Buffer Size](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/grpc.go#L42) +### [settings-global-rate-limit](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/globalratelimit.go#L30) +- [generates correct NGINX configuration](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/globalratelimit.go#L38) ### [gzip](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/gzip.go#L30) - [should be disabled by default](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/gzip.go#L40) - [should be enabled with default settings](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/gzip.go#L56) @@ -494,20 +478,22 @@ Do not try to edit it manually. - [should return status code 200 when accessing '/noauth' unauthenticated](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/no_auth_locations.go#L82) ### [Add no tls redirect locations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/no_tls_redirect_locations.go#L27) - [Check no tls redirect locations config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/no_tls_redirect_locations.go#L30) -### [OCSP](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/ocsp/ocsp.go#L43) -- [should enable OCSP and contain stapling information in the connection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/ocsp/ocsp.go#L50) +### [OCSP](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/ocsp/ocsp.go#L42) +- [should enable OCSP and contain stapling information in the connection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/ocsp/ocsp.go#L49) ### [Configure Opentelemetry](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/opentelemetry.go#L39) - [should not exists opentelemetry directive](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/opentelemetry.go#L49) - [should exists opentelemetry directive when is enabled](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/opentelemetry.go#L62) - [should include opentelemetry_trust_incoming_spans on directive when enabled](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/opentelemetry.go#L76) - [should not exists opentelemetry_operation_name directive when is empty](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/opentelemetry.go#L91) - [should exists opentelemetry_operation_name directive when is configured](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/opentelemetry.go#L106) +### [plugins](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/plugins.go#L28) +- [should exist a x-hello-world header](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/plugins.go#L35) ### [proxy-connect-timeout](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_connect_timeout.go#L29) - [should set valid proxy timeouts using configmap values](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_connect_timeout.go#L37) - [should not set invalid proxy timeouts using configmap values](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_connect_timeout.go#L53) ### [Dynamic $proxy_host](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_host.go#L28) - [should exist a proxy_host](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_host.go#L36) -- [should exist a proxy_host using the upstream-vhost annotation value](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_host.go#L60) +- [should exist a proxy_host using the upstream-vhost annotation value](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_host.go#L65) ### [proxy-next-upstream](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_next_upstream.go#L28) - [should build proxy next upstream using configmap values](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_next_upstream.go#L36) ### [use-proxy-protocol](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/proxy_protocol.go#L38) @@ -527,7 +513,7 @@ Do not try to edit it manually. - [reuse port should be enabled](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/reuse-port.go#L52) ### [configmap server-snippet](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_snippet.go#L28) - [should add value of server-snippet setting to all ingress config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_snippet.go#L35) -- [should add global server-snippet and drop annotations per admin config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_snippet.go#L100) +- [should add global server-snippet and drop annotations per admin config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_snippet.go#L98) ### [server-tokens](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_tokens.go#L29) - [should not exists Server header in the response](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_tokens.go#L38) - [should exists Server header in the response when is enabled](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/server_tokens.go#L50) @@ -539,14 +525,14 @@ Do not try to edit it manually. - [should pass unknown traffic to default backend and handle known traffic](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/ssl_passthrough.go#L78) ### [configmap stream-snippet](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/stream_snippet.go#L35) - [should add value of stream-snippet via config map to nginx config](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/stream_snippet.go#L42) -### [[SSL] TLS protocols, ciphers and headers](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L32) -- [setting cipher suite](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L66) -- [setting max-age parameter](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L110) -- [setting includeSubDomains parameter](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L127) -- [setting preload parameter](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L147) -- [overriding what's set from the upstream](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L168) -- [should not use ports during the HTTP to HTTPS redirection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L190) -- [should not use ports or X-Forwarded-Host during the HTTP to HTTPS redirection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L208) +### [[SSL] TLS protocols, ciphers and headers)](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L31) +- [setting cipher suite](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L65) +- [setting max-age parameter](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L109) +- [setting includeSubDomains parameter](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L125) +- [setting preload parameter](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L144) +- [overriding what's set from the upstream](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L164) +- [should not use ports during the HTTP to HTTPS redirection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L186) +- [should not use ports or X-Forwarded-Host during the HTTP to HTTPS redirection](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/tls.go#L204) ### [annotation validations](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/validations/validations.go#L30) - [should allow ingress based on their risk on webhooks](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/validations/validations.go#L33) - [should allow ingress based on their risk on webhooks](https://github.com/kubernetes/ingress-nginx/tree/main//test/e2e/settings/validations/validations.go#L68) diff --git a/docs/examples/canary/README.md b/docs/examples/canary/README.md index 885991a3b..4124faf6f 100644 --- a/docs/examples/canary/README.md +++ b/docs/examples/canary/README.md @@ -31,7 +31,7 @@ spec: spec: containers: - name: production - image: registry.k8s.io/ingress-nginx/e2e-test-echo:v1.1.1@sha256:a1e0152e2eeab26e3f6fd3986f3d82b17bc7711717cae5392dcd18dd447ba6ef + image: registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:6fc5aa2994c86575975bb20a5203651207029a0d28e3f491d8a127d08baadab4 ports: - containerPort: 80 env: @@ -97,7 +97,7 @@ spec: spec: containers: - name: canary - image: registry.k8s.io/ingress-nginx/e2e-test-echo:v1.1.1@sha256:a1e0152e2eeab26e3f6fd3986f3d82b17bc7711717cae5392dcd18dd447ba6ef + image: registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:6fc5aa2994c86575975bb20a5203651207029a0d28e3f491d8a127d08baadab4 ports: - containerPort: 80 env: diff --git a/docs/examples/customization/custom-errors/README.md b/docs/examples/customization/custom-errors/README.md index 2d6e124bb..a7c9545b0 100644 --- a/docs/examples/customization/custom-errors/README.md +++ b/docs/examples/customization/custom-errors/README.md @@ -2,12 +2,11 @@ This example demonstrates how to use a custom backend to render custom error pages. -If you are using the Helm Chart, look at [example values](https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/customization/custom-errors/custom-default-backend.helm.values.yaml) and don't forget to add the [ConfigMap](https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/customization/custom-errors/custom-default-backend-error_pages.configMap.yaml) to your deployment. Otherwise, continue with [Customized default backend](#customized-default-backend) manual deployment. +If you are using Helm Chart, look at [example values](https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/customization/custom-errors/custom-default-backend.helm.values.yaml) and don't forget to add [configMap](https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/customization/custom-errors/custom-default-backend-error_pages.configMap.yaml) to your deployment, otherwise continue with [Customized default backend](#customized-default-backend) manual deployment. ## Customized default backend -First, create the custom `default-backend`. It will be used by the Ingress controller later on. - +First, create the custom `default-backend`. It will be used by the Ingress controller later on. To do that, you can take a look at the [example manifest](https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/customization/custom-errors/custom-default-backend.yaml) in this project's GitHub repository. @@ -39,11 +38,11 @@ If you do not already have an instance of the Ingress-Nginx Controller running, 2. Edit the `ingress-nginx-controller` ConfigMap and create the key `custom-http-errors` with a value of `404,503`. 3. Take note of the IP address assigned to the Ingress-Nginx Controller Service. - ``` - $ kubectl get svc ingress-nginx - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - ingress-nginx ClusterIP 10.0.0.13 80/TCP,443/TCP 10m - ``` + ``` + $ kubectl get svc ingress-nginx + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + ingress-nginx ClusterIP 10.0.0.13 80/TCP,443/TCP 10m + ``` !!! note The `ingress-nginx` Service is of type `ClusterIP` in this example. This may vary depending on your environment. @@ -86,16 +85,3 @@ Vary: Accept-Encoding To go further with this example, feel free to deploy your own applications and Ingress objects, and validate that the responses are still in the correct format when a backend returns 503 (eg. if you scale a Deployment down to 0 replica). - -## Maintenance page - -You can also leverage custom error pages to set a **"_Service under maintenance_" page** for the whole cluster, useful to prevent users from accessing your services while you are performing planned scheduled maintenance. - -When enabled, the maintenance page is served to the clients with an HTTP [**503 Service Unavailable**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) response **status code**. - -To do that: - -- Enable a **custom error page for the 503 HTTP error**, by following the guide above -- Set the value of the `--watch-namespace-selector` flag to the name of some non-existent namespace, e.g. `nonexistent-namespace` - - This effectively prevents the NGINX Ingress Controller from reading `Ingress` resources from any namespace in the Kubernetes cluster -- Set your `location-snippet` to `return 503;`, to make the NGINX Ingress Controller always return the 503 HTTP error page for all the requests diff --git a/docs/examples/customization/custom-errors/custom-default-backend.helm.values.yaml b/docs/examples/customization/custom-errors/custom-default-backend.helm.values.yaml index d72001d58..708a93831 100644 --- a/docs/examples/customization/custom-errors/custom-default-backend.helm.values.yaml +++ b/docs/examples/customization/custom-errors/custom-default-backend.helm.values.yaml @@ -5,8 +5,8 @@ defaultBackend: enabled: true image: registry: registry.k8s.io - image: ingress-nginx/custom-error-pages - tag: v1.1.1@sha256:8c10776191ae44b5c387b8c7696d8bc17ceec90d7184a3a38b89ac8434b6c56b + image: ingress-nginx/nginx-errors + tag: "v20230505@sha256:3600dcd1bbd0d05959bb01af4b272714e94d22d24a64e91838e7183c80e53f7f" extraVolumes: - name: custom-error-pages configMap: diff --git a/docs/examples/customization/custom-errors/custom-default-backend.yaml b/docs/examples/customization/custom-errors/custom-default-backend.yaml index 088ca1374..e606c5b62 100644 --- a/docs/examples/customization/custom-errors/custom-default-backend.yaml +++ b/docs/examples/customization/custom-errors/custom-default-backend.yaml @@ -36,7 +36,7 @@ spec: spec: containers: - name: nginx-error-server - image: registry.k8s.io/ingress-nginx/custom-error-pages:v1.1.1@sha256:8c10776191ae44b5c387b8c7696d8bc17ceec90d7184a3a38b89ac8434b6c56b + image: registry.k8s.io/ingress-nginx/nginx-errors:v20230505@sha256:3600dcd1bbd0d05959bb01af4b272714e94d22d24a64e91838e7183c80e53f7f ports: - containerPort: 8080 # Setting the environment variable DEBUG we can see the headers sent diff --git a/docs/examples/customization/external-auth-headers/echo-service.yaml b/docs/examples/customization/external-auth-headers/echo-service.yaml index 10244458d..fc4461cd8 100644 --- a/docs/examples/customization/external-auth-headers/echo-service.yaml +++ b/docs/examples/customization/external-auth-headers/echo-service.yaml @@ -18,7 +18,7 @@ spec: terminationGracePeriodSeconds: 60 containers: - name: echo-service - image: registry.k8s.io/ingress-nginx/e2e-test-echo:v1.1.1@sha256:a1e0152e2eeab26e3f6fd3986f3d82b17bc7711717cae5392dcd18dd447ba6ef + image: registry.k8s.io/ingress-nginx/e2e-test-echo:v20230527@sha256:6fc5aa2994c86575975bb20a5203651207029a0d28e3f491d8a127d08baadab4 ports: - containerPort: 8080 resources: diff --git a/docs/examples/customization/sysctl/patch.json b/docs/examples/customization/sysctl/patch.json index 69482c7be..e87c9affa 100644 --- a/docs/examples/customization/sysctl/patch.json +++ b/docs/examples/customization/sysctl/patch.json @@ -4,7 +4,7 @@ "spec": { "initContainers": [{ "name": "sysctl", - "image": "alpine:3.21", + "image": "alpine:3.18", "securityContext": { "privileged": true }, diff --git a/docs/examples/grpc/README.md b/docs/examples/grpc/README.md index 23126c345..508b23fb8 100644 --- a/docs/examples/grpc/README.md +++ b/docs/examples/grpc/README.md @@ -166,9 +166,11 @@ This example demonstrates how to route traffic to a gRPC service through the Ing ### Notes on using response/request streams -> `grpc_read_timeout` and `grpc_send_timeout` will be set as `proxy_read_timeout` and `proxy_send_timeout` when you set backend protocol to `GRPC` or `GRPCS`. - 1. If your server only does response streaming and you expect a stream to be open longer than 60 seconds, you will have to change the `grpc_read_timeout` to accommodate this. 2. If your service only does request streaming and you expect a stream to be open longer than 60 seconds, you have to change the `grpc_send_timeout` and the `client_body_timeout`. 3. If you do both response and request streaming with an open stream longer than 60 seconds, you have to change all three timeouts: `grpc_read_timeout`, `grpc_send_timeout` and `client_body_timeout`. + +Values for the timeouts must be specified as e.g. `"1200s"`. + +> On the most recent versions of ingress-nginx, changing these timeouts requires using the `nginx.ingress.kubernetes.io/server-snippet` annotation. There are plans for future releases to allow using the Kubernetes annotations to define each timeout separately. diff --git a/docs/examples/index.md b/docs/examples/index.md index 4efdae39f..59745e014 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -23,7 +23,7 @@ Customization | [External authentication with response header propagation](custo Customization | [Sysctl tuning](customization/sysctl/README.md) | TODO | TODO Features | [Rewrite](rewrite/README.md) | TODO | TODO Features | [Session stickiness](affinity/cookie/README.md) | route requests consistently to the same endpoint | Advanced -Features | [Canary Deployments](canary/README.md) | weighted canary routing to a separate deployment | Intermediate +Features | [Canary Deployments](canary/README.md) | weighted canary routing to a seperate deployment | Intermediate Scaling | [Static IP](static-ip/README.md) | a single ingress gets a single static IP | Intermediate TLS | [Multi TLS certificate termination](multi-tls/README.md) | TODO | TODO TLS | [TLS termination](tls-termination/README.md) | TODO | TODO diff --git a/docs/examples/openpolicyagent/README.md b/docs/examples/openpolicyagent/README.md index 8d6337a38..2d653a90c 100644 --- a/docs/examples/openpolicyagent/README.md +++ b/docs/examples/openpolicyagent/README.md @@ -1,25 +1,25 @@ # OpenPolicyAgent and pathType enforcing -Ingress API allows users to specify different [pathType](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types) -on Ingress object. +Ingress API allows users to specify different [pathType](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types) +on Ingress object. While pathType `Exact` and `Prefix` should allow only a small set of characters, pathType `ImplementationSpecific` -allows any characters, as it may contain regexes, variables and other features that may be specific of the Ingress +allows any characters, as it may contain regexes, variables and other features that may be specific of the Ingress Controller being used. -This means that the Ingress Admins (the persona who deployed the Ingress Controller) should trust the users -allowed to use `pathType: ImplementationSpecific`, as this may allow arbitrary configuration, and this +This means that the Ingress Admins (the persona who deployed the Ingress Controller) should trust the users +allowed to use `pathType: ImplementationSpecific`, as this may allow arbitrary configuration, and this configuration may end on the proxy (aka Nginx) configuration. ## Example -The example in this repo uses [Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/) to block the usage of `pathType: ImplementationSpecific`, +The example in this repo uses [Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/) to block the usage of `pathType: ImplementationSpecific`, allowing just a specific list of namespaces to use it. It is recommended that the admin modifies this rules to enforce a specific set of characters when the usage of ImplementationSpecific is allowed, or in ways that best suits their needs. -First, the `ConstraintTemplate` from [template.yaml](template.yaml) will define a rule that validates if the Ingress object -is being created on an exempted namespace, and case not, will validate its pathType. +First, the `ConstraintTemplate` from [template.yaml](template.yaml) will define a rule that validates if the Ingress object +is being created on an excempted namespace, and case not, will validate its pathType. -Then, the rule `K8sBlockIngressPathType` contained in [rule.yaml](rule.yaml) will define the parameters: what kind of -object should be verified (Ingress), what are the exempted namespaces, and what kinds of pathType are blocked. +Then, the rule `K8sBlockIngressPathType` contained in [rule.yaml](rule.yaml) will define the parameters: what kind of +object should be verified (Ingress), what are the excempted namespaces, and what kinds of pathType are blocked. diff --git a/docs/examples/openpolicyagent/template.yaml b/docs/examples/openpolicyagent/template.yaml index 4302415a2..ed2a6ba1c 100644 --- a/docs/examples/openpolicyagent/template.yaml +++ b/docs/examples/openpolicyagent/template.yaml @@ -17,11 +17,11 @@ spec: properties: blockedTypes: type: array - items: - type: string + items: + type: string namespacesExceptions: type: array - items: + items: type: string targets: - target: admission.k8s.gatekeeper.sh @@ -31,8 +31,8 @@ spec: violation[{"msg": msg}] { input.review.kind.kind == "Ingress" ns := input.review.object.metadata.namespace - exemptNS := [good | exempts = input.parameters.namespacesExceptions[_] ; good = exempts == ns] - not any(exemptNS) + excemptNS := [good | excempts = input.parameters.namespacesExceptions[_] ; good = excempts == ns] + not any(excemptNS) pathType := object.get(input.review.object.spec.rules[_].http.paths[_], "pathType", "") blockedPath := [blocked | blockedTypes = input.parameters.blockedTypes[_] ; blocked = blockedTypes == pathType] any(blockedPath) diff --git a/docs/examples/psp/README.md b/docs/examples/psp/README.md new file mode 100644 index 000000000..f8426baf2 --- /dev/null +++ b/docs/examples/psp/README.md @@ -0,0 +1,17 @@ +# Pod Security Policy (PSP) + +In most clusters today, by default, all resources (e.g. `Deployments` and `ReplicatSets`) +have permissions to create pods. +Kubernetes however provides a more fine-grained authorization policy called +[Pod Security Policy (PSP)](https://kubernetes.io/docs/concepts/policy/pod-security-policy/). + +PSP allows the cluster owner to define the permission of each object, for example creating a pod. +If you have PSP enabled on the cluster, and you deploy ingress-nginx, +you will need to provide the `Deployment` with the permissions to create pods. + +Before applying any objects, first apply the PSP permissions by running: +```console +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/docs/examples/psp/psp.yaml +``` + +Note: PSP permissions must be granted before the creation of the `Deployment` and the `ReplicaSet`. diff --git a/docs/examples/psp/psp.yaml b/docs/examples/psp/psp.yaml new file mode 100644 index 000000000..0f859dece --- /dev/null +++ b/docs/examples/psp/psp.yaml @@ -0,0 +1,75 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ingress-nginx + +--- + +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: ingress-nginx + namespace: ingress-nginx +spec: + allowedCapabilities: + - NET_BIND_SERVICE + privileged: false + allowPrivilegeEscalation: true + # Allow core volume types. + volumes: + - configMap + - secret + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: MustRunAsNonRoot + supplementalGroups: + rule: MustRunAs + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: MustRunAs + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + seLinux: + rule: RunAsAny + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ingress-nginx-psp + namespace: ingress-nginx +rules: +- apiGroups: [policy] + resources: [podsecuritypolicies] + verbs: [use] + resourceNames: [ingress-nginx] + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ingress-nginx-psp + namespace: ingress-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ingress-nginx-psp +subjects: +- kind: ServiceAccount + name: default +- kind: ServiceAccount + name: ingress-nginx + namespace: ingress-nginx +- kind: ServiceAccount + name: ingress-nginx-admission + namespace: ingress-nginx diff --git a/docs/faq.md b/docs/faq.md index ea1e4d308..bd1d26718 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,19 +1,7 @@ # FAQ -## Multi-tenant Kubernetes - -Do not use in multi-tenant Kubernetes production installations. This project assumes that users that can create Ingress objects are administrators of the cluster. - -For example, the Ingress NGINX control plane has global and per Ingress configuration options that make it insecure, if enabled, in a multi-tenant environment. - -For example, enabling snippets, a global configuration, allows any Ingress object to run arbitrary Lua code that could affect the security of all Ingress objects that a controller is running. - -We changed the default to allow snippets to `false` in https://github.com/kubernetes/ingress-nginx/pull/10393. - -## Multiple controller in one cluster - -Question - How can I easily install multiple instances of the ingress-nginx controller in the same cluster? +## How can I easily install multiple instances of the ingress-nginx controller in the same cluster? You can install them in different namespaces. @@ -73,80 +61,7 @@ helm install ingress-nginx-2 ingress-nginx/ingress-nginx \ ## Retaining Client IPAddress -Question - How to obtain the real-client-ipaddress ? - -The goto solution for retaining the real-client IPaddress is to enable PROXY protocol. - -Enabling PROXY protocol has to be done on both, the Ingress NGINX controller, as well as the L4 load balancer, in front of the controller. - -The real-client IP address is lost by default, when traffic is forwarded over the network. But enabling PROXY protocol ensures that the connection details are retained and hence the real-client IP address doesn't get lost. - -Enabling proxy-protocol on the controller is documented [here](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#use-proxy-protocol) . - -For enabling proxy-protocol on the LoadBalancer, please refer to the documentation of your infrastructure provider because that is where the LB is provisioned. - -Some more info available [here](https://kubernetes.github.io/ingress-nginx/user-guide/miscellaneous/#source-ip-address) - -Some more info on proxy-protocol is [here](https://kubernetes.github.io/ingress-nginx/user-guide/miscellaneous/#proxy-protocol) - -### client-ipaddress on single-node cluster - -Single node clusters are created for dev & test uses with tools like "kind" or "minikube". A trick to simulate a real use network with these clusters (kind or minikube) is to install Metallb and configure the ipaddress of the kind container or the minikube vm/container, as the starting and ending of the pool for Metallb in L2 mode. Then the host ip becomes a real client ipaddress, for curl requests sent from the host. - -After installing ingress-nginx controller on a kind or a minikube cluster with helm, you can configure it for real-client-ip with a simple change to the service that ingress-nginx controller creates. The service object of --type LoadBalancer has a field service.spec.externalTrafficPolicy. If you set the value of this field to "Local" then the real-ipaddress of a client is visible to the controller. - -``` -% kubectl explain service.spec.externalTrafficPolicy -KIND: Service -VERSION: v1 - -FIELD: externalTrafficPolicy - -DESCRIPTION: - externalTrafficPolicy describes how nodes distribute service traffic they - receive on one of the Service's "externally-facing" addresses (NodePorts, - ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will - configure the service in a way that assumes that external load balancers - will take care of balancing the service traffic between nodes, and so each - node will deliver traffic only to the node-local endpoints of the service, - without masquerading the client source IP. (Traffic mistakenly sent to a - node with no endpoints will be dropped.) The default value, "Cluster", uses - the standard behavior of routing to all endpoints evenly (possibly modified - by topology and other features). Note that traffic sent to an External IP or - LoadBalancer IP from within the cluster will always get "Cluster" semantics, - but clients sending to a NodePort from within the cluster may need to take - traffic policy into account when picking a node. - - Possible enum values: - - `"Cluster"` routes traffic to all endpoints. - - `"Local"` preserves the source IP of the traffic by routing only to - endpoints on the same node as the traffic was received on (dropping the - traffic if there are no local endpoints). -``` - -### client-ipaddress L7 - -The solution is to get the real client IPaddress from the ["X-Forward-For" HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) - -Example : If your application pod behind Ingress NGINX controller, uses the NGINX webserver and the reverseproxy inside it, then you can do the following to preserve the remote client IP. - -- First you need to make sure that the X-Forwarded-For header reaches the backend pod. This is done by using a Ingress NGINX conftroller ConfigMap key. Its documented [here](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#use-forwarded-headers) - -- Next, edit `nginx.conf` file inside your app pod, to contain the directives shown below: - -``` -set_real_ip_from 0.0.0.0/0; # Trust all IPs (use your VPC CIDR block in production) -real_ip_header X-Forwarded-For; -real_ip_recursive on; - -log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" ' - 'host=$host x-forwarded-for=$http_x_forwarded_for'; - -access_log /var/log/nginx/access.log main; - -``` +Please read [Retain Client IPAddress Guide here](./user-guide/retaining-client-ipaddress.md). ## Kubernetes v1.22 Migration @@ -165,8 +80,8 @@ default on the next breaking change release, set for 2.0.0. - When "`ingress.spec.rules.http.pathType=Exact`" or "`pathType=Prefix`", this validation will limit the characters accepted on the field "`ingress.spec.rules.http.paths.path`", -to "`alphanumeric characters`", and "`/`", "`_`", "`-`". Also, in this case, -the path should start with "`/`". +to "`alphanumeric characters`", and `"/," "_," "-."` Also, in this case, +the path should start with `"/."` - When the ingress resource path contains other characters (like on rewrite configurations), the pathType value should be "`ImplementationSpecific`". @@ -175,7 +90,7 @@ configurations), the pathType value should be "`ImplementationSpecific`". - When this option is enabled, the validation will happen on the Admission Webhook. So if any new ingress object contains characters other than -alphanumeric characters, and, "`/`", "`_`", "`-`", in the `path` field, but +alphanumeric characters, and, `"/,","_","-"`, in the `path` field, but is not using `pathType` value as `ImplementationSpecific`, then the ingress object will be denied admission. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index ffd8f839f..e1fd6956e 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -443,7 +443,7 @@ $ capsh --decode=0000000000000400 ``` ## Create a test pod as root -(Note, this may be restricted by PodSecurityAdmission/Standards, OPA Gatekeeper, etc. in which case you will need to do the appropriate workaround for testing, e.g. deploy in a new namespace without the restrictions.) +(Note, this may be restricted by PodSecurityPolicy, PodSecurityAdmission/Standards, OPA Gatekeeper, etc. in which case you will need to do the appropriate workaround for testing, e.g. deploy in a new namespace without the restrictions.) To test further you may want to install additional utilities, etc. Modify the pod yaml by: * changing runAsUser from 101 to 0 * removing the "drop..ALL" section from the capabilities. diff --git a/docs/user-guide/cli-arguments.md b/docs/user-guide/cli-arguments.md index a33e75159..07a17a271 100644 --- a/docs/user-guide/cli-arguments.md +++ b/docs/user-guide/cli-arguments.md @@ -8,7 +8,6 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment |----------|-------------| | `--annotations-prefix` | Prefix of the Ingress annotations specific to the NGINX controller. (default "nginx.ingress.kubernetes.io") | | `--apiserver-host` | Address of the Kubernetes API server. Takes the form "protocol://address:port". If not specified, it is assumed the program runs inside a Kubernetes cluster and local discovery is attempted. | -| `--bucket-factor` | Bucket factor for native histograms. Value must be > 1 for enabling native histograms. (default 0) | | `--certificate-authority` | Path to a cert file for the certificate authority. This certificate is used only when the flag --apiserver-host is specified. | | `--configmap` | Name of the ConfigMap containing custom global configurations for the controller. | | `--controller-class` | Ingress Class Controller value this Ingress satisfies. The class of an Ingress object is set using the field IngressClassName in Kubernetes clusters version v1.19.0 or higher. The .spec.controller value of the IngressClass referenced in an Ingress Object should be the same value specified here to make this object be watched. | @@ -16,18 +15,16 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment | `--default-backend-service` | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form "namespace/name". The controller configures NGINX to forward requests to the first port of this Service. | | `--default-server-port` | Port to use for exposing the default server (catch-all). (default 8181) | | `--default-ssl-certificate` | Secret containing a SSL certificate to be used by the default HTTPS server (catch-all). Takes the form "namespace/name". | -| `--enable-annotation-validation` | If true, will enable the annotation validation feature. Defaults to true | +| `--enable-annotation-validation` | If true, will enable the annotation validation feature. This value will be defaulted to true on a future release. | | `--disable-catch-all` | Disable support for catch-all Ingresses. (default false) | | `--disable-full-test` | Disable full test of all merged ingresses at the admission stage and tests the template of the ingress being created or updated (full test of all ingresses is enabled by default). | | `--disable-svc-external-name` | Disable support for Services of type ExternalName. (default false) | | `--disable-sync-events` | Disables the creation of 'Sync' Event resources, but still logs them | | `--dynamic-configuration-retries` | Number of times to retry failed dynamic configuration before failing to sync an ingress. (default 15) | | `--election-id` | Election id to use for Ingress status updates. (default "ingress-controller-leader") | -| `--election-ttl` | Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s) | -| `--enable-metrics` | Enables the collection of NGINX metrics. (Default: false) | +| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) | | `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)| | `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) | -| `--disable-leader-election` | Disable Leader Election on Nginx Controller. (default false) | | `--enable-topology-aware-routing` | Enable topology aware routing feature, needs service object annotation service.kubernetes.io/topology-mode sets to auto. (default false) | | `--exclude-socket-metrics` | Set of socket request metrics to exclude which won't be exported nor being calculated. The possible socket request metrics to exclude are documented in the monitoring guide e.g. 'nginx_ingress_controller_request_duration_seconds,nginx_ingress_controller_response_size'| | `--health-check-path` | URL path of the health check endpoint. Configured inside the NGINX status server. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. (default "/healthz") | @@ -41,14 +38,12 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment | `--internal-logger-address` | Address to be used when binding internal syslogger. (default 127.0.0.1:11514) | | `--kubeconfig` | Path to a kubeconfig file containing authorization and API server information. | | `--length-buckets` | Set of buckets which will be used for prometheus histogram metrics such as RequestLength, ResponseLength. (default `[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]`) | -| `--max-buckets` | Maximum number of buckets for native histograms. (default 100) | | `--maxmind-edition-ids` | Maxmind edition ids to download GeoLite2 Databases. (default "GeoLite2-City,GeoLite2-ASN") | | `--maxmind-retries-timeout` | Maxmind downloading delay between 1st and 2nd attempt, 0s - do not retry to download if something went wrong. (default 0s) | | `--maxmind-retries-count` | Number of attempts to download the GeoIP DB. (default 1) | -| `--maxmind-license-key` | Maxmind license key to download GeoLite2 Databases. https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geolite2-databases/ . | +| `--maxmind-license-key` | Maxmind license key to download GeoLite2 Databases. https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases . | | `--maxmind-mirror` | Maxmind mirror url (example: http://geoip.local/databases. | | `--metrics-per-host` | Export metrics per-host. (default true) | -| `--metrics-per-undefined-host` | Export metrics per-host even if the host is not defined in an ingress. Requires --metrics-per-host to be set to true. (default false) | | `--monitor-max-batch-size` | Max batch size of NGINX metrics. (default 10000)| | `--post-shutdown-grace-period` | Additional delay in seconds before controller container exits. (default 10) | | `--profiler-port` | Port to use for expose the ingress controller Go profiler when it is enabled. (default 10245) | diff --git a/docs/user-guide/exposing-tcp-udp-services.md b/docs/user-guide/exposing-tcp-udp-services.md index 9c14a7c39..dbc143ff1 100644 --- a/docs/user-guide/exposing-tcp-udp-services.md +++ b/docs/user-guide/exposing-tcp-udp-services.md @@ -3,7 +3,7 @@ While the Kubernetes Ingress resource only officially supports routing external HTTP(s) traffic to services, ingress-nginx can be configured to receive external TCP/UDP traffic from non-HTTP protocols and route them to internal services using TCP/UDP port mappings that are specified within a ConfigMap. To support this, the `--tcp-services-configmap` and `--udp-services-configmap` flags can be used to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: -`:::[PROXY]:[PROXY]` +`::[PROXY]:[PROXY]` It is also possible to use a number or the name of the port. The two last fields are optional. Adding `PROXY` in either or both of the two last fields we can use [Proxy Protocol](https://www.nginx.com/resources/admin-guide/proxy-protocol) decoding (listen) and/or encoding (proxy_pass) in a TCP service. diff --git a/docs/user-guide/miscellaneous.md b/docs/user-guide/miscellaneous.md index ee3d63056..e7d1ac59c 100644 --- a/docs/user-guide/miscellaneous.md +++ b/docs/user-guide/miscellaneous.md @@ -4,11 +4,9 @@ By default NGINX uses the content of the header `X-Forwarded-For` as the source of truth to get information about the client IP address. This works without issues in L7 **if we configure the setting `proxy-real-ip-cidr`** with the correct information of the IP/network address of trusted external load balancer. -This setting can be enabled/disabled by setting [`use-forwarded-headers`](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#use-forwarded-headers). - If the ingress controller is running in AWS we need to use the VPC IPv4 CIDR. -Another option is to enable the **PROXY protocol** using [`use-proxy-protocol: "true"`](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#use-proxy-protocol). +Another option is to enable proxy protocol using `use-proxy-protocol: "true"`. In this mode NGINX does not use the content of the header to get the source IP address of the connection. @@ -19,7 +17,7 @@ By default NGINX path type is Prefix to not break existing definitions ## Proxy Protocol -If you are using a L4 proxy to forward the traffic to the Ingress NGINX pods and terminate HTTP/HTTPS there, you will lose the remote endpoint's IP address. To prevent this you could use the [PROXY Protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) for forwarding traffic, this will send the connection details before forwarding the actual TCP connection itself. +If you are using a L4 proxy to forward the traffic to the NGINX pods and terminate HTTP/HTTPS there, you will lose the remote endpoint's IP address. To prevent this you could use the [Proxy Protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) for forwarding traffic, this will send the connection details before forwarding the actual TCP connection itself. Amongst others [ELBs in AWS](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/enable-proxy-protocol.html) and [HAProxy](http://www.haproxy.org/) support Proxy Protocol. diff --git a/docs/user-guide/monitoring.md b/docs/user-guide/monitoring.md index 4ad2795cf..28608e850 100644 --- a/docs/user-guide/monitoring.md +++ b/docs/user-guide/monitoring.md @@ -166,9 +166,7 @@ According to the above example, this URL will be http://10.192.0.3:31086 #### Wildcard ingresses - - By default request metrics are labeled with the hostname. When you have a wildcard domain ingress, then there will be no metrics for that ingress (to prevent the metrics from exploding in cardinality). To get metrics in this case you have two options: - - Run the ingress controller with `--metrics-per-host=false`. You will lose labeling by hostname, but still have labeling by ingress. - - Run the ingress controller with `--metrics-per-undefined-host=true --metrics-per-host=true`. You will get labeling by hostname even if the hostname is not explicitly defined on an ingress. Be warned that cardinality could explode due to many hostnames and CPU usage could also increase. + - By default request metrics are labeled with the hostname. When you have a wildcard domain ingress, then there will be no metrics for that ingress (to prevent the metrics from exploding in cardinality). To get metrics in this case you need to run the ingress controller with `--metrics-per-host=false` (you will lose labeling by hostname, but still have labeling by ingress). ### Grafana dashboard using ingress resource - If you want to expose the dashboard for grafana using an ingress resource, then you can : @@ -388,6 +386,10 @@ Prometheus metrics are exposed on port 10254. The number of bytes sent to a client. **Deprecated**, use `nginx_ingress_controller_response_size`\ nginx var: `bytes_sent` +* `nginx_ingress_controller_ingress_upstream_latency_seconds` Summary\ + Upstream service latency per Ingress. **Deprecated**, use `nginx_ingress_controller_connect_duration_seconds`\ + nginx var: `upstream_connect_time` + ``` # HELP nginx_ingress_controller_bytes_sent The number of bytes sent to a client. DEPRECATED! Use nginx_ingress_controller_response_size # TYPE nginx_ingress_controller_bytes_sent histogram @@ -395,6 +397,8 @@ Prometheus metrics are exposed on port 10254. # TYPE nginx_ingress_controller_connect_duration_seconds nginx_ingress_controller_connect_duration_seconds * HELP nginx_ingress_controller_header_duration_seconds The time spent on receiving first header from the upstream server # TYPE nginx_ingress_controller_header_duration_seconds histogram +# HELP nginx_ingress_controller_ingress_upstream_latency_seconds Upstream service latency per Ingress DEPRECATED! Use nginx_ingress_controller_connect_duration_seconds +# TYPE nginx_ingress_controller_ingress_upstream_latency_seconds summary # HELP nginx_ingress_controller_request_duration_seconds The request processing time in milliseconds # TYPE nginx_ingress_controller_request_duration_seconds histogram # HELP nginx_ingress_controller_request_size The request length (including request line, header, and request body) diff --git a/docs/user-guide/nginx-configuration/annotations-risk.md b/docs/user-guide/nginx-configuration/annotations-risk.md deleted file mode 100755 index aff9357b8..000000000 --- a/docs/user-guide/nginx-configuration/annotations-risk.md +++ /dev/null @@ -1,141 +0,0 @@ -# Annotations Scope and Risk - -|Group |Annotation | Risk | Scope | -|--------|------------------|------|-------| -| Aliases | server-alias | High | ingress | -| Allowlist | allowlist-source-range | Medium | location | -| BackendProtocol | backend-protocol | Low | location | -| BasicDigestAuth | auth-realm | Medium | location | -| BasicDigestAuth | auth-secret | Medium | location | -| BasicDigestAuth | auth-secret-type | Low | location | -| BasicDigestAuth | auth-type | Low | location | -| Canary | canary | Low | ingress | -| Canary | canary-by-cookie | Medium | ingress | -| Canary | canary-by-header | Medium | ingress | -| Canary | canary-by-header-pattern | Medium | ingress | -| Canary | canary-by-header-value | Medium | ingress | -| Canary | canary-weight | Low | ingress | -| Canary | canary-weight-total | Low | ingress | -| CertificateAuth | auth-tls-error-page | High | location | -| CertificateAuth | auth-tls-match-cn | High | location | -| CertificateAuth | auth-tls-pass-certificate-to-upstream | Low | location | -| CertificateAuth | auth-tls-secret | Medium | location | -| CertificateAuth | auth-tls-verify-client | Medium | location | -| CertificateAuth | auth-tls-verify-depth | Low | location | -| ClientBodyBufferSize | client-body-buffer-size | Low | location | -| ConfigurationSnippet | configuration-snippet | Critical | location | -| Connection | connection-proxy-header | Low | location | -| CorsConfig | cors-allow-credentials | Low | ingress | -| CorsConfig | cors-allow-headers | Medium | ingress | -| CorsConfig | cors-allow-methods | Medium | ingress | -| CorsConfig | cors-allow-origin | Medium | ingress | -| CorsConfig | cors-expose-headers | Medium | ingress | -| CorsConfig | cors-max-age | Low | ingress | -| CorsConfig | enable-cors | Low | ingress | -| CustomHTTPErrors | custom-http-errors | Low | location | -| CustomHeaders | custom-headers | Medium | location | -| DefaultBackend | default-backend | Low | location | -| Denylist | denylist-source-range | Medium | location | -| DisableProxyInterceptErrors | disable-proxy-intercept-errors | Low | location | -| EnableGlobalAuth | enable-global-auth | Low | location | -| ExternalAuth | auth-always-set-cookie | Low | location | -| ExternalAuth | auth-cache-duration | Medium | location | -| ExternalAuth | auth-cache-key | Medium | location | -| ExternalAuth | auth-keepalive | Low | location | -| ExternalAuth | auth-keepalive-requests | Low | location | -| ExternalAuth | auth-keepalive-share-vars | Low | location | -| ExternalAuth | auth-keepalive-timeout | Low | location | -| ExternalAuth | auth-method | Low | location | -| ExternalAuth | auth-proxy-set-headers | Medium | location | -| ExternalAuth | auth-request-redirect | Medium | location | -| ExternalAuth | auth-response-headers | Medium | location | -| ExternalAuth | auth-signin | High | location | -| ExternalAuth | auth-signin-redirect-param | Medium | location | -| ExternalAuth | auth-snippet | Critical | location | -| ExternalAuth | auth-url | High | location | -| FastCGI | fastcgi-index | Medium | location | -| FastCGI | fastcgi-params-configmap | Medium | location | -| HTTP2PushPreload | http2-push-preload | Low | location | -| LoadBalancing | load-balance | Low | location | -| Logs | enable-access-log | Low | location | -| Logs | enable-rewrite-log | Low | location | -| Mirror | mirror-host | High | ingress | -| Mirror | mirror-request-body | Low | ingress | -| Mirror | mirror-target | High | ingress | -| ModSecurity | enable-modsecurity | Low | ingress | -| ModSecurity | enable-owasp-core-rules | Low | ingress | -| ModSecurity | modsecurity-snippet | Critical | ingress | -| ModSecurity | modsecurity-transaction-id | High | ingress | -| Opentelemetry | enable-opentelemetry | Low | location | -| Opentelemetry | opentelemetry-operation-name | Medium | location | -| Opentelemetry | opentelemetry-trust-incoming-span | Low | location | -| Proxy | proxy-body-size | Medium | location | -| Proxy | proxy-buffer-size | Low | location | -| Proxy | proxy-buffering | Low | location | -| Proxy | proxy-buffers-number | Low | location | -| Proxy | proxy-busy-buffers-size | Low | location | -| Proxy | proxy-connect-timeout | Low | location | -| Proxy | proxy-cookie-domain | Medium | location | -| Proxy | proxy-cookie-path | Medium | location | -| Proxy | proxy-http-version | Low | location | -| Proxy | proxy-max-temp-file-size | Low | location | -| Proxy | proxy-next-upstream | Medium | location | -| Proxy | proxy-next-upstream-timeout | Low | location | -| Proxy | proxy-next-upstream-tries | Low | location | -| Proxy | proxy-read-timeout | Low | location | -| Proxy | proxy-redirect-from | Medium | location | -| Proxy | proxy-redirect-to | Medium | location | -| Proxy | proxy-request-buffering | Low | location | -| Proxy | proxy-send-timeout | Low | location | -| ProxySSL | proxy-ssl-ciphers | Medium | ingress | -| ProxySSL | proxy-ssl-name | High | ingress | -| ProxySSL | proxy-ssl-protocols | Low | ingress | -| ProxySSL | proxy-ssl-secret | Medium | ingress | -| ProxySSL | proxy-ssl-server-name | Low | ingress | -| ProxySSL | proxy-ssl-verify | Low | ingress | -| ProxySSL | proxy-ssl-verify-depth | Low | ingress | -| RateLimit | limit-allowlist | Low | location | -| RateLimit | limit-burst-multiplier | Low | location | -| RateLimit | limit-connections | Low | location | -| RateLimit | limit-rate | Low | location | -| RateLimit | limit-rate-after | Low | location | -| RateLimit | limit-rpm | Low | location | -| RateLimit | limit-rps | Low | location | -| Redirect | from-to-www-redirect | Low | location | -| Redirect | permanent-redirect | Medium | location | -| Redirect | permanent-redirect-code | Low | location | -| Redirect | relative-redirects | Low | location | -| Redirect | temporal-redirect | Medium | location | -| Redirect | temporal-redirect-code | Low | location | -| Rewrite | app-root | Medium | location | -| Rewrite | force-ssl-redirect | Medium | location | -| Rewrite | preserve-trailing-slash | Medium | location | -| Rewrite | rewrite-target | Medium | ingress | -| Rewrite | ssl-redirect | Low | location | -| Rewrite | use-regex | Low | location | -| SSLCipher | ssl-ciphers | Low | ingress | -| SSLCipher | ssl-prefer-server-ciphers | Low | ingress | -| SSLPassthrough | ssl-passthrough | Low | ingress | -| Satisfy | satisfy | Low | location | -| ServerSnippet | server-snippet | Critical | ingress | -| ServiceUpstream | service-upstream | Low | ingress | -| SessionAffinity | affinity | Low | ingress | -| SessionAffinity | affinity-canary-behavior | Low | ingress | -| SessionAffinity | affinity-mode | Medium | ingress | -| SessionAffinity | session-cookie-change-on-failure | Low | ingress | -| SessionAffinity | session-cookie-conditional-samesite-none | Low | ingress | -| SessionAffinity | session-cookie-domain | Medium | ingress | -| SessionAffinity | session-cookie-expires | Medium | ingress | -| SessionAffinity | session-cookie-max-age | Medium | ingress | -| SessionAffinity | session-cookie-name | Medium | ingress | -| SessionAffinity | session-cookie-path | Medium | ingress | -| SessionAffinity | session-cookie-samesite | Low | ingress | -| SessionAffinity | session-cookie-secure | Low | ingress | -| StreamSnippet | stream-snippet | Critical | ingress | -| UpstreamHashBy | upstream-hash-by | High | location | -| UpstreamHashBy | upstream-hash-by-subset | Low | location | -| UpstreamHashBy | upstream-hash-by-subset-size | Low | location | -| UpstreamVhost | upstream-vhost | Low | location | -| UsePortInRedirects | use-port-in-redirects | Low | location | -| XForwardedPrefix | x-forwarded-prefix | Medium | location | - diff --git a/docs/user-guide/nginx-configuration/annotations.md b/docs/user-guide/nginx-configuration/annotations.md index b0ea3cce3..180592574 100755 --- a/docs/user-guide/nginx-configuration/annotations.md +++ b/docs/user-guide/nginx-configuration/annotations.md @@ -50,7 +50,6 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz |[nginx.ingress.kubernetes.io/client-body-buffer-size](#client-body-buffer-size)|string| |[nginx.ingress.kubernetes.io/configuration-snippet](#configuration-snippet)|string| |[nginx.ingress.kubernetes.io/custom-http-errors](#custom-http-errors)|[]int| -|[nginx.ingress.kubernetes.io/custom-headers](#custom-headers)|string| |[nginx.ingress.kubernetes.io/default-backend](#default-backend)|string| |[nginx.ingress.kubernetes.io/enable-cors](#enable-cors)|"true" or "false"| |[nginx.ingress.kubernetes.io/cors-allow-origin](#enable-cors)|string| @@ -64,10 +63,13 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz |[nginx.ingress.kubernetes.io/http2-push-preload](#http2-push-preload)|"true" or "false"| |[nginx.ingress.kubernetes.io/limit-connections](#rate-limiting)|number| |[nginx.ingress.kubernetes.io/limit-rps](#rate-limiting)|number| +|[nginx.ingress.kubernetes.io/global-rate-limit](#global-rate-limiting)|number| +|[nginx.ingress.kubernetes.io/global-rate-limit-window](#global-rate-limiting)|duration| +|[nginx.ingress.kubernetes.io/global-rate-limit-key](#global-rate-limiting)|string| +|[nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs](#global-rate-limiting)|string| |[nginx.ingress.kubernetes.io/permanent-redirect](#permanent-redirect)|string| |[nginx.ingress.kubernetes.io/permanent-redirect-code](#permanent-redirect-code)|number| |[nginx.ingress.kubernetes.io/temporal-redirect](#temporal-redirect)|string| -|[nginx.ingress.kubernetes.io/temporal-redirect-code](#temporal-redirect-code)|number| |[nginx.ingress.kubernetes.io/preserve-trailing-slash](#server-side-https-enforcement-through-redirect)|"true" or "false"| |[nginx.ingress.kubernetes.io/proxy-body-size](#custom-max-body-size)|string| |[nginx.ingress.kubernetes.io/proxy-cookie-domain](#proxy-cookie-domain)|string| @@ -116,7 +118,6 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz |[nginx.ingress.kubernetes.io/proxy-buffering](#proxy-buffering)|string| |[nginx.ingress.kubernetes.io/proxy-buffers-number](#proxy-buffers-number)|number| |[nginx.ingress.kubernetes.io/proxy-buffer-size](#proxy-buffer-size)|string| -|[nginx.ingress.kubernetes.io/proxy-busy-buffers-size](#proxy-busy-buffers-size)|string| |[nginx.ingress.kubernetes.io/proxy-max-temp-file-size](#proxy-max-temp-file-size)|string| |[nginx.ingress.kubernetes.io/ssl-ciphers](#ssl-ciphers)|string| |[nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers](#ssl-ciphers)|"true" or "false"| @@ -335,29 +336,6 @@ Example usage: nginx.ingress.kubernetes.io/custom-http-errors: "404,415" ``` -### Custom Headers -This annotation is of the form `nginx.ingress.kubernetes.io/custom-headers: /` to specify a namespace and configmap name that contains custom headers. This annotation uses `more_set_headers` nginx directive. - -Example annotation for following example configmap: - -```yaml -nginx.ingress.kubernetes.io/custom-headers: default/custom-headers-configmap -``` - -Example configmap: -```yaml -apiVersion: v1 -data: - Content-Type: application/json -kind: ConfigMap -metadata: - name: custom-headers-configmap - namespace: default -``` - -!!! attention - First define the allowed response headers in [global-allowed-response-headers](https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/configmap.md#global-allowed-response-headers). - ### Default Backend This annotation is of the form `nginx.ingress.kubernetes.io/default-backend: ` to specify a custom default backend. This `` is a reference to a service inside of the same namespace in which you are applying this annotation. This annotation overrides the global default backend. In case the service has [multiple ports](https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services), the first one is the one which will receive the backend traffic. @@ -395,13 +373,13 @@ CORS can be controlled with the following annotations: * `nginx.ingress.kubernetes.io/cors-allow-origin`: Controls what's the accepted Origin for CORS. - This is a multi-valued field, separated by ','. It must follow this format: `protocol://origin-site.com` or `protocol://origin-site.com:port` + This is a multi-valued field, separated by ','. It must follow this format: `http(s)://origin-site.com` or `http(s)://origin-site.com:port` - Default: `*` - - Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443, http://origin-site.com, myprotocol://example.org:1199"` + - Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443, http://origin-site.com, https://example.org:1199"` - It also supports single level wildcard subdomains and follows this format: `protocol://*.foo.bar`, `protocol://*.bar.foo:8080` or `protocol://*.abc.bar.foo:9000` - - Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.origin-site.com:4443, http://*.origin-site.com, myprotocol://example.org:1199"` + It also supports single level wildcard subdomains and follows this format: `http(s)://*.foo.bar`, `http(s)://*.bar.foo:8080` or `http(s)://*.abc.bar.foo:9000` + - Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.origin-site.com:4443, http://*.origin-site.com, https://example.org:1199"` * `nginx.ingress.kubernetes.io/cors-allow-credentials`: Controls if credentials can be passed during CORS operations. @@ -550,15 +528,10 @@ By default the controller redirects all requests to an existing service that pro These annotations define limits on connections and transmission rates. These can be used to mitigate [DDoS Attacks](https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus). -!!! attention - Rate limits are applied per Ingress NGINX controller replica. - If you're running multiple replicas or using a horizontal pod autoscaler (HPA), the effective rate limit will be multiplied by the number of replicas. - When using HPA, the exact rate limit becomes dynamic as the number of replicas may change based on load. - -* `nginx.ingress.kubernetes.io/limit-connections`: number of concurrent connections allowed from a single IP address per controller replica. A 503 error is returned when exceeding this limit. -* `nginx.ingress.kubernetes.io/limit-rps`: number of requests accepted from a given IP each second per controller replica. The burst limit is set to this limit multiplied by the burst multiplier, the default multiplier is 5. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned. -* `nginx.ingress.kubernetes.io/limit-rpm`: number of requests accepted from a given IP each minute per controller replica. The burst limit is set to this limit multiplied by the burst multiplier, the default multiplier is 5. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned. -* `nginx.ingress.kubernetes.io/limit-burst-multiplier`: multiplier of the limit rate for burst size. The default burst multiplier is 5, this annotation override the default multiplier. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned. +* `nginx.ingress.kubernetes.io/limit-connections`: number of concurrent connections allowed from a single IP address. A 503 error is returned when exceeding this limit. +* `nginx.ingress.kubernetes.io/limit-rps`: number of requests accepted from a given IP each second. The burst limit is set to this limit multiplied by the burst multiplier, the default multiplier is 5. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned. +* `nginx.ingress.kubernetes.io/limit-rpm`: number of requests accepted from a given IP each minute. The burst limit is set to this limit multiplied by the burst multiplier, the default multiplier is 5. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned. +* `nginx.ingress.kubernetes.io/limit-burst-multiplier`: multiplier of the limit rate for burst size. The default burst multiplier is 5, this annotation override the default multiplier. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned. * `nginx.ingress.kubernetes.io/limit-rate-after`: initial number of kilobytes after which the further transmission of a response to a given connection will be rate limited. This feature must be used with [proxy-buffering](#proxy-buffering) enabled. * `nginx.ingress.kubernetes.io/limit-rate`: number of kilobytes per second allowed to send to a given connection. The zero value disables rate limiting. This feature must be used with [proxy-buffering](#proxy-buffering) enabled. * `nginx.ingress.kubernetes.io/limit-whitelist`: client IP source ranges to be excluded from rate-limiting. The value is a comma separated list of CIDRs. @@ -569,6 +542,46 @@ To configure settings globally for all Ingress rules, the `limit-rate-after` and The client IP address will be set based on the use of [PROXY protocol](./configmap.md#use-proxy-protocol) or from the `X-Forwarded-For` header value when [use-forwarded-headers](./configmap.md#use-forwarded-headers) is enabled. +### Global Rate Limiting + +**Note:** Be careful when configuring both (Local) Rate Limiting and Global Rate Limiting at the same time. +They are two completely different rate limiting implementations. Whichever limit exceeds first will reject the +requests. It might be a good idea to configure both of them to ease load on Global Rate Limiting backend +in cases of spike in traffic. + +The stock NGINX rate limiting does not share its counters among different NGINX instances. +Given that most ingress-nginx deployments are elastic and number of replicas can change any day +it is impossible to configure a proper rate limit using stock NGINX functionalities. +Global Rate Limiting overcome this by using [lua-resty-global-throttle](https://github.com/ElvinEfendi/lua-resty-global-throttle). `lua-resty-global-throttle` shares its counters via a central store such as `memcached`. +The obvious shortcoming of this is users have to deploy and operate a `memcached` instance +in order to benefit from this functionality. Configure the `memcached` +using [these configmap settings](./configmap.md#global-rate-limit). + +**Here are a few remarks for ingress-nginx integration of `lua-resty-global-throttle`:** + +1. We minimize `memcached` access by caching exceeding limit decisions. The expiry of +cache entry is the desired delay `lua-resty-global-throttle` calculates for us. +The Lua Shared Dictionary used for that is `global_throttle_cache`. Currently its size defaults to 10M. +Customize it as per your needs using [lua-shared-dicts](./configmap.md#lua-shared-dicts). +When we fail to cache the exceeding limit decision then we log an NGINX error. You can monitor +for that error to decide if you need to bump the cache size. Without cache the cost of processing a +request is two memcached commands: `GET`, and `INCR`. With the cache it is only `INCR`. +1. Log NGINX variable `$global_rate_limit_exceeding`'s value to have some visibility into +what portion of requests are rejected (value `y`), whether they are rejected using cached decision (value `c`), +or if they are not rejected (default value `n`). You can use [log-format-upstream](./configmap.md#log-format-upstream) +to include that in access logs. +1. In case of an error it will log the error message and **fail open**. +1. The annotations below creates Global Rate Limiting instance per ingress. +That means if there are multiple paths configured under the same ingress, +the Global Rate Limiting will count requests to all the paths under the same counter. +Extract a path out into its own ingress if you need to isolate a certain path. + + +* `nginx.ingress.kubernetes.io/global-rate-limit`: Configures maximum allowed number of requests per window. Required. +* `nginx.ingress.kubernetes.io/global-rate-limit-window`: Configures a time window (i.e `1m`) that the limit is applied. Required. +* `nginx.ingress.kubernetes.io/global-rate-limit-key`: Configures a key for counting the samples. Defaults to `$remote_addr`. You can also combine multiple NGINX variables here, like `${remote_addr}-${http_x_api_client}` which would mean the limit will be applied to requests coming from the same API client (indicated by `X-API-Client` HTTP request header) with the same source IP address. +* `nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs`: comma separated list of IPs and CIDRs to match client IP against. When there's a match request is not considered for rate limiting. + ### Permanent Redirect This annotation allows to return a permanent redirect (Return Code 301) instead of sending data to the upstream. For example `nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com` would redirect everything to Google. @@ -580,10 +593,6 @@ This annotation allows you to modify the status code used for permanent redirect ### Temporal Redirect This annotation allows you to return a temporal redirect (Return Code 302) instead of sending data to the upstream. For example `nginx.ingress.kubernetes.io/temporal-redirect: https://www.google.com` would redirect everything to Google with a Return Code of 302 (Moved Temporarily) -### Temporal Redirect Code - -This annotation allows you to modify the status code used for temporal redirects. For example `nginx.ingress.kubernetes.io/temporal-redirect-code: '307'` would return your temporal-redirect with a 307. - ### SSL Passthrough The annotation `nginx.ingress.kubernetes.io/ssl-passthrough` instructs the controller to send TLS connections directly @@ -629,10 +638,7 @@ To preserve the trailing slash in the URI with `ssl-redirect`, set `nginx.ingres ### Redirect from/to www -In some scenarios, it is required to redirect from `www.domain.com` to `domain.com` or vice versa, which way the redirect is performed depends on the configured `host` value in the Ingress object. - -For example, if `.spec.rules.host` is configured with a value like `www.example.com`, then this annotation will redirect from `example.com` to `www.example.com`. If `.spec.rules.host` is configured with a value like `example.com`, so without a `www`, then this annotation will redirect from `www.example.com` to `example.com` instead. - +In some scenarios is required to redirect from `www.domain.com` to `domain.com` or vice versa. To enable this feature use the annotation `nginx.ingress.kubernetes.io/from-to-www-redirect: "true"` !!! attention @@ -675,12 +681,6 @@ In some scenarios is required to have different values. To allow this we provide - `nginx.ingress.kubernetes.io/proxy-next-upstream-tries` - `nginx.ingress.kubernetes.io/proxy-request-buffering` -If you indicate [Backend Protocol](#backend-protocol) as `GRPC` or `GRPCS`, the following grpc values will be set and inherited from proxy timeouts: - -- [`grpc_connect_timeout=5s`](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_connect_timeout), from `nginx.ingress.kubernetes.io/proxy-connect-timeout` -- [`grpc_send_timeout=60s`](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_send_timeout), from `nginx.ingress.kubernetes.io/proxy-send-timeout` -- [`grpc_read_timeout=60s`](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_read_timeout), from `nginx.ingress.kubernetes.io/proxy-read-timeout` - Note: All timeout values are unitless and in seconds e.g. `nginx.ingress.kubernetes.io/proxy-read-timeout: "120"` sets a valid 120 seconds proxy read timeout. ### Proxy redirect @@ -748,18 +748,6 @@ To configure this setting globally, set `proxy-buffer-size` in [NGINX ConfigMap] nginx.ingress.kubernetes.io/proxy-buffer-size: "8k" ``` -### Proxy busy buffers size - -[Limits the total size of buffers that can be busy](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_busy_buffers_size) sending a response to the client while the response is not yet fully read. - -By default proxy busy buffers size is set as "8k". - -To configure this setting globally, set `proxy-busy-buffers-size` in the [ConfigMap](./configmap.md#proxy-busy-buffers-size). To use custom values in an Ingress rule, define this annotation: - -```yaml -nginx.ingress.kubernetes.io/proxy-busy-buffers-size: "16k" -``` - ### Proxy max temp file size When [`buffering`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering) of responses from the proxied server is enabled, and the whole response does not fit into the buffers set by the [`proxy_buffer_size`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) and [`proxy_buffers`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffers) directives, a part of the response can be saved to a temporary file. This directive sets the maximum `size` of the temporary file setting the [`proxy_max_temp_file_size`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_max_temp_file_size). The size of data written to the temporary file at a time is set by the [`proxy_temp_file_write_size`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_temp_file_write_size) directive. diff --git a/docs/user-guide/nginx-configuration/configmap.md b/docs/user-guide/nginx-configuration/configmap.md index d8b4f6693..6834193a2 100644 --- a/docs/user-guide/nginx-configuration/configmap.md +++ b/docs/user-guide/nginx-configuration/configmap.md @@ -25,206 +25,207 @@ data: The following table shows a configuration option's name, type, and the default value: -| name | type | default | notes | -|:--------------------------------------------------------------------------------|:-------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------| -| [add-headers](#add-headers) | string | "" | | -| [allow-backend-server-header](#allow-backend-server-header) | bool | "false" | | -| [allow-cross-namespace-resources](#allow-cross-namespace-resources) | bool | "false" | | -| [allow-snippet-annotations](#allow-snippet-annotations) | bool | "false" | | -| [annotations-risk-level](#annotations-risk-level) | string | High | | -| [annotation-value-word-blocklist](#annotation-value-word-blocklist) | string array | "" | | -| [hide-headers](#hide-headers) | string array | empty | | -| [access-log-params](#access-log-params) | string | "" | | -| [access-log-path](#access-log-path) | string | "/var/log/nginx/access.log" | | -| [http-access-log-path](#http-access-log-path) | string | "" | | -| [stream-access-log-path](#stream-access-log-path) | string | "" | | -| [enable-access-log-for-default-backend](#enable-access-log-for-default-backend) | bool | "false" | | -| [error-log-path](#error-log-path) | string | "/var/log/nginx/error.log" | | -| [enable-modsecurity](#enable-modsecurity) | bool | "false" | | -| [modsecurity-snippet](#modsecurity-snippet) | string | "" | | -| [enable-owasp-modsecurity-crs](#enable-owasp-modsecurity-crs) | bool | "false" | | -| [client-header-buffer-size](#client-header-buffer-size) | string | "1k" | | -| [client-header-timeout](#client-header-timeout) | int | 60 | | -| [client-body-buffer-size](#client-body-buffer-size) | string | "8k" | | -| [client-body-timeout](#client-body-timeout) | int | 60 | | -| [disable-access-log](#disable-access-log) | bool | "false" | | -| [disable-ipv6](#disable-ipv6) | bool | "false" | | -| [disable-ipv6-dns](#disable-ipv6-dns) | bool | "false" | | -| [enable-underscores-in-headers](#enable-underscores-in-headers) | bool | "false" | | -| [enable-ocsp](#enable-ocsp) | bool | "false" | | -| [ignore-invalid-headers](#ignore-invalid-headers) | bool | "true" | | -| [retry-non-idempotent](#retry-non-idempotent) | bool | "false" | | -| [error-log-level](#error-log-level) | string | "notice" | | -| [http2-max-field-size](#http2-max-field-size) | string | "" | DEPRECATED in favour of [large_client_header_buffers](#large-client-header-buffers) | -| [http2-max-header-size](#http2-max-header-size) | string | "" | DEPRECATED in favour of [large_client_header_buffers](#large-client-header-buffers) | -| [http2-max-requests](#http2-max-requests) | int | 0 | DEPRECATED in favour of [keepalive_requests](#keepalive-requests) | -| [http2-max-concurrent-streams](#http2-max-concurrent-streams) | int | 128 | | -| [hsts](#hsts) | bool | "true" | | -| [hsts-include-subdomains](#hsts-include-subdomains) | bool | "true" | | -| [hsts-max-age](#hsts-max-age) | string | "31536000" | | -| [hsts-preload](#hsts-preload) | bool | "false" | | -| [keep-alive](#keep-alive) | int | 75 | | -| [keep-alive-requests](#keep-alive-requests) | int | 1000 | | -| [large-client-header-buffers](#large-client-header-buffers) | string | "4 8k" | | -| [log-format-escape-none](#log-format-escape-none) | bool | "false" | | -| [log-format-escape-json](#log-format-escape-json) | bool | "false" | | -| [log-format-upstream](#log-format-upstream) | string | `$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id` | | -| [log-format-stream](#log-format-stream) | string | `[$remote_addr] [$time_local] $protocol $status $bytes_sent $bytes_received $session_time` | | -| [enable-multi-accept](#enable-multi-accept) | bool | "true" | | -| [max-worker-connections](#max-worker-connections) | int | 16384 | | -| [max-worker-open-files](#max-worker-open-files) | int | 0 | | -| [map-hash-bucket-size](#max-hash-bucket-size) | int | 64 | | -| [nginx-status-ipv4-whitelist](#nginx-status-ipv4-whitelist) | []string | "127.0.0.1" | | -| [nginx-status-ipv6-whitelist](#nginx-status-ipv6-whitelist) | []string | "::1" | | -| [proxy-real-ip-cidr](#proxy-real-ip-cidr) | []string | "0.0.0.0/0" | | -| [proxy-set-headers](#proxy-set-headers) | string | "" | | -| [server-name-hash-max-size](#server-name-hash-max-size) | int | 1024 | | -| [server-name-hash-bucket-size](#server-name-hash-bucket-size) | int | `` | -| [proxy-headers-hash-max-size](#proxy-headers-hash-max-size) | int | 512 | | -| [proxy-headers-hash-bucket-size](#proxy-headers-hash-bucket-size) | int | 64 | | -| [reuse-port](#reuse-port) | bool | "true" | | -| [server-tokens](#server-tokens) | bool | "false" | | -| [ssl-ciphers](#ssl-ciphers) | string | "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" | | -| [ssl-ecdh-curve](#ssl-ecdh-curve) | string | "auto" | | -| [ssl-dh-param](#ssl-dh-param) | string | "" | | -| [ssl-protocols](#ssl-protocols) | string | "TLSv1.2 TLSv1.3" | | -| [ssl-session-cache](#ssl-session-cache) | bool | "true" | | -| [ssl-session-cache-size](#ssl-session-cache-size) | string | "10m" | | -| [ssl-session-tickets](#ssl-session-tickets) | bool | "false" | | -| [ssl-session-ticket-key](#ssl-session-ticket-key) | string | `` | -| [ssl-session-timeout](#ssl-session-timeout) | string | "10m" | | -| [ssl-buffer-size](#ssl-buffer-size) | string | "4k" | | -| [use-proxy-protocol](#use-proxy-protocol) | bool | "false" | | -| [proxy-protocol-header-timeout](#proxy-protocol-header-timeout) | string | "5s" | | -| [enable-aio-write](#enable-aio-write) | bool | "true" | | -| [use-gzip](#use-gzip) | bool | "false" | | -| [use-geoip](#use-geoip) | bool | "true" | | -| [use-geoip2](#use-geoip2) | bool | "false" | | -| [geoip2-autoreload-in-minutes](#geoip2-autoreload-in-minutes) | int | "0" | | -| [enable-brotli](#enable-brotli) | bool | "false" | | -| [brotli-level](#brotli-level) | int | 4 | | -| [brotli-min-length](#brotli-min-length) | int | 20 | | -| [brotli-types](#brotli-types) | string | "application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component" | | -| [use-http2](#use-http2) | bool | "true" | | -| [gzip-disable](#gzip-disable) | string | "" | | -| [gzip-level](#gzip-level) | int | 1 | | -| [gzip-min-length](#gzip-min-length) | int | 256 | | -| [gzip-types](#gzip-types) | string | "application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component" | | -| [worker-processes](#worker-processes) | string | `` | | -| [worker-cpu-affinity](#worker-cpu-affinity) | string | "" | | -| [worker-shutdown-timeout](#worker-shutdown-timeout) | string | "240s" | | -| [enable-serial-reloads](#enable-serial-reloads) | bool | "false" | | -| [load-balance](#load-balance) | string | "round_robin" | | -| [variables-hash-bucket-size](#variables-hash-bucket-size) | int | 128 | | -| [variables-hash-max-size](#variables-hash-max-size) | int | 2048 | | -| [upstream-keepalive-connections](#upstream-keepalive-connections) | int | 320 | | -| [upstream-keepalive-time](#upstream-keepalive-time) | string | "1h" | | -| [upstream-keepalive-timeout](#upstream-keepalive-timeout) | int | 60 | | -| [upstream-keepalive-requests](#upstream-keepalive-requests) | int | 10000 | | -| [limit-conn-zone-variable](#limit-conn-zone-variable) | string | "$binary_remote_addr" | | -| [proxy-stream-timeout](#proxy-stream-timeout) | string | "600s" | | -| [proxy-stream-next-upstream](#proxy-stream-next-upstream) | bool | "true" | | -| [proxy-stream-next-upstream-timeout](#proxy-stream-next-upstream-timeout) | string | "600s" | | -| [proxy-stream-next-upstream-tries](#proxy-stream-next-upstream-tries) | int | 3 | | -| [proxy-stream-responses](#proxy-stream-responses) | int | 1 | | -| [bind-address](#bind-address) | []string | "" | | -| [use-forwarded-headers](#use-forwarded-headers) | bool | "false" | | -| [enable-real-ip](#enable-real-ip) | bool | "false" | | -| [forwarded-for-header](#forwarded-for-header) | string | "X-Forwarded-For" | | -| [compute-full-forwarded-for](#compute-full-forwarded-for) | bool | "false" | | -| [proxy-add-original-uri-header](#proxy-add-original-uri-header) | bool | "false" | | -| [generate-request-id](#generate-request-id) | bool | "true" | | -| [jaeger-collector-host](#jaeger-collector-host) | string | "" | | -| [jaeger-collector-port](#jaeger-collector-port) | int | 6831 | | -| [jaeger-endpoint](#jaeger-endpoint) | string | "" | | -| [jaeger-service-name](#jaeger-service-name) | string | "nginx" | | -| [jaeger-propagation-format](#jaeger-propagation-format) | string | "jaeger" | | -| [jaeger-sampler-type](#jaeger-sampler-type) | string | "const" | | -| [jaeger-sampler-param](#jaeger-sampler-param) | string | "1" | | -| [jaeger-sampler-host](#jaeger-sampler-host) | string | "http://127.0.0.1" | | -| [jaeger-sampler-port](#jaeger-sampler-port) | int | 5778 | | -| [jaeger-trace-context-header-name](#jaeger-trace-context-header-name) | string | uber-trace-id | | -| [jaeger-debug-header](#jaeger-debug-header) | string | uber-debug-id | | -| [jaeger-baggage-header](#jaeger-baggage-header) | string | jaeger-baggage | | -| [jaeger-trace-baggage-header-prefix](#jaeger-trace-baggage-header-prefix) | string | uberctx- | | -| [datadog-collector-host](#datadog-collector-host) | string | "" | | -| [datadog-collector-port](#datadog-collector-port) | int | 8126 | | -| [datadog-service-name](#datadog-service-name) | string | "nginx" | | -| [datadog-environment](#datadog-environment) | string | "prod" | | -| [datadog-operation-name-override](#datadog-operation-name-override) | string | "nginx.handle" | | -| [datadog-priority-sampling](#datadog-priority-sampling) | bool | "true" | | -| [datadog-sample-rate](#datadog-sample-rate) | float | 1.0 | | -| [enable-opentelemetry](#enable-opentelemetry) | bool | "false" | | -| [opentelemetry-trust-incoming-span](#opentelemetry-trust-incoming-span) | bool | "true" | | -| [opentelemetry-operation-name](#opentelemetry-operation-name) | string | "" | | -| [opentelemetry-config](#/etc/nginx/opentelemetry.toml) | string | "/etc/nginx/opentelemetry.toml" | | -| [otlp-collector-host](#otlp-collector-host) | string | "" | | -| [otlp-collector-port](#otlp-collector-port) | int | 4317 | | -| [otel-max-queuesize](#otel-max-queuesize) | int | | | -| [otel-schedule-delay-millis](#otel-schedule-delay-millis) | int | | | -| [otel-max-export-batch-size](#otel-max-export-batch-size) | int | | | -| [otel-service-name](#otel-service-name) | string | "nginx" | | -| [otel-sampler](#otel-sampler) | string | "AlwaysOff" | | -| [otel-sampler-parent-based](#otel-sampler-parent-based) | bool | "false" | | -| [otel-sampler-ratio](#otel-sampler-ratio) | float | 0.01 | | -| [main-snippet](#main-snippet) | string | "" | | -| [http-snippet](#http-snippet) | string | "" | | -| [server-snippet](#server-snippet) | string | "" | | -| [stream-snippet](#stream-snippet) | string | "" | | -| [location-snippet](#location-snippet) | string | "" | | -| [custom-http-errors](#custom-http-errors) | []int | []int{} | | -| [proxy-body-size](#proxy-body-size) | string | "1m" | | -| [proxy-connect-timeout](#proxy-connect-timeout) | int | 5 | | -| [proxy-read-timeout](#proxy-read-timeout) | int | 60 | | -| [proxy-send-timeout](#proxy-send-timeout) | int | 60 | | -| [proxy-buffers-number](#proxy-buffers-number) | int | 4 | | -| [proxy-buffer-size](#proxy-buffer-size) | string | "4k" | | -| [proxy-busy-buffers-size](#proxy-busy-buffers-size) | string | "8k" | | -| [proxy-cookie-path](#proxy-cookie-path) | string | "off" | | -| [proxy-cookie-domain](#proxy-cookie-domain) | string | "off" | | -| [proxy-next-upstream](#proxy-next-upstream) | string | "error timeout" | | -| [proxy-next-upstream-timeout](#proxy-next-upstream-timeout) | int | 0 | | -| [proxy-next-upstream-tries](#proxy-next-upstream-tries) | int | 3 | | -| [proxy-redirect-from](#proxy-redirect-from) | string | "off" | | -| [proxy-request-buffering](#proxy-request-buffering) | string | "on" | | -| [ssl-redirect](#ssl-redirect) | bool | "true" | | -| [force-ssl-redirect](#force-ssl-redirect) | bool | "false" | | -| [denylist-source-range](#denylist-source-range) | []string | []string{} | | -| [whitelist-source-range](#whitelist-source-range) | []string | []string{} | | -| [skip-access-log-urls](#skip-access-log-urls) | []string | []string{} | | -| [limit-rate](#limit-rate) | int | 0 | | -| [limit-rate-after](#limit-rate-after) | int | 0 | | -| [lua-shared-dicts](#lua-shared-dicts) | string | "" | | -| [http-redirect-code](#http-redirect-code) | int | 308 | | -| [proxy-buffering](#proxy-buffering) | string | "off" | | -| [limit-req-status-code](#limit-req-status-code) | int | 503 | | -| [limit-conn-status-code](#limit-conn-status-code) | int | 503 | | -| [enable-syslog](#enable-syslog) | bool | "false" | | -| [syslog-host](#syslog-host) | string | "" | | -| [syslog-port](#syslog-port) | int | 514 | | -| [no-tls-redirect-locations](#no-tls-redirect-locations) | string | "/.well-known/acme-challenge" | | -| [global-allowed-response-headers](#global-allowed-response-headers) | string | "" | | -| [global-auth-url](#global-auth-url) | string | "" | | -| [global-auth-method](#global-auth-method) | string | "" | | -| [global-auth-signin](#global-auth-signin) | string | "" | | -| [global-auth-signin-redirect-param](#global-auth-signin-redirect-param) | string | "rd" | | -| [global-auth-response-headers](#global-auth-response-headers) | string | "" | | -| [global-auth-request-redirect](#global-auth-request-redirect) | string | "" | | -| [global-auth-snippet](#global-auth-snippet) | string | "" | | -| [global-auth-cache-key](#global-auth-cache-key) | string | "" | | -| [global-auth-cache-duration](#global-auth-cache-duration) | string | "200 202 401 5m" | | -| [no-auth-locations](#no-auth-locations) | string | "/.well-known/acme-challenge" | | -| [block-cidrs](#block-cidrs) | []string | "" | | -| [block-user-agents](#block-user-agents) | []string | "" | | -| [block-referers](#block-referers) | []string | "" | | -| [proxy-ssl-location-only](#proxy-ssl-location-only) | bool | "false" | | -| [default-type](#default-type) | string | "text/html" | | -| [service-upstream](#service-upstream) | bool | "false" | | -| [ssl-reject-handshake](#ssl-reject-handshake) | bool | "false" | | -| [debug-connections](#debug-connections) | []string | "127.0.0.1,1.1.1.1/24" | | -| [strict-validate-path-type](#strict-validate-path-type) | bool | "true" | | -| [grpc-buffer-size-kb](#grpc-buffer-size-kb) | int | 0 | | -| [relative-redirects](#relative-redirects) | bool | false | | +|name|type|default|notes| +|:---|:---|:------|:----| +|[add-headers](#add-headers)|string|""|| +|[allow-backend-server-header](#allow-backend-server-header)|bool|"false"|| +|[allow-cross-namespace-resources](#allow-cross-namespace-resources)|bool|"true"|| +|[allow-snippet-annotations](#allow-snippet-annotations)|bool|"false"|| +|[annotations-risk-level](#annotations-risk-level)|string|Critical|| +|[annotation-value-word-blocklist](#annotation-value-word-blocklist)|string array|""|| +|[hide-headers](#hide-headers)|string array|empty|| +|[access-log-params](#access-log-params)|string|""|| +|[access-log-path](#access-log-path)|string|"/var/log/nginx/access.log"|| +|[http-access-log-path](#http-access-log-path)|string|""|| +|[stream-access-log-path](#stream-access-log-path)|string|""|| +|[enable-access-log-for-default-backend](#enable-access-log-for-default-backend)|bool|"false"|| +|[error-log-path](#error-log-path)|string|"/var/log/nginx/error.log"|| +|[enable-modsecurity](#enable-modsecurity)|bool|"false"|| +|[modsecurity-snippet](#modsecurity-snippet)|string|""|| +|[enable-owasp-modsecurity-crs](#enable-owasp-modsecurity-crs)|bool|"false"|| +|[client-header-buffer-size](#client-header-buffer-size)|string|"1k"|| +|[client-header-timeout](#client-header-timeout)|int|60|| +|[client-body-buffer-size](#client-body-buffer-size)|string|"8k"|| +|[client-body-timeout](#client-body-timeout)|int|60|| +|[disable-access-log](#disable-access-log)|bool|"false"|| +|[disable-ipv6](#disable-ipv6)|bool|"false"|| +|[disable-ipv6-dns](#disable-ipv6-dns)|bool|"false"|| +|[enable-underscores-in-headers](#enable-underscores-in-headers)|bool|"false"|| +|[enable-ocsp](#enable-ocsp)|bool|"false"|| +|[ignore-invalid-headers](#ignore-invalid-headers)|bool|"true"|| +|[retry-non-idempotent](#retry-non-idempotent)|bool|"false"|| +|[error-log-level](#error-log-level)|string|"notice"|| +|[http2-max-field-size](#http2-max-field-size)|string|""|DEPRECATED in favour of [large_client_header_buffers](#large-client-header-buffers)| +|[http2-max-header-size](#http2-max-header-size)|string|""|DEPRECATED in favour of [large_client_header_buffers](#large-client-header-buffers)| +|[http2-max-requests](#http2-max-requests)|int|0|DEPRECATED in favour of [keepalive_requests](#keepalive-requests)| +|[http2-max-concurrent-streams](#http2-max-concurrent-streams)|int|128|| +|[hsts](#hsts)|bool|"true"|| +|[hsts-include-subdomains](#hsts-include-subdomains)|bool|"true"|| +|[hsts-max-age](#hsts-max-age)|string|"31536000"|| +|[hsts-preload](#hsts-preload)|bool|"false"|| +|[keep-alive](#keep-alive)|int|75|| +|[keep-alive-requests](#keep-alive-requests)|int|1000|| +|[large-client-header-buffers](#large-client-header-buffers)|string|"4 8k"|| +|[log-format-escape-none](#log-format-escape-none)|bool|"false"|| +|[log-format-escape-json](#log-format-escape-json)|bool|"false"|| +|[log-format-upstream](#log-format-upstream)|string|`$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id`|| +|[log-format-stream](#log-format-stream)|string|`[$remote_addr] [$time_local] $protocol $status $bytes_sent $bytes_received $session_time`|| +|[enable-multi-accept](#enable-multi-accept)|bool|"true"|| +|[max-worker-connections](#max-worker-connections)|int|16384|| +|[max-worker-open-files](#max-worker-open-files)|int|0|| +|[map-hash-bucket-size](#max-hash-bucket-size)|int|64|| +|[nginx-status-ipv4-whitelist](#nginx-status-ipv4-whitelist)|[]string|"127.0.0.1"|| +|[nginx-status-ipv6-whitelist](#nginx-status-ipv6-whitelist)|[]string|"::1"|| +|[proxy-real-ip-cidr](#proxy-real-ip-cidr)|[]string|"0.0.0.0/0"|| +|[proxy-set-headers](#proxy-set-headers)|string|""|| +|[server-name-hash-max-size](#server-name-hash-max-size)|int|1024|| +|[server-name-hash-bucket-size](#server-name-hash-bucket-size)|int|``| +|[proxy-headers-hash-max-size](#proxy-headers-hash-max-size)|int|512|| +|[proxy-headers-hash-bucket-size](#proxy-headers-hash-bucket-size)|int|64|| +|[plugins](#plugins)|[]string| || +|[reuse-port](#reuse-port)|bool|"true"|| +|[server-tokens](#server-tokens)|bool|"false"|| +|[ssl-ciphers](#ssl-ciphers)|string|"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"|| +|[ssl-ecdh-curve](#ssl-ecdh-curve)|string|"auto"|| +|[ssl-dh-param](#ssl-dh-param)|string|""|| +|[ssl-protocols](#ssl-protocols)|string|"TLSv1.2 TLSv1.3"|| +|[ssl-session-cache](#ssl-session-cache)|bool|"true"|| +|[ssl-session-cache-size](#ssl-session-cache-size)|string|"10m"|| +|[ssl-session-tickets](#ssl-session-tickets)|bool|"false"|| +|[ssl-session-ticket-key](#ssl-session-ticket-key)|string|``| +|[ssl-session-timeout](#ssl-session-timeout)|string|"10m"|| +|[ssl-buffer-size](#ssl-buffer-size)|string|"4k"|| +|[use-proxy-protocol](#use-proxy-protocol)|bool|"false"|| +|[proxy-protocol-header-timeout](#proxy-protocol-header-timeout)|string|"5s"|| +|[enable-aio-write](#enable-aio-write)|bool|"true"|| +|[use-gzip](#use-gzip)|bool|"false"|| +|[use-geoip](#use-geoip)|bool|"true"|| +|[use-geoip2](#use-geoip2)|bool|"false"|| +|[enable-brotli](#enable-brotli)|bool|"false"|| +|[brotli-level](#brotli-level)|int|4|| +|[brotli-min-length](#brotli-min-length)|int|20|| +|[brotli-types](#brotli-types)|string|"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component"|| +|[use-http2](#use-http2)|bool|"true"|| +|[gzip-disable](#gzip-disable)|string|""|| +|[gzip-level](#gzip-level)|int|1|| +|[gzip-min-length](#gzip-min-length)|int|256|| +|[gzip-types](#gzip-types)|string|"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component"|| +|[worker-processes](#worker-processes)|string|``|| +|[worker-cpu-affinity](#worker-cpu-affinity)|string|""|| +|[worker-shutdown-timeout](#worker-shutdown-timeout)|string|"240s"|| +|[load-balance](#load-balance)|string|"round_robin"|| +|[variables-hash-bucket-size](#variables-hash-bucket-size)|int|128|| +|[variables-hash-max-size](#variables-hash-max-size)|int|2048|| +|[upstream-keepalive-connections](#upstream-keepalive-connections)|int|320|| +|[upstream-keepalive-time](#upstream-keepalive-time)|string|"1h"|| +|[upstream-keepalive-timeout](#upstream-keepalive-timeout)|int|60|| +|[upstream-keepalive-requests](#upstream-keepalive-requests)|int|10000|| +|[limit-conn-zone-variable](#limit-conn-zone-variable)|string|"$binary_remote_addr"|| +|[proxy-stream-timeout](#proxy-stream-timeout)|string|"600s"|| +|[proxy-stream-next-upstream](#proxy-stream-next-upstream)|bool|"true"|| +|[proxy-stream-next-upstream-timeout](#proxy-stream-next-upstream-timeout)|string|"600s"|| +|[proxy-stream-next-upstream-tries](#proxy-stream-next-upstream-tries)|int|3|| +|[proxy-stream-responses](#proxy-stream-responses)|int|1|| +|[bind-address](#bind-address)|[]string|""|| +|[use-forwarded-headers](#use-forwarded-headers)|bool|"false"|| +|[enable-real-ip](#enable-real-ip)|bool|"false"|| +|[forwarded-for-header](#forwarded-for-header)|string|"X-Forwarded-For"|| +|[compute-full-forwarded-for](#compute-full-forwarded-for)|bool|"false"|| +|[proxy-add-original-uri-header](#proxy-add-original-uri-header)|bool|"false"|| +|[generate-request-id](#generate-request-id)|bool|"true"|| +|[jaeger-collector-host](#jaeger-collector-host)|string|""|| +|[jaeger-collector-port](#jaeger-collector-port)|int|6831|| +|[jaeger-endpoint](#jaeger-endpoint)|string|""|| +|[jaeger-service-name](#jaeger-service-name)|string|"nginx"|| +|[jaeger-propagation-format](#jaeger-propagation-format)|string|"jaeger"|| +|[jaeger-sampler-type](#jaeger-sampler-type)|string|"const"|| +|[jaeger-sampler-param](#jaeger-sampler-param)|string|"1"|| +|[jaeger-sampler-host](#jaeger-sampler-host)|string|"http://127.0.0.1"|| +|[jaeger-sampler-port](#jaeger-sampler-port)|int|5778|| +|[jaeger-trace-context-header-name](#jaeger-trace-context-header-name)|string|uber-trace-id|| +|[jaeger-debug-header](#jaeger-debug-header)|string|uber-debug-id|| +|[jaeger-baggage-header](#jaeger-baggage-header)|string|jaeger-baggage|| +|[jaeger-trace-baggage-header-prefix](#jaeger-trace-baggage-header-prefix)|string|uberctx-|| +|[datadog-collector-host](#datadog-collector-host)|string|""|| +|[datadog-collector-port](#datadog-collector-port)|int|8126|| +|[datadog-service-name](#datadog-service-name)|string|"nginx"|| +|[datadog-environment](#datadog-environment)|string|"prod"|| +|[datadog-operation-name-override](#datadog-operation-name-override)|string|"nginx.handle"|| +|[datadog-priority-sampling](#datadog-priority-sampling)|bool|"true"|| +|[datadog-sample-rate](#datadog-sample-rate)|float|1.0|| +|[enable-opentelemetry](#enable-opentelemetry)|bool|"false"|| +|[opentelemetry-trust-incoming-span](#opentelemetry-trust-incoming-span)|bool|"true"|| +|[opentelemetry-operation-name](#opentelemetry-operation-name)|string|""|| +|[opentelemetry-config](#/etc/nginx/opentelemetry.toml)|string|"/etc/nginx/opentelemetry.toml"|| +|[otlp-collector-host](#otlp-collector-host)|string|""|| +|[otlp-collector-port](#otlp-collector-port)|int|4317|| +|[otel-max-queuesize](#otel-max-queuesize)|int||| +|[otel-schedule-delay-millis](#otel-schedule-delay-millis)|int||| +|[otel-max-export-batch-size](#otel-max-export-batch-size)|int||| +|[otel-service-name](#otel-service-name)|string|"nginx"|| +|[otel-sampler](#otel-sampler)|string|"AlwaysOff"|| +|[otel-sampler-parent-based](#otel-sampler-parent-based)|bool|"false"|| +|[otel-sampler-ratio](#otel-sampler-ratio)|float|0.01|| +|[main-snippet](#main-snippet)|string|""|| +|[http-snippet](#http-snippet)|string|""|| +|[server-snippet](#server-snippet)|string|""|| +|[stream-snippet](#stream-snippet)|string|""|| +|[location-snippet](#location-snippet)|string|""|| +|[custom-http-errors](#custom-http-errors)|[]int|[]int{}|| +|[proxy-body-size](#proxy-body-size)|string|"1m"|| +|[proxy-connect-timeout](#proxy-connect-timeout)|int|5|| +|[proxy-read-timeout](#proxy-read-timeout)|int|60|| +|[proxy-send-timeout](#proxy-send-timeout)|int|60|| +|[proxy-buffers-number](#proxy-buffers-number)|int|4|| +|[proxy-buffer-size](#proxy-buffer-size)|string|"4k"|| +|[proxy-cookie-path](#proxy-cookie-path)|string|"off"|| +|[proxy-cookie-domain](#proxy-cookie-domain)|string|"off"|| +|[proxy-next-upstream](#proxy-next-upstream)|string|"error timeout"|| +|[proxy-next-upstream-timeout](#proxy-next-upstream-timeout)|int|0|| +|[proxy-next-upstream-tries](#proxy-next-upstream-tries)|int|3|| +|[proxy-redirect-from](#proxy-redirect-from)|string|"off"|| +|[proxy-request-buffering](#proxy-request-buffering)|string|"on"|| +|[ssl-redirect](#ssl-redirect)|bool|"true"|| +|[force-ssl-redirect](#force-ssl-redirect)|bool|"false"|| +|[denylist-source-range](#denylist-source-range)|[]string|[]string{}|| +|[whitelist-source-range](#whitelist-source-range)|[]string|[]string{}|| +|[skip-access-log-urls](#skip-access-log-urls)|[]string|[]string{}|| +|[limit-rate](#limit-rate)|int|0|| +|[limit-rate-after](#limit-rate-after)|int|0|| +|[lua-shared-dicts](#lua-shared-dicts)|string|""|| +|[http-redirect-code](#http-redirect-code)|int|308|| +|[proxy-buffering](#proxy-buffering)|string|"off"|| +|[limit-req-status-code](#limit-req-status-code)|int|503|| +|[limit-conn-status-code](#limit-conn-status-code)|int|503|| +|[enable-syslog](#enable-syslog)|bool|"false"|| +|[syslog-host](#syslog-host)|string|""|| +|[syslog-port](#syslog-port)|int|514|| +|[no-tls-redirect-locations](#no-tls-redirect-locations)|string|"/.well-known/acme-challenge"|| +|[global-auth-url](#global-auth-url)|string|""|| +|[global-auth-method](#global-auth-method)|string|""|| +|[global-auth-signin](#global-auth-signin)|string|""|| +|[global-auth-signin-redirect-param](#global-auth-signin-redirect-param)|string|"rd"|| +|[global-auth-response-headers](#global-auth-response-headers)|string|""|| +|[global-auth-request-redirect](#global-auth-request-redirect)|string|""|| +|[global-auth-snippet](#global-auth-snippet)|string|""|| +|[global-auth-cache-key](#global-auth-cache-key)|string|""|| +|[global-auth-cache-duration](#global-auth-cache-duration)|string|"200 202 401 5m"|| +|[no-auth-locations](#no-auth-locations)|string|"/.well-known/acme-challenge"|| +|[block-cidrs](#block-cidrs)|[]string|""|| +|[block-user-agents](#block-user-agents)|[]string|""|| +|[block-referers](#block-referers)|[]string|""|| +|[proxy-ssl-location-only](#proxy-ssl-location-only)|bool|"false"|| +|[default-type](#default-type)|string|"text/html"|| +|[global-rate-limit-memcached-host](#global-rate-limit)|string|""|| +|[global-rate-limit-memcached-port](#global-rate-limit)|int|11211|| +|[global-rate-limit-memcached-connect-timeout](#global-rate-limit)|int|50|| +|[global-rate-limit-memcached-max-idle-timeout](#global-rate-limit)|int|10000|| +|[global-rate-limit-memcached-pool-size](#global-rate-limit)|int|50|| +|[global-rate-limit-status-code](#global-rate-limit)|int|429|| +|[service-upstream](#service-upstream)|bool|"false"|| +|[ssl-reject-handshake](#ssl-reject-handshake)|bool|"false"|| +|[debug-connections](#debug-connections)|[]string|"127.0.0.1,1.1.1.1/24"|| +|[strict-validate-path-type](#strict-validate-path-type)|bool|"false" (v1.7.x)|| ## add-headers @@ -236,16 +237,18 @@ Enables the return of the header Server from the backend instead of the generic ## allow-cross-namespace-resources -Enables users to consume cross namespace resource on annotations, when was previously enabled . _**default:**_ false +Enables users to consume cross namespace resource on annotations, when was previously enabled . _**default:**_ true **Annotations that may be impacted with this change**: - * `auth-secret` * `auth-proxy-set-header` * `auth-tls-secret` * `fastcgi-params-configmap` * `proxy-ssl-secret` + +**This option will be defaulted to false in the next major release** + ## allow-snippet-annotations Enables Ingress to parse and add *-snippet annotations/directives created by the user. _**default:**_ `false` @@ -253,13 +256,15 @@ Enables Ingress to parse and add *-snippet annotations/directives created by the Warning: We recommend enabling this option only if you TRUST users with permission to create Ingress objects, as this may allow a user to add restricted configurations to the final nginx.conf file +**This option will be defaulted to false in the next major release** + ## annotations-risk-level Represents the risk accepted on an annotation. If the risk is, for instance `Medium`, annotations with risk High and Critical will not be accepted. Accepted values are `Critical`, `High`, `Medium` and `Low`. -_**default:**_ `High` +Defaults to `Critical` but will be changed to `High` on the next minor release ## annotation-value-word-blocklist @@ -603,6 +608,10 @@ _References:_ - [https://nginx.org/en/docs/hash.html](https://nginx.org/en/docs/hash.html) - [https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size) +## plugins + +Activates plugins installed in `/etc/nginx/lua/plugins`. Refer to [ingress-nginx plugins README](https://github.com/kubernetes/ingress-nginx/blob/main/rootfs/etc/nginx/lua/plugins/README.md) for more information on how to write and install a plugin. + ## server-tokens Send NGINX Server header in responses and display NGINX version in error pages. _**default:**_ is disabled @@ -712,7 +721,7 @@ _**default:**_ true ## use-geoip2 Enables the [geoip2 module](https://github.com/leev/ngx_http_geoip2_module) for NGINX. -Since `0.27.0` and due to a [change in the MaxMind databases](https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geolite2-databases/) a license is required to have access to the databases. +Since `0.27.0` and due to a [change in the MaxMind databases](https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases) a license is required to have access to the databases. For this reason, it is required to define a new flag `--maxmind-license-key` in the ingress controller deployment to download the databases needed during the initialization of the ingress controller. Alternatively, it is possible to use a volume to mount the files `/etc/ingress-controller/geoip/GeoLite2-City.mmdb` and `/etc/ingress-controller/geoip/GeoLite2-ASN.mmdb`, avoiding the overhead of the download. @@ -721,12 +730,6 @@ Alternatively, it is possible to use a volume to mount the files `/etc/ingress-c _**default:**_ false -## geoip2-autoreload-in-minutes - -Enables the [geoip2 module](https://github.com/leev/ngx_http_geoip2_module) autoreload in MaxMind databases setting the interval in minutes. - -_**default:**_ 0 - ## enable-brotli Enables or disables compression of HTTP responses using the ["brotli" module](https://github.com/google/ngx_brotli). @@ -1088,20 +1091,14 @@ See NGINX [client_max_body_size](https://nginx.org/en/docs/http/ngx_http_core_mo Sets the timeout for [establishing a connection with a proxied server](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_connect_timeout). It should be noted that this timeout cannot usually exceed 75 seconds. -It will also set the [grpc_connect_timeout](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_connect_timeout) for gRPC connections. - ## proxy-read-timeout Sets the timeout in seconds for [reading a response from the proxied server](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout). The timeout is set only between two successive read operations, not for the transmission of the whole response. -It will also set the [grpc_read_timeout](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_read_timeout) for gRPC connections. - ## proxy-send-timeout Sets the timeout in seconds for [transmitting a request to the proxied server](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_send_timeout). The timeout is set only between two successive write operations, not for the transmission of the whole request. -It will also set the [grpc_send_timeout](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_send_timeout) for gRPC connections. - ## proxy-buffers-number Sets the number of the buffer used for [reading the first part of the response](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffers) received from the proxied server. This part usually contains a small response header. @@ -1110,10 +1107,6 @@ Sets the number of the buffer used for [reading the first part of the response]( Sets the size of the buffer used for [reading the first part of the response](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) received from the proxied server. This part usually contains a small response header. -## proxy-busy-buffers-size - -[Limits the total size of buffers that can be busy](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_busy_buffers_size) sending a response to the client while the response is not yet fully read. - ## proxy-cookie-path Sets a text that [should be changed in the path attribute](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_path) of the “Set-Cookie” header fields of a proxied server response. @@ -1179,9 +1172,6 @@ _References:_ Sets the initial amount after which the further transmission of a response to a client will be rate limited. -_References:_ -[https://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after](https://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after) - ## lua-shared-dicts Customize default Lua shared dictionaries or define more. You can use the following syntax to do so: @@ -1203,6 +1193,9 @@ You can optionally set a size unit to allow for kilobyte-granularity. Allowed un lua-shared-dicts: "certificate_data: 100, my_custom_plugin: 512k" ``` +_References:_ +[https://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after](https://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after) + ## http-redirect-code Sets the HTTP status code to be used in redirects. @@ -1242,10 +1235,6 @@ Sets the port of syslog server. _**default:**_ 514 A comma-separated list of locations on which http requests will never get redirected to their https counterpart. _**default:**_ "/.well-known/acme-challenge" -## global-allowed-response-headers - -A comma-separated list of allowed response headers inside the [custom headers annotations](https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#custom-headers) - ## global-auth-url A url to an existing service that provides authentication for all the locations. @@ -1345,6 +1334,22 @@ _**default:**_ text/html _References:_ [https://nginx.org/en/docs/http/ngx_http_core_module.html#default_type](https://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) +## global-rate-limit + +* `global-rate-limit-status-code`: configure HTTP status code to return when rejecting requests. Defaults to 429. + +Configure `memcached` client for [Global Rate Limiting](https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#global-rate-limiting). + +* `global-rate-limit-memcached-host`: IP/FQDN of memcached server to use. Required to enable Global Rate Limiting. +* `global-rate-limit-memcached-port`: port of memcached server to use. Defaults default memcached port of `11211`. +* `global-rate-limit-memcached-connect-timeout`: configure timeout for connect, send and receive operations. Unit is millisecond. Defaults to 50ms. +* `global-rate-limit-memcached-max-idle-timeout`: configure timeout for cleaning idle connections. Unit is millisecond. Defaults to 50ms. +* `global-rate-limit-memcached-pool-size`: configure number of max connections to keep alive. Make sure your `memcached` server can handle +`global-rate-limit-memcached-pool-size * worker-processes * ` simultaneous connections. + +These settings get used by [lua-resty-global-throttle](https://github.com/ElvinEfendi/lua-resty-global-throttle) +that ingress-nginx includes. Refer to the link to learn more about `lua-resty-global-throttle`. + ## service-upstream Set if the service's Cluster IP and port should be used instead of a list of all endpoints. This can be overwritten by an annotation on an Ingress rule. @@ -1366,7 +1371,6 @@ _References:_ [http://nginx.org/en/docs/ngx_core_module.html#debug_connection](http://nginx.org/en/docs/ngx_core_module.html#debug_connection) ## strict-validate-path-type - Ingress objects contains a field called pathType that defines the proxy behavior. It can be `Exact`, `Prefix` and `ImplementationSpecific`. When pathType is configured as `Exact` or `Prefix`, there should be a more strict validation, allowing only paths starting with "/" and @@ -1379,23 +1383,3 @@ This means that Ingress objects that rely on paths containing regex characters s The cluster admin should establish validation rules using mechanisms like [Open Policy Agent](https://www.openpolicyagent.org/) to validate that only authorized users can use `ImplementationSpecific` pathType and that only the authorized characters can be used. - -_**default:**_ "true" - -## grpc-buffer-size-kb - -Sets the configuration for the GRPC Buffer Size parameter. If not set it will use the default from NGINX. - -_References:_ -[https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_buffer_size](https://nginx.org/en/docs/http/ngx_http_grpc_module.html#grpc_buffer_size) - -## relative-redirects - -Use relative redirects instead of absolute redirects. Absolute redirects are the default in nginx. RFC7231 allows relative redirects since 2014. -Similar to the Ingress rule annotation `nginx.ingress.kubernetes.io/relative-redirects`. - -_**default:**_ "false" - -_References:_ -- [https://nginx.org/en/docs/http/ngx_http_core_module.html#absolute_redirect](https://nginx.org/en/docs/http/ngx_http_core_module.html#absolute_redirect) -- [https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.2](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.2) diff --git a/docs/user-guide/retaining-client-ipaddress.md b/docs/user-guide/retaining-client-ipaddress.md new file mode 100644 index 000000000..237bd3004 --- /dev/null +++ b/docs/user-guide/retaining-client-ipaddress.md @@ -0,0 +1,44 @@ + +## Retaining Client IPAddress + +Please read this https://kubernetes.github.io/ingress-nginx/user-guide/miscellaneous/#source-ip-address , to get details of retaining the client IPAddress. + +### Using proxy-protocol + +Please read this https://kubernetes.github.io/ingress-nginx/user-guide/miscellaneous/#proxy-protocol , to use proxy-protocol for retaining client IPAddress + + +### Using the K8S spec service.spec.externalTrafficPolicy + +``` +% kubectl explain service.spec.externalTrafficPolicy +KIND: Service +VERSION: v1 + +FIELD: externalTrafficPolicy + +DESCRIPTION: + externalTrafficPolicy describes how nodes distribute service traffic they + receive on one of the Service's "externally-facing" addresses (NodePorts, + ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will + configure the service in a way that assumes that external load balancers + will take care of balancing the service traffic between nodes, and so each + node will deliver traffic only to the node-local endpoints of the service, + without masquerading the client source IP. (Traffic mistakenly sent to a + node with no endpoints will be dropped.) The default value, "Cluster", uses + the standard behavior of routing to all endpoints evenly (possibly modified + by topology and other features). Note that traffic sent to an External IP or + LoadBalancer IP from within the cluster will always get "Cluster" semantics, + but clients sending to a NodePort from within the cluster may need to take + traffic policy into account when picking a node. + + Possible enum values: + - `"Cluster"` routes traffic to all endpoints. + - `"Local"` preserves the source IP of the traffic by routing only to + endpoints on the same node as the traffic was received on (dropping the + traffic if there are no local endpoints). + +``` + + +- Setting the field `externalTrafficPolicy`, in the ingress-controller service, to a value of `Local` retains the client's ipaddress, within the scope explained above diff --git a/docs/user-guide/third-party-addons/opentelemetry.md b/docs/user-guide/third-party-addons/opentelemetry.md index 255ba1ffa..e681e1c69 100644 --- a/docs/user-guide/third-party-addons/opentelemetry.md +++ b/docs/user-guide/third-party-addons/opentelemetry.md @@ -1,304 +1,314 @@ -# OpenTelemetry - -Enables requests served by NGINX for distributed telemetry via The OpenTelemetry Project. - -Using the third party module [opentelemetry-cpp-contrib/nginx](https://github.com/open-telemetry/opentelemetry-cpp-contrib/tree/main/instrumentation/nginx) the Ingress-Nginx Controller can configure NGINX to enable [OpenTelemetry](http://opentelemetry.io) instrumentation. -By default this feature is disabled. - -Check out this demo showcasing OpenTelemetry in Ingress NGINX. The video provides an overview and -practical demonstration of how OpenTelemetry can be utilized in Ingress NGINX for observability -and monitoring purposes. - -

- - Video Thumbnail - -

- -

Demo: OpenTelemetry in Ingress NGINX.

- -## Usage - -To enable the instrumentation we must enable OpenTelemetry in the configuration ConfigMap: -```yaml -data: - enable-opentelemetry: "true" -``` - -To enable or disable instrumentation for a single Ingress, use -the `enable-opentelemetry` annotation: -```yaml -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/enable-opentelemetry: "true" -``` - -We must also set the host to use when uploading traces: - -```yaml -otlp-collector-host: "otel-coll-collector.otel.svc" -``` -NOTE: While the option is called `otlp-collector-host`, you will need to point this to any backend that receives otlp-grpc. - -Next you will need to deploy a distributed telemetry system which uses OpenTelemetry. -[opentelemetry-collector](https://github.com/open-telemetry/opentelemetry-collector), [Jaeger](https://www.jaegertracing.io/) -[Tempo](https://github.com/grafana/tempo), and [zipkin](https://zipkin.io/) -have been tested. - -Other optional configuration options: -```yaml -# specifies the name to use for the server span -opentelemetry-operation-name - -# sets whether or not to trust incoming telemetry spans -opentelemetry-trust-incoming-span - -# specifies the port to use when uploading traces, Default: 4317 -otlp-collector-port - -# specifies the service name to use for any traces created, Default: nginx -otel-service-name - -# The maximum queue size. After the size is reached data are dropped. -otel-max-queuesize - -# The delay interval in milliseconds between two consecutive exports. -otel-schedule-delay-millis - -# How long the export can run before it is cancelled. -otel-schedule-delay-millis - -# The maximum batch size of every export. It must be smaller or equal to maxQueueSize. -otel-max-export-batch-size - -# specifies sample rate for any traces created, Default: 0.01 -otel-sampler-ratio - -# specifies the sampler to be used when sampling traces. -# The available samplers are: AlwaysOn, AlwaysOff, TraceIdRatioBased, Default: AlwaysOff -otel-sampler - -# Uses sampler implementation which by default will take a sample if parent Activity is sampled, Default: false -otel-sampler-parent-based -``` - -Note that you can also set whether to trust incoming spans (global default is true) per-location using annotations like the following: -```yaml -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span: "true" -``` - -## Examples - -The following examples show how to deploy and test different distributed telemetry systems. These example can be performed using Docker Desktop. - -In the [esigo/nginx-example](https://github.com/esigo/nginx-example) -GitHub repository is an example of a simple hello service: - -```mermaid -graph TB - subgraph Browser - start["http://esigo.dev/hello/nginx"] - end - - subgraph app - sa[service-a] - sb[service-b] - sa --> |name: nginx| sb - sb --> |hello nginx!| sa - end - - subgraph otel - otc["Otel Collector"] - end - - subgraph observability - tempo["Tempo"] - grafana["Grafana"] - backend["Jaeger"] - zipkin["Zipkin"] - end - - subgraph ingress-nginx - ngx[nginx] - end - - subgraph ngx[nginx] - ng[nginx] - om[OpenTelemetry module] - end - - subgraph Node - app - otel - observability - ingress-nginx - om --> |otlp-gRPC| otc --> |jaeger| backend - otc --> |zipkin| zipkin - otc --> |otlp-gRPC| tempo --> grafana - sa --> |otlp-gRPC| otc - sb --> |otlp-gRPC| otc - start --> ng --> sa - end -``` - -To install the example and collectors run: - -1. Enable OpenTelemetry and set the otlp-collector-host: - - ```yaml - $ echo ' - apiVersion: v1 - kind: ConfigMap - data: - enable-opentelemetry: "true" - opentelemetry-config: "/etc/nginx/opentelemetry.toml" - opentelemetry-operation-name: "HTTP $request_method $service_name $uri" - opentelemetry-trust-incoming-span: "true" - otlp-collector-host: "otel-coll-collector.otel.svc" - otlp-collector-port: "4317" - otel-max-queuesize: "2048" - otel-schedule-delay-millis: "5000" - otel-max-export-batch-size: "512" - otel-service-name: "nginx-proxy" # Opentelemetry resource name - otel-sampler: "AlwaysOn" # Also: AlwaysOff, TraceIdRatioBased - otel-sampler-ratio: "1.0" - otel-sampler-parent-based: "false" - metadata: - name: ingress-nginx-controller - namespace: ingress-nginx - ' | kubectl replace -f - - ``` - -2. Deploy otel-collector, grafana and Jaeger backend: - - ```bash - # add helm charts needed for grafana and OpenTelemetry collector - helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts - helm repo add grafana https://grafana.github.io/helm-charts - helm repo update - # deploy cert-manager needed for OpenTelemetry collector operator - kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml - # create observability namespace - kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/namespace.yaml - # install OpenTelemetry collector operator - helm upgrade --install otel-collector-operator -n otel --create-namespace open-telemetry/opentelemetry-operator - # deploy OpenTelemetry collector - kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/collector.yaml - # deploy Jaeger all-in-one - kubectl apply -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.37.0/jaeger-operator.yaml -n observability - kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/jaeger.yaml -n observability - # deploy zipkin - kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/zipkin.yaml -n observability - # deploy tempo and grafana - helm upgrade --install tempo grafana/tempo --create-namespace -n observability - helm upgrade -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/grafana/grafana-values.yaml --install grafana grafana/grafana --create-namespace -n observability - ``` - -3. Build and deploy demo app: - - ```bash - # build images - make images - - # deploy demo app: - make deploy-app - ``` - -4. Make a few requests to the Service: - - ```bash - kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8090:80 - curl http://esigo.dev:8090/hello/nginx - - - StatusCode : 200 - StatusDescription : OK - Content : {"v":"hello nginx!"} - - RawContent : HTTP/1.1 200 OK - Connection: keep-alive - Content-Length: 21 - Content-Type: text/plain; charset=utf-8 - Date: Mon, 10 Oct 2022 17:43:33 GMT - - {"v":"hello nginx!"} - - Forms : {} - Headers : {[Connection, keep-alive], [Content-Length, 21], [Content-Type, text/plain; charset=utf-8], [Date, - Mon, 10 Oct 2022 17:43:33 GMT]} - Images : {} - InputFields : {} - Links : {} - ParsedHtml : System.__ComObject - RawContentLength : 21 - ``` - -5. View the Grafana UI: - - ```bash - kubectl port-forward --namespace=observability service/grafana 3000:80 - ``` - In the Grafana interface we can see the details: - ![grafana screenshot](../../images/otel-grafana-demo.png "grafana screenshot") - -6. View the Jaeger UI: - - ```bash - kubectl port-forward --namespace=observability service/jaeger-all-in-one-query 16686:16686 - ``` - In the Jaeger interface we can see the details: - ![Jaeger screenshot](../../images/otel-jaeger-demo.png "Jaeger screenshot") - -7. View the Zipkin UI: - - ```bash - kubectl port-forward --namespace=observability service/zipkin 9411:9411 - ``` - In the Zipkin interface we can see the details: - ![zipkin screenshot](../../images/otel-zipkin-demo.png "zipkin screenshot") - -## Migration from OpenTracing, Jaeger, Zipkin and Datadog - -If you are migrating from OpenTracing, Jaeger, Zipkin, or Datadog to OpenTelemetry, -you may need to update various annotations and configurations. Here are the mappings -for common annotations and configurations: - -### Annotations - -| Legacy | OpenTelemetry | -|---------------------------------------------------------------|-----------------------------------------------------------------| -| `nginx.ingress.kubernetes.io/enable-opentracing` | `nginx.ingress.kubernetes.io/enable-opentelemetry` | -| `nginx.ingress.kubernetes.io/opentracing-trust-incoming-span` | `nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span` | - -### Configs - -| Legacy | OpenTelemetry | -|---------------------------------------|----------------------------------------------| -| `opentracing-operation-name` | `opentelemetry-operation-name` | -| `opentracing-location-operation-name` | `opentelemetry-operation-name` | -| `opentracing-trust-incoming-span` | `opentelemetry-trust-incoming-span` | -| `zipkin-collector-port` | `otlp-collector-port` | -| `zipkin-service-name` | `otel-service-name` | -| `zipkin-sample-rate` | `otel-sampler-ratio` | -| `jaeger-collector-port` | `otlp-collector-port` | -| `jaeger-endpoint` | `otlp-collector-port`, `otlp-collector-host` | -| `jaeger-service-name` | `otel-service-name` | -| `jaeger-propagation-format` | `N/A` | -| `jaeger-sampler-type` | `otel-sampler` | -| `jaeger-sampler-param` | `otel-sampler` | -| `jaeger-sampler-host` | `N/A` | -| `jaeger-sampler-port` | `N/A` | -| `jaeger-trace-context-header-name` | `N/A` | -| `jaeger-debug-header` | `N/A` | -| `jaeger-baggage-header` | `N/A` | -| `jaeger-tracer-baggage-header-prefix` | `N/A` | -| `datadog-collector-port` | `otlp-collector-port` | -| `datadog-service-name` | `otel-service-name` | -| `datadog-environment` | `N/A` | -| `datadog-operation-name-override` | `N/A` | -| `datadog-priority-sampling` | `otel-sampler` | -| `datadog-sample-rate` | `otel-sampler-ratio` | +# OpenTelemetry + +Enables requests served by NGINX for distributed telemetry via The OpenTelemetry Project. + +Using the third party module [opentelemetry-cpp-contrib/nginx](https://github.com/open-telemetry/opentelemetry-cpp-contrib/tree/main/instrumentation/nginx) the Ingress-Nginx Controller can configure NGINX to enable [OpenTelemetry](http://opentelemetry.io) instrumentation. +By default this feature is disabled. + +Check out this demo showcasing OpenTelemetry in Ingress NGINX. The video provides an overview and +practical demonstration of how OpenTelemetry can be utilized in Ingress NGINX for observability +and monitoring purposes. + +

+ + Video Thumbnail + +

+ +

Demo: OpenTelemetry in Ingress NGINX.

+ +## Usage + +To enable the instrumentation we must enable OpenTelemetry in the configuration ConfigMap: +```yaml +data: + enable-opentelemetry: "true" +``` + +To enable or disable instrumentation for a single Ingress, use +the `enable-opentelemetry` annotation: +```yaml +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/enable-opentelemetry: "true" +``` + +We must also set the host to use when uploading traces: + +```yaml +otlp-collector-host: "otel-coll-collector.otel.svc" +``` +NOTE: While the option is called `otlp-collector-host`, you will need to point this to any backend that receives otlp-grpc. + +Next you will need to deploy a distributed telemetry system which uses OpenTelemetry. +[opentelemetry-collector](https://github.com/open-telemetry/opentelemetry-collector), [Jaeger](https://www.jaegertracing.io/) +[Tempo](https://github.com/grafana/tempo), and [zipkin](https://zipkin.io/) +have been tested. + +Other optional configuration options: +```yaml +# specifies the name to use for the server span +opentelemetry-operation-name + +# sets whether or not to trust incoming telemetry spans +opentelemetry-trust-incoming-span + +# specifies the port to use when uploading traces, Default: 4317 +otlp-collector-port + +# specifies the service name to use for any traces created, Default: nginx +otel-service-name + +# The maximum queue size. After the size is reached data are dropped. +otel-max-queuesize + +# The delay interval in milliseconds between two consecutive exports. +otel-schedule-delay-millis + +# How long the export can run before it is cancelled. +otel-schedule-delay-millis + +# The maximum batch size of every export. It must be smaller or equal to maxQueueSize. +otel-max-export-batch-size + +# specifies sample rate for any traces created, Default: 0.01 +otel-sampler-ratio + +# specifies the sampler to be used when sampling traces. +# The available samplers are: AlwaysOn, AlwaysOff, TraceIdRatioBased, Default: AlwaysOff +otel-sampler + +# Uses sampler implementation which by default will take a sample if parent Activity is sampled, Default: false +otel-sampler-parent-based +``` + +Note that you can also set whether to trust incoming spans (global default is true) per-location using annotations like the following: +```yaml +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span: "true" +``` + +## Examples + +The following examples show how to deploy and test different distributed telemetry systems. These example can be performed using Docker Desktop. + +In the [esigo/nginx-example](https://github.com/esigo/nginx-example) +GitHub repository is an example of a simple hello service: + +```mermaid +graph TB + subgraph Browser + start["http://esigo.dev/hello/nginx"] + end + + subgraph app + sa[service-a] + sb[service-b] + sa --> |name: nginx| sb + sb --> |hello nginx!| sa + end + + subgraph otel + otc["Otel Collector"] + end + + subgraph observability + tempo["Tempo"] + grafana["Grafana"] + backend["Jaeger"] + zipkin["Zipkin"] + end + + subgraph ingress-nginx + ngx[nginx] + end + + subgraph ngx[nginx] + ng[nginx] + om[OpenTelemetry module] + end + + subgraph Node + app + otel + observability + ingress-nginx + om --> |otlp-gRPC| otc --> |jaeger| backend + otc --> |zipkin| zipkin + otc --> |otlp-gRPC| tempo --> grafana + sa --> |otlp-gRPC| otc + sb --> |otlp-gRPC| otc + start --> ng --> sa + end +``` + +To install the example and collectors run: + +1. Enable Ingress addon with: + + ```yaml + opentelemetry: + enabled: true + image: registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0 + containerSecurityContext: + allowPrivilegeEscalation: false + ``` + +2. Enable OpenTelemetry and set the otlp-collector-host: + + ```yaml + $ echo ' + apiVersion: v1 + kind: ConfigMap + data: + enable-opentelemetry: "true" + opentelemetry-config: "/etc/nginx/opentelemetry.toml" + opentelemetry-operation-name: "HTTP $request_method $service_name $uri" + opentelemetry-trust-incoming-span: "true" + otlp-collector-host: "otel-coll-collector.otel.svc" + otlp-collector-port: "4317" + otel-max-queuesize: "2048" + otel-schedule-delay-millis: "5000" + otel-max-export-batch-size: "512" + otel-service-name: "nginx-proxy" # Opentelemetry resource name + otel-sampler: "AlwaysOn" # Also: AlwaysOff, TraceIdRatioBased + otel-sampler-ratio: "1.0" + otel-sampler-parent-based: "false" + metadata: + name: ingress-nginx-controller + namespace: ingress-nginx + ' | kubectl replace -f - + ``` + +4. Deploy otel-collector, grafana and Jaeger backend: + + ```bash + # add helm charts needed for grafana and OpenTelemetry collector + helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts + helm repo add grafana https://grafana.github.io/helm-charts + helm repo update + # deply cert-manager needed for OpenTelemetry collector operator + kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml + # create observability namespace + kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/namespace.yaml + # install OpenTelemetry collector operator + helm upgrade --install otel-collector-operator -n otel --create-namespace open-telemetry/opentelemetry-operator + # deploy OpenTelemetry collector + kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/collector.yaml + # deploy Jaeger all-in-one + kubectl apply -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.37.0/jaeger-operator.yaml -n observability + kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/jaeger.yaml -n observability + # deploy zipkin + kubectl apply -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/zipkin.yaml -n observability + # deploy tempo and grafana + helm upgrade --install tempo grafana/tempo --create-namespace -n observability + helm upgrade -f https://raw.githubusercontent.com/esigo/nginx-example/main/observability/grafana/grafana-values.yaml --install grafana grafana/grafana --create-namespace -n observability + ``` + +3. Build and deploy demo app: + + ```bash + # build images + make images + + # deploy demo app: + make deploy-app + ``` + +5. Make a few requests to the Service: + + ```bash + kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8090:80 + curl http://esigo.dev:8090/hello/nginx + + + StatusCode : 200 + StatusDescription : OK + Content : {"v":"hello nginx!"} + + RawContent : HTTP/1.1 200 OK + Connection: keep-alive + Content-Length: 21 + Content-Type: text/plain; charset=utf-8 + Date: Mon, 10 Oct 2022 17:43:33 GMT + + {"v":"hello nginx!"} + + Forms : {} + Headers : {[Connection, keep-alive], [Content-Length, 21], [Content-Type, text/plain; charset=utf-8], [Date, + Mon, 10 Oct 2022 17:43:33 GMT]} + Images : {} + InputFields : {} + Links : {} + ParsedHtml : System.__ComObject + RawContentLength : 21 + ``` + +6. View the Grafana UI: + + ```bash + kubectl port-forward --namespace=observability service/grafana 3000:80 + ``` + In the Grafana interface we can see the details: + ![grafana screenshot](../../images/otel-grafana-demo.png "grafana screenshot") + +7. View the Jaeger UI: + + ```bash + kubectl port-forward --namespace=observability service/jaeger-all-in-one-query 16686:16686 + ``` + In the Jaeger interface we can see the details: + ![Jaeger screenshot](../../images/otel-jaeger-demo.png "Jaeger screenshot") + +8. View the Zipkin UI: + + ```bash + kubectl port-forward --namespace=observability service/zipkin 9411:9411 + ``` + In the Zipkin interface we can see the details: + ![zipkin screenshot](../../images/otel-zipkin-demo.png "zipkin screenshot") + +## Migration from OpenTracing, Jaeger, Zipkin and Datadog + +If you are migrating from OpenTracing, Jaeger, Zipkin, or Datadog to OpenTelemetry, +you may need to update various annotations and configurations. Here are the mappings +for common annotations and configurations: + +### Annotations + +| Legacy | OpenTelemetry | +|---------------------------------------------------------------|-----------------------------------------------------------------| +| `nginx.ingress.kubernetes.io/enable-opentracing` | `nginx.ingress.kubernetes.io/enable-opentelemetry` | +| `nginx.ingress.kubernetes.io/opentracing-trust-incoming-span` | `nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span` | + +### Configs + +| Legacy | OpenTelemetry | +|---------------------------------------|----------------------------------------------| +| `opentracing-operation-name` | `opentelemetry-operation-name` | +| `opentracing-location-operation-name` | `opentelemetry-operation-name` | +| `opentracing-trust-incoming-span` | `opentelemetry-trust-incoming-span` | +| `zipkin-collector-port` | `otlp-collector-port` | +| `zipkin-service-name` | `otel-service-name` | +| `zipkin-sample-rate` | `otel-sampler-ratio` | +| `jaeger-collector-port` | `otlp-collector-port` | +| `jaeger-endpoint` | `otlp-collector-port`, `otlp-collector-host` | +| `jaeger-service-name` | `otel-service-name` | +| `jaeger-propagation-format` | `N/A` | +| `jaeger-sampler-type` | `otel-sampler` | +| `jaeger-sampler-param` | `otel-sampler` | +| `jaeger-sampler-host` | `N/A` | +| `jaeger-sampler-port` | `N/A` | +| `jaeger-trace-context-header-name` | `N/A` | +| `jaeger-debug-header` | `N/A` | +| `jaeger-baggage-header` | `N/A` | +| `jaeger-tracer-baggage-header-prefix` | `N/A` | +| `datadog-collector-port` | `otlp-collector-port` | +| `datadog-service-name` | `otel-service-name` | +| `datadog-environment` | `N/A` | +| `datadog-operation-name-override` | `N/A` | +| `datadog-priority-sampling` | `otel-sampler` | +| `datadog-sample-rate` | `otel-sampler-ratio` | diff --git a/ginkgo_upgrade.md b/ginkgo_upgrade.md index 87e6bd9fd..57db0f28f 100644 --- a/ginkgo_upgrade.md +++ b/ginkgo_upgrade.md @@ -49,7 +49,7 @@ Promoting the images basically means that images, that were pushed to staging co ``` ... - pushing manifest for us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx/controller:v1.0.2@sha256:e15fac6e8474d77e1f017edc33d804ce72a184e3c0a30963b2a0d7f0b89f6b16 + pushing manifest for gcr.io/k8s-staging-ingress-nginx/controller:v1.0.2@sha256:e15fac6e8474d77e1f017edc33d804ce72a184e3c0a30963b2a0d7f0b89f6b16 ... ``` @@ -65,11 +65,11 @@ Promoting the images basically means that images, that were pushed to staging co - Create a branch in your fork, named as the issue number for this release -- In the related branch, of your fork, edit the file registry.k8s.io/images/k8s-staging-ingress-nginx/images.yaml. +- In the related branch, of your fork, edit the file k8s.gcr.io/images/k8s-staging-ingress-nginx/images.yaml. - For making it easier, you can edit your branch directly in the browser. But be careful about making any mistake. -- Insert the sha(s) & the tag(s), in a new line, in this file [Project kubernetes/k8s.io Ingress-Nginx-Controller Images](https://github.com/kubernetes/k8s.io/blob/main/registry.k8s.io/images/k8s-staging-ingress-nginx/images.yaml) Look at this [example PR and the diff](https://github.com/kubernetes/k8s.io/pull/4499) to see how it was done before +- Insert the sha(s) & the tag(s), in a new line, in this file [Project kubernetes/k8s.io Ingress-Nginx-Controller Images](https://github.com/kubernetes/k8s.io/blob/main/k8s.gcr.io/images/k8s-staging-ingress-nginx/images.yaml) Look at this [example PR and the diff](https://github.com/kubernetes/k8s.io/pull/4499) to see how it was done before - Save and commit @@ -128,4 +128,4 @@ Promoting the images basically means that images, that were pushed to staging co - Finally merge the PR. -## END ## +## END ## \ No newline at end of file diff --git a/go.mod b/go.mod index 34584bbf9..701a07cbe 100644 --- a/go.mod +++ b/go.mod @@ -1,93 +1,86 @@ module k8s.io/ingress-nginx -go 1.23.6 +go 1.22.0 + +toolchain go1.22.4 require ( - dario.cat/mergo v1.0.1 + dario.cat/mergo v1.0.0 github.com/armon/go-proxyproto v0.1.0 github.com/eapache/channels v1.1.0 - github.com/fsnotify/fsnotify v1.8.0 + github.com/fsnotify/fsnotify v1.7.0 github.com/json-iterator/go v1.1.12 github.com/kylelemons/godebug v1.1.0 github.com/mitchellh/go-ps v1.0.0 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 github.com/moul/pb v0.0.0-20220425114252-bca18df4138c - github.com/ncabatoff/process-exporter v0.8.5 - github.com/onsi/ginkgo/v2 v2.22.2 - github.com/opencontainers/runc v1.2.5 - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 - github.com/prometheus/client_golang v1.20.5 + github.com/ncabatoff/process-exporter v0.8.2 + github.com/onsi/ginkgo/v2 v2.19.0 + github.com/opencontainers/runc v1.1.13 + github.com/pmezard/go-difflib v1.0.0 + github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.62.0 - github.com/spf13/cobra v1.9.1 - github.com/spf13/pflag v1.0.6 - github.com/stretchr/testify v1.10.0 + github.com/prometheus/common v0.55.0 + github.com/spf13/cobra v1.8.1 + github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.9.0 github.com/yudai/gojsondiff v1.0.0 github.com/zakjan/cert-chain-resolver v0.0.0-20221221105603-fcedb00c5b30 - golang.org/x/crypto v0.33.0 - google.golang.org/grpc v1.70.0 + golang.org/x/crypto v0.25.0 + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f + google.golang.org/grpc v1.65.0 google.golang.org/grpc/examples v0.0.0-20240223204917-5ccf176a08ab gopkg.in/go-playground/pool.v3 v3.1.1 gopkg.in/mcuadros/go-syslog.v2 v2.3.0 - k8s.io/api v0.32.2 - k8s.io/apiextensions-apiserver v0.32.2 - k8s.io/apimachinery v0.32.2 - k8s.io/apiserver v0.32.2 - k8s.io/cli-runtime v0.32.2 - k8s.io/client-go v0.32.2 - k8s.io/code-generator v0.32.2 - k8s.io/component-base v0.32.2 + k8s.io/api v0.30.2 + k8s.io/apiextensions-apiserver v0.30.1 + k8s.io/apimachinery v0.30.2 + k8s.io/apiserver v0.30.1 + k8s.io/cli-runtime v0.30.0 + k8s.io/client-go v0.30.2 + k8s.io/code-generator v0.30.1 + k8s.io/component-base v0.30.2 k8s.io/klog/v2 v2.130.1 pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 - sigs.k8s.io/controller-runtime v0.20.2 - sigs.k8s.io/mdtoc v1.4.0 + sigs.k8s.io/controller-runtime v0.18.4 + sigs.k8s.io/mdtoc v1.1.0 ) require ( - github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/moby/sys/userns v0.1.0 // indirect - github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/otel v1.32.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect - sigs.k8s.io/release-utils v0.8.3 // indirect -) - -require ( - github.com/Anddd7/pb v0.0.0-20240425032658-369b0f6a404c github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cyphar/filepath-securejoin v0.4.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.12.0 // indirect - github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa // indirect github.com/go-errors/errors v1.5.1 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect - github.com/google/btree v1.1.3 // indirect + github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect @@ -112,26 +105,30 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yudai/pp v2.0.1+incompatible // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.29.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.28.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/protobuf v1.36.1 // indirect + go.starlark.net v0.0.0-20240123142251-f86470692795 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/evanphx/json-patch.v5 v5.9.0 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/kustomize/api v0.18.0 // indirect - sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 // indirect + k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f // indirect + k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.16.0 // indirect + sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 6e933d349..a4a11afe3 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,8 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/Anddd7/pb v0.0.0-20240425032658-369b0f6a404c h1:uhBf0CHXi7nCFZXxHV7l1cBcYFEEVRK4FYxvm1l9lKg= -github.com/Anddd7/pb v0.0.0-20240425032658-369b0f6a404c/go.mod h1:vYWKbnXd2KAZHUECLPzSE0Er3FgiEmOdPtxwSIRihck= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/armon/go-proxyproto v0.1.0 h1:TWWcSsjco7o2itn6r25/5AqKBiWmsiuzsUDLT/MTl7k= @@ -14,42 +13,37 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= -github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= -github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -66,6 +60,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -75,10 +71,11 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= -github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= -github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU= +github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 h1:k4Tw0nt6lwro3Uin8eqoET7MDA4JnT8YgbCjc/g5E3k= +github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -90,8 +87,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -99,6 +96,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -107,8 +106,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -137,8 +134,6 @@ github.com/mmarkdown/mmark v2.0.40+incompatible h1:vMeUeDzBK3H+/mU0oMVfMuhSXJlIA github.com/mmarkdown/mmark v2.0.40+incompatible/go.mod h1:Uvmoz7tvsWpr7bMVxIpqZPyN3FbOtzDmnsJDFp7ltJs= github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g= github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= -github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= -github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -154,8 +149,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833 h1:t4WWQ9I797y7QUgeEjeXnVb+oYuEDQc6gLvrZJTYo94= github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmXSjMEqs5Tezj/w2emQoM41wzYM9KpDKUHPYag= -github.com/ncabatoff/process-exporter v0.8.5 h1:Hk1sflgRWn0Xrh/OsupQLVVCTW01kv0YYrGxu7NvkmM= -github.com/ncabatoff/process-exporter v0.8.5/go.mod h1:IZndG/m2Y++D90y99NhDJfg0SOkpbx/Fl6MlnBr4SC0= +github.com/ncabatoff/process-exporter v0.8.2 h1:g08B7UMSn9nrEjCrqGtBG/IagnCAc/2lSGzGZgcxJFs= +github.com/ncabatoff/process-exporter v0.8.2/go.mod h1:MxEOWl740VK/hlWycJkq91VrA2mI+U9Bvc1wuyAaxA4= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -163,42 +158,41 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/opencontainers/runc v1.2.5 h1:8KAkq3Wrem8bApgOHyhRI/8IeLXIfmZ6Qaw6DNSLnA4= -github.com/opencontainers/runc v1.2.5/go.mod h1:dOQeFo29xZKBNeRBI0B19mJtfHv68YgCTh1X+YphA+4= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs= +github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -207,11 +201,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli v1.17.1-0.20160602030128-01a33823596e/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= @@ -224,47 +216,42 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zakjan/cert-chain-resolver v0.0.0-20221221105603-fcedb00c5b30 h1:rzHvkiukOVYcf840FqAsHqBMhfLofvQIxWtczkGRklU= github.com/zakjan/cert-chain-resolver v0.0.0-20221221105603-fcedb00c5b30/go.mod h1:/Hzu8ych2oXCs1iNI+MeASyFzWTncQ6nlu/wgqbqC2A= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.starlark.net v0.0.0-20240123142251-f86470692795 h1:LmbG8Pq7KDGkglKVn8VpZOZj6vb9b8nKEGcg9l03epM= +go.starlark.net v0.0.0-20240123142251-f86470692795/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -279,33 +266,33 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/examples v0.0.0-20240223204917-5ccf176a08ab h1:tg8hvIl5RmFBuXlcJMuL0h4Psh1gx5Q5xEMwzBZIzWA= google.golang.org/grpc/examples v0.0.0-20240223204917-5ccf176a08ab/go.mod h1:liVNnGuZDITxuksuZ+BBvdy7FcJfeNk+efF9qgqNUmc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -314,14 +301,14 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/evanphx/json-patch.v5 v5.9.0 h1:hx1VU2SGj4F8r9b8GUwJLdc8DNO8sy79ZGui0G05GLo= +gopkg.in/evanphx/json-patch.v5 v5.9.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= @@ -335,50 +322,50 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= -k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= -k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4= -k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw= -k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM= -k8s.io/cli-runtime v0.32.2 h1:aKQR4foh9qeyckKRkNXUccP9moxzffyndZAvr+IXMks= -k8s.io/cli-runtime v0.32.2/go.mod h1:a/JpeMztz3xDa7GCyyShcwe55p8pbcCVQxvqZnIwXN8= -k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= -k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= -k8s.io/code-generator v0.32.2 h1:CIvyPrLWP7cMgrqval2qYT839YAwCDeSvGfXgWSNpHQ= -k8s.io/code-generator v0.32.2/go.mod h1:plh7bWk7JztAUkHM4zpbdy0KOMdrhsePcZL2HLWFH7Y= -k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU= -k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0= -k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4= -k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= +k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= +k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= +k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= +k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= +k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= +k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8= +k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo= +k8s.io/cli-runtime v0.30.0 h1:0vn6/XhOvn1RJ2KJOC6IRR2CGqrpT6QQF4+8pYpWQ48= +k8s.io/cli-runtime v0.30.0/go.mod h1:vATpDMATVTMA79sZ0YUCzlMelf6rUjoBzlp+RnoM+cg= +k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= +k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= +k8s.io/code-generator v0.30.1 h1:ZsG++q5Vt0ScmKCeLhynUuWgcwFGg1Hl1AGfatqPJBI= +k8s.io/code-generator v0.30.1/go.mod h1:hFgxRsvOUg79mbpbVKfjJvRhVz1qLoe40yZDJ/hwRH4= +k8s.io/component-base v0.30.2 h1:pqGBczYoW1sno8q9ObExUqrYSKhtE5rW3y6gX88GZII= +k8s.io/component-base v0.30.2/go.mod h1:yQLkQDrkK8J6NtP+MGJOws+/PPeEXNpwFixsUI7h/OE= +k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 h1:bKcdZJOPICVmIIuaM9+MXmapE94dn5AYv5ODs1jA43o= +k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM= +k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= +k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= +k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg= pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg= -sigs.k8s.io/controller-runtime v0.20.2 h1:/439OZVxoEc02psi1h4QO3bHzTgu49bb347Xp4gW1pc= -sigs.k8s.io/controller-runtime v0.20.2/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= -sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= -sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= -sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= -sigs.k8s.io/mdtoc v1.4.0 h1:2pDEwJSjoVrGr5BPkG+LoLkYLKvgtGYurrBY8ul3SxQ= -sigs.k8s.io/mdtoc v1.4.0/go.mod h1:KVnRRtK1rX9aQ95qF0rt3x2ytTxf3r7W7N41H+0KF0k= -sigs.k8s.io/release-utils v0.8.3 h1:KtOtA4qDmzJyeQ2zkDsFVI25+NViwms/o5eL2NftFdA= -sigs.k8s.io/release-utils v0.8.3/go.mod h1:fp82Fma06OXBhEJ+GUJKqvcplDBomruK1R/1fWJnsrQ= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= +sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.16.0 h1:/zAR4FOQDCkgSDmVzV2uiFbuy9bhu3jEzthrHCuvm1g= +sigs.k8s.io/kustomize/api v0.16.0/go.mod h1:MnFZ7IP2YqVyVwMWoRxPtgl/5hpA+eCCrQR/866cm5c= +sigs.k8s.io/kustomize/kyaml v0.16.0 h1:6J33uKSoATlKZH16unr2XOhDI+otoe2sR3M8PDzW3K0= +sigs.k8s.io/kustomize/kyaml v0.16.0/go.mod h1:xOK/7i+vmE14N2FdFyugIshB8eF6ALpy7jI87Q2nRh4= +sigs.k8s.io/mdtoc v1.1.0 h1:q3YtqYzmC2e0hgLXRIOm7/QLuPux1CX3ZHCwlbABxZo= +sigs.k8s.io/mdtoc v1.1.0/go.mod h1:QZLVEdHH2iNIR4uHAZyvFRtjloHgVItk8lo/mzCtq3w= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/go.work b/go.work new file mode 100644 index 000000000..c963e3c0e --- /dev/null +++ b/go.work @@ -0,0 +1,7 @@ +go 1.22.0 + +use ( + . + ./images/kube-webhook-certgen/rootfs + ./magefiles +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 000000000..847afcea0 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,1089 @@ +cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= +cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go/accessapproval v1.6.0 h1:x0cEHro/JFPd7eS4BlEWNTMecIj2HdXjOVB5BtvwER0= +cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= +cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc= +cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= +cloud.google.com/go/accesscontextmanager v1.7.0 h1:MG60JgnEoawHJrbWw0jGdv6HLNSf6gQvYRiXpuzqgEA= +cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= +cloud.google.com/go/accesscontextmanager v1.8.4/go.mod h1:ParU+WbMpD34s5JFEnGAnPBYAgUHozaTmDJU7aCU9+M= +cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= +cloud.google.com/go/aiplatform v1.37.0 h1:zTw+suCVchgZyO+k847wjzdVjWmrAuehxdvcZvJwfGg= +cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= +cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= +cloud.google.com/go/aiplatform v1.52.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= +cloud.google.com/go/aiplatform v1.58.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= +cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= +cloud.google.com/go/analytics v0.19.0 h1:LqAo3tAh2FU9+w/r7vc3hBjU23Kv7GhO/PDIW7kIYgM= +cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= +cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= +cloud.google.com/go/analytics v0.21.6/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= +cloud.google.com/go/analytics v0.22.0/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= +cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= +cloud.google.com/go/apigateway v1.5.0 h1:ZI9mVO7x3E9RK/BURm2p1aw9YTBSCQe3klmyP1WxWEg= +cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= +cloud.google.com/go/apigateway v1.6.4/go.mod h1:0EpJlVGH5HwAN4VF4Iec8TAzGN1aQgbxAWGJsnPCGGY= +cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= +cloud.google.com/go/apigeeconnect v1.5.0 h1:sWOmgDyAsi1AZ48XRHcATC0tsi9SkPT7DA/+VCfkaeA= +cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= +cloud.google.com/go/apigeeconnect v1.6.4/go.mod h1:CapQCWZ8TCjnU0d7PobxhpOdVz/OVJ2Hr/Zcuu1xFx0= +cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= +cloud.google.com/go/apigeeregistry v0.6.0 h1:E43RdhhCxdlV+I161gUY2rI4eOaMzHTA5kNkvRsFXvc= +cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= +cloud.google.com/go/apigeeregistry v0.8.2/go.mod h1:h4v11TDGdeXJDJvImtgK2AFVvMIgGWjSb0HRnBSjcX8= +cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= +cloud.google.com/go/apikeys v0.6.0 h1:B9CdHFZTFjVti89tmyXXrO+7vSNo2jvZuHG8zD5trdQ= +cloud.google.com/go/appengine v1.7.1 h1:aBGDKmRIaRRoWJ2tAoN0oVSHoWLhtO9aj/NvUyP4aYs= +cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= +cloud.google.com/go/appengine v1.8.4/go.mod h1:TZ24v+wXBujtkK77CXCpjZbnuTvsFNT41MUaZ28D6vg= +cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= +cloud.google.com/go/area120 v0.7.1 h1:ugckkFh4XkHJMPhTIx0CyvdoBxmOpMe8rNs4Ok8GAag= +cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= +cloud.google.com/go/area120 v0.8.4/go.mod h1:jfawXjxf29wyBXr48+W+GyX/f8fflxp642D/bb9v68M= +cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= +cloud.google.com/go/artifactregistry v1.13.0 h1:o1Q80vqEB6Qp8WLEH3b8FBLNUCrGQ4k5RFj0sn/sgO8= +cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= +cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE= +cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= +cloud.google.com/go/asset v1.13.0 h1:YAsssO08BqZ6mncbb6FPlj9h6ACS7bJQUOlzciSfbNk= +cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= +cloud.google.com/go/asset v1.15.3/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= +cloud.google.com/go/asset v1.17.0/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= +cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4= +cloud.google.com/go/assuredworkloads v1.10.0 h1:VLGnVFta+N4WM+ASHbhc14ZOItOabDLH1MSoDv+Xuag= +cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= +cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U= +cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= +cloud.google.com/go/automl v1.12.0 h1:50VugllC+U4IGl3tDNcZaWvApHBTrn/TvyHDJ0wM+Uw= +cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= +cloud.google.com/go/automl v1.13.4/go.mod h1:ULqwX/OLZ4hBVfKQaMtxMSTlPx0GqGbWN8uA/1EqCP8= +cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= +cloud.google.com/go/baremetalsolution v0.5.0 h1:2AipdYXL0VxMboelTTw8c1UJ7gYu35LZYUbuRv9Q28s= +cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= +cloud.google.com/go/baremetalsolution v1.2.3/go.mod h1:/UAQ5xG3faDdy180rCUv47e0jvpp3BFxT+Cl0PFjw5g= +cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= +cloud.google.com/go/batch v0.7.0 h1:YbMt0E6BtqeD5FvSv1d56jbVsWEzlGm55lYte+M6Mzs= +cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= +cloud.google.com/go/batch v1.6.3/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= +cloud.google.com/go/batch v1.7.0/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= +cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= +cloud.google.com/go/beyondcorp v0.5.0 h1:UkY2BTZkEUAVrgqnSdOJ4p3y9ZRBPEe1LkjgC8Bj/Pc= +cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/beyondcorp v1.0.3/go.mod h1:HcBvnEd7eYr+HGDd5ZbuVmBYX019C6CEXBonXbCVwJo= +cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= +cloud.google.com/go/bigquery v1.50.0 h1:RscMV6LbnAmhAzD893Lv9nXXy2WCaJmbxYPWDLbGqNQ= +cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= +cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= +cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug= +cloud.google.com/go/bigquery v1.58.0/go.mod h1:0eh4mWNY0KrBTjUzLjoYImapGORq9gEPT7MWjCy9lik= +cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc= +cloud.google.com/go/billing v1.13.0 h1:JYj28UYF5w6VBAh0gQYlgHJ/OD1oA+JgW29YZQU+UHM= +cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= +cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= +cloud.google.com/go/billing v1.17.4/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= +cloud.google.com/go/billing v1.18.0/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= +cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= +cloud.google.com/go/binaryauthorization v1.5.0 h1:d3pMDBCCNivxt5a4eaV7FwL7cSH0H7RrEnFrTb1QKWs= +cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= +cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= +cloud.google.com/go/binaryauthorization v1.7.3/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= +cloud.google.com/go/binaryauthorization v1.8.0/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= +cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= +cloud.google.com/go/certificatemanager v1.6.0 h1:5C5UWeSt8Jkgp7OWn2rCkLmYurar/vIWIoSQ2+LaTOc= +cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= +cloud.google.com/go/certificatemanager v1.7.4/go.mod h1:FHAylPe/6IIKuaRmHbjbdLhGhVQ+CWHSD5Jq0k4+cCE= +cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= +cloud.google.com/go/channel v1.12.0 h1:GpcQY5UJKeOekYgsX3QXbzzAc/kRGtBq43fTmyKe6Uw= +cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= +cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= +cloud.google.com/go/channel v1.17.3/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= +cloud.google.com/go/channel v1.17.4/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= +cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= +cloud.google.com/go/cloudbuild v1.9.0 h1:GHQCjV4WlPPVU/j3Rlpc8vNIDwThhd1U9qSY/NPZdko= +cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/cloudbuild v1.14.3/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= +cloud.google.com/go/cloudbuild v1.15.0/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= +cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= +cloud.google.com/go/clouddms v1.5.0 h1:E7v4TpDGUyEm1C/4KIrpVSOCTm0P6vWdHT0I4mostRA= +cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= +cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= +cloud.google.com/go/clouddms v1.7.3/go.mod h1:fkN2HQQNUYInAU3NQ3vRLkV2iWs8lIdmBKOx4nrL6Hc= +cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= +cloud.google.com/go/cloudtasks v1.10.0 h1:uK5k6abf4yligFgYFnG0ni8msai/dSv6mDmiBulU0hU= +cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= +cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= +cloud.google.com/go/cloudtasks v1.12.4/go.mod h1:BEPu0Gtt2dU6FxZHNqqNdGqIG86qyWKBPGnsb7udGY0= +cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/contactcenterinsights v1.6.0 h1:jXIpfcH/VYSE1SYcPzO0n1VVb+sAamiLOgCw45JbOQk= +cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= +cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= +cloud.google.com/go/contactcenterinsights v1.11.3/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= +cloud.google.com/go/contactcenterinsights v1.12.1/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= +cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= +cloud.google.com/go/container v1.15.0 h1:NKlY/wCDapfVZlbVVaeuu2UZZED5Dy1z4Zx1KhEzm8c= +cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= +cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= +cloud.google.com/go/container v1.27.1/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= +cloud.google.com/go/container v1.29.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= +cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA= +cloud.google.com/go/containeranalysis v0.9.0 h1:EQ4FFxNaEAg8PqQCO7bVQfWz9NVwZCUKaM1b3ycfx3U= +cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= +cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= +cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= +cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= +cloud.google.com/go/datacatalog v1.13.0 h1:4H5IJiyUE0X6ShQBqgFFZvGGcrwGVndTwUSLP4c52gw= +cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= +cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= +cloud.google.com/go/datacatalog v1.18.3/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= +cloud.google.com/go/datacatalog v1.19.2/go.mod h1:2YbODwmhpLM4lOFe3PuEhHK9EyTzQJ5AXgIy7EDKTEE= +cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= +cloud.google.com/go/dataflow v0.8.0 h1:eYyD9o/8Nm6EttsKZaEGD84xC17bNgSKCu0ZxwqUbpg= +cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= +cloud.google.com/go/dataflow v0.9.4/go.mod h1:4G8vAkHYCSzU8b/kmsoR2lWyHJD85oMJPHMtan40K8w= +cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= +cloud.google.com/go/dataform v0.7.0 h1:Dyk+fufup1FR6cbHjFpMuP4SfPiF3LI3JtoIIALoq48= +cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= +cloud.google.com/go/dataform v0.9.1/go.mod h1:pWTg+zGQ7i16pyn0bS1ruqIE91SdL2FDMvEYu/8oQxs= +cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= +cloud.google.com/go/datafusion v1.6.0 h1:sZjRnS3TWkGsu1LjYPFD/fHeMLZNXDK6PDHi2s2s/bk= +cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= +cloud.google.com/go/datafusion v1.7.4/go.mod h1:BBs78WTOLYkT4GVZIXQCZT3GFpkpDN4aBY4NDX/jVlM= +cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= +cloud.google.com/go/datalabeling v0.7.0 h1:ch4qA2yvddGRUrlfwrNJCr79qLqhS9QBwofPHfFlDIk= +cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= +cloud.google.com/go/datalabeling v0.8.4/go.mod h1:Z1z3E6LHtffBGrNUkKwbwbDxTiXEApLzIgmymj8A3S8= +cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= +cloud.google.com/go/dataplex v1.6.0 h1:RvoZ5T7gySwm1CHzAw7yY1QwwqaGswunmqEssPxU/AM= +cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataplex v1.11.1/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= +cloud.google.com/go/dataplex v1.14.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= +cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U= +cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= +cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= +cloud.google.com/go/dataproc/v2 v2.2.3/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= +cloud.google.com/go/dataproc/v2 v2.3.0/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= +cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= +cloud.google.com/go/dataqna v0.7.0 h1:yFzi/YU4YAdjyo7pXkBE2FeHbgz5OQQBVDdbErEHmVQ= +cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= +cloud.google.com/go/dataqna v0.8.4/go.mod h1:mySRKjKg5Lz784P6sCov3p1QD+RZQONRMRjzGNcFd0c= +cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= +cloud.google.com/go/datastore v1.11.0 h1:iF6I/HaLs3Ado8uRKMvZRvF/ZLkWaWE9i8AiHzbC774= +cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= +cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= +cloud.google.com/go/datastream v1.7.0 h1:BBCBTnWMDwwEzQQmipUXxATa7Cm7CA/gKjKcR2w35T0= +cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= +cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= +cloud.google.com/go/datastream v1.10.3/go.mod h1:YR0USzgjhqA/Id0Ycu1VvZe8hEWwrkjuXrGbzeDOSEA= +cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= +cloud.google.com/go/deploy v1.8.0 h1:otshdKEbmsi1ELYeCKNYppwV0UH5xD05drSdBm7ouTk= +cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= +cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= +cloud.google.com/go/deploy v1.14.2/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= +cloud.google.com/go/deploy v1.17.0/go.mod h1:XBr42U5jIr64t92gcpOXxNrqL2PStQCXHuKK5GRUuYo= +cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= +cloud.google.com/go/dialogflow v1.32.0 h1:uVlKKzp6G/VtSW0E7IH1Y5o0H48/UOCmqksG2riYCwQ= +cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= +cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= +cloud.google.com/go/dialogflow v1.44.3/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= +cloud.google.com/go/dialogflow v1.48.1/go.mod h1:C1sjs2/g9cEwjCltkKeYp3FFpz8BOzNondEaAlCpt+A= +cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0= +cloud.google.com/go/dlp v1.9.0 h1:1JoJqezlgu6NWCroBxr4rOZnwNFILXr4cB9dMaSKO4A= +cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= +cloud.google.com/go/dlp v1.11.1/go.mod h1:/PA2EnioBeXTL/0hInwgj0rfsQb3lpE3R8XUJxqUNKI= +cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= +cloud.google.com/go/documentai v1.18.0 h1:KM3Xh0QQyyEdC8Gs2vhZfU+rt6OCPF0dwVwxKgLmWfI= +cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= +cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= +cloud.google.com/go/documentai v1.23.5/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= +cloud.google.com/go/documentai v1.23.7/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= +cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY= +cloud.google.com/go/domains v0.8.0 h1:2ti/o9tlWL4N+wIuWUNH+LbfgpwxPr8J1sv9RHA4bYQ= +cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= +cloud.google.com/go/domains v0.9.4/go.mod h1:27jmJGShuXYdUNjyDG0SodTfT5RwLi7xmH334Gvi3fY= +cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= +cloud.google.com/go/edgecontainer v1.0.0 h1:O0YVE5v+O0Q/ODXYsQHmHb+sYM8KNjGZw2pjX2Ws41c= +cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= +cloud.google.com/go/edgecontainer v1.1.4/go.mod h1:AvFdVuZuVGdgaE5YvlL1faAoa1ndRR/5XhXZvPBHbsE= +cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= +cloud.google.com/go/errorreporting v0.3.0 h1:kj1XEWMu8P0qlLhm3FwcaFsUvXChV/OraZwA70trRR0= +cloud.google.com/go/essentialcontacts v1.5.0 h1:gIzEhCoOT7bi+6QZqZIzX1Erj4SswMPIteNvYVlu+pM= +cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= +cloud.google.com/go/essentialcontacts v1.6.5/go.mod h1:jjYbPzw0x+yglXC890l6ECJWdYeZ5dlYACTFL0U/VuM= +cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= +cloud.google.com/go/eventarc v1.11.0 h1:fsJmNeqvqtk74FsaVDU6cH79lyZNCYP8Rrv7EhaB/PU= +cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= +cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= +cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hSWcqD3kaclg= +cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= +cloud.google.com/go/filestore v1.6.0 h1:ckTEXN5towyTMu4q0uQ1Mde/JwTHur0gXs8oaIZnKfw= +cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= +cloud.google.com/go/filestore v1.7.4/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= +cloud.google.com/go/filestore v1.8.0/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= +cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= +cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA= +cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= +cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= +cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= +cloud.google.com/go/functions v1.13.0 h1:pPDqtsXG2g9HeOQLoquLbmvmb82Y4Ezdo1GXuotFoWg= +cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= +cloud.google.com/go/functions v1.15.4/go.mod h1:CAsTc3VlRMVvx+XqXxKqVevguqJpnVip4DdonFsX28I= +cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= +cloud.google.com/go/gaming v1.9.0 h1:7vEhFnZmd931Mo7sZ6pJy7uQPDxF7m7v8xtBheG08tc= +cloud.google.com/go/gkebackup v0.4.0 h1:za3QZvw6ujR0uyqkhomKKKNoXDyqYGPJies3voUK8DA= +cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= +cloud.google.com/go/gkebackup v1.3.4/go.mod h1:gLVlbM8h/nHIs09ns1qx3q3eaXcGSELgNu1DWXYz1HI= +cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= +cloud.google.com/go/gkeconnect v0.7.0 h1:gXYKciHS/Lgq0GJ5Kc9SzPA35NGc3yqu6SkjonpEr2Q= +cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= +cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq8vbzjU0yJkw= +cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= +cloud.google.com/go/gkehub v0.12.0 h1:TqCSPsEBQ6oZSJgEYZ3XT8x2gUadbvfwI32YB0kuHCs= +cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= +cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc= +cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= +cloud.google.com/go/gkemulticloud v0.5.0 h1:8I84Q4vl02rJRsFiinBxl7WCozfdLlUVBQuSrqr9Wtk= +cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= +cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= +cloud.google.com/go/gkemulticloud v1.0.3/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= +cloud.google.com/go/gkemulticloud v1.1.0/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= +cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= +cloud.google.com/go/grafeas v0.2.0 h1:CYjC+xzdPvbV65gi6Dr4YowKcmLo045pm18L0DhdELM= +cloud.google.com/go/gsuiteaddons v1.5.0 h1:1mvhXqJzV0Vg5Fa95QwckljODJJfDFXV4pn+iL50zzA= +cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= +cloud.google.com/go/gsuiteaddons v1.6.4/go.mod h1:rxtstw7Fx22uLOXBpsvb9DUbC+fiXs7rF4U29KHM/pE= +cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/iap v1.7.1 h1:PxVHFuMxmSZyfntKXHXhd8bo82WJ+LcATenq7HLdVnU= +cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= +cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= +cloud.google.com/go/iap v1.9.3/go.mod h1:DTdutSZBqkkOm2HEOTBzhZxh2mwwxshfD/h3yofAiCw= +cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= +cloud.google.com/go/ids v1.3.0 h1:fodnCDtOXuMmS8LTC2y3h8t24U8F3eKWfhi+3LY6Qf0= +cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= +cloud.google.com/go/ids v1.4.4/go.mod h1:z+WUc2eEl6S/1aZWzwtVNWoSZslgzPxAboS0lZX0HjI= +cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= +cloud.google.com/go/iot v1.6.0 h1:39W5BFSarRNZfVG0eXI5LYux+OVQT8GkgpHCnrZL2vM= +cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= +cloud.google.com/go/iot v1.7.4/go.mod h1:3TWqDVvsddYBG++nHSZmluoCAVGr1hAcabbWZNKEZLk= +cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= +cloud.google.com/go/kms v1.10.1 h1:7hm1bRqGCA1GBRQUrp831TwJ9TWhP+tvLuP497CQS2g= +cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= +cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/language v1.9.0 h1:7Ulo2mDk9huBoBi8zCE3ONOoBrL6UXfAI71CLQ9GEIM= +cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= +cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= +cloud.google.com/go/language v1.12.2/go.mod h1:9idWapzr/JKXBBQ4lWqVX/hcadxB194ry20m/bTrhWc= +cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= +cloud.google.com/go/lifesciences v0.8.0 h1:uWrMjWTsGjLZpCTWEAzYvyXj+7fhiZST45u9AgasasI= +cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= +cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqNj+Nia7hF0Z7JA= +cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= +cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5I= +cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= +cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= +cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= +cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= +cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/managedidentities v1.5.0 h1:ZRQ4k21/jAhrHBVKl/AY7SjgzeJwG1iZa+mJ82P+VNg= +cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= +cloud.google.com/go/managedidentities v1.6.4/go.mod h1:WgyaECfHmF00t/1Uk8Oun3CQ2PGUtjc3e9Alh79wyiM= +cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= +cloud.google.com/go/maps v0.7.0 h1:mv9YaczD4oZBZkM5XJl6fXQ984IkJNHPwkc8MUsdkBo= +cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= +cloud.google.com/go/maps v1.6.1/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= +cloud.google.com/go/maps v1.6.3/go.mod h1:VGAn809ADswi1ASofL5lveOHPnE6Rk/SFTTBx1yuOLw= +cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= +cloud.google.com/go/mediatranslation v0.7.0 h1:anPxH+/WWt8Yc3EdoEJhPMBRF7EhIdz426A+tuoA0OU= +cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= +cloud.google.com/go/mediatranslation v0.8.4/go.mod h1:9WstgtNVAdN53m6TQa5GjIjLqKQPXe74hwSCxUP6nj4= +cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= +cloud.google.com/go/memcache v1.9.0 h1:8/VEmWCpnETCrBwS3z4MhT+tIdKgR1Z4Tr2tvYH32rg= +cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= +cloud.google.com/go/memcache v1.10.4/go.mod h1:v/d8PuC8d1gD6Yn5+I3INzLR01IDn0N4Ym56RgikSI0= +cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= +cloud.google.com/go/metastore v1.10.0 h1:QCFhZVe2289KDBQ7WxaHV2rAmPrmRAdLC6gbjUd3HPo= +cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= +cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= +cloud.google.com/go/metastore v1.13.3/go.mod h1:K+wdjXdtkdk7AQg4+sXS8bRrQa9gcOr+foOMF2tqINE= +cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= +cloud.google.com/go/monitoring v1.13.0 h1:2qsrgXGVoRXpP7otZ14eE1I568zAa92sJSDPyOJvwjM= +cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= +cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= +cloud.google.com/go/monitoring v1.16.3/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= +cloud.google.com/go/monitoring v1.17.0/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= +cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg= +cloud.google.com/go/networkconnectivity v1.11.0 h1:ZD6b4Pk1jEtp/cx9nx0ZYcL3BKqDa+KixNDZ6Bjs1B8= +cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= +cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= +cloud.google.com/go/networkconnectivity v1.14.3/go.mod h1:4aoeFdrJpYEXNvrnfyD5kIzs8YtHg945Og4koAjHQek= +cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= +cloud.google.com/go/networkmanagement v1.6.0 h1:8KWEUNGcpSX9WwZXq7FtciuNGPdPdPN/ruDm769yAEM= +cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= +cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= +cloud.google.com/go/networkmanagement v1.9.3/go.mod h1:y7WMO1bRLaP5h3Obm4tey+NquUvB93Co1oh4wpL+XcU= +cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= +cloud.google.com/go/networksecurity v0.8.0 h1:sOc42Ig1K2LiKlzG71GUVloeSJ0J3mffEBYmvu+P0eo= +cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= +cloud.google.com/go/networksecurity v0.9.4/go.mod h1:E9CeMZ2zDsNBkr8axKSYm8XyTqNhiCHf1JO/Vb8mD1w= +cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= +cloud.google.com/go/notebooks v1.8.0 h1:Kg2K3K7CbSXYJHZ1aGQpf1xi5x2GUvQWf2sFVuiZh8M= +cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= +cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= +cloud.google.com/go/notebooks v1.11.2/go.mod h1:z0tlHI/lREXC8BS2mIsUeR3agM1AkgLiS+Isov3SS70= +cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= +cloud.google.com/go/optimization v1.3.1 h1:dj8O4VOJRB4CUwZXdmwNViH1OtI0WtWL867/lnYH248= +cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= +cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= +cloud.google.com/go/optimization v1.6.2/go.mod h1:mWNZ7B9/EyMCcwNl1frUGEuY6CPijSkz88Fz2vwKPOY= +cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= +cloud.google.com/go/orchestration v1.6.0 h1:Vw+CEXo8M/FZ1rb4EjcLv0gJqqw89b7+g+C/EmniTb8= +cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= +cloud.google.com/go/orchestration v1.8.4/go.mod h1:d0lywZSVYtIoSZXb0iFjv9SaL13PGyVOKDxqGxEf/qI= +cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= +cloud.google.com/go/orgpolicy v1.10.0 h1:XDriMWug7sd0kYT1QKofRpRHzjad0bK8Q8uA9q+XrU4= +cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= +cloud.google.com/go/orgpolicy v1.11.4/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= +cloud.google.com/go/orgpolicy v1.12.0/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= +cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= +cloud.google.com/go/osconfig v1.11.0 h1:PkSQx4OHit5xz2bNyr11KGcaFccL5oqglFPdTboyqwQ= +cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= +cloud.google.com/go/osconfig v1.12.4/go.mod h1:B1qEwJ/jzqSRslvdOCI8Kdnp0gSng0xW4LOnIebQomA= +cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= +cloud.google.com/go/oslogin v1.9.0 h1:whP7vhpmc+ufZa90eVpkfbgzJRK/Xomjz+XCD4aGwWw= +cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= +cloud.google.com/go/oslogin v1.12.2/go.mod h1:CQ3V8Jvw4Qo4WRhNPF0o+HAM4DiLuE27Ul9CX9g2QdY= +cloud.google.com/go/oslogin v1.13.0/go.mod h1:xPJqLwpTZ90LSE5IL1/svko+6c5avZLluiyylMb/sRA= +cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= +cloud.google.com/go/phishingprotection v0.7.0 h1:l6tDkT7qAEV49MNEJkEJTB6vOO/onbSOcNtAT09HPuA= +cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= +cloud.google.com/go/phishingprotection v0.8.4/go.mod h1:6b3kNPAc2AQ6jZfFHioZKg9MQNybDg4ixFd4RPZZ2nE= +cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= +cloud.google.com/go/policytroubleshooter v1.6.0 h1:yKAGC4p9O61ttZUswaq9GAn1SZnEzTd0vUYXD7ZBT7Y= +cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= +cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= +cloud.google.com/go/policytroubleshooter v1.10.2/go.mod h1:m4uF3f6LseVEnMV6nknlN2vYGRb+75ylQwJdnOXfnv0= +cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= +cloud.google.com/go/privatecatalog v0.8.0 h1:EPEJ1DpEGXLDnmc7mnCAqFmkwUJbIsaLAiLHVOkkwtc= +cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= +cloud.google.com/go/privatecatalog v0.9.4/go.mod h1:SOjm93f+5hp/U3PqMZAHTtBtluqLygrDrVO8X8tYtG0= +cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= +cloud.google.com/go/pubsub v1.30.0 h1:vCge8m7aUKBJYOgrZp7EsNDf6QMd2CAlXZqWTn3yq6s= +cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsub v1.34.0/go.mod h1:alj4l4rBg+N3YTFDDC+/YyFTs6JAjam2QfYsddcAW4c= +cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= +cloud.google.com/go/pubsublite v1.7.0 h1:cb9fsrtpINtETHiJ3ECeaVzrfIVhcGjhhJEjybHXHao= +cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= +cloud.google.com/go/recaptchaenterprise v1.3.1 h1:u6EznTGzIdsyOsvm+Xkw0aSuKFXQlyjGE9a4exk6iNQ= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0 h1:6iOCujSNJ0YS7oNymI64hXsjGq60T4FK1zdLugxbzvU= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= +cloud.google.com/go/recaptchaenterprise/v2 v2.8.3/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= +cloud.google.com/go/recaptchaenterprise/v2 v2.9.0/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= +cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= +cloud.google.com/go/recommendationengine v0.7.0 h1:VibRFCwWXrFebEWKHfZAt2kta6pS7Tlimsnms0fjv7k= +cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= +cloud.google.com/go/recommendationengine v0.8.4/go.mod h1:GEteCf1PATl5v5ZsQ60sTClUE0phbWmo3rQ1Js8louU= +cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= +cloud.google.com/go/recommender v1.9.0 h1:ZnFRY5R6zOVk2IDS1Jbv5Bw+DExCI5rFumsTnMXiu/A= +cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= +cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= +cloud.google.com/go/recommender v1.11.3/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= +cloud.google.com/go/recommender v1.12.0/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= +cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= +cloud.google.com/go/redis v1.11.0 h1:JoAd3SkeDt3rLFAAxEvw6wV4t+8y4ZzfZcZmddqphQ8= +cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= +cloud.google.com/go/redis v1.14.1/go.mod h1:MbmBxN8bEnQI4doZPC1BzADU4HGocHBk2de3SbgOkqs= +cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= +cloud.google.com/go/resourcemanager v1.7.0 h1:NRM0p+RJkaQF9Ee9JMnUV9BQ2QBIOq/v8M+Pbv/wmCs= +cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= +cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0= +cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= +cloud.google.com/go/resourcesettings v1.5.0 h1:8Dua37kQt27CCWHm4h/Q1XqCF6ByD7Ouu49xg95qJzI= +cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= +cloud.google.com/go/resourcesettings v1.6.4/go.mod h1:pYTTkWdv2lmQcjsthbZLNBP4QW140cs7wqA3DuqErVI= +cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= +cloud.google.com/go/retail v1.12.0 h1:1Dda2OpFNzIb4qWgFZjYlpP7sxX3aLeypKG6A3H4Yys= +cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= +cloud.google.com/go/retail v1.14.4/go.mod h1:l/N7cMtY78yRnJqp5JW8emy7MB1nz8E4t2yfOmklYfg= +cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE= +cloud.google.com/go/run v0.9.0 h1:ydJQo+k+MShYnBfhaRHSZYeD/SQKZzZLAROyfpeD9zw= +cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= +cloud.google.com/go/run v1.3.3/go.mod h1:WSM5pGyJ7cfYyYbONVQBN4buz42zFqwG67Q3ch07iK4= +cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= +cloud.google.com/go/scheduler v1.9.0 h1:NpQAHtx3sulByTLe2dMwWmah8PWgeoieFPpJpArwFV0= +cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= +cloud.google.com/go/scheduler v1.10.4/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= +cloud.google.com/go/scheduler v1.10.5/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= +cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= +cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60= +cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= +cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= +cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= +cloud.google.com/go/security v1.13.0 h1:PYvDxopRQBfYAXKAuDpFCKBvDOWPWzp9k/H5nB3ud3o= +cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= +cloud.google.com/go/security v1.15.4/go.mod h1:oN7C2uIZKhxCLiAAijKUCuHLZbIt/ghYEo8MqwD/Ty4= +cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= +cloud.google.com/go/securitycenter v1.19.0 h1:AF3c2s3awNTMoBtMX3oCUoOMmGlYxGOeuXSYHNBkf14= +cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= +cloud.google.com/go/securitycenter v1.24.2/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= +cloud.google.com/go/securitycenter v1.24.3/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= +cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= +cloud.google.com/go/servicecontrol v1.11.1 h1:d0uV7Qegtfaa7Z2ClDzr9HJmnbJW7jn0WhZ7wOX6hLE= +cloud.google.com/go/servicedirectory v1.9.0 h1:SJwk0XX2e26o25ObYUORXx6torSFiYgsGkWSkZgkoSU= +cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= +cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= +cloud.google.com/go/servicedirectory v1.11.3/go.mod h1:LV+cHkomRLr67YoQy3Xq2tUXBGOs5z5bPofdq7qtiAw= +cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= +cloud.google.com/go/servicemanagement v1.8.0 h1:fopAQI/IAzlxnVeiKn/8WiV6zKndjFkvi+gzu+NjywY= +cloud.google.com/go/serviceusage v1.6.0 h1:rXyq+0+RSIm3HFypctp7WoXxIA563rn206CfMWdqXX4= +cloud.google.com/go/shell v1.6.0 h1:wT0Uw7ib7+AgZST9eCDygwTJn4+bHMDtZo5fh7kGWDU= +cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= +cloud.google.com/go/shell v1.7.4/go.mod h1:yLeXB8eKLxw0dpEmXQ/FjriYrBijNsONpwnWsdPqlKM= +cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= +cloud.google.com/go/spanner v1.45.0 h1:7VdjZ8zj4sHbDw55atp5dfY6kn1j9sam9DRNpPQhqR4= +cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= +cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= +cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0= +cloud.google.com/go/spanner v1.55.0/go.mod h1:HXEznMUVhC+PC+HDyo9YFG2Ajj5BQDkcbqB9Z2Ffxi0= +cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0= +cloud.google.com/go/spanner v1.57.0/go.mod h1:aXQ5QDdhPRIqVhYmnkAdwPYvj/DRN0FguclhEWw+jOo= +cloud.google.com/go/speech v1.15.0 h1:JEVoWGNnTF128kNty7T4aG4eqv2z86yiMJPT9Zjp+iw= +cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/speech v1.20.1/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= +cloud.google.com/go/speech v1.21.0/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= +cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= +cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/storagetransfer v1.8.0 h1:5T+PM+3ECU3EY2y9Brv0Sf3oka8pKmsCfpQ07+91G9o= +cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= +cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= +cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= +cloud.google.com/go/talent v1.5.0 h1:nI9sVZPjMKiO2q3Uu0KhTDVov3Xrlpt63fghP9XjyEM= +cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= +cloud.google.com/go/talent v1.6.5/go.mod h1:Mf5cma696HmE+P2BWJ/ZwYqeJXEeU0UqjHFXVLadEDI= +cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= +cloud.google.com/go/texttospeech v1.6.0 h1:H4g1ULStsbVtalbZGktyzXzw6jP26RjVGYx9RaYjBzc= +cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= +cloud.google.com/go/texttospeech v1.7.4/go.mod h1:vgv0002WvR4liGuSd5BJbWy4nDn5Ozco0uJymY5+U74= +cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= +cloud.google.com/go/tpu v1.5.0 h1:/34T6CbSi+kTv5E19Q9zbU/ix8IviInZpzwz3rsFE+A= +cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= +cloud.google.com/go/tpu v1.6.4/go.mod h1:NAm9q3Rq2wIlGnOhpYICNI7+bpBebMJbh0yyp3aNw1Y= +cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= +cloud.google.com/go/trace v1.9.0 h1:olxC0QHC59zgJVALtgqfD9tGk0lfeCP5/AGXL3Px/no= +cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= +cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY= +cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= +cloud.google.com/go/translate v1.7.0 h1:GvLP4oQ4uPdChBmBaUSa/SaZxCdyWELtlAaKzpHsXdA= +cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= +cloud.google.com/go/translate v1.10.0/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= +cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= +cloud.google.com/go/video v1.15.0 h1:upIbnGI0ZgACm58HPjAeBMleW3sl5cT84AbYQ8PWOgM= +cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= +cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= +cloud.google.com/go/video v1.20.3/go.mod h1:TnH/mNZKVHeNtpamsSPygSR0iHtvrR/cW1/GDjN5+GU= +cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= +cloud.google.com/go/videointelligence v1.10.0 h1:Uh5BdoET8XXqXX2uXIahGb+wTKbLkGH7s4GXR58RrG8= +cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= +cloud.google.com/go/videointelligence v1.11.4/go.mod h1:kPBMAYsTPFiQxMLmmjpcZUMklJp3nC9+ipJJtprccD8= +cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= +cloud.google.com/go/vision v1.2.0 h1:/CsSTkbmO9HC8iQpxbK8ATms3OQaX3YQUeTMGCxlaK4= +cloud.google.com/go/vision/v2 v2.7.0 h1:8C8RXUJoflCI4yVdqhTy9tRyygSHmp60aP363z23HKg= +cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= +cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= +cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU= +cloud.google.com/go/vmmigration v1.6.0 h1:Azs5WKtfOC8pxvkyrDvt7J0/4DYBch0cVbuFfCCFt5k= +cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= +cloud.google.com/go/vmmigration v1.7.4/go.mod h1:yBXCmiLaB99hEl/G9ZooNx2GyzgsjKnw5fWcINRgD70= +cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= +cloud.google.com/go/vmwareengine v0.3.0 h1:b0NBu7S294l0gmtrT0nOJneMYgZapr5x9tVWvgDoVEM= +cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= +cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= +cloud.google.com/go/vmwareengine v1.0.3/go.mod h1:QSpdZ1stlbfKtyt6Iu19M6XRxjmXO+vb5a/R6Fvy2y4= +cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= +cloud.google.com/go/vpcaccess v1.6.0 h1:FOe6CuiQD3BhHJWt7E8QlbBcaIzVRddupwJlp7eqmn4= +cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= +cloud.google.com/go/vpcaccess v1.7.4/go.mod h1:lA0KTvhtEOb/VOdnH/gwPuOzGgM+CWsmGu6bb4IoMKk= +cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= +cloud.google.com/go/webrisk v1.8.0 h1:IY+L2+UwxcVm2zayMAtBhZleecdIFLiC+QJMzgb0kT0= +cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= +cloud.google.com/go/webrisk v1.9.4/go.mod h1:w7m4Ib4C+OseSr2GL66m0zMBywdrVNTDKsdEsfMl7X0= +cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= +cloud.google.com/go/websecurityscanner v1.5.0 h1:AHC1xmaNMOZtNqxI9Rmm87IJEyPaRkOxeI0gpAacXGk= +cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= +cloud.google.com/go/websecurityscanner v1.6.4/go.mod h1:mUiyMQ+dGpPPRkHgknIZeCzSHJ45+fY4F52nZFDHm2o= +cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= +cloud.google.com/go/workflows v1.10.0 h1:FfGp9w0cYnaKZJhUOMqCOJCYT/WlvYBfTQhFWV3sRKI= +cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= +cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= +cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= +cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= +gioui.org v0.0.0-20210308172011-57750fc8a0a6 h1:K72hopUosKG3ntOPNG4OzzbuhxGuVf06fa2la1/H/Ho= +git.sr.ht/~sbinet/gg v0.3.1 h1:LNhjNn8DerC8f9DHLz6lS0YYul/b602DUxDgGkd/Aik= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9 h1:7kQgkwGRoLzC9K0oyXdJo7nve/bynv/KwUsxbiTlzAM= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19 h1:iXUgAaqDcIUGbRoy2TdeofRG/j1zpGRSEmNK05T+bi8= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI= +github.com/apache/arrow/go/v11 v11.0.0 h1:hqauxvFQxww+0mEU/2XHG6LT7eZternCZq+A5Yly2uM= +github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/checkpoint-restore/go-criu/v5 v5.3.0 h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89 h1:aPflPkRFkVwbW6dmcVqfgwp1i+UWGFH6VgR1Jim5Ygc= +github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/chromedp v0.9.2 h1:dKtNz4kApb06KuSXoTQIyUC2TrA0fhGDwNZf3bcgfKw= +github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= +github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cilium/ebpf v0.7.0 h1:1k/q3ATgxSXRdrmPfH8d7YK0GfqVsEKZAX9dQZvs56k= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= +github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= +github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= +github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= +github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/getsentry/sentry-go v0.21.0 h1:c9l5F1nPF30JIppulk4veau90PK6Smu3abgVtVQWon4= +github.com/getsentry/sentry-go v0.21.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ= +github.com/go-fonts/latin-modern v0.2.0 h1:5/Tv1Ek/QCr20C6ZOz15vw3g7GELYL98KWr8Hgo+3vk= +github.com/go-fonts/liberation v0.2.0 h1:jAkAWJP4S+OsrPLZM4/eC9iW7CtHy+HBXrEwZXWo5VM= +github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= +github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= +github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto= +github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= +github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 h1:KwWnWVWCNtNq/ewIX7HIKnELmEx2nDP42yskD/pi7QE= +github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5 h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= +github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lyft/protoc-gen-star v0.6.1 h1:erE0rdztuaDq3bpGifD95wfoPrSZc95nGA6tbiNYh6M= +github.com/lyft/protoc-gen-star/v2 v2.0.1 h1:keaAo8hRuAT0O3DfJ/wM3rufbAjGeJ1lAtWZHDjKGB0= +github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/mrunalp/fileutils v0.5.1 h1:F+S7ZlNKnrwHfSwdlgNSkKo67ReVf8o9fel6C3dkm/Q= +github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncabatoff/fakescraper v0.0.0-20201102132415-4b37ba603d65 h1:Og+dVkxEQNvRGU2vUKeOwYT2UJ+pEaDMWB6tIQnIh6A= +github.com/ncabatoff/fakescraper v0.0.0-20201102132415-4b37ba603d65/go.mod h1:Tx6UMSMyIsjLG/VU/F6xA1+0XI+/f9o1dGJnf1l+bPg= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= +github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ= +github.com/phpdave11/gofpdi v1.0.13 h1:o61duiW8M9sMlkVXWlvP92sZJtGKENvW3VExs6dZukQ= +github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= +github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= +github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 h1:K1Xf3bKttbF+koVGaX5xngRIZ5bVjbmPnaxE/dR08uY= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646 h1:RpforrEYXWkmGwJHIGnLZ3tTWStkjVVstwzNGqxX2Ds= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xhit/go-str2duration v1.2.0 h1:BcV5u025cITWxEQKGWr1URRzrcXtu7uk8+luz3Yuhwc= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= +go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= +go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= +go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= +go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= +go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= +go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= +go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= +go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 h1:KfYpVmrjI7JuToy5k8XV3nkapjWx48k4E4JOtVstzQI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/dl v0.0.0-20190829154251-82a15e2f2ead h1:jeP6FgaSLNTMP+Yri3qjlACywQLye+huGLmNGhBzm6k= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867 h1:TcHcE0vrmgzNH1v3ppjcMGbhG5+9fMuvOmUYwNEF4q4= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= +gonum.org/v1/plot v0.10.1 h1:dnifSs43YJuNMDzB7v8wV64O4ABBHReuAVAoBxqBqS4= +google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= +google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= +google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= +google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= +google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= +google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:PVreiBMirk8ypES6aw9d4p6iiBNSIfZEBqr3UGoAi2E= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc h1:g3hIDl0jRNd9PPTs2uBzYuaD5mQuwOkZY0vSc0LR32o= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20231212172506-995d672761c0/go.mod h1:guYXGPwC6jwxgWKW5Y405fKWOFNwlvUlUnzyp9i0uqo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= +gopkg.in/evanphx/json-patch.v5 v5.6.0 h1:BMT6KIwBD9CaU91PJCZIe46bDmBWa9ynTQgJIOpfQBk= +gopkg.in/evanphx/json-patch.v5 v5.6.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +honnef.co/go/tools v0.1.3 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= +k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks= +k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.29.3/go.mod h1:TBGbJKpRUMk59neTMDMddjIDL+D4HuFUbpuiuzmOPg0= +k8s.io/kms v0.30.0 h1:ZlnD/ei5lpvUlPw6eLfVvH7d8i9qZ6HwUQgydNVks8g= +k8s.io/kms v0.30.0/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= +k8s.io/kms v0.30.1/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg= +modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/libc v1.17.1 h1:Q8/Cpi36V/QBfuQaFVeisEBs3WqoGAJprZzmf7TfEYI= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/memory v1.2.1 h1:dkRh86wgmq/bJu2cAS2oqBCz/KsMZU7TUM4CibQ7eBs= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= +modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= +modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= +rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hack/init-buildx.sh b/hack/init-buildx.sh index bac68e1ae..1a47bf145 100755 --- a/hack/init-buildx.sh +++ b/hack/init-buildx.sh @@ -42,11 +42,12 @@ fi # We can skip setup if the current builder already has multi-arch # AND if it isn't the docker driver, which doesn't work current_builder="$(docker buildx inspect)" -# linux/amd64, linux/arm, linux/arm64 +# linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 if ! grep -q "^Driver: docker$" <<<"${current_builder}" && \ grep -q "linux/amd64" <<<"${current_builder}" && \ grep -q "linux/arm" <<<"${current_builder}" && \ - grep -q "linux/arm64" <<<"${current_builder}"; then + grep -q "linux/arm64" <<<"${current_builder}" && \ + grep -q "linux/s390x" <<<"${current_builder}"; then exit 0 fi diff --git a/hack/manifest-templates/provider/kind/values.yaml b/hack/manifest-templates/provider/kind/values.yaml index 6140f6500..ed636f372 100644 --- a/hack/manifest-templates/provider/kind/values.yaml +++ b/hack/manifest-templates/provider/kind/values.yaml @@ -8,9 +8,11 @@ controller: enabled: true terminationGracePeriodSeconds: 0 service: - type: LoadBalancer + type: NodePort watchIngressWithoutClass: true + nodeSelector: + ingress-ready: "true" tolerations: - key: "node-role.kubernetes.io/master" operator: "Equal" diff --git a/hack/update-annotation-doc.sh b/hack/update-annotation-doc.sh deleted file mode 100755 index c4feb41ce..000000000 --- a/hack/update-annotation-doc.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Copyright 2024 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit -set -o nounset - -SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/.. -ANNOTATIONFILE="${SCRIPT_ROOT}/docs/user-guide/nginx-configuration/annotations-risk.md" - -go run "${SCRIPT_ROOT}"/cmd/annotations/main.go -output "${ANNOTATIONFILE}" \ No newline at end of file diff --git a/hack/verify-annotation-docs.sh b/hack/verify-annotation-docs.sh deleted file mode 100755 index 54034539b..000000000 --- a/hack/verify-annotation-docs.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# Copyright 2024 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit -set -o nounset -set -o pipefail - -SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/.. - -ANNOTATIONFILE="${SCRIPT_ROOT}/docs/user-guide/nginx-configuration/annotations-risk.md" -TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp" -TMP_FILE="${TMP_DIFFROOT}/annotations-risk.md" - -cleanup() { - rm -rf "${TMP_DIFFROOT}" -} -trap "cleanup" EXIT SIGINT - -cleanup - -mkdir -p "${TMP_DIFFROOT}" - -go run cmd/annotations/main.go -output "${TMP_FILE}" -echo "diffing ${ANNOTATIONFILE} against freshly generated annotation doc" -ret=0 -diff -Naupr --no-dereference "${ANNOTATIONFILE}" "${TMP_FILE}" || ret=1 - -if [[ $ret -eq 0 ]]; then - echo "${ANNOTATIONFILE} up to date." -else - echo "${ANNOTATIONFILE} is out of date. Please run hack/update-annotation-doc.sh" - exit 1 -fi diff --git a/hack/verify-lualint.sh b/hack/verify-lualint.sh index 769d7a6cd..1f6048de0 100755 --- a/hack/verify-lualint.sh +++ b/hack/verify-lualint.sh @@ -18,13 +18,6 @@ set -o errexit set -o nounset set -o pipefail -luacheck --codes --globals lua_ingress \ - --globals configuration \ - --globals balancer \ - --globals monitor \ - --globals certificate \ - --globals tcp_udp_configuration \ - --globals tcp_udp_balancer \ - --no-max-comment-line-length -q rootfs/etc/nginx/lua/ +luacheck --codes -q rootfs/etc/nginx/lua/ find rootfs/etc/nginx/lua/ -name "*.lua" -not -path "*/test/*" -exec lj-releng -L -s {} + && echo "lj-releng validation is success!" diff --git a/images/Makefile b/images/Makefile index 31560168d..990d77231 100644 --- a/images/Makefile +++ b/images/Makefile @@ -41,7 +41,7 @@ EXTRAARGS ?= $(shell cat $(NAME)/EXTRAARGS) export DOCKER_CLI_EXPERIMENTAL=enabled # build with buildx -PLATFORMS?=linux/amd64,linux/arm,linux/arm64 +PLATFORMS?=linux/amd64,linux/arm,linux/arm64,linux/s390x OUTPUT= PROGRESS=plain diff --git a/images/cfssl/TAG b/images/cfssl/TAG index 56130fb3a..7df503e63 100644 --- a/images/cfssl/TAG +++ b/images/cfssl/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.4 diff --git a/images/cfssl/cloudbuild.yaml b/images/cfssl/cloudbuild.yaml index 33fafdb08..32d91ca83 100644 --- a/images/cfssl/cloudbuild.yaml +++ b/images/cfssl/cloudbuild.yaml @@ -1,11 +1,17 @@ +timeout: 600s options: - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images && make NAME=cfssl push + - -c + - | + gcloud auth configure-docker \ + && cd images && make NAME=cfssl push diff --git a/images/cfssl/rootfs/Dockerfile b/images/cfssl/rootfs/Dockerfile index 3978c8f4b..c23f66d49 100644 --- a/images/cfssl/rootfs/Dockerfile +++ b/images/cfssl/rootfs/Dockerfile @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM alpine:3.21 +FROM alpine:3.20.0 -RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories +RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories RUN apk update \ && apk upgrade && \ apk add --no-cache \ diff --git a/images/custom-error-pages/README.md b/images/custom-error-pages/README.md new file mode 100644 index 000000000..cd6df3e0a --- /dev/null +++ b/images/custom-error-pages/README.md @@ -0,0 +1,3 @@ +# custom-error-pages + +Example of Custom error pages for the Ingress-Nginx Controller diff --git a/images/custom-error-pages/TAG b/images/custom-error-pages/TAG index 56130fb3a..8ce995b80 100644 --- a/images/custom-error-pages/TAG +++ b/images/custom-error-pages/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.3 \ No newline at end of file diff --git a/images/custom-error-pages/cloudbuild.yaml b/images/custom-error-pages/cloudbuild.yaml index 324a8f19a..bb74da6b8 100644 --- a/images/custom-error-pages/cloudbuild.yaml +++ b/images/custom-error-pages/cloudbuild.yaml @@ -1,11 +1,17 @@ +timeout: 1800s options: - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images && make NAME=custom-error-pages push + - -c + - | + gcloud auth configure-docker \ + && cd images/ && make NAME=custom-error-pages push diff --git a/images/custom-error-pages/rootfs/Dockerfile b/images/custom-error-pages/rootfs/Dockerfile index 478e4c22d..345f92ba3 100755 --- a/images/custom-error-pages/rootfs/Dockerfile +++ b/images/custom-error-pages/rootfs/Dockerfile @@ -14,7 +14,7 @@ ARG GOLANG_VERSION -FROM golang:${GOLANG_VERSION}-alpine3.21 as builder +FROM golang:${GOLANG_VERSION}-alpine3.20 as builder RUN apk update \ && apk upgrade && apk add git diff --git a/images/custom-error-pages/rootfs/go.mod b/images/custom-error-pages/rootfs/go.mod index 5c0377284..eebc562a5 100644 --- a/images/custom-error-pages/rootfs/go.mod +++ b/images/custom-error-pages/rootfs/go.mod @@ -1,17 +1,17 @@ module k8s.io/ingress-nginx/custom-error-pages -go 1.23.6 +go 1.21 -require github.com/prometheus/client_golang v1.20.5 +require github.com/prometheus/client_golang v1.11.1 require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - golang.org/x/sys v0.22.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/golang/protobuf v1.5.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.26.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect + golang.org/x/sys v0.1.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/images/custom-error-pages/rootfs/go.sum b/images/custom-error-pages/rootfs/go.sum index d5318cf86..99c959a36 100644 --- a/images/custom-error-pages/rootfs/go.sum +++ b/images/custom-error-pages/rootfs/go.sum @@ -1,24 +1,141 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/images/e2e-test-echo/TAG b/images/e2e-test-echo/TAG index 56130fb3a..8ce995b80 100644 --- a/images/e2e-test-echo/TAG +++ b/images/e2e-test-echo/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.3 \ No newline at end of file diff --git a/images/e2e-test-echo/cloudbuild.yaml b/images/e2e-test-echo/cloudbuild.yaml deleted file mode 100644 index 02bfc034a..000000000 --- a/images/e2e-test-echo/cloudbuild.yaml +++ /dev/null @@ -1,11 +0,0 @@ -options: - # Ignore Prow provided substitutions. - substitution_option: ALLOW_LOOSE -steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx - entrypoint: bash - args: - - -c - - gcloud auth configure-docker && cd images && make NAME=e2e-test-echo push diff --git a/images/ext-auth-example-authsvc/TAG b/images/ext-auth-example-authsvc/TAG index 56130fb3a..8ce995b80 100644 --- a/images/ext-auth-example-authsvc/TAG +++ b/images/ext-auth-example-authsvc/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.3 \ No newline at end of file diff --git a/images/ext-auth-example-authsvc/cloudbuild.yaml b/images/ext-auth-example-authsvc/cloudbuild.yaml new file mode 100644 index 000000000..506e20111 --- /dev/null +++ b/images/ext-auth-example-authsvc/cloudbuild.yaml @@ -0,0 +1,19 @@ +timeout: 1200s +options: + substitution_option: ALLOW_LOOSE + # job builds a multi-arch docker image for amd64,arm,arm64 and s390x. + machineType: E2_HIGHCPU_8 +steps: + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 + entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root + args: + - -c + - | + gcloud auth configure-docker \ + && cd images/ && make NAME=ext-auth-example-authsvc push \ No newline at end of file diff --git a/images/ext-auth-example-authsvc/rootfs/Dockerfile b/images/ext-auth-example-authsvc/rootfs/Dockerfile index ca142e663..ec611fa54 100644 --- a/images/ext-auth-example-authsvc/rootfs/Dockerfile +++ b/images/ext-auth-example-authsvc/rootfs/Dockerfile @@ -1,6 +1,6 @@ ARG GOLANG_VERSION -FROM golang:${GOLANG_VERSION}-alpine3.21 as builder +FROM golang:${GOLANG_VERSION}-alpine3.18 as builder RUN mkdir /authsvc WORKDIR /authsvc COPY . ./ @@ -9,4 +9,4 @@ RUN CGO_ENABLED=0 GOOS=linux go build -o authsvc authsvc.go FROM gcr.io/distroless/base-debian11 COPY --from=builder /authsvc/authsvc / EXPOSE 8080 -ENTRYPOINT ["/authsvc"] +ENTRYPOINT ["/authsvc"] \ No newline at end of file diff --git a/images/ext-auth-example-authsvc/rootfs/go.mod b/images/ext-auth-example-authsvc/rootfs/go.mod index 5f33a86ff..8c3abdcf2 100644 --- a/images/ext-auth-example-authsvc/rootfs/go.mod +++ b/images/ext-auth-example-authsvc/rootfs/go.mod @@ -1,7 +1,7 @@ module example.com/authsvc -go 1.23.6 +go 1.21 -require k8s.io/apimachinery v0.32.2 +require k8s.io/apimachinery v0.23.1 -require github.com/google/uuid v1.6.0 // indirect +require github.com/google/uuid v1.1.2 // indirect diff --git a/images/ext-auth-example-authsvc/rootfs/go.sum b/images/ext-auth-example-authsvc/rootfs/go.sum index 770c22f6a..6e3fab295 100644 --- a/images/ext-auth-example-authsvc/rootfs/go.sum +++ b/images/ext-auth-example-authsvc/rootfs/go.sum @@ -1,4 +1,215 @@ -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo= +k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/images/fastcgi-helloserver/TAG b/images/fastcgi-helloserver/TAG index 56130fb3a..8ce995b80 100644 --- a/images/fastcgi-helloserver/TAG +++ b/images/fastcgi-helloserver/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.3 \ No newline at end of file diff --git a/images/fastcgi-helloserver/cloudbuild.yaml b/images/fastcgi-helloserver/cloudbuild.yaml index c2c6135df..e3ab3b375 100644 --- a/images/fastcgi-helloserver/cloudbuild.yaml +++ b/images/fastcgi-helloserver/cloudbuild.yaml @@ -1,11 +1,17 @@ +timeout: 1800s options: - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images && make NAME=fastcgi-helloserver push + - -c + - | + gcloud auth configure-docker \ + && cd images/ && make NAME=fastcgi-helloserver push \ No newline at end of file diff --git a/images/fastcgi-helloserver/rootfs/Dockerfile b/images/fastcgi-helloserver/rootfs/Dockerfile index 7d8e95c47..eec93c844 100755 --- a/images/fastcgi-helloserver/rootfs/Dockerfile +++ b/images/fastcgi-helloserver/rootfs/Dockerfile @@ -13,7 +13,7 @@ # limitations under the License. ARG GOLANG_VERSION -FROM golang:${GOLANG_VERSION}-alpine3.21 as builder +FROM golang:${GOLANG_VERSION}-alpine3.18 as builder WORKDIR /go/src/k8s.io/ingress-nginx/images/fastcgi @@ -30,4 +30,4 @@ FROM gcr.io/distroless/static:nonroot COPY --from=builder /go/src/k8s.io/ingress-nginx/images/fastcgi/fastcgi-helloserver / USER nonroot:nonroot -CMD ["/fastcgi-helloserver"] +CMD ["/fastcgi-helloserver"] \ No newline at end of file diff --git a/images/go-grpc-greeter-server/TAG b/images/go-grpc-greeter-server/TAG index 56130fb3a..8ce995b80 100644 --- a/images/go-grpc-greeter-server/TAG +++ b/images/go-grpc-greeter-server/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.3 \ No newline at end of file diff --git a/images/go-grpc-greeter-server/cloudbuild.yaml b/images/go-grpc-greeter-server/cloudbuild.yaml new file mode 100644 index 000000000..b690ffbec --- /dev/null +++ b/images/go-grpc-greeter-server/cloudbuild.yaml @@ -0,0 +1,19 @@ +timeout: 1200s +options: + substitution_option: ALLOW_LOOSE + # job builds a multi-arch docker image for amd64,arm,arm64 and s390x. + machineType: E2_HIGHCPU_8 +steps: + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 + entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root + args: + - -c + - | + gcloud auth configure-docker \ + && cd images/ && make NAME=go-grpc-greeter-server push \ No newline at end of file diff --git a/images/go-grpc-greeter-server/rootfs/Dockerfile b/images/go-grpc-greeter-server/rootfs/Dockerfile index 39be2990f..79693eaeb 100644 --- a/images/go-grpc-greeter-server/rootfs/Dockerfile +++ b/images/go-grpc-greeter-server/rootfs/Dockerfile @@ -1,6 +1,6 @@ ARG GOLANG_VERSION -FROM golang:${GOLANG_VERSION}-alpine3.21 as build +FROM golang:${GOLANG_VERSION}-alpine3.18 as build WORKDIR /go/src/greeter-server @@ -15,4 +15,4 @@ COPY --from=build /greeter-server / EXPOSE 50051 -CMD ["/greeter-server"] +CMD ["/greeter-server"] \ No newline at end of file diff --git a/images/httpbun/TAG b/images/httpbun/TAG index 56130fb3a..8ce995b80 100644 --- a/images/httpbun/TAG +++ b/images/httpbun/TAG @@ -1 +1 @@ -v1.1.1 +v0.0.3 \ No newline at end of file diff --git a/images/httpbun/cloudbuild.yaml b/images/httpbun/cloudbuild.yaml index c56820d15..c532a3908 100644 --- a/images/httpbun/cloudbuild.yaml +++ b/images/httpbun/cloudbuild.yaml @@ -1,11 +1,19 @@ +timeout: 1200s options: - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE + # job builds a multi-arch docker image for amd64,arm,arm64 and s390x. + machineType: E2_HIGHCPU_8 steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images && make NAME=httpbun push + - -c + - | + gcloud auth configure-docker \ + && cd images/ && make NAME=httpbun push \ No newline at end of file diff --git a/images/kube-webhook-certgen/OWNERS b/images/kube-webhook-certgen/OWNERS new file mode 100644 index 000000000..b4424221c --- /dev/null +++ b/images/kube-webhook-certgen/OWNERS @@ -0,0 +1,4 @@ +# See the OWNERS docs: https://www.kubernetes.dev/docs/guide/owners + +reviewers: +- ingress-nginx-kube-webhook-certgen-reviewers diff --git a/images/kube-webhook-certgen/TAG b/images/kube-webhook-certgen/TAG index 53b5bbb12..c432e90f2 100644 --- a/images/kube-webhook-certgen/TAG +++ b/images/kube-webhook-certgen/TAG @@ -1 +1 @@ -v1.5.1 +v1.4.2 diff --git a/images/kube-webhook-certgen/cloudbuild.yaml b/images/kube-webhook-certgen/cloudbuild.yaml index e4118ff88..690f13126 100644 --- a/images/kube-webhook-certgen/cloudbuild.yaml +++ b/images/kube-webhook-certgen/cloudbuild.yaml @@ -1,11 +1,32 @@ + +# Copyright 2021 The Kubernetes Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +timeout: 10800s options: - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images && make NAME=kube-webhook-certgen push + - -c + - | + gcloud auth configure-docker \ + && cd images/ && make NAME=kube-webhook-certgen push diff --git a/images/kube-webhook-certgen/rootfs/go.mod b/images/kube-webhook-certgen/rootfs/go.mod index 2b8567748..9c7f96e1b 100644 --- a/images/kube-webhook-certgen/rootfs/go.mod +++ b/images/kube-webhook-certgen/rootfs/go.mod @@ -1,31 +1,31 @@ module github.com/jet/kube-webhook-certgen -go 1.23.6 +go 1.21 require ( github.com/onrik/logrus v0.11.0 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.9.1 - k8s.io/api v0.32.2 - k8s.io/apimachinery v0.32.2 - k8s.io/client-go v0.32.2 - k8s.io/kube-aggregator v0.32.2 + github.com/spf13/cobra v1.8.0 + k8s.io/api v0.29.3 + k8s.io/apimachinery v0.29.3 + k8s.io/client-go v0.29.3 + k8s.io/kube-aggregator v0.29.3 ) require ( - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.3 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.22.9 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -33,25 +33,26 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.22.2 // indirect - github.com/onsi/gomega v1.36.2 // indirect + github.com/onsi/ginkgo/v2 v2.19.0 // indirect + github.com/onsi/gomega v1.33.1 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect - github.com/x448/float16 v0.8.4 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.7.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240224005224-582cce78233b // indirect + k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/images/kube-webhook-certgen/rootfs/go.sum b/images/kube-webhook-certgen/rootfs/go.sum index 1c660f020..57b4a450b 100644 --- a/images/kube-webhook-certgen/rootfs/go.sum +++ b/images/kube-webhook-certgen/rootfs/go.sum @@ -1,38 +1,43 @@ -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.11.3 h1:yagOQz/38xJmcNeZJtrUcKjkHRltIaIFXKWeG1SkWGE= github.com/emicklei/go-restful/v3 v3.11.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= +github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -56,24 +61,23 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onrik/logrus v0.11.0 h1:pu+BCaWL36t0yQaj/2UHK2erf88dwssAKOT51mxPUVs= github.com/onrik/logrus v0.11.0/go.mod h1:fO2vlZwIdti6PidD3gV5YKt9Lq5ptpnP293RAe1ITwk= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -85,79 +89,97 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= -k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= -k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-aggregator v0.32.2 h1:kg9pke+i2qRbJwX1UKwZV4fsCRvmbaCEFk38R4FqHmw= -k8s.io/kube-aggregator v0.32.2/go.mod h1:rRm+xY1yIFIt3zBc727nG5SBLYywywD87klfIAw+7+c= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= +k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= +k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-aggregator v0.29.3 h1:5KvTyFN8sQq2imq8tMAHWEKoE64Zg9WSMaGX78KV6ps= +k8s.io/kube-aggregator v0.29.3/go.mod h1:xGJqV/SJJ1fbwTGfQLAZfwgqX1EMoaqfotDTkDrqqSk= +k8s.io/kube-openapi v0.0.0-20240224005224-582cce78233b h1:1dzw/KqgSPod72SUp2tuTOmK33TlY2fHlrVU2M9VrOM= +k8s.io/kube-openapi v0.0.0-20240224005224-582cce78233b/go.mod h1:Pa1PvrP7ACSkuX6I7KYomY6cmMA0Tx86waBhDUgoKPw= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/images/kube-webhook-certgen/rootfs/pkg/k8s/k8s_test.go b/images/kube-webhook-certgen/rootfs/pkg/k8s/k8s_test.go index b326697b6..f11bef981 100644 --- a/images/kube-webhook-certgen/rootfs/pkg/k8s/k8s_test.go +++ b/images/kube-webhook-certgen/rootfs/pkg/k8s/k8s_test.go @@ -186,7 +186,7 @@ func Test_Patching_objects(t *testing.T) { }) // This is to preserve old behavior and log format, it could be improved. - t.Run("different_non_empty_names_are_specified_for_validating_and_mutating_webhook", func(t *testing.T) { + t.Run("diffent_non_empty_names_are_specified_for_validating_and_mutating_webhook", func(t *testing.T) { t.Parallel() k := testK8sWithUnpatchedObjects() diff --git a/images/nginx-1.25/Makefile b/images/nginx-1.25/Makefile new file mode 100644 index 000000000..cdd3e2a3c --- /dev/null +++ b/images/nginx-1.25/Makefile @@ -0,0 +1,59 @@ +# Copyright 2024 The Kubernetes Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.DEFAULT_GOAL:=build + +# set default shell +SHELL=/bin/bash -o pipefail -o errexit + +DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))) +INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh + +# 0.0.0 shouldn't clobber any released builds +SHORT_SHA ?=$(shell git rev-parse --short HEAD) +TAG ?=$(shell cat TAG) + +REGISTRY ?= gcr.io/k8s-staging-ingress-nginx + +IMAGE = $(REGISTRY)/nginx-1.25 + +# required to enable buildx +export DOCKER_CLI_EXPERIMENTAL=enabled + +# build with buildx +PLATFORMS?=linux/amd64,linux/arm,linux/arm64,linux/s390x +OUTPUT= +PROGRESS=plain +build: ensure-buildx + docker buildx build \ + --platform=${PLATFORMS} $(OUTPUT) \ + --progress=$(PROGRESS) \ + --pull \ + --tag $(IMAGE):$(TAG) rootfs + +# push the cross built image +push: OUTPUT=--push +push: build + +# enable buildx +ensure-buildx: +# this is required for cloudbuild +ifeq ("$(wildcard $(INIT_BUILDX))","") + @curl -sSL https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/hack/init-buildx.sh | bash +else + @exec $(INIT_BUILDX) +endif + @echo "done" + +.PHONY: build push ensure-buildx \ No newline at end of file diff --git a/images/nginx-1.25/README.md b/images/nginx-1.25/README.md new file mode 100644 index 000000000..b5c6d593f --- /dev/null +++ b/images/nginx-1.25/README.md @@ -0,0 +1,47 @@ +NGINX 1.25 base image + +### HTTP/3 Support + +**HTTP/3 support is experimental and under development** + +[HTTP/3](https://datatracker.ietf.org/doc/html/rfc9114)\ +[QUIC](https://datatracker.ietf.org/doc/html/rfc9000) + +[According to the documentation, NGINX 1.25.0 or higher supports HTTP/3:](https://nginx.org/en/docs/quic.html) + +> Support for QUIC and HTTP/3 protocols is available since 1.25.0. + +But this requires adding a new flag during the build: + +> When configuring nginx, it is possible to enable QUIC and HTTP/3 using the --with-http_v3_module configuration parameter. + +[We have added this flag](https://github.com/kubernetes/ingress-nginx/pull/11470), but it is not enough to use HTTP/3 in ingress-nginx, this is the first step. + +The next steps will be: + +1. **Waiting for OpenSSL 3.4.**\ + The main problem is, that we still use OpenSSL (3.x) and it does not support the important mechanism of TLS 1.3 - [early_data](https://datatracker.ietf.org/doc/html/rfc8446#section-2.3): + + > Otherwise, the OpenSSL compatibility layer will be used that does not support early data. + + [And although another part of the documentation says that the directive is supported with OpenSSL:](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data) + + > The directive is supported when using OpenSSL 1.1.1 or higher. + + But this is incomplete support, because OpenSSL does not support this feature, and [it has only client side support:](https://github.com/openssl/openssl) + + > ... the QUIC (currently client side only) version 1 protocol + + [And also there are some issues even with client side](https://github.com/openssl/openssl/discussions/23339) + + Due to this, we currently have incomplete HTTP/3 support, without important security and performance features.\ + But the good news is that [OpenSSL plans to add server-side support in 3.4](https://www.openssl.org/roadmap.html): + + > Server-side QUIC support + + [Overview of SSL libraries(HAProxy Documentation)](https://github.com/haproxy/wiki/wiki/SSL-Libraries-Support-Status#tldr) + +2. **Adding [parameters](https://nginx.org/en/docs/http/ngx_http_v3_module.html) to the configmap to configure HTTP/3 and quic(enableHTTP3, enableHTTP/0.9, maxCurrentStream, and so on).** +3. **Adding options to the nginx config template(`listen 443 quic` to server blocks and `add_header Alt-Svc 'h3=":8443"; ma=86400';` to location blocks).** +4. **Opening the https port for UDP in the container(because QUIC uses UDP).** +5. **Adding tests.** diff --git a/images/nginx-1.25/TAG b/images/nginx-1.25/TAG new file mode 100644 index 000000000..51bbb66dc --- /dev/null +++ b/images/nginx-1.25/TAG @@ -0,0 +1 @@ +v0.0.10 diff --git a/images/nginx-1.25/cloudbuild.yaml b/images/nginx-1.25/cloudbuild.yaml new file mode 100644 index 000000000..c94539165 --- /dev/null +++ b/images/nginx-1.25/cloudbuild.yaml @@ -0,0 +1,17 @@ +timeout: 10800s +options: + substitution_option: ALLOW_LOOSE + # job builds a multi-arch docker image for amd64,arm,arm64 + machineType: E2_HIGHCPU_32 +steps: + - name: 'gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90' + entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + - HOME=/root + args: + - -c + - | + gcloud auth configure-docker \ + && cd images/nginx-1.25 && make push \ No newline at end of file diff --git a/images/nginx-1.25/rootfs/Dockerfile b/images/nginx-1.25/rootfs/Dockerfile new file mode 100644 index 000000000..13dcec33d --- /dev/null +++ b/images/nginx-1.25/rootfs/Dockerfile @@ -0,0 +1,74 @@ +# Copyright 2024 The Kubernetes Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +FROM alpine:3.20.0 as builder + +COPY . / + +RUN apk update \ + && apk upgrade \ + && apk add -U bash --no-cache \ + && /build.sh + +# Use a multi-stage build +FROM alpine:3.20.0 + +ENV PATH=$PATH:/usr/local/luajit/bin:/usr/local/nginx/sbin:/usr/local/nginx/bin + +ENV LUA_PATH="/usr/local/share/luajit-2.1.0-beta3/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/lib/lua/?.lua;;" +ENV LUA_CPATH="/usr/local/lib/lua/?/?.so;/usr/local/lib/lua/?.so;;" + +COPY --from=builder /usr/local /usr/local +COPY --from=builder /usr/lib/libopentelemetry* /usr/local/lib +COPY --from=builder /opt /opt +COPY --from=builder /etc/nginx /etc/nginx + +RUN apk update \ + && apk upgrade \ + && apk add -U --no-cache \ + bash \ + openssl \ + pcre \ + zlib \ + ca-certificates \ + patch \ + yajl \ + lmdb \ + libxml2 \ + libmaxminddb \ + yaml-cpp \ + dumb-init \ + tzdata \ + grpc-cpp \ + libprotobuf \ + && ln -s /usr/local/nginx/sbin/nginx /sbin/nginx \ + && adduser -S -D -H -u 101 -h /usr/local/nginx \ + -s /sbin/nologin -G www-data -g www-data www-data \ + && bash -eu -c ' \ + writeDirs=( \ + /var/log/nginx \ + /var/lib/nginx/body \ + /var/lib/nginx/fastcgi \ + /var/lib/nginx/proxy \ + /var/lib/nginx/scgi \ + /var/lib/nginx/uwsgi \ + /var/log/audit \ + ); \ + for dir in "${writeDirs[@]}"; do \ + mkdir -p ${dir}; \ + chown -R www-data.www-data ${dir}; \ + done' + +EXPOSE 80 443 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/images/nginx-1.25/rootfs/build.sh b/images/nginx-1.25/rootfs/build.sh new file mode 100755 index 000000000..f60a260f9 --- /dev/null +++ b/images/nginx-1.25/rootfs/build.sh @@ -0,0 +1,628 @@ +#!/bin/bash + +# Copyright 2023 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +export NGINX_VERSION=1.25.5 + +# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.3...master +export NDK_VERSION=v0.3.3 + +# Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master +export SETMISC_VERSION=796f5a3e518748eb29a93bd450324e0ad45b704e + +# Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.37...master +export MORE_HEADERS_VERSION=v0.37 + +# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...atomx:master +export NGINX_DIGEST_AUTH=v1.0.0 + +# Check for recent changes: https://github.com/yaoweibin/ngx_http_substitutions_filter_module/compare/v0.6.4...master +export NGINX_SUBSTITUTIONS=e12e965ac1837ca709709f9a26f572a54d83430e + +# Check for recent changes: https://github.com/SpiderLabs/ModSecurity-nginx/compare/v1.0.3...master +export MODSECURITY_VERSION=v1.0.3 + +# Check for recent changes: https://github.com/SpiderLabs/ModSecurity/compare/v3.0.8...v3/master +export MODSECURITY_LIB_VERSION=v3.0.12 + +# Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.5...v4.0/main +export OWASP_MODSECURITY_CRS_VERSION=v4.4.0 + +# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.26``...master +export LUA_NGX_VERSION=v0.10.26 + +# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/bea8a0c0de94cede71554f53818ac0267d675d63...master +export LUA_STREAM_NGX_VERSION=bea8a0c0de94cede71554f53818ac0267d675d63 + +# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master +export LUA_UPSTREAM_VERSION=542be0893543a4e42d89f6dd85372972f5ff2a36 + +# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.13...openresty:master +export LUA_CJSON_VERSION=2.1.0.13 + +# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/a607a41a8115fecfc05b5c283c81532a3d605425...master +export GEOIP2_VERSION=a607a41a8115fecfc05b5c283c81532a3d605425 + +# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20240314...v2.1-agentzh +export LUAJIT_VERSION=v2.1-20240314 + +# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/1cd4363c0a239afe4765ec607dcfbbb4e5900eea...master +export LUA_RESTY_BALANCER=1cd4363c0a239afe4765ec607dcfbbb4e5900eea + +# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/99e7578465b40f36f596d099b82eab404f2b42ed...master +export LUA_RESTY_CACHE=99e7578465b40f36f596d099b82eab404f2b42ed + +# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.27...master +export LUA_RESTY_CORE=v0.1.28 + +# Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/f418d77082eaef48331302e84330488fdc810ef4...master +export LUA_RESTY_COOKIE_VERSION=f418d77082eaef48331302e84330488fdc810ef4 + +# Check for recent changes: https://github.com/openresty/lua-resty-dns/compare/8bb53516e2933e61c317db740a9b7c2048847c2f...master +export LUA_RESTY_DNS=8bb53516e2933e61c317db740a9b7c2048847c2f + +# Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.17.1...master +export LUA_RESTY_HTTP=v0.17.1 + +# Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.09...master +export LUA_RESTY_LOCK=405d0bf4cbfa74d742c6ed3158d442221e6212a9 + +# Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.11...master +export LUA_RESTY_UPLOAD_VERSION=979372cce011f3176af3c9aff53fd0e992c4bfd3 + +# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master +export LUA_RESTY_STRING_VERSION=6f1bc21d86daef804df3cc34d6427ef68da26844 + +# Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.17...master +export LUA_RESTY_MEMCACHED_VERSION=2f02b68bf65fa2332cce070674a93a69a6c7239b + +# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master +export LUA_RESTY_REDIS_VERSION=8641b9f1b6f75cca50c90cf8ca5c502ad8950aa8 + +# Check for recent changes: https://github.com/api7/lua-resty-ipmatcher/compare/v0.6.1...master +export LUA_RESTY_IPMATCHER_VERSION=3e93c53eb8c9884efe939ef070486a0e507cc5be + +# Check for recent changes: https://github.com/ElvinEfendi/lua-resty-global-throttle/compare/v0.2.0...main +export LUA_RESTY_GLOBAL_THROTTLE_VERSION=v0.2.0 + +# Check for recent changes: https://github.com/microsoft/mimalloc/compare/v2.1.7...master +export MIMALOC_VERSION=v2.1.7 + +# Check on https://github.com/open-telemetry/opentelemetry-cpp +export OPENTELEMETRY_CPP_VERSION="v1.11.0" +# Check on https://github.com/open-telemetry/opentelemetry-proto +export OPENTELEMETRY_PROTO_VERSION="v1.1.0" + +export BUILD_PATH=/tmp/build + +ARCH=$(uname -m) + +get_src() +{ + hash="$1" + url="$2" + dest="${3-}" + ARGS="" + f=$(basename "$url") + + echo "Downloading $url" + + curl -sSL "$url" -o "$f" + # TODO: Reenable checksum verification but make it smarter + # echo "$hash $f" | sha256sum -c - || exit 10 + if [ ! -z "$dest" ]; then + mkdir ${BUILD_PATH}/${dest} + ARGS="-C ${BUILD_PATH}/${dest} --strip-components=1" + fi + tar xvzf "$f" $ARGS + rm -rf "$f" +} + +# install required packages to build +# Dependencies from "ninja" and below are OTEL dependencies +apk add \ + bash \ + gcc \ + clang \ + libc-dev \ + make \ + automake \ + openssl-dev \ + pcre-dev \ + zlib-dev \ + linux-headers \ + libxslt-dev \ + gd-dev \ + perl-dev \ + libedit-dev \ + mercurial \ + alpine-sdk \ + findutils \ + curl \ + ca-certificates \ + patch \ + libaio-dev \ + openssl \ + cmake \ + util-linux \ + lmdb-tools \ + wget \ + curl-dev \ + libprotobuf \ + git g++ pkgconf flex bison doxygen yajl-dev lmdb-dev libtool autoconf libxml2 libxml2-dev \ + python3 \ + libmaxminddb-dev \ + bc \ + unzip \ + dos2unix \ + yaml-cpp \ + coreutils \ + ninja \ + gtest-dev \ + git \ + build-base \ + pkgconfig \ + c-ares-dev \ + re2-dev \ + grpc-dev \ + protobuf-dev + +# apk add -X http://dl-cdn.alpinelinux.org/alpine/edge/testing opentelemetry-cpp-dev + +# There is some bug with some platforms and git, so force HTTP/1.1 +git config --global http.version HTTP/1.1 +git config --global http.postBuffer 157286400 + +mkdir -p /etc/nginx + +mkdir --verbose -p "$BUILD_PATH" +cd "$BUILD_PATH" + +# download, verify and extract the source files +get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \ + "https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz" + +get_src aa961eafb8317e0eb8da37eb6e2c9ff42267edd18b56947384e719b85188f58b \ + "https://github.com/vision5/ngx_devel_kit/archive/$NDK_VERSION.tar.gz" "ngx_devel_kit" + +get_src abc123 \ + "https://github.com/open-telemetry/opentelemetry-cpp/archive/$OPENTELEMETRY_CPP_VERSION.tar.gz" "opentelemetry-cpp" + +get_src abc123 \ + "https://github.com/open-telemetry/opentelemetry-proto/archive/$OPENTELEMETRY_PROTO_VERSION.tar.gz" "opentelemetry-proto" + +get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \ + "https://github.com/openresty/set-misc-nginx-module/archive/$SETMISC_VERSION.tar.gz" "set-misc-nginx-module" + +get_src 0c0d2ced2ce895b3f45eb2b230cd90508ab2a773299f153de14a43e44c1209b3 \ + "https://github.com/openresty/headers-more-nginx-module/archive/$MORE_HEADERS_VERSION.tar.gz" "headers-more-nginx-module" + +get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \ + "https://github.com/atomx/nginx-http-auth-digest/archive/$NGINX_DIGEST_AUTH.tar.gz" "nginx-http-auth-digest" + +get_src a98b48947359166326d58700ccdc27256d2648218072da138ab6b47de47fbd8f \ + "https://github.com/yaoweibin/ngx_http_substitutions_filter_module/archive/$NGINX_SUBSTITUTIONS.tar.gz" "ngx_http_substitutions_filter_module" + +get_src 32a42256616cc674dca24c8654397390adff15b888b77eb74e0687f023c8751b \ + "https://github.com/SpiderLabs/ModSecurity-nginx/archive/$MODSECURITY_VERSION.tar.gz" "ModSecurity-nginx" + +get_src bc764db42830aeaf74755754b900253c233ad57498debe7a441cee2c6f4b07c2 \ + "https://github.com/openresty/lua-nginx-module/archive/$LUA_NGX_VERSION.tar.gz" "lua-nginx-module" + +get_src 01b715754a8248cc7228e0c8f97f7488ae429d90208de0481394e35d24cef32f \ + "https://github.com/openresty/stream-lua-nginx-module/archive/$LUA_STREAM_NGX_VERSION.tar.gz" "stream-lua-nginx-module" + +get_src a92c9ee6682567605ece55d4eed5d1d54446ba6fba748cff0a2482aea5713d5f \ + "https://github.com/openresty/lua-upstream-nginx-module/archive/$LUA_UPSTREAM_VERSION.tar.gz" "lua-upstream-nginx-module" + +get_src 77bbcbb24c3c78f51560017288f3118d995fe71240aa379f5818ff6b166712ff \ + "https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz" "luajit2" + +get_src b6c9c09fd43eb34a71e706ad780b2ead26549a9a9f59280fe558f5b7b980b7c6 \ + "https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz" "ngx_http_geoip2_module" + +get_src deb4ab1ffb9f3d962c4b4a2c4bdff692b86a209e3835ae71ebdf3b97189e40a9 \ + "https://github.com/openresty/lua-resty-upload/archive/$LUA_RESTY_UPLOAD_VERSION.tar.gz" "lua-resty-upload" + +get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \ + "https://github.com/openresty/lua-resty-string/archive/$LUA_RESTY_STRING_VERSION.tar.gz" "lua-resty-string" + +get_src 16d72ed133f0c6df376a327386c3ef4e9406cf51003a700737c3805770ade7c5 \ + "https://github.com/openresty/lua-resty-balancer/archive/$LUA_RESTY_BALANCER.tar.gz" "lua-resty-balancer" + +get_src 39baab9e2b31cc48cecf896cea40ef6e80559054fd8a6e440cc804a858ea84d4 \ + "https://github.com/openresty/lua-resty-core/archive/$LUA_RESTY_CORE.tar.gz" "lua-resty-core" + +get_src a77b9de160d81712f2f442e1de8b78a5a7ef0d08f13430ff619f79235db974d4 \ + "https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz" "lua-cjson" + +get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \ + "https://github.com/cloudflare/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz" "lua-resty-cookie" + +get_src 573184006b98ccee2594b0d134fa4d05e5d2afd5141cbad315051ccf7e9b6403 \ + "https://github.com/openresty/lua-resty-lrucache/archive/$LUA_RESTY_CACHE.tar.gz" "lua-resty-lrucache" + +get_src b4ddcd47db347e9adf5c1e1491a6279a6ae2a3aff3155ef77ea0a65c998a69c1 \ + "https://github.com/openresty/lua-resty-lock/archive/$LUA_RESTY_LOCK.tar.gz" "lua-resty-lock" + +get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \ + "https://github.com/openresty/lua-resty-dns/archive/$LUA_RESTY_DNS.tar.gz" "lua-resty-dns" + +get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \ + "https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz" "lua-resty-http" + +get_src 02733575c4aed15f6cab662378e4b071c0a4a4d07940c4ef19a7319e9be943d4 \ + "https://github.com/openresty/lua-resty-memcached/archive/$LUA_RESTY_MEMCACHED_VERSION.tar.gz" "lua-resty-memcached" + +get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \ + "https://github.com/openresty/lua-resty-redis/archive/$LUA_RESTY_REDIS_VERSION.tar.gz" "lua-resty-redis" + +get_src efb767487ea3f6031577b9b224467ddbda2ad51a41c5867a47582d4ad85d609e \ + "https://github.com/api7/lua-resty-ipmatcher/archive/$LUA_RESTY_IPMATCHER_VERSION.tar.gz" "lua-resty-ipmatcher" + +get_src 0fb790e394510e73fdba1492e576aaec0b8ee9ef08e3e821ce253a07719cf7ea \ + "https://github.com/ElvinEfendi/lua-resty-global-throttle/archive/$LUA_RESTY_GLOBAL_THROTTLE_VERSION.tar.gz" "lua-resty-global-throttle" + +get_src d74f86ada2329016068bc5a243268f1f555edd620b6a7d6ce89295e7d6cf18da \ + "https://github.com/microsoft/mimalloc/archive/${MIMALOC_VERSION}.tar.gz" "mimalloc" + +# improve compilation times +CORES=$(($(grep -c ^processor /proc/cpuinfo) - 1)) + +export MAKEFLAGS=-j${CORES} +export CTEST_BUILD_FLAGS=${MAKEFLAGS} + +# Install luajit from openresty fork +export LUAJIT_LIB=/usr/local/lib +export LUA_LIB_DIR="$LUAJIT_LIB/lua" +export LUAJIT_INC=/usr/local/include/luajit-2.1 + +cd "$BUILD_PATH/luajit2" +make CCDEBUG=-g +make install + +ln -s /usr/local/bin/luajit /usr/local/bin/lua +ln -s "$LUAJIT_INC" /usr/local/include/lua + +cd "$BUILD_PATH/opentelemetry-cpp" +export CXXFLAGS="-DBENCHMARK_HAS_NO_INLINE_ASSEMBLY" +cmake -B build -G Ninja -Wno-dev \ + -DOTELCPP_PROTO_PATH="${BUILD_PATH}/opentelemetry-proto/" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_TESTING="OFF" \ + -DBUILD_W3CTRACECONTEXT_TEST="OFF" \ + -DCMAKE_BUILD_TYPE=None \ + -DWITH_ABSEIL=ON \ + -DWITH_STL=ON \ + -DWITH_EXAMPLES=OFF \ + -DWITH_ZPAGES=OFF \ + -DWITH_OTLP_GRPC=ON \ + -DWITH_OTLP_HTTP=ON \ + -DWITH_ZIPKIN=ON \ + -DWITH_PROMETHEUS=OFF \ + -DWITH_ASYNC_EXPORT_PREVIEW=OFF \ + -DWITH_METRICS_EXEMPLAR_PREVIEW=OFF + cmake --build build + cmake --install build + +# Git tuning +git config --global --add core.compression -1 + +# Get Brotli source and deps +cd "$BUILD_PATH" +git clone --depth=100 https://github.com/google/ngx_brotli.git +cd ngx_brotli +# https://github.com/google/ngx_brotli/issues/156 +git reset --hard 63ca02abdcf79c9e788d2eedcc388d2335902e52 +git submodule init +git submodule update + +cd "$BUILD_PATH" +git clone --depth=1 https://github.com/ssdeep-project/ssdeep +cd ssdeep/ + +./bootstrap +./configure + +make +make install + +# build modsecurity library +cd "$BUILD_PATH" +git clone -n https://github.com/SpiderLabs/ModSecurity +cd ModSecurity/ +git checkout $MODSECURITY_LIB_VERSION +git submodule init +git submodule update + +sh build.sh + +# https://github.com/SpiderLabs/ModSecurity/issues/1909#issuecomment-465926762 +sed -i '115i LUA_CFLAGS="${LUA_CFLAGS} -DWITH_LUA_JIT_2_1"' build/lua.m4 +sed -i '117i AC_SUBST(LUA_CFLAGS)' build/lua.m4 + +./configure \ + --disable-doxygen-doc \ + --disable-doxygen-html \ + --disable-examples + +make +make install + +mkdir -p /etc/nginx/modsecurity +cp modsecurity.conf-recommended /etc/nginx/modsecurity/modsecurity.conf +cp unicode.mapping /etc/nginx/modsecurity/unicode.mapping + +# Replace serial logging with concurrent +sed -i 's|SecAuditLogType Serial|SecAuditLogType Concurrent|g' /etc/nginx/modsecurity/modsecurity.conf + +# Concurrent logging implies the log is stored in several files +echo "SecAuditLogStorageDir /var/log/audit/" >> /etc/nginx/modsecurity/modsecurity.conf + +# Download owasp modsecurity crs +cd /etc/nginx/ + +git clone -b $OWASP_MODSECURITY_CRS_VERSION https://github.com/coreruleset/coreruleset +mv coreruleset owasp-modsecurity-crs +cd owasp-modsecurity-crs + +mv crs-setup.conf.example crs-setup.conf +mv rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf +mv rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf +cd .. + +# OWASP CRS v4 rules +echo " +Include /etc/nginx/owasp-modsecurity-crs/crs-setup.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-922-MULTIPART-ATTACK.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-934-APPLICATION-ATTACK-GENERIC.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-944-APPLICATION-ATTACK-JAVA.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-955-WEB-SHELLS.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf +" > /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf + +# build nginx +cd "$BUILD_PATH/nginx-$NGINX_VERSION" + +# apply nginx patches +for PATCH in `ls /patches`;do + echo "Patch: $PATCH" + if [[ "$PATCH" == *.txt ]]; then + patch -p0 < /patches/$PATCH + else + patch -p1 < /patches/$PATCH + fi +done + +WITH_FLAGS="--with-debug \ + --with-compat \ + --with-pcre-jit \ + --with-http_ssl_module \ + --with-http_stub_status_module \ + --with-http_realip_module \ + --with-http_auth_request_module \ + --with-http_addition_module \ + --with-http_gzip_static_module \ + --with-http_sub_module \ + --with-http_v2_module \ + --with-http_v3_module \ + --with-stream \ + --with-stream_ssl_module \ + --with-stream_realip_module \ + --with-stream_ssl_preread_module \ + --with-threads \ + --with-http_secure_link_module \ + --with-http_gunzip_module" + +# "Combining -flto with -g is currently experimental and expected to produce unexpected results." +# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html +CC_OPT="-g -O2 -fPIE -fstack-protector-strong \ + -Wformat \ + -Werror=format-security \ + -Wno-deprecated-declarations \ + -fno-strict-aliasing \ + -D_FORTIFY_SOURCE=2 \ + --param=ssp-buffer-size=4 \ + -DTCP_FASTOPEN=23 \ + -fPIC \ + -Wno-cast-function-type" + +LD_OPT="-fPIE -fPIC -pie -Wl,-z,relro -Wl,-z,now" + +if [[ ${ARCH} != "aarch64" ]]; then + WITH_FLAGS+=" --with-file-aio" +fi + +if [[ ${ARCH} == "x86_64" ]]; then + CC_OPT+=' -m64 -mtune=generic' +fi + +WITH_MODULES=" \ + --add-module=$BUILD_PATH/ngx_devel_kit \ + --add-module=$BUILD_PATH/set-misc-nginx-module \ + --add-module=$BUILD_PATH/headers-more-nginx-module \ + --add-module=$BUILD_PATH/ngx_http_substitutions_filter_module \ + --add-module=$BUILD_PATH/lua-nginx-module \ + --add-module=$BUILD_PATH/stream-lua-nginx-module \ + --add-module=$BUILD_PATH/lua-upstream-nginx-module \ + --add-dynamic-module=$BUILD_PATH/nginx-http-auth-digest \ + --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx \ + --add-dynamic-module=$BUILD_PATH/ngx_http_geoip2_module \ + --add-dynamic-module=$BUILD_PATH/ngx_brotli" + +./configure \ + --prefix=/usr/local/nginx \ + --conf-path=/etc/nginx/nginx.conf \ + --modules-path=/etc/nginx/modules \ + --http-log-path=/var/log/nginx/access.log \ + --error-log-path=/var/log/nginx/error.log \ + --lock-path=/var/lock/nginx.lock \ + --pid-path=/run/nginx.pid \ + --http-client-body-temp-path=/var/lib/nginx/body \ + --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \ + --http-proxy-temp-path=/var/lib/nginx/proxy \ + --http-scgi-temp-path=/var/lib/nginx/scgi \ + --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \ + ${WITH_FLAGS} \ + --without-mail_pop3_module \ + --without-mail_smtp_module \ + --without-mail_imap_module \ + --without-http_uwsgi_module \ + --without-http_scgi_module \ + --with-cc-opt="${CC_OPT}" \ + --with-ld-opt="${LD_OPT}" \ + --user=www-data \ + --group=www-data \ + ${WITH_MODULES} + +make +make modules +make install + +export OPENTELEMETRY_CONTRIB_COMMIT=aaa51e2297bcb34297f3c7aa44fa790497d2f7f3 +cd "$BUILD_PATH" + +git clone https://github.com/open-telemetry/opentelemetry-cpp-contrib.git opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT} + +cd ${BUILD_PATH}/opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT} +git reset --hard ${OPENTELEMETRY_CONTRIB_COMMIT} + +export OTEL_TEMP_INSTALL=/tmp/otel +mkdir -p ${OTEL_TEMP_INSTALL} + +cd ${BUILD_PATH}/opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT}/instrumentation/nginx +mkdir -p build +cd build +cmake -DCMAKE_BUILD_TYPE=Release \ + -G Ninja \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_INSTALL_PREFIX=${OTEL_TEMP_INSTALL} \ + -DBUILD_SHARED_LIBS=ON \ + -DNGINX_VERSION=${NGINX_VERSION} \ + .. +cmake --build . -j ${CORES} --target install + +mkdir -p /etc/nginx/modules +cp ${OTEL_TEMP_INSTALL}/otel_ngx_module.so /etc/nginx/modules/otel_ngx_module.so + + +cd "$BUILD_PATH/lua-resty-core" +make install + +cd "$BUILD_PATH/lua-resty-balancer" +make all +make install + +export LUA_INCLUDE_DIR=/usr/local/include/luajit-2.1 +ln -s $LUA_INCLUDE_DIR /usr/include/lua5.1 + +cd "$BUILD_PATH/lua-cjson" +make all +make install + +cd "$BUILD_PATH/lua-resty-cookie" +make all +make install + +cd "$BUILD_PATH/lua-resty-lrucache" +make install + +cd "$BUILD_PATH/lua-resty-dns" +make install + +cd "$BUILD_PATH/lua-resty-lock" +make install + +# required for OCSP verification +cd "$BUILD_PATH/lua-resty-http" +make install + +cd "$BUILD_PATH/lua-resty-upload" +make install + +cd "$BUILD_PATH/lua-resty-string" +make install + +cd "$BUILD_PATH/lua-resty-memcached" +make install + +cd "$BUILD_PATH/lua-resty-redis" +make install + +cd "$BUILD_PATH/lua-resty-ipmatcher" +INST_LUADIR=/usr/local/lib/lua make install + +cd "$BUILD_PATH/lua-resty-global-throttle" +make install + +cd "$BUILD_PATH/mimalloc" +mkdir -p out/release +cd out/release + +cmake ../.. + +make +make install + +# update image permissions +writeDirs=( \ + /etc/nginx \ + /usr/local/nginx \ + /opt/modsecurity/var/log \ + /opt/modsecurity/var/upload \ + /opt/modsecurity/var/audit \ + /var/log/audit \ + /var/log/nginx \ +); + +adduser -S -D -H -u 101 -h /usr/local/nginx -s /sbin/nologin -G www-data -g www-data www-data + +for dir in "${writeDirs[@]}"; do + mkdir -p ${dir}; + chown -R www-data.www-data ${dir}; +done + +rm -rf /etc/nginx/owasp-modsecurity-crs/.git +rm -rf /etc/nginx/owasp-modsecurity-crs/tests + +# remove .a files +find /usr/local -name "*.a" -print | xargs /bin/rm diff --git a/images/nginx/rootfs/patches/00_drop-alias-root.patch b/images/nginx-1.25/rootfs/patches/00_drop-alias-root.patch similarity index 100% rename from images/nginx/rootfs/patches/00_drop-alias-root.patch rename to images/nginx-1.25/rootfs/patches/00_drop-alias-root.patch diff --git a/images/nginx/rootfs/patches/01_nginx-1.27.1-win32_max_err_str.patch b/images/nginx-1.25/rootfs/patches/01_nginx-1.25.3-win32_max_err_str.patch similarity index 100% rename from images/nginx/rootfs/patches/01_nginx-1.27.1-win32_max_err_str.patch rename to images/nginx-1.25/rootfs/patches/01_nginx-1.25.3-win32_max_err_str.patch diff --git a/images/nginx/rootfs/patches/02_nginx-1.27.1-stream_balancer_export.patch b/images/nginx-1.25/rootfs/patches/02_nginx-1.25.3-stream_balancer_export.patch similarity index 100% rename from images/nginx/rootfs/patches/02_nginx-1.27.1-stream_balancer_export.patch rename to images/nginx-1.25/rootfs/patches/02_nginx-1.25.3-stream_balancer_export.patch diff --git a/images/nginx/rootfs/patches/03_nginx-1.27.1-stream_proxy_get_next_upstream_tries.patch b/images/nginx-1.25/rootfs/patches/03_nginx-1.25.3-stream_proxy_get_next_upstream_tries.patch similarity index 100% rename from images/nginx/rootfs/patches/03_nginx-1.27.1-stream_proxy_get_next_upstream_tries.patch rename to images/nginx-1.25/rootfs/patches/03_nginx-1.25.3-stream_proxy_get_next_upstream_tries.patch diff --git a/images/nginx/rootfs/patches/04_nginx-1.27.1-stream_proxy_timeout_fields.patch b/images/nginx-1.25/rootfs/patches/04_nginx-1.25.3-stream_proxy_timeout_fields.patch similarity index 92% rename from images/nginx/rootfs/patches/04_nginx-1.27.1-stream_proxy_timeout_fields.patch rename to images/nginx-1.25/rootfs/patches/04_nginx-1.25.3-stream_proxy_timeout_fields.patch index e205abb8b..39c59e206 100644 --- a/images/nginx/rootfs/patches/04_nginx-1.27.1-stream_proxy_timeout_fields.patch +++ b/images/nginx-1.25/rootfs/patches/04_nginx-1.25.3-stream_proxy_timeout_fields.patch @@ -1,6 +1,6 @@ -diff -u -r -p -Naur nginx-1.27.1/src/stream/ngx_stream.h nginx-1.27.1-patched/src/stream/ngx_stream.h ---- nginx-1.27.1/src/stream/ngx_stream.h 2021-11-04 21:27:55.288708527 +0800 -+++ nginx-1.27.1-patched/src/stream/ngx_stream.h 2021-11-04 21:28:50.768035209 +0800 +diff -u -r -p -Naur nginx-1.25.3/src/stream/ngx_stream.h nginx-1.25.3-patched/src/stream/ngx_stream.h +--- nginx-1.25.3/src/stream/ngx_stream.h 2021-11-04 21:27:55.288708527 +0800 ++++ nginx-1.25.3-patched/src/stream/ngx_stream.h 2021-11-04 21:28:50.768035209 +0800 @@ -254,6 +254,15 @@ typedef struct { } ngx_stream_module_t; @@ -25,9 +25,9 @@ diff -u -r -p -Naur nginx-1.27.1/src/stream/ngx_stream.h nginx-1.27.1-patched/sr typedef ngx_int_t (*ngx_stream_filter_pt)(ngx_stream_session_t *s, -diff -u -r -p -Naur nginx-1.27.1/src/stream/ngx_stream_proxy_module.c nginx-1.27.1-patched/src/stream/ngx_stream_proxy_module.c ---- nginx-1.27.1/src/stream/ngx_stream_proxy_module.c 2021-11-04 21:27:55.289708533 +0800 -+++ nginx-1.27.1-patched/src/stream/ngx_stream_proxy_module.c 2021-11-04 21:37:03.578936990 +0800 +diff -u -r -p -Naur nginx-1.25.3/src/stream/ngx_stream_proxy_module.c nginx-1.25.3-patched/src/stream/ngx_stream_proxy_module.c +--- nginx-1.25.3/src/stream/ngx_stream_proxy_module.c 2021-11-04 21:27:55.289708533 +0800 ++++ nginx-1.25.3-patched/src/stream/ngx_stream_proxy_module.c 2021-11-04 21:37:03.578936990 +0800 @@ -400,6 +400,7 @@ ngx_stream_proxy_handler(ngx_stream_sess ngx_stream_proxy_srv_conf_t *pscf; ngx_stream_upstream_srv_conf_t *uscf, **uscfp; diff --git a/images/nginx/rootfs/patches/05_nginx-1.27.1-stream_ssl_preread_no_skip.patch b/images/nginx-1.25/rootfs/patches/05_nginx-1.25.3-stream_ssl_preread_no_skip.patch similarity index 100% rename from images/nginx/rootfs/patches/05_nginx-1.27.1-stream_ssl_preread_no_skip.patch rename to images/nginx-1.25/rootfs/patches/05_nginx-1.25.3-stream_ssl_preread_no_skip.patch diff --git a/images/nginx/rootfs/patches/06_nginx-1.27.1-resolver_conf_parsing.patch b/images/nginx-1.25/rootfs/patches/06_nginx-1.25.3-resolver_conf_parsing.patch similarity index 100% rename from images/nginx/rootfs/patches/06_nginx-1.27.1-resolver_conf_parsing.patch rename to images/nginx-1.25/rootfs/patches/06_nginx-1.25.3-resolver_conf_parsing.patch diff --git a/images/nginx/rootfs/patches/07_nginx-1.27.1-daemon_destroy_pool.patch b/images/nginx-1.25/rootfs/patches/07_nginx-1.25.3-daemon_destroy_pool.patch similarity index 100% rename from images/nginx/rootfs/patches/07_nginx-1.27.1-daemon_destroy_pool.patch rename to images/nginx-1.25/rootfs/patches/07_nginx-1.25.3-daemon_destroy_pool.patch diff --git a/images/nginx/rootfs/patches/08_nginx-1.27.1-init_cycle_pool_release.patch b/images/nginx-1.25/rootfs/patches/08_nginx-1.25.3-init_cycle_pool_release.patch similarity index 65% rename from images/nginx/rootfs/patches/08_nginx-1.27.1-init_cycle_pool_release.patch rename to images/nginx-1.25/rootfs/patches/08_nginx-1.25.3-init_cycle_pool_release.patch index 4a26b92c5..bd2e9a7d9 100644 --- a/images/nginx/rootfs/patches/08_nginx-1.27.1-init_cycle_pool_release.patch +++ b/images/nginx-1.25/rootfs/patches/08_nginx-1.25.3-init_cycle_pool_release.patch @@ -1,6 +1,6 @@ -diff -rup nginx-1.27.1/src/core/nginx.c nginx-1.27.1-patched/src/core/nginx.c ---- nginx-1.27.1/src/core/nginx.c 2017-12-17 00:00:38.136470108 -0800 -+++ nginx-1.27.1-patched/src/core/nginx.c 2017-12-16 23:59:51.680958322 -0800 +diff -rup nginx-1.25.3/src/core/nginx.c nginx-1.25.3-patched/src/core/nginx.c +--- nginx-1.25.3/src/core/nginx.c 2017-12-17 00:00:38.136470108 -0800 ++++ nginx-1.25.3-patched/src/core/nginx.c 2017-12-16 23:59:51.680958322 -0800 @@ -186,6 +186,7 @@ static u_char *ngx_prefix; static u_char *ngx_conf_file; static u_char *ngx_conf_params; @@ -18,9 +18,9 @@ diff -rup nginx-1.27.1/src/core/nginx.c nginx-1.27.1-patched/src/core/nginx.c if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { return 1; } -diff -rup nginx-1.27.1/src/core/ngx_core.h nginx-1.27.1-patched/src/core/ngx_core.h ---- nginx-1.27.1/src/core/ngx_core.h 2017-10-10 08:22:51.000000000 -0700 -+++ nginx-1.27.1-patched/src/core/ngx_core.h 2017-12-16 23:59:51.679958370 -0800 +diff -rup nginx-1.25.3/src/core/ngx_core.h nginx-1.25.3-patched/src/core/ngx_core.h +--- nginx-1.25.3/src/core/ngx_core.h 2017-10-10 08:22:51.000000000 -0700 ++++ nginx-1.25.3-patched/src/core/ngx_core.h 2017-12-16 23:59:51.679958370 -0800 @@ -108,4 +108,6 @@ void ngx_cpuinfo(void); #define NGX_DISABLE_SYMLINKS_NOTOWNER 2 #endif @@ -28,9 +28,9 @@ diff -rup nginx-1.27.1/src/core/ngx_core.h nginx-1.27.1-patched/src/core/ngx_cor +extern ngx_pool_t *saved_init_cycle_pool; + #endif /* _NGX_CORE_H_INCLUDED_ */ -diff -rup nginx-1.27.1/src/core/ngx_cycle.c nginx-1.27.1-patched/src/core/ngx_cycle.c ---- nginx-1.27.1/src/core/ngx_cycle.c 2017-10-10 08:22:51.000000000 -0700 -+++ nginx-1.27.1-patched/src/core/ngx_cycle.c 2017-12-16 23:59:51.678958419 -0800 +diff -rup nginx-1.25.3/src/core/ngx_cycle.c nginx-1.25.3-patched/src/core/ngx_cycle.c +--- nginx-1.25.3/src/core/ngx_cycle.c 2017-10-10 08:22:51.000000000 -0700 ++++ nginx-1.25.3-patched/src/core/ngx_cycle.c 2017-12-16 23:59:51.678958419 -0800 @@ -748,6 +748,10 @@ old_shm_zone_done: if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { @@ -42,9 +42,9 @@ diff -rup nginx-1.27.1/src/core/ngx_cycle.c nginx-1.27.1-patched/src/core/ngx_cy ngx_destroy_pool(old_cycle->pool); cycle->old_cycle = NULL; -diff -rup nginx-1.27.1/src/os/unix/ngx_process_cycle.c nginx-1.27.1-patched/src/os/unix/ngx_process_cycle.c ---- nginx-1.27.1/src/os/unix/ngx_process_cycle.c 2017-12-17 00:00:38.142469762 -0800 -+++ nginx-1.27.1-patched/src/os/unix/ngx_process_cycle.c 2017-12-16 23:59:51.691957791 -0800 +diff -rup nginx-1.25.3/src/os/unix/ngx_process_cycle.c nginx-1.25.3-patched/src/os/unix/ngx_process_cycle.c +--- nginx-1.25.3/src/os/unix/ngx_process_cycle.c 2017-12-17 00:00:38.142469762 -0800 ++++ nginx-1.25.3-patched/src/os/unix/ngx_process_cycle.c 2017-12-16 23:59:51.691957791 -0800 @@ -687,6 +692,11 @@ ngx_master_process_exit(ngx_cycle_t *cyc ngx_exit_cycle.files_n = ngx_cycle->files_n; ngx_cycle = &ngx_exit_cycle; diff --git a/images/nginx/rootfs/patches/09_nginx-1.27.1-balancer_status_code.patch b/images/nginx-1.25/rootfs/patches/09_nginx-1.25.3-balancer_status_code.patch similarity index 100% rename from images/nginx/rootfs/patches/09_nginx-1.27.1-balancer_status_code.patch rename to images/nginx-1.25/rootfs/patches/09_nginx-1.25.3-balancer_status_code.patch diff --git a/images/nginx/rootfs/patches/10_nginx-1.27.1-delayed_posted_events.patch b/images/nginx-1.25/rootfs/patches/10_nginx-1.25.3-delayed_posted_events.patch similarity index 100% rename from images/nginx/rootfs/patches/10_nginx-1.27.1-delayed_posted_events.patch rename to images/nginx-1.25/rootfs/patches/10_nginx-1.25.3-delayed_posted_events.patch diff --git a/images/nginx/rootfs/patches/11_nginx-1.27.1-privileged_agent_process.patch b/images/nginx-1.25/rootfs/patches/11_nginx-1.25.3-privileged_agent_process.patch similarity index 100% rename from images/nginx/rootfs/patches/11_nginx-1.27.1-privileged_agent_process.patch rename to images/nginx-1.25/rootfs/patches/11_nginx-1.25.3-privileged_agent_process.patch diff --git a/images/nginx/rootfs/patches/12_nginx-1.27.1-privileged_agent_process_connections.patch b/images/nginx-1.25/rootfs/patches/12_nginx-1.25.3-privileged_agent_process_connections.patch similarity index 100% rename from images/nginx/rootfs/patches/12_nginx-1.27.1-privileged_agent_process_connections.patch rename to images/nginx-1.25/rootfs/patches/12_nginx-1.25.3-privileged_agent_process_connections.patch diff --git a/images/nginx/rootfs/patches/13_nginx-1.27.1-privileged_agent_process_thread_pool.patch b/images/nginx-1.25/rootfs/patches/13_nginx-1.25.3-privileged_agent_process_thread_pool.patch similarity index 100% rename from images/nginx/rootfs/patches/13_nginx-1.27.1-privileged_agent_process_thread_pool.patch rename to images/nginx-1.25/rootfs/patches/13_nginx-1.25.3-privileged_agent_process_thread_pool.patch diff --git a/images/nginx/rootfs/patches/14_nginx-1.27.1-single_process_graceful_exit.patch b/images/nginx-1.25/rootfs/patches/14_nginx-1.25.3-single_process_graceful_exit.patch similarity index 100% rename from images/nginx/rootfs/patches/14_nginx-1.27.1-single_process_graceful_exit.patch rename to images/nginx-1.25/rootfs/patches/14_nginx-1.25.3-single_process_graceful_exit.patch diff --git a/images/nginx/rootfs/patches/15_nginx-1.27.1-intercept_error_log.patch b/images/nginx-1.25/rootfs/patches/15_nginx-1.25.3-intercept_error_log.patch similarity index 100% rename from images/nginx/rootfs/patches/15_nginx-1.27.1-intercept_error_log.patch rename to images/nginx-1.25/rootfs/patches/15_nginx-1.25.3-intercept_error_log.patch diff --git a/images/nginx/rootfs/patches/16_nginx-1.27.1-upstream_pipelining.patch b/images/nginx-1.25/rootfs/patches/16_nginx-1.25.3-upstream_pipelining.patch similarity index 100% rename from images/nginx/rootfs/patches/16_nginx-1.27.1-upstream_pipelining.patch rename to images/nginx-1.25/rootfs/patches/16_nginx-1.25.3-upstream_pipelining.patch diff --git a/images/nginx/rootfs/patches/17_nginx-1.27.1-no_error_pages.patch b/images/nginx-1.25/rootfs/patches/17_nginx-1.25.3-no_error_pages.patch similarity index 93% rename from images/nginx/rootfs/patches/17_nginx-1.27.1-no_error_pages.patch rename to images/nginx-1.25/rootfs/patches/17_nginx-1.25.3-no_error_pages.patch index 593fcefd6..aceb2e988 100644 --- a/images/nginx/rootfs/patches/17_nginx-1.27.1-no_error_pages.patch +++ b/images/nginx-1.25/rootfs/patches/17_nginx-1.25.3-no_error_pages.patch @@ -1,6 +1,6 @@ -diff -upr nginx-1.27.1/src/http/ngx_http_core_module.c nginx-1.27.1-patched/src/http/ngx_http_core_module.c ---- nginx-1.27.1/src/http/ngx_http_core_module.c 2017-08-31 18:14:41.000000000 -0700 -+++ nginx-1.27.1-patched/src/http/ngx_http_core_module.c 2017-08-31 18:21:31.638098196 -0700 +diff -upr nginx-1.25.3/src/http/ngx_http_core_module.c nginx-1.25.3-patched/src/http/ngx_http_core_module.c +--- nginx-1.25.3/src/http/ngx_http_core_module.c 2017-08-31 18:14:41.000000000 -0700 ++++ nginx-1.25.3-patched/src/http/ngx_http_core_module.c 2017-08-31 18:21:31.638098196 -0700 @@ -64,6 +64,8 @@ static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, diff --git a/images/nginx-1.25/rootfs/patches/18_nginx-1.25.3-no_Werror.patch b/images/nginx-1.25/rootfs/patches/18_nginx-1.25.3-no_Werror.patch new file mode 100644 index 000000000..f7176faff --- /dev/null +++ b/images/nginx-1.25/rootfs/patches/18_nginx-1.25.3-no_Werror.patch @@ -0,0 +1,36 @@ +diff -urp nginx-1.25.3/auto/cc/clang nginx-1.25.3-patched/auto/cc/clang +--- nginx-1.25.3/auto/cc/clang 2014-03-04 03:39:24.000000000 -0800 ++++ nginx-1.25.3-patched/auto/cc/clang 2014-03-13 20:54:26.241413360 -0700 +@@ -89,7 +89,7 @@ CFLAGS="$CFLAGS -Wconditional-uninitiali + CFLAGS="$CFLAGS -Wno-unused-parameter" + + # stop on warning +-CFLAGS="$CFLAGS -Werror" ++#CFLAGS="$CFLAGS -Werror" + + # debug + CFLAGS="$CFLAGS -g" +diff -urp nginx-1.25.3/auto/cc/gcc nginx-1.25.3-patched/auto/cc/gcc +--- nginx-1.25.3/auto/cc/gcc 2014-03-04 03:39:24.000000000 -0800 ++++ nginx-1.25.3-patched/auto/cc/gcc 2014-03-13 20:54:13.301355329 -0700 +@@ -168,7 +168,7 @@ esac + + + # stop on warning +-CFLAGS="$CFLAGS -Werror" ++#CFLAGS="$CFLAGS -Werror" + + # debug + CFLAGS="$CFLAGS -g" +diff -urp nginx-1.25.3/auto/cc/icc nginx-1.25.3-patched/auto/cc/icc +--- nginx-1.25.3/auto/cc/icc 2014-03-04 03:39:24.000000000 -0800 ++++ nginx-1.25.3-patched/auto/cc/icc 2014-03-13 20:54:13.301355329 -0700 +@@ -115,7 +115,7 @@ case "$NGX_ICC_VER" in + esac + + # stop on warning +-CFLAGS="$CFLAGS -Werror" ++#CFLAGS="$CFLAGS -Werror" + + # debug + CFLAGS="$CFLAGS -g" diff --git a/images/nginx/rootfs/patches/19_nginx-1.27.1-log_escape_non_ascii.patch b/images/nginx-1.25/rootfs/patches/19_nginx-1.25.3-log_escape_non_ascii.patch similarity index 100% rename from images/nginx/rootfs/patches/19_nginx-1.27.1-log_escape_non_ascii.patch rename to images/nginx-1.25/rootfs/patches/19_nginx-1.25.3-log_escape_non_ascii.patch diff --git a/images/nginx/rootfs/patches/20_nginx-1.27.1-proxy_host_port_vars.patch b/images/nginx-1.25/rootfs/patches/20_nginx-1.25.3-proxy_host_port_vars.patch similarity index 87% rename from images/nginx/rootfs/patches/20_nginx-1.27.1-proxy_host_port_vars.patch rename to images/nginx-1.25/rootfs/patches/20_nginx-1.25.3-proxy_host_port_vars.patch index b81a299c8..82a344324 100644 --- a/images/nginx/rootfs/patches/20_nginx-1.27.1-proxy_host_port_vars.patch +++ b/images/nginx-1.25/rootfs/patches/20_nginx-1.25.3-proxy_host_port_vars.patch @@ -1,5 +1,5 @@ ---- nginx-1.27.1/src/http/modules/ngx_http_proxy_module.c 2017-07-16 14:02:51.000000000 +0800 -+++ nginx-1.27.1-patched/src/http/modules/ngx_http_proxy_module.c 2017-07-16 14:02:51.000000000 +0800 +--- nginx-1.25.3/src/http/modules/ngx_http_proxy_module.c 2017-07-16 14:02:51.000000000 +0800 ++++ nginx-1.25.3-patched/src/http/modules/ngx_http_proxy_module.c 2017-07-16 14:02:51.000000000 +0800 @@ -793,13 +793,13 @@ static ngx_keyval_t ngx_http_proxy_cach static ngx_http_variable_t ngx_http_proxy_vars[] = { diff --git a/images/nginx/rootfs/patches/21_nginx-1.27.1-cache_manager_exit.patch b/images/nginx-1.25/rootfs/patches/21_nginx-1.25.3-cache_manager_exit.patch similarity index 100% rename from images/nginx/rootfs/patches/21_nginx-1.27.1-cache_manager_exit.patch rename to images/nginx-1.25/rootfs/patches/21_nginx-1.25.3-cache_manager_exit.patch diff --git a/images/nginx/rootfs/patches/22_nginx-1.27.1-larger_max_error_str.patch b/images/nginx-1.25/rootfs/patches/22_nginx-1.25.3-larger_max_error_str.patch similarity index 62% rename from images/nginx/rootfs/patches/22_nginx-1.27.1-larger_max_error_str.patch rename to images/nginx-1.25/rootfs/patches/22_nginx-1.25.3-larger_max_error_str.patch index b821297e6..e5cd07e67 100644 --- a/images/nginx/rootfs/patches/22_nginx-1.27.1-larger_max_error_str.patch +++ b/images/nginx-1.25/rootfs/patches/22_nginx-1.25.3-larger_max_error_str.patch @@ -1,5 +1,5 @@ ---- nginx-1.27.1/src/core/ngx_log.h 2013-10-08 05:07:14.000000000 -0700 -+++ nginx-1.27.1-patched/src/core/ngx_log.h 2013-12-05 20:35:35.996236720 -0800 +--- nginx-1.25.3/src/core/ngx_log.h 2013-10-08 05:07:14.000000000 -0700 ++++ nginx-1.25.3-patched/src/core/ngx_log.h 2013-12-05 20:35:35.996236720 -0800 @@ -64,7 +64,9 @@ struct ngx_log_s { }; diff --git a/images/nginx/rootfs/patches/23_nginx-1.27.1-pcre_conf_opt.patch b/images/nginx-1.25/rootfs/patches/23_nginx-1.25.3-pcre_conf_opt.patch similarity index 100% rename from images/nginx/rootfs/patches/23_nginx-1.27.1-pcre_conf_opt.patch rename to images/nginx-1.25/rootfs/patches/23_nginx-1.25.3-pcre_conf_opt.patch diff --git a/images/nginx/rootfs/patches/24_nginx-1.27.1-always_enable_cc_feature_tests.patch b/images/nginx-1.25/rootfs/patches/24_nginx-1.25.3-always_enable_cc_feature_tests.patch similarity index 65% rename from images/nginx/rootfs/patches/24_nginx-1.27.1-always_enable_cc_feature_tests.patch rename to images/nginx-1.25/rootfs/patches/24_nginx-1.25.3-always_enable_cc_feature_tests.patch index 9517e92c4..b381d9b07 100644 --- a/images/nginx/rootfs/patches/24_nginx-1.27.1-always_enable_cc_feature_tests.patch +++ b/images/nginx-1.25/rootfs/patches/24_nginx-1.25.3-always_enable_cc_feature_tests.patch @@ -1,5 +1,5 @@ ---- nginx-1.27.1/auto/cc/conf 2015-10-30 22:47:50.000000000 +0800 -+++ nginx-1.27.1-patched/auto/cc/conf 2015-11-02 12:23:05.385156987 +0800 +--- nginx-1.25.3/auto/cc/conf 2015-10-30 22:47:50.000000000 +0800 ++++ nginx-1.25.3-patched/auto/cc/conf 2015-11-02 12:23:05.385156987 +0800 @@ -144,7 +144,7 @@ fi CFLAGS="$CFLAGS $NGX_CC_OPT" NGX_TEST_LD_OPT="$NGX_LD_OPT" diff --git a/images/nginx/rootfs/patches/25_nginx-1.27.1-ssl_cert_cb_yield.patch b/images/nginx-1.25/rootfs/patches/25_nginx-1.25.3-ssl_cert_cb_yield.patch similarity index 100% rename from images/nginx/rootfs/patches/25_nginx-1.27.1-ssl_cert_cb_yield.patch rename to images/nginx-1.25/rootfs/patches/25_nginx-1.25.3-ssl_cert_cb_yield.patch diff --git a/images/nginx/rootfs/patches/26_nginx-1.27.1-ssl_sess_cb_yield.patch b/images/nginx-1.25/rootfs/patches/26_nginx-1.25.3-ssl_sess_cb_yield.patch similarity index 100% rename from images/nginx/rootfs/patches/26_nginx-1.27.1-ssl_sess_cb_yield.patch rename to images/nginx-1.25/rootfs/patches/26_nginx-1.25.3-ssl_sess_cb_yield.patch diff --git a/images/nginx/rootfs/patches/27_nginx-1.27.1-ssl_client_hello_cb_yield.patch b/images/nginx-1.25/rootfs/patches/27_nginx-1.25.3-ssl_client_hello_cb_yield.patch similarity index 100% rename from images/nginx/rootfs/patches/27_nginx-1.27.1-ssl_client_hello_cb_yield.patch rename to images/nginx-1.25/rootfs/patches/27_nginx-1.25.3-ssl_client_hello_cb_yield.patch diff --git a/images/nginx/rootfs/patches/28_nginx-1.27.1-upstream_timeout_fields.patch b/images/nginx-1.25/rootfs/patches/28_nginx-1.25.3-upstream_timeout_fields.patch similarity index 100% rename from images/nginx/rootfs/patches/28_nginx-1.27.1-upstream_timeout_fields.patch rename to images/nginx-1.25/rootfs/patches/28_nginx-1.25.3-upstream_timeout_fields.patch diff --git a/images/nginx/rootfs/patches/29_nginx-1.27.1-safe_resolver_ipv6_option.patch b/images/nginx-1.25/rootfs/patches/29_nginx-1.25.3-safe_resolver_ipv6_option.patch similarity index 100% rename from images/nginx/rootfs/patches/29_nginx-1.27.1-safe_resolver_ipv6_option.patch rename to images/nginx-1.25/rootfs/patches/29_nginx-1.25.3-safe_resolver_ipv6_option.patch diff --git a/images/nginx/rootfs/patches/30_nginx-1.27.1-socket_cloexec.patch b/images/nginx-1.25/rootfs/patches/30_nginx-1.25.3-socket_cloexec.patch similarity index 100% rename from images/nginx/rootfs/patches/30_nginx-1.27.1-socket_cloexec.patch rename to images/nginx-1.25/rootfs/patches/30_nginx-1.25.3-socket_cloexec.patch diff --git a/images/nginx/rootfs/patches/31_nginx-1.27.1-reuseport_close_unused_fds.patch b/images/nginx-1.25/rootfs/patches/31_nginx-1.25.3-reuseport_close_unused_fds.patch similarity index 100% rename from images/nginx/rootfs/patches/31_nginx-1.27.1-reuseport_close_unused_fds.patch rename to images/nginx-1.25/rootfs/patches/31_nginx-1.25.3-reuseport_close_unused_fds.patch diff --git a/images/nginx/Makefile b/images/nginx/Makefile index 3cc14e5b3..b54a7739b 100644 --- a/images/nginx/Makefile +++ b/images/nginx/Makefile @@ -1,4 +1,4 @@ -# Copyright 2024 The Kubernetes Authors. All rights reserved. +# Copyright 2017 The Kubernetes Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,9 +22,9 @@ INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh # 0.0.0 shouldn't clobber any released builds SHORT_SHA ?=$(shell git rev-parse --short HEAD) -TAG ?=$(shell cat TAG) +TAG ?=v$(shell date +%Y%m%d)-$(SHORT_SHA) -REGISTRY ?= us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx +REGISTRY ?= gcr.io/k8s-staging-ingress-nginx IMAGE = $(REGISTRY)/nginx @@ -32,7 +32,7 @@ IMAGE = $(REGISTRY)/nginx export DOCKER_CLI_EXPERIMENTAL=enabled # build with buildx -PLATFORMS?=linux/amd64,linux/arm,linux/arm64 +PLATFORMS?=linux/amd64,linux/arm,linux/arm64,linux/s390x OUTPUT= PROGRESS=plain build: ensure-buildx diff --git a/images/nginx/README.md b/images/nginx/README.md index 768077215..da6994fb5 100644 --- a/images/nginx/README.md +++ b/images/nginx/README.md @@ -1,47 +1,27 @@ -NGINX base image +NGINX base image using [alpine](https://www.alpinelinux.org/) -### HTTP/3 Support +This custom image contains: -**HTTP/3 support is experimental and under development** +- [nginx-http-auth-digest](https://github.com/atomx/nginx-http-auth-digest) +- [ngx_http_substitutions_filter_module](https://github.com/yaoweibin/ngx_http_substitutions_filter_module) +- [OpenTelemetry-CPP](https://github.com/open-telemetry/opentelemetry-cpp) +- [OpenTelemetry-CPP-Nginx](https://github.com/open-telemetry/opentelemetry-cpp-contrib/tree/main/instrumentation/nginx) +- [nginx-opentracing](https://github.com/opentracing-contrib/nginx-opentracing) +- [opentracing-cpp](https://github.com/opentracing/opentracing-cpp) +- [zipkin-cpp-opentracing](https://github.com/rnburn/zipkin-cpp-opentracing) +- [dd-opentracing-cpp](https://github.com/DataDog/dd-opentracing-cpp) +- [ModSecurity-nginx](https://github.com/SpiderLabs/ModSecurity-nginx) (only supported in x86_64) +- [brotli](https://github.com/google/brotli) +- [geoip2](https://github.com/leev/ngx_http_geoip2_module) -[HTTP/3](https://datatracker.ietf.org/doc/html/rfc9114)\ -[QUIC](https://datatracker.ietf.org/doc/html/rfc9000) +**How to use this image:** +This image provides a default configuration file with no backend servers. -[According to the documentation, NGINX 1.25.0 or higher supports HTTP/3:](https://nginx.org/en/docs/quic.html) +_Using docker_ -> Support for QUIC and HTTP/3 protocols is available since 1.25.0. +NGINX base image we use is defined in NGINX_BASE file at the root of the project -But this requires adding a new flag during the build: +```console +docker run -v /some/nginx.conf:/etc/nginx/nginx.conf:ro $(cat ../../NGINX_BASE) +``` -> When configuring nginx, it is possible to enable QUIC and HTTP/3 using the --with-http_v3_module configuration parameter. - -[We have added this flag](https://github.com/kubernetes/ingress-nginx/pull/11470), but it is not enough to use HTTP/3 in ingress-nginx, this is the first step. - -The next steps will be: - -1. **Waiting for OpenSSL 3.4.**\ - The main problem is, that we still use OpenSSL (3.x) and it does not support the important mechanism of TLS 1.3 - [early_data](https://datatracker.ietf.org/doc/html/rfc8446#section-2.3): - - > Otherwise, the OpenSSL compatibility layer will be used that does not support early data. - - [And although another part of the documentation says that the directive is supported with OpenSSL:](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data) - - > The directive is supported when using OpenSSL 1.1.1 or higher. - - But this is incomplete support, because OpenSSL does not support this feature, and [it has only client side support:](https://github.com/openssl/openssl) - - > ... the QUIC (currently client side only) version 1 protocol - - [And also there are some issues even with client side](https://github.com/openssl/openssl/discussions/23339) - - Due to this, we currently have incomplete HTTP/3 support, without important security and performance features.\ - But the good news is that [OpenSSL plans to add server-side support in 3.4](https://github.com/openssl/web/blob/master/roadmap.md): - - > Server-side QUIC support - - [Overview of SSL libraries(HAProxy Documentation)](https://github.com/haproxy/wiki/wiki/SSL-Libraries-Support-Status#tldr) - -2. **Adding [parameters](https://nginx.org/en/docs/http/ngx_http_v3_module.html) to the configmap to configure HTTP/3 and quic(enableHTTP3, enableHTTP/0.9, maxCurrentStream, and so on).** -3. **Adding options to the nginx config template(`listen 443 quic` to server blocks and `add_header Alt-Svc 'h3=":8443"; ma=86400';` to location blocks).** -4. **Opening the https port for UDP in the container(because QUIC uses UDP).** -5. **Adding tests.** diff --git a/images/nginx/TAG b/images/nginx/TAG index 46b105a30..bbdeab622 100644 --- a/images/nginx/TAG +++ b/images/nginx/TAG @@ -1 +1 @@ -v2.0.0 +0.0.5 diff --git a/images/nginx/cloudbuild.yaml b/images/nginx/cloudbuild.yaml index 2563692d7..71051f26d 100644 --- a/images/nginx/cloudbuild.yaml +++ b/images/nginx/cloudbuild.yaml @@ -1,14 +1,17 @@ +timeout: 10800s options: - # Increase machine type for multi-arch builds. - machineType: E2_HIGHCPU_32 - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE + # job builds a multi-arch docker image for amd64,arm,arm64 and s390x. + machineType: E2_HIGHCPU_32 steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: 'gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90' entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images/nginx && make push -timeout: 7200s + - -c + - | + gcloud auth configure-docker \ + && cd images/nginx && make push diff --git a/images/nginx/rc.yaml b/images/nginx/rc.yaml new file mode 100644 index 000000000..bcf2b0274 --- /dev/null +++ b/images/nginx/rc.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +spec: + type: NodePort + ports: + - port: 80 + protocol: TCP + name: http + - port: 443 + protocol: TCP + name: https + selector: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx +spec: + replicas: 1 + selector: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + template: + metadata: + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/part-of: ingress-nginx + spec: + containers: + - name: nginx + image: registry.k8s.io/ingress-nginx/nginx:c5766dc011965f22fac2f4437e86d0fd9960a50c@sha256:94ff9b435a5f3f4570bbdaed4a3a523f63a54ce2ad6b132b5640bae2af5d9d90 + ports: + - containerPort: 80 + - containerPort: 443 diff --git a/images/nginx/rootfs/Dockerfile b/images/nginx/rootfs/Dockerfile index 834a9bcf3..f3d61017e 100644 --- a/images/nginx/rootfs/Dockerfile +++ b/images/nginx/rootfs/Dockerfile @@ -1,4 +1,4 @@ -# Copyright 2024 The Kubernetes Authors. All rights reserved. +# Copyright 2015 The Kubernetes Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -FROM alpine:3.21 as builder +FROM alpine:3.20.0 as builder COPY . / @@ -21,7 +21,7 @@ RUN apk update \ && /build.sh # Use a multi-stage build -FROM alpine:3.21 +FROM alpine:3.20.0 ENV PATH=$PATH:/usr/local/luajit/bin:/usr/local/nginx/sbin:/usr/local/nginx/bin @@ -29,10 +29,11 @@ ENV LUA_PATH="/usr/local/share/luajit-2.1.0-beta3/?.lua;/usr/local/share/lua/5.1 ENV LUA_CPATH="/usr/local/lib/lua/?/?.so;/usr/local/lib/lua/?.so;;" COPY --from=builder /usr/local /usr/local -COPY --from=builder /usr/lib/libopentelemetry* /usr/local/lib COPY --from=builder /opt /opt COPY --from=builder /etc/nginx /etc/nginx +LABEL org.opencontainers.image.source=https://github.com/kubernetes/ingress-nginx + RUN apk update \ && apk upgrade \ && apk add -U --no-cache \ @@ -49,10 +50,6 @@ RUN apk update \ yaml-cpp \ dumb-init \ tzdata \ - grpc-cpp \ - libprotobuf \ - abseil-cpp-crc-cpu-detect \ - abseil-cpp-vlog-config-internal \ && ln -s /usr/local/nginx/sbin/nginx /sbin/nginx \ && adduser -S -D -H -u 101 -h /usr/local/nginx \ -s /sbin/nologin -G www-data -g www-data www-data \ @@ -68,7 +65,7 @@ RUN apk update \ ); \ for dir in "${writeDirs[@]}"; do \ mkdir -p ${dir}; \ - chown -R www-data:www-data ${dir}; \ + chown -R www-data.www-data ${dir}; \ done' EXPOSE 80 443 diff --git a/images/nginx/rootfs/build.sh b/images/nginx/rootfs/build.sh index 297abf777..2f5f3c66f 100755 --- a/images/nginx/rootfs/build.sh +++ b/images/nginx/rootfs/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2023 The Kubernetes Authors. +# Copyright 2015 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,119 +18,139 @@ set -o errexit set -o nounset set -o pipefail -export NGINX_VERSION=1.27.1 +export NGINX_VERSION=1.21.6 -# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.3...master -export NDK_VERSION=v0.3.3 +# Check for recent changes: https://github.com/vision5/ngx_devel_kit/compare/v0.3.2...master +export NDK_VERSION=0.3.2 # Check for recent changes: https://github.com/openresty/set-misc-nginx-module/compare/v0.33...master -export SETMISC_VERSION=v0.33 +export SETMISC_VERSION=0.33 # Check for recent changes: https://github.com/openresty/headers-more-nginx-module/compare/v0.37...master -export MORE_HEADERS_VERSION=v0.37 +export MORE_HEADERS_VERSION=0.37 -# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...master -export NGINX_DIGEST_AUTH=v1.0.0 +# Check for recent changes: https://github.com/atomx/nginx-http-auth-digest/compare/v1.0.0...atomx:master +export NGINX_DIGEST_AUTH=1.0.0 + +# Check for recent changes: https://github.com/yaoweibin/ngx_http_substitutions_filter_module/compare/v0.6.4...master +export NGINX_SUBSTITUTIONS=b8a71eacc7f986ba091282ab8b1bbbc6ae1807e0 + +# Check for recent changes: https://github.com/opentracing-contrib/nginx-opentracing/compare/v0.19.0...master +export NGINX_OPENTRACING_VERSION=0.19.0 + +#Check for recent changes: https://github.com/opentracing/opentracing-cpp/compare/v1.6.0...master +export OPENTRACING_CPP_VERSION=f86b33f3d9e7322b1298ba62d5ffa7a9519c4c41 + +# Check for recent changes: https://github.com/rnburn/zipkin-cpp-opentracing/compare/v0.5.2...master +export ZIPKIN_CPP_VERSION=f69593138ff84ca2f6bc115992e18ca3d35f344a + +# Check for recent changes: https://github.com/jbeder/yaml-cpp/compare/yaml-cpp-0.7.0...master +export YAML_CPP_VERSION=yaml-cpp-0.7.0 + +# Check for recent changes: https://github.com/jaegertracing/jaeger-client-cpp/compare/v0.7.0...master +export JAEGER_VERSION=0.7.0 + +# Check for recent changes: https://github.com/msgpack/msgpack-c/compare/cpp-3.3.0...master +export MSGPACK_VERSION=3.3.0 + +# Check for recent changes: https://github.com/DataDog/dd-opentracing-cpp/compare/v1.3.7...master +export DATADOG_CPP_VERSION=1.3.7 # Check for recent changes: https://github.com/SpiderLabs/ModSecurity-nginx/compare/v1.0.3...master -export MODSECURITY_VERSION=v1.0.3 +export MODSECURITY_VERSION=1.0.3 -# Check for recent changes: https://github.com/SpiderLabs/ModSecurity/compare/v3.0.13...v3/master -export MODSECURITY_LIB_VERSION=v3.0.13 +# Check for recent changes: https://github.com/SpiderLabs/ModSecurity/compare/v3.0.11...v3/master +export MODSECURITY_LIB_VERSION=bbde9381cbccb49ea73f6194b08b478adc53f3bc -# Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v4.10.0...main -export OWASP_MODSECURITY_CRS_VERSION=v4.10.0 +# Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.2...v3.3/master +export OWASP_MODSECURITY_CRS_VERSION=v3.3.5 -# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.27...master -export LUA_NGX_VERSION=v0.10.27 +# Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.25...master +export LUA_NGX_VERSION=0.10.25 -# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.15...master -export LUA_STREAM_NGX_VERSION=v0.0.15 +# Check for recent changes: https://github.com/openresty/stream-lua-nginx-module/compare/v0.0.13...master +export LUA_STREAM_NGX_VERSION=0.0.13 -# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/v0.07...master -export LUA_UPSTREAM_VERSION=v0.07 +# Check for recent changes: https://github.com/openresty/lua-upstream-nginx-module/compare/8aa93ead98ba2060d4efd594ae33a35d153589bf...master +export LUA_UPSTREAM_VERSION=8aa93ead98ba2060d4efd594ae33a35d153589bf -# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.14...master -export LUA_CJSON_VERSION=2.1.0.14 +# Check for recent changes: https://github.com/openresty/lua-cjson/compare/2.1.0.11...openresty:master +export LUA_CJSON_VERSION=2.1.0.11 -# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/445df24ef3781e488cee3dfe8a1e111997fc1dfe...master -export GEOIP2_VERSION=445df24ef3781e488cee3dfe8a1e111997fc1dfe +# Check for recent changes: https://github.com/leev/ngx_http_geoip2_module/compare/3.4...master +export GEOIP2_VERSION=a607a41a8115fecfc05b5c283c81532a3d605425 -# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20240815...v2.1-agentzh -export LUAJIT_VERSION=v2.1-20240815 +# Check for recent changes: https://github.com/openresty/luajit2/compare/v2.1-20230410...v2.1-agentzh +export LUAJIT_VERSION=2.1-20230410 -# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.05...master -export LUA_RESTY_BALANCER=v0.05 +# Check for recent changes: https://github.com/openresty/lua-resty-balancer/compare/v0.04...master +export LUA_RESTY_BALANCER=0.04 -# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.15...master -export LUA_RESTY_CACHE=v0.15 +# Check for recent changes: https://github.com/openresty/lua-resty-lrucache/compare/v0.13...master +export LUA_RESTY_CACHE=0.13 -# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.30...master -export LUA_RESTY_CORE=v0.1.30 +# Check for recent changes: https://github.com/openresty/lua-resty-core/compare/v0.1.27...master +export LUA_RESTY_CORE=0.1.27 -# Check for recent changes: https://github.com/cloudflare/lua-resty-cookie/compare/f418d77082eaef48331302e84330488fdc810ef4...master -export LUA_RESTY_COOKIE_VERSION=f418d77082eaef48331302e84330488fdc810ef4 +# Check for recent changes: https://github.com/utix/lua-resty-cookie/compare/9533f47...master +export LUA_RESTY_COOKIE_VERSION=9533f479371663107b515590fc9daf00d61ebf11 -# Check for recent changes: https://github.com/openresty/lua-resty-dns/compare/v0.23...master -export LUA_RESTY_DNS=v0.23 +# Check for recent changes: https://github.com/openresty/lua-resty-dns/compare/v0.22...master +export LUA_RESTY_DNS=0.22 -# Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.17.2...master -export LUA_RESTY_HTTP=v0.17.2 +# Check for recent changes: https://github.com/ledgetech/lua-resty-http/compare/v0.16.1...master +export LUA_RESTY_HTTP=0ce55d6d15da140ecc5966fa848204c6fd9074e8 # Check for recent changes: https://github.com/openresty/lua-resty-lock/compare/v0.09...master -export LUA_RESTY_LOCK=v0.09 +export LUA_RESTY_LOCK=0.09 # Check for recent changes: https://github.com/openresty/lua-resty-upload/compare/v0.11...master -export LUA_RESTY_UPLOAD_VERSION=v0.11 +export LUA_RESTY_UPLOAD_VERSION=0.11 -# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.16...master -export LUA_RESTY_STRING_VERSION=v0.16 +# Check for recent changes: https://github.com/openresty/lua-resty-string/compare/v0.15...master +export LUA_RESTY_STRING_VERSION=0.15 # Check for recent changes: https://github.com/openresty/lua-resty-memcached/compare/v0.17...master -export LUA_RESTY_MEMCACHED_VERSION=v0.17 +export LUA_RESTY_MEMCACHED_VERSION=0.17 -# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.31...master -export LUA_RESTY_REDIS_VERSION=v0.31 +# Check for recent changes: https://github.com/openresty/lua-resty-redis/compare/v0.30...master +export LUA_RESTY_REDIS_VERSION=0.30 -# Check for recent changes: https://github.com/api7/lua-resty-ipmatcher/compare/3e93c53eb8c9884efe939ef070486a0e507cc5be...master -export LUA_RESTY_IPMATCHER_VERSION=3e93c53eb8c9884efe939ef070486a0e507cc5be +# Check for recent changes: https://github.com/api7/lua-resty-ipmatcher/compare/v0.6.1...master +export LUA_RESTY_IPMATCHER_VERSION=0.6.1 -# Check for recent changes: https://github.com/microsoft/mimalloc/compare/v2.1.9...master -export MIMALOC_VERSION=v2.1.9 +# Check for recent changes: https://github.com/ElvinEfendi/lua-resty-global-throttle/compare/v0.2.0...main +export LUA_RESTY_GLOBAL_THROTTLE_VERSION=0.2.0 -# Check for recent changes: https://github.com/open-telemetry/opentelemetry-cpp/compare/v1.18.0...main -export OPENTELEMETRY_CPP_VERSION=v1.18.0 - -# Check for recent changes: https://github.com/open-telemetry/opentelemetry-proto/compare/v1.5.0...main -export OPENTELEMETRY_PROTO_VERSION=v1.5.0 +# Check for recent changes: https://github.com/microsoft/mimalloc/compare/v1.7.6...master +export MIMALOC_VERSION=1.7.6 export BUILD_PATH=/tmp/build ARCH=$(uname -m) +if [[ ${ARCH} == "s390x" ]]; then + export LUAJIT_VERSION=9d5750d28478abfdcaefdfdc408f87752a21e431 + export LUA_RESTY_CORE=0.1.17 + export LUA_NGX_VERSION=0.10.15 + export LUA_STREAM_NGX_VERSION=0.0.7 +fi + get_src() { hash="$1" url="$2" - dest="${3-}" - ARGS="" f=$(basename "$url") echo "Downloading $url" curl -sSL "$url" -o "$f" - # TODO: Reenable checksum verification but make it smarter - # echo "$hash $f" | sha256sum -c - || exit 10 - if [ ! -z "$dest" ]; then - mkdir ${BUILD_PATH}/${dest} - ARGS="-C ${BUILD_PATH}/${dest} --strip-components=1" - fi - tar xvzf "$f" $ARGS + echo "$hash $f" | sha256sum -c - || exit 10 + tar xzf "$f" rm -rf "$f" } # install required packages to build -# Dependencies from "ninja" and below are OTEL dependencies apk add \ bash \ gcc \ @@ -167,22 +187,7 @@ apk add \ unzip \ dos2unix \ yaml-cpp \ - coreutils \ - ninja \ - gtest-dev \ - git \ - build-base \ - pkgconfig \ - c-ares-dev \ - re2-dev \ - grpc-dev \ - protobuf-dev - -# apk add -X http://dl-cdn.alpinelinux.org/alpine/edge/testing opentelemetry-cpp-dev - -# There is some bug with some platforms and git, so force HTTP/1.1 -git config --global http.version HTTP/1.1 -git config --global http.postBuffer 157286400 + coreutils mkdir -p /etc/nginx @@ -194,131 +199,274 @@ get_src 66dc7081488811e9f925719e34d1b4504c2801c81dee2920e5452a86b11405ae \ "https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz" get_src aa961eafb8317e0eb8da37eb6e2c9ff42267edd18b56947384e719b85188f58b \ - "https://github.com/vision5/ngx_devel_kit/archive/$NDK_VERSION.tar.gz" "ngx_devel_kit" - -get_src abc123 \ - "https://github.com/open-telemetry/opentelemetry-cpp/archive/$OPENTELEMETRY_CPP_VERSION.tar.gz" "opentelemetry-cpp" - -get_src abc123 \ - "https://github.com/open-telemetry/opentelemetry-proto/archive/$OPENTELEMETRY_PROTO_VERSION.tar.gz" "opentelemetry-proto" + "https://github.com/vision5/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz" get_src cd5e2cc834bcfa30149e7511f2b5a2183baf0b70dc091af717a89a64e44a2985 \ - "https://github.com/openresty/set-misc-nginx-module/archive/$SETMISC_VERSION.tar.gz" "set-misc-nginx-module" + "https://github.com/openresty/set-misc-nginx-module/archive/v$SETMISC_VERSION.tar.gz" -get_src 0c0d2ced2ce895b3f45eb2b230cd90508ab2a773299f153de14a43e44c1209b3 \ - "https://github.com/openresty/headers-more-nginx-module/archive/$MORE_HEADERS_VERSION.tar.gz" "headers-more-nginx-module" +get_src cf6e169d6b350c06d0c730b0eaf4973394026ad40094cddd3b3a5b346577019d \ + "https://github.com/openresty/headers-more-nginx-module/archive/v$MORE_HEADERS_VERSION.tar.gz" get_src f09851e6309560a8ff3e901548405066c83f1f6ff88aa7171e0763bd9514762b \ - "https://github.com/atomx/nginx-http-auth-digest/archive/$NGINX_DIGEST_AUTH.tar.gz" "nginx-http-auth-digest" + "https://github.com/atomx/nginx-http-auth-digest/archive/v$NGINX_DIGEST_AUTH.tar.gz" + +get_src a98b48947359166326d58700ccdc27256d2648218072da138ab6b47de47fbd8f \ + "https://github.com/yaoweibin/ngx_http_substitutions_filter_module/archive/$NGINX_SUBSTITUTIONS.tar.gz" + +get_src 6f97776ebdf019b105a755c7736b70bdbd7e575c7f0d39db5fe127873c7abf17 \ + "https://github.com/opentracing-contrib/nginx-opentracing/archive/v$NGINX_OPENTRACING_VERSION.tar.gz" + +get_src cbe625cba85291712253db5bc3870d60c709acfad9a8af5a302673d3d201e3ea \ + "https://github.com/opentracing/opentracing-cpp/archive/$OPENTRACING_CPP_VERSION.tar.gz" + +get_src 71de3d0658935db7ccea20e006b35e58ddc7e4c18878b9523f2addc2371e9270 \ + "https://github.com/rnburn/zipkin-cpp-opentracing/archive/$ZIPKIN_CPP_VERSION.tar.gz" get_src 32a42256616cc674dca24c8654397390adff15b888b77eb74e0687f023c8751b \ - "https://github.com/SpiderLabs/ModSecurity-nginx/archive/$MODSECURITY_VERSION.tar.gz" "ModSecurity-nginx" + "https://github.com/SpiderLabs/ModSecurity-nginx/archive/v$MODSECURITY_VERSION.tar.gz" +get_src 43e6a9fcb146ad871515f0d0873947e5d497a1c9c60c58cb102a97b47208b7c3 \ + "https://github.com/jbeder/yaml-cpp/archive/$YAML_CPP_VERSION.tar.gz" + +get_src 3a3a03060bf5e3fef52c9a2de02e6035cb557f389453d8f3b0c1d3d570636994 \ + "https://github.com/jaegertracing/jaeger-client-cpp/archive/v$JAEGER_VERSION.tar.gz" + +get_src 754c3ace499a63e45b77ef4bcab4ee602c2c414f58403bce826b76ffc2f77d0b \ + "https://github.com/msgpack/msgpack-c/archive/cpp-$MSGPACK_VERSION.tar.gz" + +if [[ ${ARCH} == "s390x" ]]; then +get_src 7d5f3439c8df56046d0564b5857fd8a30296ab1bd6df0f048aed7afb56a0a4c2 \ + "https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz" +get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \ + "https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz" +else get_src bc764db42830aeaf74755754b900253c233ad57498debe7a441cee2c6f4b07c2 \ - "https://github.com/openresty/lua-nginx-module/archive/$LUA_NGX_VERSION.tar.gz" "lua-nginx-module" + "https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz" get_src 01b715754a8248cc7228e0c8f97f7488ae429d90208de0481394e35d24cef32f \ - "https://github.com/openresty/stream-lua-nginx-module/archive/$LUA_STREAM_NGX_VERSION.tar.gz" "stream-lua-nginx-module" + "https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz" + +fi get_src a92c9ee6682567605ece55d4eed5d1d54446ba6fba748cff0a2482aea5713d5f \ - "https://github.com/openresty/lua-upstream-nginx-module/archive/$LUA_UPSTREAM_VERSION.tar.gz" "lua-upstream-nginx-module" + "https://github.com/openresty/lua-upstream-nginx-module/archive/$LUA_UPSTREAM_VERSION.tar.gz" +if [[ ${ARCH} == "s390x" ]]; then +get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \ + "https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz" +else get_src 77bbcbb24c3c78f51560017288f3118d995fe71240aa379f5818ff6b166712ff \ - "https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz" "luajit2" + "https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz" +fi + +get_src 8d39c6b23f941a2d11571daaccc04e69539a3fcbcc50a631837560d5861a7b96 \ + "https://github.com/DataDog/dd-opentracing-cpp/archive/v$DATADOG_CPP_VERSION.tar.gz" get_src b6c9c09fd43eb34a71e706ad780b2ead26549a9a9f59280fe558f5b7b980b7c6 \ - "https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz" "ngx_http_geoip2_module" + "https://github.com/leev/ngx_http_geoip2_module/archive/$GEOIP2_VERSION.tar.gz" get_src deb4ab1ffb9f3d962c4b4a2c4bdff692b86a209e3835ae71ebdf3b97189e40a9 \ - "https://github.com/openresty/lua-resty-upload/archive/$LUA_RESTY_UPLOAD_VERSION.tar.gz" "lua-resty-upload" + "https://github.com/openresty/lua-resty-upload/archive/v$LUA_RESTY_UPLOAD_VERSION.tar.gz" get_src bdbf271003d95aa91cab0a92f24dca129e99b33f79c13ebfcdbbcbb558129491 \ - "https://github.com/openresty/lua-resty-string/archive/$LUA_RESTY_STRING_VERSION.tar.gz" "lua-resty-string" + "https://github.com/openresty/lua-resty-string/archive/v$LUA_RESTY_STRING_VERSION.tar.gz" get_src 16d72ed133f0c6df376a327386c3ef4e9406cf51003a700737c3805770ade7c5 \ - "https://github.com/openresty/lua-resty-balancer/archive/$LUA_RESTY_BALANCER.tar.gz" "lua-resty-balancer" + "https://github.com/openresty/lua-resty-balancer/archive/v$LUA_RESTY_BALANCER.tar.gz" +if [[ ${ARCH} == "s390x" ]]; then +get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \ + "https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz" +else get_src 39baab9e2b31cc48cecf896cea40ef6e80559054fd8a6e440cc804a858ea84d4 \ - "https://github.com/openresty/lua-resty-core/archive/$LUA_RESTY_CORE.tar.gz" "lua-resty-core" + "https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz" +fi get_src a77b9de160d81712f2f442e1de8b78a5a7ef0d08f13430ff619f79235db974d4 \ - "https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz" "lua-cjson" + "https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz" -get_src 5ed48c36231e2622b001308622d46a0077525ac2f751e8cc0c9905914254baa4 \ - "https://github.com/cloudflare/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz" "lua-resty-cookie" +get_src a404c790553617424d743b82a9f01feccd0d2930b306b370c665ca3b7c09ccb6 \ + "https://github.com/utix/lua-resty-cookie/archive/$LUA_RESTY_COOKIE_VERSION.tar.gz" get_src 573184006b98ccee2594b0d134fa4d05e5d2afd5141cbad315051ccf7e9b6403 \ - "https://github.com/openresty/lua-resty-lrucache/archive/$LUA_RESTY_CACHE.tar.gz" "lua-resty-lrucache" + "https://github.com/openresty/lua-resty-lrucache/archive/v$LUA_RESTY_CACHE.tar.gz" get_src b4ddcd47db347e9adf5c1e1491a6279a6ae2a3aff3155ef77ea0a65c998a69c1 \ - "https://github.com/openresty/lua-resty-lock/archive/$LUA_RESTY_LOCK.tar.gz" "lua-resty-lock" + "https://github.com/openresty/lua-resty-lock/archive/v$LUA_RESTY_LOCK.tar.gz" get_src 70e9a01eb32ccade0d5116a25bcffde0445b94ad35035ce06b94ccd260ad1bf0 \ - "https://github.com/openresty/lua-resty-dns/archive/$LUA_RESTY_DNS.tar.gz" "lua-resty-dns" + "https://github.com/openresty/lua-resty-dns/archive/v$LUA_RESTY_DNS.tar.gz" get_src 9fcb6db95bc37b6fce77d3b3dc740d593f9d90dce0369b405eb04844d56ac43f \ - "https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz" "lua-resty-http" + "https://github.com/ledgetech/lua-resty-http/archive/$LUA_RESTY_HTTP.tar.gz" get_src 02733575c4aed15f6cab662378e4b071c0a4a4d07940c4ef19a7319e9be943d4 \ - "https://github.com/openresty/lua-resty-memcached/archive/$LUA_RESTY_MEMCACHED_VERSION.tar.gz" "lua-resty-memcached" + "https://github.com/openresty/lua-resty-memcached/archive/v$LUA_RESTY_MEMCACHED_VERSION.tar.gz" get_src c15aed1a01c88a3a6387d9af67a957dff670357f5fdb4ee182beb44635eef3f1 \ - "https://github.com/openresty/lua-resty-redis/archive/$LUA_RESTY_REDIS_VERSION.tar.gz" "lua-resty-redis" + "https://github.com/openresty/lua-resty-redis/archive/v$LUA_RESTY_REDIS_VERSION.tar.gz" get_src efb767487ea3f6031577b9b224467ddbda2ad51a41c5867a47582d4ad85d609e \ - "https://github.com/api7/lua-resty-ipmatcher/archive/$LUA_RESTY_IPMATCHER_VERSION.tar.gz" "lua-resty-ipmatcher" + "https://github.com/api7/lua-resty-ipmatcher/archive/v$LUA_RESTY_IPMATCHER_VERSION.tar.gz" + +get_src 0fb790e394510e73fdba1492e576aaec0b8ee9ef08e3e821ce253a07719cf7ea \ + "https://github.com/ElvinEfendi/lua-resty-global-throttle/archive/v$LUA_RESTY_GLOBAL_THROTTLE_VERSION.tar.gz" get_src d74f86ada2329016068bc5a243268f1f555edd620b6a7d6ce89295e7d6cf18da \ - "https://github.com/microsoft/mimalloc/archive/${MIMALOC_VERSION}.tar.gz" "mimalloc" + "https://github.com/microsoft/mimalloc/archive/refs/tags/v${MIMALOC_VERSION}.tar.gz" # improve compilation times CORES=$(($(grep -c ^processor /proc/cpuinfo) - 1)) export MAKEFLAGS=-j${CORES} export CTEST_BUILD_FLAGS=${MAKEFLAGS} +export HUNTER_JOBS_NUMBER=${CORES} +export HUNTER_USE_CACHE_SERVERS=true # Install luajit from openresty fork export LUAJIT_LIB=/usr/local/lib export LUA_LIB_DIR="$LUAJIT_LIB/lua" export LUAJIT_INC=/usr/local/include/luajit-2.1 -cd "$BUILD_PATH/luajit2" +cd "$BUILD_PATH/luajit2-$LUAJIT_VERSION" make CCDEBUG=-g make install ln -s /usr/local/bin/luajit /usr/local/bin/lua ln -s "$LUAJIT_INC" /usr/local/include/lua -cd "$BUILD_PATH/opentelemetry-cpp" -export CXXFLAGS="-DBENCHMARK_HAS_NO_INLINE_ASSEMBLY" -cmake -B build -G Ninja -Wno-dev \ - -DOTELCPP_PROTO_PATH="${BUILD_PATH}/opentelemetry-proto/" \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DBUILD_SHARED_LIBS=ON \ - -DBUILD_TESTING="OFF" \ - -DBUILD_W3CTRACECONTEXT_TEST="OFF" \ - -DCMAKE_BUILD_TYPE=None \ - -DWITH_ABSEIL=ON \ - -DWITH_STL=ON \ - -DWITH_EXAMPLES=OFF \ - -DWITH_ZPAGES=OFF \ - -DWITH_OTLP_GRPC=ON \ - -DWITH_OTLP_HTTP=ON \ - -DWITH_ZIPKIN=ON \ - -DWITH_PROMETHEUS=OFF \ - -DWITH_ASYNC_EXPORT_PREVIEW=OFF \ - -DWITH_METRICS_EXEMPLAR_PREVIEW=OFF - cmake --build build - cmake --install build +cd "$BUILD_PATH" # Git tuning git config --global --add core.compression -1 +# build opentracing lib +cd "$BUILD_PATH/opentracing-cpp-$OPENTRACING_CPP_VERSION" +mkdir .build +cd .build + +cmake -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_MOCKTRACER=OFF \ + -DBUILD_STATIC_LIBS=ON \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + .. + +make +make install + +# build yaml-cpp +# TODO @timmysilv: remove this and jaeger sed calls once it is fixed in jaeger-client-cpp +cd "$BUILD_PATH/yaml-cpp-$YAML_CPP_VERSION" +mkdir .build +cd .build + +cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + -DYAML_BUILD_SHARED_LIBS=ON \ + -DYAML_CPP_BUILD_TESTS=OFF \ + -DYAML_CPP_BUILD_TOOLS=OFF \ + .. + +make +make install + +# build jaeger lib +cd "$BUILD_PATH/jaeger-client-cpp-$JAEGER_VERSION" +sed -i 's/-Werror/-Wno-psabi/' CMakeLists.txt +# use the above built yaml-cpp instead until a new version of jaeger-client-cpp fixes the yaml-cpp issue +# tl;dr new hunter is needed for new yaml-cpp, but new hunter has a conflict with old Thrift and new Boost +sed -i 's/hunter_add_package(yaml-cpp)/#hunter_add_package(yaml-cpp)/' CMakeLists.txt +sed -i 's/yaml-cpp::yaml-cpp/yaml-cpp/' CMakeLists.txt + +cat < export.map +{ + global: + OpenTracingMakeTracerFactory; + local: *; +}; +EOF + +mkdir .build +cd .build + +cmake -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=OFF \ + -DJAEGERTRACING_BUILD_EXAMPLES=OFF \ + -DJAEGERTRACING_BUILD_CROSSDOCK=OFF \ + -DJAEGERTRACING_COVERAGE=OFF \ + -DJAEGERTRACING_PLUGIN=ON \ + -DHUNTER_CONFIGURATION_TYPES=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DJAEGERTRACING_WITH_YAML_CPP=ON \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + .. + +make +make install + +export HUNTER_INSTALL_DIR=$(cat _3rdParty/Hunter/install-root-dir) \ + +mv libjaegertracing_plugin.so /usr/local/lib/libjaegertracing_plugin.so + + +# build zipkin lib +cd "$BUILD_PATH/zipkin-cpp-opentracing-$ZIPKIN_CPP_VERSION" + +cat < export.map +{ + global: + OpenTracingMakeTracerFactory; + local: *; +}; +EOF + +mkdir .build +cd .build + +cmake -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_PLUGIN=ON \ + -DBUILD_TESTING=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + .. + +make +make install + +# build msgpack lib +cd "$BUILD_PATH/msgpack-c-cpp-$MSGPACK_VERSION" + +mkdir .build +cd .build +cmake -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DMSGPACK_BUILD_EXAMPLES=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + .. + +make +make install + +# build datadog lib +cd "$BUILD_PATH/dd-opentracing-cpp-$DATADOG_CPP_VERSION" + +mkdir .build +cd .build + +cmake -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + .. + +make +make install + # Get Brotli source and deps cd "$BUILD_PATH" -git clone --depth=100 https://github.com/google/ngx_brotli.git +git clone --depth=1 https://github.com/google/ngx_brotli.git cd ngx_brotli -git reset --hard a71f9312c2deb28875acc7bacfdd5695a111aa53 git submodule init git submodule update @@ -376,13 +524,17 @@ mv rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-E mv rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf cd .. -# OWASP CRS v4 rules +# OWASP CRS v3 rules echo " Include /etc/nginx/owasp-modsecurity-crs/crs-setup.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-910-IP-REPUTATION.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf @@ -391,7 +543,7 @@ Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LF Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf -Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-934-APPLICATION-ATTACK-GENERIC.conf +Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-934-APPLICATION-ATTACK-NODEJS.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf @@ -402,27 +554,11 @@ Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.co Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf -Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-955-WEB-SHELLS.conf Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf " > /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf -# NGINX compiles a small test program to check if an added module works as expected. -# -# ModSecurity-nginx provides 'printf("hello");' as a test, but newer versions of GCC, -# as included in Alpine 3.21, do not allow implicit declaration of function 'printf': -# -# objs/autotest.c:7:5: error: implicit declaration of function 'printf' [-Wimplicit-function-declaration] -# -# For this reason we replace 'printf("hello");' by 'msc_init();', which is always available. -# -# This fix is taken from a PR, that has been proposed to the ModSecurity-nginx project: -# -# https://github.com/owasp-modsecurity/ModSecurity-nginx/pull/275 -# -sed -i "s/ngx_feature_test='printf(\"hello\");'/ngx_feature_test='msc_init();'/" $BUILD_PATH/ModSecurity-nginx/config - # build nginx cd "$BUILD_PATH/nginx-$NGINX_VERSION" @@ -447,7 +583,6 @@ WITH_FLAGS="--with-debug \ --with-http_gzip_static_module \ --with-http_sub_module \ --with-http_v2_module \ - --with-http_v3_module \ --with-stream \ --with-stream_ssl_module \ --with-stream_realip_module \ @@ -467,9 +602,10 @@ CC_OPT="-g -O2 -fPIE -fstack-protector-strong \ --param=ssp-buffer-size=4 \ -DTCP_FASTOPEN=23 \ -fPIC \ + -I$HUNTER_INSTALL_DIR/include \ -Wno-cast-function-type" -LD_OPT="-fPIE -fPIC -pie -Wl,-z,relro -Wl,-z,now" +LD_OPT="-fPIE -fPIC -pie -Wl,-z,relro -Wl,-z,now -L$HUNTER_INSTALL_DIR/lib" if [[ ${ARCH} != "aarch64" ]]; then WITH_FLAGS+=" --with-file-aio" @@ -480,15 +616,17 @@ if [[ ${ARCH} == "x86_64" ]]; then fi WITH_MODULES=" \ - --add-module=$BUILD_PATH/ngx_devel_kit \ - --add-module=$BUILD_PATH/set-misc-nginx-module \ - --add-module=$BUILD_PATH/headers-more-nginx-module \ - --add-module=$BUILD_PATH/lua-nginx-module \ - --add-module=$BUILD_PATH/stream-lua-nginx-module \ - --add-module=$BUILD_PATH/lua-upstream-nginx-module \ - --add-dynamic-module=$BUILD_PATH/nginx-http-auth-digest \ - --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx \ - --add-dynamic-module=$BUILD_PATH/ngx_http_geoip2_module \ + --add-module=$BUILD_PATH/ngx_devel_kit-$NDK_VERSION \ + --add-module=$BUILD_PATH/set-misc-nginx-module-$SETMISC_VERSION \ + --add-module=$BUILD_PATH/headers-more-nginx-module-$MORE_HEADERS_VERSION \ + --add-module=$BUILD_PATH/ngx_http_substitutions_filter_module-$NGINX_SUBSTITUTIONS \ + --add-module=$BUILD_PATH/lua-nginx-module-$LUA_NGX_VERSION \ + --add-module=$BUILD_PATH/stream-lua-nginx-module-$LUA_STREAM_NGX_VERSION \ + --add-module=$BUILD_PATH/lua-upstream-nginx-module-$LUA_UPSTREAM_VERSION \ + --add-dynamic-module=$BUILD_PATH/nginx-http-auth-digest-$NGINX_DIGEST_AUTH \ + --add-dynamic-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING_VERSION/opentracing \ + --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx-$MODSECURITY_VERSION \ + --add-dynamic-module=$BUILD_PATH/ngx_http_geoip2_module-${GEOIP2_VERSION} \ --add-dynamic-module=$BUILD_PATH/ngx_brotli" ./configure \ @@ -520,81 +658,56 @@ make make modules make install -# Check for recent changes: https://github.com/open-telemetry/opentelemetry-cpp-contrib/compare/8933841f0a7f8737f61404cf0a64acf6b079c8a5...main -export OPENTELEMETRY_CONTRIB_COMMIT=8933841f0a7f8737f61404cf0a64acf6b079c8a5 -cd "$BUILD_PATH" - -git clone https://github.com/open-telemetry/opentelemetry-cpp-contrib.git opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT} - -cd ${BUILD_PATH}/opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT} -git reset --hard ${OPENTELEMETRY_CONTRIB_COMMIT} - -export OTEL_TEMP_INSTALL=/tmp/otel -mkdir -p ${OTEL_TEMP_INSTALL} - -cd ${BUILD_PATH}/opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT}/instrumentation/nginx -mkdir -p build -cd build -cmake -DCMAKE_BUILD_TYPE=Release \ - -G Ninja \ - -DCMAKE_CXX_STANDARD=17 \ - -DCMAKE_INSTALL_PREFIX=${OTEL_TEMP_INSTALL} \ - -DBUILD_SHARED_LIBS=ON \ - -DNGINX_VERSION=${NGINX_VERSION} \ - .. -cmake --build . -j ${CORES} --target install - -mkdir -p /etc/nginx/modules -cp ${OTEL_TEMP_INSTALL}/otel_ngx_module.so /etc/nginx/modules/otel_ngx_module.so - - -cd "$BUILD_PATH/lua-resty-core" +cd "$BUILD_PATH/lua-resty-core-$LUA_RESTY_CORE" make install -cd "$BUILD_PATH/lua-resty-balancer" +cd "$BUILD_PATH/lua-resty-balancer-$LUA_RESTY_BALANCER" make all make install export LUA_INCLUDE_DIR=/usr/local/include/luajit-2.1 ln -s $LUA_INCLUDE_DIR /usr/include/lua5.1 -cd "$BUILD_PATH/lua-cjson" +cd "$BUILD_PATH/lua-cjson-$LUA_CJSON_VERSION" make all make install -cd "$BUILD_PATH/lua-resty-cookie" +cd "$BUILD_PATH/lua-resty-cookie-$LUA_RESTY_COOKIE_VERSION" make all make install -cd "$BUILD_PATH/lua-resty-lrucache" +cd "$BUILD_PATH/lua-resty-lrucache-$LUA_RESTY_CACHE" make install -cd "$BUILD_PATH/lua-resty-dns" +cd "$BUILD_PATH/lua-resty-dns-$LUA_RESTY_DNS" make install -cd "$BUILD_PATH/lua-resty-lock" +cd "$BUILD_PATH/lua-resty-lock-$LUA_RESTY_LOCK" make install # required for OCSP verification -cd "$BUILD_PATH/lua-resty-http" +cd "$BUILD_PATH/lua-resty-http-$LUA_RESTY_HTTP" make install -cd "$BUILD_PATH/lua-resty-upload" +cd "$BUILD_PATH/lua-resty-upload-$LUA_RESTY_UPLOAD_VERSION" make install -cd "$BUILD_PATH/lua-resty-string" +cd "$BUILD_PATH/lua-resty-string-$LUA_RESTY_STRING_VERSION" make install -cd "$BUILD_PATH/lua-resty-memcached" +cd "$BUILD_PATH/lua-resty-memcached-$LUA_RESTY_MEMCACHED_VERSION" make install -cd "$BUILD_PATH/lua-resty-redis" +cd "$BUILD_PATH/lua-resty-redis-$LUA_RESTY_REDIS_VERSION" make install -cd "$BUILD_PATH/lua-resty-ipmatcher" +cd "$BUILD_PATH/lua-resty-ipmatcher-$LUA_RESTY_IPMATCHER_VERSION" INST_LUADIR=/usr/local/lib/lua make install -cd "$BUILD_PATH/mimalloc" +cd "$BUILD_PATH/lua-resty-global-throttle-$LUA_RESTY_GLOBAL_THROTTLE_VERSION" +make install + +cd "$BUILD_PATH/mimalloc-$MIMALOC_VERSION" mkdir -p out/release cd out/release @@ -618,7 +731,7 @@ adduser -S -D -H -u 101 -h /usr/local/nginx -s /sbin/nologin -G www-data -g www- for dir in "${writeDirs[@]}"; do mkdir -p ${dir}; - chown -R www-data:www-data ${dir}; + chown -R www-data.www-data ${dir}; done rm -rf /etc/nginx/owasp-modsecurity-crs/.git diff --git a/images/nginx/rootfs/patches/18_nginx-1.27.1-no_Werror.patch b/images/nginx/rootfs/patches/18_nginx-1.27.1-no_Werror.patch deleted file mode 100644 index d0aa7a31e..000000000 --- a/images/nginx/rootfs/patches/18_nginx-1.27.1-no_Werror.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff -urp nginx-1.27.1/auto/cc/clang nginx-1.27.1-patched/auto/cc/clang ---- nginx-1.27.1/auto/cc/clang 2014-03-04 03:39:24.000000000 -0800 -+++ nginx-1.27.1-patched/auto/cc/clang 2014-03-13 20:54:26.241413360 -0700 -@@ -89,7 +89,7 @@ CFLAGS="$CFLAGS -Wconditional-uninitiali - CFLAGS="$CFLAGS -Wno-unused-parameter" - - # stop on warning --CFLAGS="$CFLAGS -Werror" -+#CFLAGS="$CFLAGS -Werror" - - # debug - CFLAGS="$CFLAGS -g" -diff -urp nginx-1.27.1/auto/cc/gcc nginx-1.27.1-patched/auto/cc/gcc ---- nginx-1.27.1/auto/cc/gcc 2014-03-04 03:39:24.000000000 -0800 -+++ nginx-1.27.1-patched/auto/cc/gcc 2014-03-13 20:54:13.301355329 -0700 -@@ -168,7 +168,7 @@ esac - - - # stop on warning --CFLAGS="$CFLAGS -Werror" -+#CFLAGS="$CFLAGS -Werror" - - # debug - CFLAGS="$CFLAGS -g" -diff -urp nginx-1.27.1/auto/cc/icc nginx-1.27.1-patched/auto/cc/icc ---- nginx-1.27.1/auto/cc/icc 2014-03-04 03:39:24.000000000 -0800 -+++ nginx-1.27.1-patched/auto/cc/icc 2014-03-13 20:54:13.301355329 -0700 -@@ -115,7 +115,7 @@ case "$NGX_ICC_VER" in - esac - - # stop on warning --CFLAGS="$CFLAGS -Werror" -+#CFLAGS="$CFLAGS -Werror" - - # debug - CFLAGS="$CFLAGS -g" diff --git a/images/nginx/rootfs/patches/32_nginx-1.27.1-proc_exit_handler.patch b/images/nginx/rootfs/patches/32_nginx-1.27.1-proc_exit_handler.patch deleted file mode 100644 index f050c09d8..000000000 --- a/images/nginx/rootfs/patches/32_nginx-1.27.1-proc_exit_handler.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c -index c4e3c50..fa1408b 100644 ---- a/src/core/ngx_cycle.c -+++ b/src/core/ngx_cycle.c -@@ -264,6 +264,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) - } - - -+#if !(NGX_WIN32) -+ ngx_proc_exit_top_handler = ngx_proc_exit_def_handler; -+#endif - conf.ctx = cycle->conf_ctx; - conf.cycle = cycle; - conf.pool = pool; -diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c -index 12a8c68..874c9bf 100644 ---- a/src/os/unix/ngx_process.c -+++ b/src/os/unix/ngx_process.c -@@ -34,6 +34,7 @@ ngx_int_t ngx_process_slot; - ngx_socket_t ngx_channel; - ngx_int_t ngx_last_process; - ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; -+ngx_proc_exit_pt ngx_proc_exit_top_handler; - - - ngx_signal_t signals[] = { -@@ -83,6 +84,13 @@ ngx_signal_t signals[] = { - }; - - -+void -+ngx_proc_exit_def_handler(ngx_pid_t pid) -+{ -+ /* do nothing */ -+} -+ -+ - ngx_pid_t - ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, - char *name, ngx_int_t respawn) -@@ -564,6 +572,7 @@ ngx_process_get_status(void) - } - - ngx_unlock_mutexes(pid); -+ ngx_proc_exit_top_handler(pid); - } - } - -diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h -index 3986639..0b55d98 100644 ---- a/src/os/unix/ngx_process.h -+++ b/src/os/unix/ngx_process.h -@@ -18,6 +18,8 @@ typedef pid_t ngx_pid_t; - #define NGX_INVALID_PID -1 - - typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data); -+#define NGX_HAVE_PROC_EXIT 1 -+typedef void (*ngx_proc_exit_pt)(ngx_pid_t pid); - - typedef struct { - ngx_pid_t pid; -@@ -66,6 +68,7 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, - ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); - ngx_int_t ngx_init_signals(ngx_log_t *log); - void ngx_debug_point(void); -+void ngx_proc_exit_def_handler(ngx_pid_t pid); - - - #if (NGX_HAVE_SCHED_YIELD) -@@ -85,6 +88,7 @@ extern ngx_socket_t ngx_channel; - extern ngx_int_t ngx_process_slot; - extern ngx_int_t ngx_last_process; - extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; -+extern ngx_proc_exit_pt ngx_proc_exit_top_handler; - - - #endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/images/nginx/rootfs/patches/drop-alias-root.patch b/images/nginx/rootfs/patches/drop-alias-root.patch new file mode 100644 index 000000000..a92e08bd0 --- /dev/null +++ b/images/nginx/rootfs/patches/drop-alias-root.patch @@ -0,0 +1,144 @@ +:100644 100644 c7463dcd 00000000 M src/http/ngx_http_core_module.c +diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c +index c7463dcd..e2e45931 100644 +--- a/src/http/ngx_http_core_module.c ++++ b/src/http/ngx_http_core_module.c +@@ -55,7 +55,6 @@ static char *ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +-static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static char *ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, +@@ -323,21 +322,6 @@ static ngx_command_t ngx_http_core_commands[] = { + offsetof(ngx_http_core_loc_conf_t, default_type), + NULL }, + +- { ngx_string("root"), +- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF +- |NGX_CONF_TAKE1, +- ngx_http_core_root, +- NGX_HTTP_LOC_CONF_OFFSET, +- 0, +- NULL }, +- +- { ngx_string("alias"), +- NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, +- ngx_http_core_root, +- NGX_HTTP_LOC_CONF_OFFSET, +- 0, +- NULL }, +- + { ngx_string("limit_except"), + NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE, + ngx_http_core_limit_except, +@@ -4312,108 +4296,6 @@ ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + } + + +-static char * +-ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +-{ +- ngx_http_core_loc_conf_t *clcf = conf; +- +- ngx_str_t *value; +- ngx_int_t alias; +- ngx_uint_t n; +- ngx_http_script_compile_t sc; +- +- alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0; +- +- if (clcf->root.data) { +- +- if ((clcf->alias != 0) == alias) { +- return "is duplicate"; +- } +- +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "\"%V\" directive is duplicate, " +- "\"%s\" directive was specified earlier", +- &cmd->name, clcf->alias ? "alias" : "root"); +- +- return NGX_CONF_ERROR; +- } +- +- if (clcf->named && alias) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "the \"alias\" directive cannot be used " +- "inside the named location"); +- +- return NGX_CONF_ERROR; +- } +- +- value = cf->args->elts; +- +- if (ngx_strstr(value[1].data, "$document_root") +- || ngx_strstr(value[1].data, "${document_root}")) +- { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "the $document_root variable cannot be used " +- "in the \"%V\" directive", +- &cmd->name); +- +- return NGX_CONF_ERROR; +- } +- +- if (ngx_strstr(value[1].data, "$realpath_root") +- || ngx_strstr(value[1].data, "${realpath_root}")) +- { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "the $realpath_root variable cannot be used " +- "in the \"%V\" directive", +- &cmd->name); +- +- return NGX_CONF_ERROR; +- } +- +- clcf->alias = alias ? clcf->name.len : 0; +- clcf->root = value[1]; +- +- if (!alias && clcf->root.len > 0 +- && clcf->root.data[clcf->root.len - 1] == '/') +- { +- clcf->root.len--; +- } +- +- if (clcf->root.data[0] != '$') { +- if (ngx_conf_full_name(cf->cycle, &clcf->root, 0) != NGX_OK) { +- return NGX_CONF_ERROR; +- } +- } +- +- n = ngx_http_script_variables_count(&clcf->root); +- +- ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); +- sc.variables = n; +- +-#if (NGX_PCRE) +- if (alias && clcf->regex) { +- clcf->alias = NGX_MAX_SIZE_T_VALUE; +- n = 1; +- } +-#endif +- +- if (n) { +- sc.cf = cf; +- sc.source = &clcf->root; +- sc.lengths = &clcf->root_lengths; +- sc.values = &clcf->root_values; +- sc.complete_lengths = 1; +- sc.complete_values = 1; +- +- if (ngx_http_script_compile(&sc) != NGX_OK) { +- return NGX_CONF_ERROR; +- } +- } +- +- return NGX_CONF_OK; +-} +- +- + static ngx_http_method_name_t ngx_methods_names[] = { + { (u_char *) "GET", (uint32_t) ~NGX_HTTP_GET }, + { (u_char *) "HEAD", (uint32_t) ~NGX_HTTP_HEAD }, diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-balancer_status_code.patch b/images/nginx/rootfs/patches/nginx-1.21.4-balancer_status_code.patch new file mode 100644 index 000000000..c4d87e2fb --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-balancer_status_code.patch @@ -0,0 +1,72 @@ +diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c +index f8d5707d..6efe0047 100644 +--- a/src/http/ngx_http_upstream.c ++++ b/src/http/ngx_http_upstream.c +@@ -1515,6 +1515,11 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) + return; + } + ++ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { ++ ngx_http_upstream_finalize_request(r, u, rc); ++ return; ++ } ++ + u->state->peer = u->peer.name; + + if (rc == NGX_BUSY) { +diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h +index 3e714e5b..dfbb25e0 100644 +--- a/src/http/ngx_http_upstream.h ++++ b/src/http/ngx_http_upstream.h +@@ -427,4 +427,9 @@ extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[]; + extern ngx_conf_bitmask_t ngx_http_upstream_ignore_headers_masks[]; + + ++#ifndef HAVE_BALANCER_STATUS_CODE_PATCH ++#define HAVE_BALANCER_STATUS_CODE_PATCH ++#endif ++ ++ + #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ +diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h +index 09d24593..d8b4b584 100644 +--- a/src/stream/ngx_stream.h ++++ b/src/stream/ngx_stream.h +@@ -27,6 +27,7 @@ typedef struct ngx_stream_session_s ngx_stream_session_t; + + + #define NGX_STREAM_OK 200 ++#define NGX_STREAM_SPECIAL_RESPONSE 300 + #define NGX_STREAM_BAD_REQUEST 400 + #define NGX_STREAM_FORBIDDEN 403 + #define NGX_STREAM_INTERNAL_SERVER_ERROR 500 +diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c +index 818d7329..329dcdc6 100644 +--- a/src/stream/ngx_stream_proxy_module.c ++++ b/src/stream/ngx_stream_proxy_module.c +@@ -691,6 +691,11 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) + return; + } + ++ if (rc >= NGX_STREAM_SPECIAL_RESPONSE) { ++ ngx_stream_proxy_finalize(s, rc); ++ return; ++ } ++ + u->state->peer = u->peer.name; + + if (rc == NGX_BUSY) { +diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h +index 73947f46..21bc0ad7 100644 +--- a/src/stream/ngx_stream_upstream.h ++++ b/src/stream/ngx_stream_upstream.h +@@ -151,4 +151,9 @@ ngx_stream_upstream_srv_conf_t *ngx_stream_upstream_add(ngx_conf_t *cf, + extern ngx_module_t ngx_stream_upstream_module; + + ++#ifndef HAVE_BALANCER_STATUS_CODE_PATCH ++#define HAVE_BALANCER_STATUS_CODE_PATCH ++#endif ++ ++ + #endif /* _NGX_STREAM_UPSTREAM_H_INCLUDED_ */ diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-cache_manager_exit.patch b/images/nginx/rootfs/patches/nginx-1.21.4-cache_manager_exit.patch new file mode 100644 index 000000000..91ee63a26 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-cache_manager_exit.patch @@ -0,0 +1,19 @@ +# HG changeset patch +# User Yichun Zhang +# Date 1383598130 28800 +# Node ID f64218e1ac963337d84092536f588b8e0d99bbaa +# Parent dea321e5c0216efccbb23e84bbce7cf3e28f130c +Cache: gracefully exit the cache manager process. + +diff -r dea321e5c021 -r f64218e1ac96 src/os/unix/ngx_process_cycle.c +--- a/src/os/unix/ngx_process_cycle.c Thu Oct 31 18:23:49 2013 +0400 ++++ b/src/os/unix/ngx_process_cycle.c Mon Nov 04 12:48:50 2013 -0800 +@@ -1134,7 +1134,7 @@ + + if (ngx_terminate || ngx_quit) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); +- exit(0); ++ ngx_worker_process_exit(cycle); + } + + if (ngx_reopen) { diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-delayed_posted_events.patch b/images/nginx/rootfs/patches/nginx-1.21.4-delayed_posted_events.patch new file mode 100644 index 000000000..687584324 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-delayed_posted_events.patch @@ -0,0 +1,98 @@ +diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c +index 57af8132..4853945f 100644 +--- a/src/event/ngx_event.c ++++ b/src/event/ngx_event.c +@@ -196,6 +196,9 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) + ngx_uint_t flags; + ngx_msec_t timer, delta; + ++ ngx_queue_t *q; ++ ngx_event_t *ev; ++ + if (ngx_timer_resolution) { + timer = NGX_TIMER_INFINITE; + flags = 0; +@@ -215,6 +218,13 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) + #endif + } + ++ if (!ngx_queue_empty(&ngx_posted_delayed_events)) { ++ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, ++ "posted delayed event queue not empty" ++ " making poll timeout 0"); ++ timer = 0; ++ } ++ + if (ngx_use_accept_mutex) { + if (ngx_accept_disabled > 0) { + ngx_accept_disabled--; +@@ -257,6 +267,35 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) + } + + ngx_event_process_posted(cycle, &ngx_posted_events); ++ ++ while (!ngx_queue_empty(&ngx_posted_delayed_events)) { ++ q = ngx_queue_head(&ngx_posted_delayed_events); ++ ++ ev = ngx_queue_data(q, ngx_event_t, queue); ++ if (ev->delayed) { ++ /* start of newly inserted nodes */ ++ for (/* void */; ++ q != ngx_queue_sentinel(&ngx_posted_delayed_events); ++ q = ngx_queue_next(q)) ++ { ++ ev = ngx_queue_data(q, ngx_event_t, queue); ++ ev->delayed = 0; ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, ++ "skipping delayed posted event %p," ++ " till next iteration", ev); ++ } ++ ++ break; ++ } ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, ++ "delayed posted event %p", ev); ++ ++ ngx_delete_posted_event(ev); ++ ++ ev->handler(ev); ++ } + } + + +@@ -600,6 +639,7 @@ ngx_event_process_init(ngx_cycle_t *cycle) + + ngx_queue_init(&ngx_posted_accept_events); + ngx_queue_init(&ngx_posted_events); ++ ngx_queue_init(&ngx_posted_delayed_events); + + if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { + return NGX_ERROR; +diff --git a/src/event/ngx_event_posted.c b/src/event/ngx_event_posted.c +index d851f3d1..b6cea009 100644 +--- a/src/event/ngx_event_posted.c ++++ b/src/event/ngx_event_posted.c +@@ -12,6 +12,7 @@ + + ngx_queue_t ngx_posted_accept_events; + ngx_queue_t ngx_posted_events; ++ngx_queue_t ngx_posted_delayed_events; + + + void +diff --git a/src/event/ngx_event_posted.h b/src/event/ngx_event_posted.h +index 145d30fe..6c388553 100644 +--- a/src/event/ngx_event_posted.h ++++ b/src/event/ngx_event_posted.h +@@ -43,6 +43,9 @@ void ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted); + + extern ngx_queue_t ngx_posted_accept_events; + extern ngx_queue_t ngx_posted_events; ++extern ngx_queue_t ngx_posted_delayed_events; ++ ++#define HAVE_POSTED_DELAYED_EVENTS_PATCH + + + #endif /* _NGX_EVENT_POSTED_H_INCLUDED_ */ diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-hash_overflow.patch b/images/nginx/rootfs/patches/nginx-1.21.4-hash_overflow.patch new file mode 100644 index 000000000..449d214ba --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-hash_overflow.patch @@ -0,0 +1,20 @@ +# HG changeset patch +# User Yichun Zhang +# Date 1412276417 25200 +# Thu Oct 02 12:00:17 2014 -0700 +# Node ID 4032b992f23b054c1a2cfb0be879330d2c6708e5 +# Parent 1ff0f68d9376e3d184d65814a6372856bf65cfcd +Hash: buffer overflow might happen when exceeding the pre-configured limits. + +diff -r 1ff0f68d9376 -r 4032b992f23b src/core/ngx_hash.c +--- a/src/core/ngx_hash.c Tue Sep 30 15:50:28 2014 -0700 ++++ b/src/core/ngx_hash.c Thu Oct 02 12:00:17 2014 -0700 +@@ -312,6 +312,8 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng + continue; + } + ++ size--; ++ + ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0, + "could not build optimal %s, you should increase " + "either %s_max_size: %i or %s_bucket_size: %i; " diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-http2.patch b/images/nginx/rootfs/patches/nginx-1.21.4-http2.patch new file mode 100644 index 000000000..3b9d57736 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-http2.patch @@ -0,0 +1,57 @@ +#commit 6ceef192e7af1c507826ac38a2d43f08bf265fb9 +#repository: https://github.com/nginx/nginx +#Author: Maxim Dounin +#Date: Tue Oct 10 15:13:39 2023 +0300 +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 7c05ff1e7..410a8be24 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -347,6 +347,7 @@ ngx_http_v2_read_handler(ngx_event_t *rev) + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); + + h2c->blocked = 1; ++ h2c->new_streams = 0; + + if (c->close) { + c->close = 0; +@@ -1284,6 +1285,14 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, + goto rst_stream; + } + ++ if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent too many streams at once"); ++ ++ status = NGX_HTTP_V2_REFUSED_STREAM; ++ goto rst_stream; ++ } ++ + if (!h2c->settings_ack + && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) + && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW) +@@ -1349,6 +1358,12 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, + + rst_stream: + ++ if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent too many refused streams"); ++ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR); ++ } ++ + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } +diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h +index cb9014ccf..6751b3026 100644 +--- a/src/http/v2/ngx_http_v2.h ++++ b/src/http/v2/ngx_http_v2.h +@@ -131,6 +131,8 @@ struct ngx_http_v2_connection_s { + ngx_uint_t processing; + ngx_uint_t frames; + ngx_uint_t idle; ++ ngx_uint_t new_streams; ++ ngx_uint_t refused_streams; + ngx_uint_t priority_limit; + + size_t send_window; \ No newline at end of file diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-init_cycle_pool_release.patch b/images/nginx/rootfs/patches/nginx-1.21.4-init_cycle_pool_release.patch new file mode 100644 index 000000000..9cfa4f7cb --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-init_cycle_pool_release.patch @@ -0,0 +1,59 @@ +diff -rup nginx-1.21.4/src/core/nginx.c nginx-1.21.4-patched/src/core/nginx.c +--- nginx-1.21.4/src/core/nginx.c 2017-12-17 00:00:38.136470108 -0800 ++++ nginx-1.21.4-patched/src/core/nginx.c 2017-12-16 23:59:51.680958322 -0800 +@@ -186,6 +186,7 @@ static u_char *ngx_prefix; + static u_char *ngx_conf_file; + static u_char *ngx_conf_params; + static char *ngx_signal; ++ngx_pool_t *saved_init_cycle_pool = NULL; + + + static char **ngx_os_environ; +@@ -253,6 +254,8 @@ main(int argc, char *const *argv) + return 1; + } + ++ saved_init_cycle_pool = init_cycle.pool; ++ + if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { + return 1; + } +diff -rup nginx-1.21.4/src/core/ngx_core.h nginx-1.21.4-patched/src/core/ngx_core.h +--- nginx-1.21.4/src/core/ngx_core.h 2017-10-10 08:22:51.000000000 -0700 ++++ nginx-1.21.4-patched/src/core/ngx_core.h 2017-12-16 23:59:51.679958370 -0800 +@@ -108,4 +108,6 @@ void ngx_cpuinfo(void); + #define NGX_DISABLE_SYMLINKS_NOTOWNER 2 + #endif + ++extern ngx_pool_t *saved_init_cycle_pool; ++ + #endif /* _NGX_CORE_H_INCLUDED_ */ +diff -rup nginx-1.21.4/src/core/ngx_cycle.c nginx-1.21.4-patched/src/core/ngx_cycle.c +--- nginx-1.21.4/src/core/ngx_cycle.c 2017-10-10 08:22:51.000000000 -0700 ++++ nginx-1.21.4-patched/src/core/ngx_cycle.c 2017-12-16 23:59:51.678958419 -0800 +@@ -748,6 +748,10 @@ old_shm_zone_done: + + if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { + ++ if (ngx_is_init_cycle(old_cycle)) { ++ saved_init_cycle_pool = NULL; ++ } ++ + ngx_destroy_pool(old_cycle->pool); + cycle->old_cycle = NULL; + +diff -rup nginx-1.21.4/src/os/unix/ngx_process_cycle.c nginx-1.21.4-patched/src/os/unix/ngx_process_cycle.c +--- nginx-1.21.4/src/os/unix/ngx_process_cycle.c 2017-12-17 00:00:38.142469762 -0800 ++++ nginx-1.21.4-patched/src/os/unix/ngx_process_cycle.c 2017-12-16 23:59:51.691957791 -0800 +@@ -687,6 +692,11 @@ ngx_master_process_exit(ngx_cycle_t *cyc + ngx_exit_cycle.files_n = ngx_cycle->files_n; + ngx_cycle = &ngx_exit_cycle; + ++ if (saved_init_cycle_pool != NULL && saved_init_cycle_pool != cycle->pool) { ++ ngx_destroy_pool(saved_init_cycle_pool); ++ saved_init_cycle_pool = NULL; ++ } ++ + ngx_destroy_pool(cycle->pool); + + exit(0); diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-larger_max_error_str.patch b/images/nginx/rootfs/patches/nginx-1.21.4-larger_max_error_str.patch new file mode 100644 index 000000000..c89032c9f --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-larger_max_error_str.patch @@ -0,0 +1,13 @@ +--- nginx-1.21.4/src/core/ngx_log.h 2013-10-08 05:07:14.000000000 -0700 ++++ nginx-1.21.4-patched/src/core/ngx_log.h 2013-12-05 20:35:35.996236720 -0800 +@@ -64,7 +64,9 @@ struct ngx_log_s { + }; + + +-#define NGX_MAX_ERROR_STR 2048 ++#ifndef NGX_MAX_ERROR_STR ++#define NGX_MAX_ERROR_STR 4096 ++#endif + + + /*********************************/ diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-no_Werror.patch b/images/nginx/rootfs/patches/nginx-1.21.4-no_Werror.patch new file mode 100644 index 000000000..f4d6fd0e5 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-no_Werror.patch @@ -0,0 +1,36 @@ +diff -urp nginx-1.21.4/auto/cc/clang nginx-1.21.4-patched/auto/cc/clang +--- nginx-1.21.4/auto/cc/clang 2014-03-04 03:39:24.000000000 -0800 ++++ nginx-1.21.4-patched/auto/cc/clang 2014-03-13 20:54:26.241413360 -0700 +@@ -89,7 +89,7 @@ CFLAGS="$CFLAGS -Wconditional-uninitiali + CFLAGS="$CFLAGS -Wno-unused-parameter" + + # stop on warning +-CFLAGS="$CFLAGS -Werror" ++#CFLAGS="$CFLAGS -Werror" + + # debug + CFLAGS="$CFLAGS -g" +diff -urp nginx-1.21.4/auto/cc/gcc nginx-1.21.4-patched/auto/cc/gcc +--- nginx-1.21.4/auto/cc/gcc 2014-03-04 03:39:24.000000000 -0800 ++++ nginx-1.21.4-patched/auto/cc/gcc 2014-03-13 20:54:13.301355329 -0700 +@@ -168,7 +168,7 @@ esac + + + # stop on warning +-CFLAGS="$CFLAGS -Werror" ++#CFLAGS="$CFLAGS -Werror" + + # debug + CFLAGS="$CFLAGS -g" +diff -urp nginx-1.21.4/auto/cc/icc nginx-1.21.4-patched/auto/cc/icc +--- nginx-1.21.4/auto/cc/icc 2014-03-04 03:39:24.000000000 -0800 ++++ nginx-1.21.4-patched/auto/cc/icc 2014-03-13 20:54:13.301355329 -0700 +@@ -115,7 +115,7 @@ case "$NGX_ICC_VER" in + esac + + # stop on warning +-CFLAGS="$CFLAGS -Werror" ++#CFLAGS="$CFLAGS -Werror" + + # debug + CFLAGS="$CFLAGS -g" diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-proxy_host_port_vars.patch b/images/nginx/rootfs/patches/nginx-1.21.4-proxy_host_port_vars.patch new file mode 100644 index 000000000..01cebd65a --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-proxy_host_port_vars.patch @@ -0,0 +1,19 @@ +--- nginx-1.21.4/src/http/modules/ngx_http_proxy_module.c 2017-07-16 14:02:51.000000000 +0800 ++++ nginx-1.21.4-patched/src/http/modules/ngx_http_proxy_module.c 2017-07-16 14:02:51.000000000 +0800 +@@ -793,13 +793,13 @@ static ngx_keyval_t ngx_http_proxy_cach + static ngx_http_variable_t ngx_http_proxy_vars[] = { + + { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0, +- NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, ++ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0, +- NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, ++ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("proxy_add_x_forwarded_for"), NULL, +- ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, ++ ngx_http_proxy_add_x_forwarded_for_variable, 0, 0, 0 }, + + #if 0 + { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 }, diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-resolver_conf_parsing.patch b/images/nginx/rootfs/patches/nginx-1.21.4-resolver_conf_parsing.patch new file mode 100644 index 000000000..8638cdf2a --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-resolver_conf_parsing.patch @@ -0,0 +1,263 @@ +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index cd55520c..dade1846 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -9,12 +9,26 @@ + #include + #include + ++#if !(NGX_WIN32) ++#include ++#endif ++ + + #define NGX_RESOLVER_UDP_SIZE 4096 + + #define NGX_RESOLVER_TCP_RSIZE (2 + 65535) + #define NGX_RESOLVER_TCP_WSIZE 8192 + ++#if !(NGX_WIN32) ++/* ++ * note that 2KB should be more than enough for majority of the ++ * resolv.conf files out there. it also acts as a safety guard to prevent ++ * abuse. ++ */ ++#define NGX_RESOLVER_FILE_BUF_SIZE 2048 ++#define NGX_RESOLVER_FILE_NAME "/etc/resolv.conf" ++#endif ++ + + typedef struct { + u_char ident_hi; +@@ -131,6 +145,191 @@ static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r, + #endif + + ++#if !(NGX_WIN32) ++static ngx_int_t ++ngx_resolver_read_resolv_conf(ngx_conf_t *cf, ngx_resolver_t *r, u_char *path, ++ size_t path_len) ++{ ++ ngx_url_t u; ++ ngx_resolver_connection_t *rec; ++ ngx_fd_t fd; ++ ngx_file_t file; ++ u_char buf[NGX_RESOLVER_FILE_BUF_SIZE]; ++ u_char ipv6_buf[NGX_INET6_ADDRSTRLEN]; ++ ngx_uint_t address = 0, j, total = 0; ++ ssize_t n, i; ++ enum { ++ sw_nameserver, ++ sw_spaces, ++ sw_address, ++ sw_skip ++ } state; ++ ++ file.name.data = path; ++ file.name.len = path_len; ++ ++ if (ngx_conf_full_name(cf->cycle, &file.name, 1) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, ++ NGX_FILE_OPEN, 0); ++ ++ if (fd == NGX_INVALID_FILE) { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ++ ngx_open_file_n " \"%s\" failed", file.name.data); ++ ++ return NGX_ERROR; ++ } ++ ++ ngx_memzero(&file, sizeof(ngx_file_t)); ++ ++ file.fd = fd; ++ file.log = cf->log; ++ ++ state = sw_nameserver; ++ ++ n = ngx_read_file(&file, buf, NGX_RESOLVER_FILE_BUF_SIZE, 0); ++ ++ if (n == NGX_ERROR) { ++ ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno, ++ ngx_read_file_n " \"%s\" failed", file.name.data); ++ } ++ ++ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { ++ ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno, ++ ngx_close_file_n " \"%s\" failed", file.name.data); ++ } ++ ++ if (n == NGX_ERROR) { ++ return NGX_ERROR; ++ } ++ ++ if (n == 0) { ++ return NGX_OK; ++ } ++ ++ for (i = 0; i < n && total < MAXNS; /* void */) { ++ if (buf[i] == '#' || buf[i] == ';') { ++ state = sw_skip; ++ } ++ ++ switch (state) { ++ ++ case sw_nameserver: ++ ++ if ((size_t) n - i >= sizeof("nameserver") - 1 ++ && ngx_memcmp(buf + i, "nameserver", ++ sizeof("nameserver") - 1) == 0) ++ { ++ state = sw_spaces; ++ i += sizeof("nameserver") - 1; ++ ++ continue; ++ } ++ ++ break; ++ ++ case sw_spaces: ++ if (buf[i] != '\t' && buf[i] != ' ') { ++ address = i; ++ state = sw_address; ++ } ++ ++ break; ++ ++ case sw_address: ++ ++ if (buf[i] == CR || buf[i] == LF || i == n - 1) { ++ ngx_memzero(&u, sizeof(ngx_url_t)); ++ ++ u.url.data = buf + address; ++ ++ if (i == n - 1 && buf[i] != CR && buf[i] != LF) { ++ u.url.len = n - address; ++ ++ } else { ++ u.url.len = i - address; ++ } ++ ++ u.default_port = 53; ++ ++ /* IPv6? */ ++ if (ngx_strlchr(u.url.data, u.url.data + u.url.len, ++ ':') != NULL) ++ { ++ if (u.url.len + 2 > sizeof(ipv6_buf)) { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ++ "IPv6 resolver address is too long:" ++ " \"%V\"", &u.url); ++ ++ return NGX_ERROR; ++ } ++ ++ ipv6_buf[0] = '['; ++ ngx_memcpy(ipv6_buf + 1, u.url.data, u.url.len); ++ ipv6_buf[u.url.len + 1] = ']'; ++ ++ u.url.data = ipv6_buf; ++ u.url.len = u.url.len + 2; ++ } ++ ++ if (ngx_parse_url(cf->pool, &u) != NGX_OK) { ++ if (u.err) { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ++ "%s in resolver \"%V\"", ++ u.err, &u.url); ++ } ++ ++ return NGX_ERROR; ++ } ++ ++ rec = ngx_array_push_n(&r->connections, u.naddrs); ++ if (rec == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t)); ++ ++ for (j = 0; j < u.naddrs; j++) { ++ rec[j].sockaddr = u.addrs[j].sockaddr; ++ rec[j].socklen = u.addrs[j].socklen; ++ rec[j].server = u.addrs[j].name; ++ rec[j].resolver = r; ++ } ++ ++ total++; ++ ++#if (NGX_DEBUG) ++ /* ++ * logs with level below NGX_LOG_NOTICE will not be printed ++ * in this early phase ++ */ ++ ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, ++ "parsed a resolver: \"%V\"", &u.url); ++#endif ++ ++ state = sw_nameserver; ++ } ++ ++ break; ++ ++ case sw_skip: ++ if (buf[i] == CR || buf[i] == LF) { ++ state = sw_nameserver; ++ } ++ ++ break; ++ } ++ ++ i++; ++ } ++ ++ return NGX_OK; ++} ++#endif ++ ++ + ngx_resolver_t * + ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) + { +@@ -246,6 +445,39 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) + } + #endif + ++#if !(NGX_WIN32) ++ if (ngx_strncmp(names[i].data, "local=", 6) == 0) { ++ ++ if (ngx_strcmp(&names[i].data[6], "on") == 0) { ++ if (ngx_resolver_read_resolv_conf(cf, r, ++ (u_char *) ++ NGX_RESOLVER_FILE_NAME, ++ sizeof(NGX_RESOLVER_FILE_NAME) ++ - 1) ++ != NGX_OK) ++ { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ++ "unable to parse local resolver"); ++ return NULL; ++ } ++ ++ } else if (ngx_strcmp(&names[i].data[6], "off") != 0) { ++ if (ngx_resolver_read_resolv_conf(cf, r, ++ &names[i].data[6], ++ names[i].len - 6) ++ != NGX_OK) ++ { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ++ "unable to parse local resolver"); ++ return NULL; ++ } ++ ++ } ++ ++ continue; ++ } ++#endif ++ + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = names[i]; diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-reuseport_close_unused_fds.patch b/images/nginx/rootfs/patches/nginx-1.21.4-reuseport_close_unused_fds.patch new file mode 100644 index 000000000..ff4a36fd2 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-reuseport_close_unused_fds.patch @@ -0,0 +1,38 @@ +diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c +--- a/src/core/ngx_connection.c ++++ b/src/core/ngx_connection.c +@@ -1118,6 +1118,12 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle) + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + ++#if (NGX_HAVE_REUSEPORT) ++ if (ls[i].fd == (ngx_socket_t) -1) { ++ continue; ++ } ++#endif ++ + c = ls[i].connection; + + if (c) { +diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c +--- a/src/event/ngx_event.c ++++ b/src/event/ngx_event.c +@@ -775,6 +775,18 @@ ngx_event_process_init(ngx_cycle_t *cycle) + + #if (NGX_HAVE_REUSEPORT) + if (ls[i].reuseport && ls[i].worker != ngx_worker) { ++ ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, ++ "closing unused fd:%d listening on %V", ++ ls[i].fd, &ls[i].addr_text); ++ ++ if (ngx_close_socket(ls[i].fd) == -1) { ++ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ++ ngx_close_socket_n " %V failed", ++ &ls[i].addr_text); ++ } ++ ++ ls[i].fd = (ngx_socket_t) -1; ++ + continue; + } + #endif diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-single_process_graceful_exit.patch b/images/nginx/rootfs/patches/nginx-1.21.4-single_process_graceful_exit.patch new file mode 100644 index 000000000..2754fc2fe --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-single_process_graceful_exit.patch @@ -0,0 +1,75 @@ +diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c +index 15680237..12a8c687 100644 +--- a/src/os/unix/ngx_process.c ++++ b/src/os/unix/ngx_process.c +@@ -362,8 +362,15 @@ ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext) + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): +- ngx_reconfigure = 1; +- action = ", reconfiguring"; ++ if (ngx_process == NGX_PROCESS_SINGLE) { ++ ngx_terminate = 1; ++ action = ", exiting"; ++ ++ } else { ++ ngx_reconfigure = 1; ++ action = ", reconfiguring"; ++ } ++ + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): +diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c +index 5817a2c2..f3d58e97 100644 +--- a/src/os/unix/ngx_process_cycle.c ++++ b/src/os/unix/ngx_process_cycle.c +@@ -305,11 +305,26 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) + } + + for ( ;; ) { ++ if (ngx_exiting) { ++ if (ngx_event_no_timers_left() == NGX_OK) { ++ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); ++ ++ for (i = 0; cycle->modules[i]; i++) { ++ if (cycle->modules[i]->exit_process) { ++ cycle->modules[i]->exit_process(cycle); ++ } ++ } ++ ++ ngx_master_process_exit(cycle); ++ } ++ } ++ + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + + ngx_process_events_and_timers(cycle); + +- if (ngx_terminate || ngx_quit) { ++ if (ngx_terminate) { ++ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { +@@ -320,6 +335,20 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) + ngx_master_process_exit(cycle); + } + ++ if (ngx_quit) { ++ ngx_quit = 0; ++ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, ++ "gracefully shutting down"); ++ ngx_setproctitle("process is shutting down"); ++ ++ if (!ngx_exiting) { ++ ngx_exiting = 1; ++ ngx_set_shutdown_timer(cycle); ++ ngx_close_listening_sockets(cycle); ++ ngx_close_idle_connections(cycle); ++ } ++ } ++ + if (ngx_reconfigure) { + ngx_reconfigure = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-socket_cloexec.patch b/images/nginx/rootfs/patches/nginx-1.21.4-socket_cloexec.patch new file mode 100644 index 000000000..8ffe4c167 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-socket_cloexec.patch @@ -0,0 +1,185 @@ +diff --git a/auto/unix b/auto/unix +index 10835f6c..b5b33bb3 100644 +--- a/auto/unix ++++ b/auto/unix +@@ -990,3 +990,27 @@ ngx_feature_test='struct addrinfo *res; + if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1; + freeaddrinfo(res)' + . auto/feature ++ ++ngx_feature="SOCK_CLOEXEC support" ++ngx_feature_name="NGX_HAVE_SOCKET_CLOEXEC" ++ngx_feature_run=no ++ngx_feature_incs="#include ++ #include " ++ngx_feature_path= ++ngx_feature_libs= ++ngx_feature_test="int fd; ++ fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);" ++. auto/feature ++ ++ngx_feature="FD_CLOEXEC support" ++ngx_feature_name="NGX_HAVE_FD_CLOEXEC" ++ngx_feature_run=no ++ngx_feature_incs="#include ++ #include ++ #include " ++ngx_feature_path= ++ngx_feature_libs= ++ngx_feature_test="int fd; ++ fd = socket(AF_INET, SOCK_STREAM, 0); ++ fcntl(fd, F_SETFD, FD_CLOEXEC);" ++. auto/feature +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index cd55520c..438e0806 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -4466,8 +4466,14 @@ ngx_tcp_connect(ngx_resolver_connection_t *rec) + ngx_event_t *rev, *wev; + ngx_connection_t *c; + ++#if (NGX_HAVE_SOCKET_CLOEXEC) ++ s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0); ++ ++#else + s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0); + ++#endif ++ + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s); + + if (s == (ngx_socket_t) -1) { +@@ -4494,6 +4500,15 @@ ngx_tcp_connect(ngx_resolver_connection_t *rec) + goto failed; + } + ++#if (NGX_HAVE_FD_CLOEXEC) ++ if (ngx_cloexec(s) == -1) { ++ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, ++ ngx_cloexec_n " failed"); ++ ++ goto failed; ++ } ++#endif ++ + rev = c->read; + wev = c->write; + +diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h +index 19fec68..8c2f01a 100644 +--- a/src/event/ngx_event.h ++++ b/src/event/ngx_event.h +@@ -73,6 +73,9 @@ struct ngx_event_s { + /* to test on worker exit */ + unsigned channel:1; + unsigned resolver:1; ++#if (HAVE_SOCKET_CLOEXEC_PATCH) ++ unsigned skip_socket_leak_check:1; ++#endif + + unsigned cancelable:1; + +diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c +index 77563709..5827b9d0 100644 +--- a/src/event/ngx_event_accept.c ++++ b/src/event/ngx_event_accept.c +@@ -62,7 +62,9 @@ ngx_event_accept(ngx_event_t *ev) + + #if (NGX_HAVE_ACCEPT4) + if (use_accept4) { +- s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK); ++ s = accept4(lc->fd, &sa.sockaddr, &socklen, ++ SOCK_NONBLOCK | SOCK_CLOEXEC); ++ + } else { + s = accept(lc->fd, &sa.sockaddr, &socklen); + } +@@ -202,6 +204,16 @@ ngx_event_accept(ngx_event_t *ev) + ngx_close_accepted_connection(c); + return; + } ++ ++#if (NGX_HAVE_FD_CLOEXEC) ++ if (ngx_cloexec(s) == -1) { ++ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ++ ngx_cloexec_n " failed"); ++ ngx_close_accepted_connection(c); ++ return; ++ } ++#endif ++ + } + } + +diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c +index c5bb8068..cf33b1d2 100644 +--- a/src/event/ngx_event_connect.c ++++ b/src/event/ngx_event_connect.c +@@ -38,8 +38,15 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) + + type = (pc->type ? pc->type : SOCK_STREAM); + ++#if (NGX_HAVE_SOCKET_CLOEXEC) ++ s = ngx_socket(pc->sockaddr->sa_family, type | SOCK_CLOEXEC, 0); ++ ++#else + s = ngx_socket(pc->sockaddr->sa_family, type, 0); + ++#endif ++ ++ + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d", + (type == SOCK_STREAM) ? "stream" : "dgram", s); + +@@ -80,6 +87,15 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) + goto failed; + } + ++#if (NGX_HAVE_FD_CLOEXEC) ++ if (ngx_cloexec(s) == -1) { ++ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ++ ngx_cloexec_n " failed"); ++ ++ goto failed; ++ } ++#endif ++ + if (pc->local) { + + #if (NGX_HAVE_TRANSPARENT_PROXY) +diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c +index c4376a5..48e8fa8 100644 +--- a/src/os/unix/ngx_process_cycle.c ++++ b/src/os/unix/ngx_process_cycle.c +@@ -960,6 +1029,9 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) + for (i = 0; i < cycle->connection_n; i++) { + if (c[i].fd != -1 + && c[i].read ++#if (HAVE_SOCKET_CLOEXEC_PATCH) ++ && !c[i].read->skip_socket_leak_check ++#endif + && !c[i].read->accept + && !c[i].read->channel + && !c[i].read->resolver) +diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h +index fcc51533..d1eebf47 100644 +--- a/src/os/unix/ngx_socket.h ++++ b/src/os/unix/ngx_socket.h +@@ -38,6 +38,17 @@ int ngx_blocking(ngx_socket_t s); + + #endif + ++#if (NGX_HAVE_FD_CLOEXEC) ++ ++#define ngx_cloexec(s) fcntl(s, F_SETFD, FD_CLOEXEC) ++#define ngx_cloexec_n "fcntl(FD_CLOEXEC)" ++ ++/* at least FD_CLOEXEC is required to ensure connection fd is closed ++ * after execve */ ++#define HAVE_SOCKET_CLOEXEC_PATCH 1 ++ ++#endif ++ + int ngx_tcp_nopush(ngx_socket_t s); + int ngx_tcp_push(ngx_socket_t s); + diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-ssl_cert_cb_yield.patch b/images/nginx/rootfs/patches/nginx-1.21.4-ssl_cert_cb_yield.patch new file mode 100644 index 000000000..89773c05e --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-ssl_cert_cb_yield.patch @@ -0,0 +1,64 @@ +# HG changeset patch +# User Yichun Zhang +# Date 1451762084 28800 +# Sat Jan 02 11:14:44 2016 -0800 +# Node ID 449f0461859c16e95bdb18e8be6b94401545d3dd +# Parent 78b4e10b4367b31367aad3c83c9c3acdd42397c4 +SSL: handled SSL_CTX_set_cert_cb() callback yielding. + +OpenSSL 1.0.2+ introduces SSL_CTX_set_cert_cb() to allow custom +callbacks to serve the SSL certificiates and private keys dynamically +and lazily. The callbacks may yield for nonblocking I/O or sleeping. +Here we added support for such usage in NGINX 3rd-party modules +(like ngx_lua) in NGINX's event handlers for downstream SSL +connections. + +diff -r 78b4e10b4367 -r 449f0461859c src/event/ngx_event_openssl.c +--- a/src/event/ngx_event_openssl.c Thu Dec 17 16:39:15 2015 +0300 ++++ b/src/event/ngx_event_openssl.c Sat Jan 02 11:14:44 2016 -0800 +@@ -1445,6 +1445,23 @@ ngx_ssl_handshake(ngx_connection_t *c) + return NGX_AGAIN; + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10002000L ++ if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) { ++ c->read->handler = ngx_ssl_handshake_handler; ++ c->write->handler = ngx_ssl_handshake_handler; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ return NGX_AGAIN; ++ } ++#endif ++ + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; +@@ -1558,6 +1575,21 @@ ngx_ssl_try_early_data(ngx_connection_t *c) + return NGX_AGAIN; + } + ++ if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) { ++ c->read->handler = ngx_ssl_handshake_handler; ++ c->write->handler = ngx_ssl_handshake_handler; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ return NGX_AGAIN; ++ } ++ + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-ssl_sess_cb_yield.patch b/images/nginx/rootfs/patches/nginx-1.21.4-ssl_sess_cb_yield.patch new file mode 100644 index 000000000..ac5fe65eb --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-ssl_sess_cb_yield.patch @@ -0,0 +1,41 @@ +diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c +--- a/src/event/ngx_event_openssl.c ++++ b/src/event/ngx_event_openssl.c +@@ -1446,7 +1446,12 @@ ngx_ssl_handshake(ngx_connection_t *c) + } + + #if OPENSSL_VERSION_NUMBER >= 0x10002000L +- if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) { ++ if (sslerr == SSL_ERROR_WANT_X509_LOOKUP ++# ifdef SSL_ERROR_PENDING_SESSION ++ || sslerr == SSL_ERROR_PENDING_SESSION ++# endif ++ ) ++ { + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + +@@ -1575,6 +1580,23 @@ ngx_ssl_try_early_data(ngx_connection_t *c) + return NGX_AGAIN; + } + ++#ifdef SSL_ERROR_PENDING_SESSION ++ if (sslerr == SSL_ERROR_PENDING_SESSION) { ++ c->read->handler = ngx_ssl_handshake_handler; ++ c->write->handler = ngx_ssl_handshake_handler; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ return NGX_AGAIN; ++ } ++#endif ++ + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-stream_proxy_get_next_upstream_tries.patch b/images/nginx/rootfs/patches/nginx-1.21.4-stream_proxy_get_next_upstream_tries.patch new file mode 100644 index 000000000..cb881f070 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-stream_proxy_get_next_upstream_tries.patch @@ -0,0 +1,31 @@ +diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h +index 09d2459..de92724 100644 +--- a/src/stream/ngx_stream.h ++++ b/src/stream/ngx_stream.h +@@ -303,4 +303,7 @@ typedef ngx_int_t (*ngx_stream_filter_pt)(ngx_stream_session_t *s, + extern ngx_stream_filter_pt ngx_stream_top_filter; + + ++#define HAS_NGX_STREAM_PROXY_GET_NEXT_UPSTREAM_TRIES_PATCH 1 ++ ++ + #endif /* _NGX_STREAM_H_INCLUDED_ */ +diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c +index 0afde1c..3254ce1 100644 +--- a/src/stream/ngx_stream_proxy_module.c ++++ b/src/stream/ngx_stream_proxy_module.c +@@ -2156,3 +2156,14 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + + return NGX_CONF_OK; + } ++ ++ ++ngx_uint_t ++ngx_stream_proxy_get_next_upstream_tries(ngx_stream_session_t *s) ++{ ++ ngx_stream_proxy_srv_conf_t *pscf; ++ ++ pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); ++ ++ return pscf->next_upstream_tries; ++} diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-stream_ssl_preread_no_skip.patch b/images/nginx/rootfs/patches/nginx-1.21.4-stream_ssl_preread_no_skip.patch new file mode 100644 index 000000000..e45e9f69a --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-stream_ssl_preread_no_skip.patch @@ -0,0 +1,13 @@ +diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c +index e3d11fd9..3717b5fe 100644 +--- a/src/stream/ngx_stream_ssl_preread_module.c ++++ b/src/stream/ngx_stream_ssl_preread_module.c +@@ -159,7 +159,7 @@ ngx_stream_ssl_preread_handler(ngx_stream_session_t *s) + + rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len); + if (rc != NGX_AGAIN) { +- return rc; ++ return rc == NGX_OK ? NGX_DECLINED : rc; + } + + p += len; diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-upstream_pipelining.patch b/images/nginx/rootfs/patches/nginx-1.21.4-upstream_pipelining.patch new file mode 100644 index 000000000..aed80365a --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-upstream_pipelining.patch @@ -0,0 +1,23 @@ +commit f9907b72a76a21ac5413187b83177a919475c75f +Author: Yichun Zhang (agentzh) +Date: Wed Feb 10 16:05:08 2016 -0800 + + bugfix: upstream: keep sending request data after the first write attempt. + + See + http://mailman.nginx.org/pipermail/nginx-devel/2012-March/002040.html + for more details on the issue. + +diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c +index 69019417..92b7c97f 100644 +--- a/src/http/ngx_http_upstream.c ++++ b/src/http/ngx_http_upstream.c +@@ -2239,7 +2239,7 @@ ngx_http_upstream_send_request_handler(ngx_http_request_t *r, + + #endif + +- if (u->header_sent && !u->conf->preserve_output) { ++ if (u->request_body_sent && !u->conf->preserve_output) { + u->write_event_handler = ngx_http_upstream_dummy_handler; + + (void) ngx_handle_write_event(c->write, 0); diff --git a/images/nginx/rootfs/patches/nginx-1.21.4-upstream_timeout_fields.patch b/images/nginx/rootfs/patches/nginx-1.21.4-upstream_timeout_fields.patch new file mode 100644 index 000000000..2314ddf80 --- /dev/null +++ b/images/nginx/rootfs/patches/nginx-1.21.4-upstream_timeout_fields.patch @@ -0,0 +1,112 @@ +diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c +index 69019417..2265d8f7 100644 +--- a/src/http/ngx_http_upstream.c ++++ b/src/http/ngx_http_upstream.c +@@ -509,12 +509,19 @@ void + ngx_http_upstream_init(ngx_http_request_t *r) + { + ngx_connection_t *c; ++ ngx_http_upstream_t *u; + + c = r->connection; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http init upstream, client timer: %d", c->read->timer_set); + ++ u = r->upstream; ++ ++ u->connect_timeout = u->conf->connect_timeout; ++ u->send_timeout = u->conf->send_timeout; ++ u->read_timeout = u->conf->read_timeout; ++ + #if (NGX_HTTP_V2) + if (r->stream) { + ngx_http_upstream_init_request(r); +@@ -1626,7 +1633,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) + u->request_body_blocked = 0; + + if (rc == NGX_AGAIN) { +- ngx_add_timer(c->write, u->conf->connect_timeout); ++ ngx_add_timer(c->write, u->connect_timeout); + return; + } + +@@ -1704,7 +1711,7 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, + if (rc == NGX_AGAIN) { + + if (!c->write->timer_set) { +- ngx_add_timer(c->write, u->conf->connect_timeout); ++ ngx_add_timer(c->write, u->connect_timeout); + } + + c->ssl->handler = ngx_http_upstream_ssl_handshake_handler; +@@ -2022,7 +2029,7 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, + + if (rc == NGX_AGAIN) { + if (!c->write->ready || u->request_body_blocked) { +- ngx_add_timer(c->write, u->conf->send_timeout); ++ ngx_add_timer(c->write, u->send_timeout); + + } else if (c->write->timer_set) { + ngx_del_timer(c->write); +@@ -2084,7 +2091,7 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, + return; + } + +- ngx_add_timer(c->read, u->conf->read_timeout); ++ ngx_add_timer(c->read, u->read_timeout); + + if (c->read->ready) { + ngx_http_upstream_process_header(r, u); +@@ -3213,7 +3220,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) + p->cyclic_temp_file = 0; + } + +- p->read_timeout = u->conf->read_timeout; ++ p->read_timeout = u->read_timeout; + p->send_timeout = clcf->send_timeout; + p->send_lowat = clcf->send_lowat; + +@@ -3458,7 +3465,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, + } + + if (upstream->write->active && !upstream->write->ready) { +- ngx_add_timer(upstream->write, u->conf->send_timeout); ++ ngx_add_timer(upstream->write, u->send_timeout); + + } else if (upstream->write->timer_set) { + ngx_del_timer(upstream->write); +@@ -3470,7 +3477,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, + } + + if (upstream->read->active && !upstream->read->ready) { +- ngx_add_timer(upstream->read, u->conf->read_timeout); ++ ngx_add_timer(upstream->read, u->read_timeout); + + } else if (upstream->read->timer_set) { + ngx_del_timer(upstream->read); +@@ -3664,7 +3671,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, + } + + if (upstream->read->active && !upstream->read->ready) { +- ngx_add_timer(upstream->read, u->conf->read_timeout); ++ ngx_add_timer(upstream->read, u->read_timeout); + + } else if (upstream->read->timer_set) { + ngx_del_timer(upstream->read); +diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h +index c2f4dc0b..b9eef118 100644 +--- a/src/http/ngx_http_upstream.h ++++ b/src/http/ngx_http_upstream.h +@@ -333,6 +333,11 @@ struct ngx_http_upstream_s { + ngx_array_t *caches; + #endif + ++#define HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS 1 ++ ngx_msec_t connect_timeout; ++ ngx_msec_t send_timeout; ++ ngx_msec_t read_timeout; ++ + ngx_http_upstream_headers_in_t headers_in; + + ngx_http_upstream_resolved_t *resolved; diff --git a/images/opentelemetry/Makefile b/images/opentelemetry/Makefile new file mode 100644 index 000000000..eae435bef --- /dev/null +++ b/images/opentelemetry/Makefile @@ -0,0 +1,69 @@ +# Copyright 2024 The Kubernetes Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.DEFAULT_GOAL:=build + +# set default shell +SHELL=/bin/bash -o pipefail -o errexit + +DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))) +INIT_BUILDX=$(DIR)/../../hack/init-buildx.sh + +# 0.0.0 shouldn't clobber any released builds +SHORT_SHA ?=$(shell git rev-parse --short HEAD) +TAG ?=v$(shell date +%Y%m%d)-$(SHORT_SHA) + +REGISTRY ?= gcr.io/k8s-staging-ingress-nginx + +IMAGE = $(REGISTRY)/opentelemetry + +# required to enable buildx +export DOCKER_CLI_EXPERIMENTAL=enabled + +# build with buildx +PLATFORMS?=linux/amd64,linux/arm,linux/arm64 +OUTPUT= +PROGRESS=plain + +precheck: +ifndef NGINX_VERSION + $(error NGINX_VERSION variable is required) +endif + +build: precheck ensure-buildx + docker buildx build \ + --label=org.opencontainers.image.source=https://github.com/kubernetes/ingress-nginx \ + --label=org.opencontainers.image.licenses=Apache-2.0 \ + --label=org.opencontainers.image.description="Ingress NGINX Opentelemetry image" \ + --platform=${PLATFORMS} $(OUTPUT) \ + --progress=$(PROGRESS) \ + --build-arg=NGINX_VERSION=$(NGINX_VERSION) \ + --pull \ + --tag $(IMAGE)-$(NGINX_VERSION):$(TAG) rootfs + +# push the cross built image +push: OUTPUT=--push +push: build + +# enable buildx +ensure-buildx: +# this is required for cloudbuild +ifeq ("$(wildcard $(INIT_BUILDX))","") + @curl -sSL https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/hack/init-buildx.sh | bash +else + @exec $(INIT_BUILDX) +endif + @echo "done" + +.PHONY: build precheck push ensure-buildx diff --git a/images/opentelemetry/README.md b/images/opentelemetry/README.md new file mode 100644 index 000000000..f5c3d90de --- /dev/null +++ b/images/opentelemetry/README.md @@ -0,0 +1,5 @@ +# OpenTelemetry library builder + +**How to use this image:** +This image only contains the necessary files in /usr/local and /etc/nginx/opentelemetry to +be copied to Ingress Controller deployment when OpenTelemetry is enabled diff --git a/images/opentelemetry/TAG b/images/opentelemetry/TAG new file mode 100644 index 000000000..a3dce6cd3 --- /dev/null +++ b/images/opentelemetry/TAG @@ -0,0 +1 @@ +v0.0.2 diff --git a/images/opentelemetry/cloudbuild.yaml b/images/opentelemetry/cloudbuild.yaml new file mode 100644 index 000000000..bc48a93f4 --- /dev/null +++ b/images/opentelemetry/cloudbuild.yaml @@ -0,0 +1,20 @@ +timeout: 10800s +options: + substitution_option: ALLOW_LOOSE + # job builds a multi-arch docker image for amd64,arm,arm64 and s390x. + machineType: E2_HIGHCPU_32 +steps: + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 + entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root + args: + - -c + - | + gcloud auth configure-docker \ + && cd images/opentelemetry && make NGINX_VERSION=1.25.3 push \ + && make NGINX_VERSION=1.21.6 push diff --git a/images/opentelemetry/rootfs/CMakeLists.txt b/images/opentelemetry/rootfs/CMakeLists.txt new file mode 100644 index 000000000..1c68d6fc6 --- /dev/null +++ b/images/opentelemetry/rootfs/CMakeLists.txt @@ -0,0 +1,74 @@ +#!/bin/bash + +# Copyright 2021 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.11 FATAL_ERROR) + +project( + dependencies + LANGUAGES CXX + VERSION 0.0.1) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "-O2 -fpic") +set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON" FORCE) + +set(CMAKE_BUILD_TYPE + Release + CACHE STRING "Build type" FORCE) + +include(GNUInstallDirs) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) + +set(INSTALL_LIBDIR + ${CMAKE_INSTALL_LIBDIR} + CACHE PATH "directory for libraries") +set(INSTALL_BINDIR + ${CMAKE_INSTALL_BINDIR} + CACHE PATH "directory for executables") +set(INSTALL_INCLUDEDIR + ${CMAKE_INSTALL_INCLUDEDIR} + CACHE PATH "directory for header files") + +set(DEF_INSTALL_CMAKEDIR share/cmake/${PROJECT_NAME}) +set(INSTALL_CMAKEDIR + ${DEF_INSTALL_CMAKEDIR} + CACHE PATH "directory for CMake files") + +set_property(DIRECTORY PROPERTY EP_BASE ${CMAKE_BINARY_DIR}/subs) + +set(STAGED_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/stage) +message(STATUS "${PROJECT_NAME} staged install: ${STAGED_INSTALL_PREFIX}") + +find_package(OpenSSL REQUIRED) +message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}") +message("OpenSSL libraries: ${OPENSSL_LIBRARIES}") + +find_package(Protobuf REQUIRED) +find_package(gRPC REQUIRED) +find_package(OpentelemetryCPP REQUIRED) + +install( + DIRECTORY ${STAGED_INSTALL_PREFIX}/ + DESTINATION . + USE_SOURCE_PERMISSIONS) diff --git a/images/opentelemetry/rootfs/Dockerfile b/images/opentelemetry/rootfs/Dockerfile new file mode 100644 index 000000000..eb951e5c4 --- /dev/null +++ b/images/opentelemetry/rootfs/Dockerfile @@ -0,0 +1,46 @@ +# Copyright 2021 The Kubernetes Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +FROM alpine:3.20.0 as base + +RUN mkdir -p /opt/third_party/install +COPY . /opt/third_party/ + +# install build tools +RUN apk update \ + && apk upgrade \ + && apk add -U bash \ + && bash /opt/third_party/build.sh -p + +ENV NINJA_STATUS "[%p/%f/%t] " + +# install otel_ngx_module.so +FROM base as nginx +ARG NGINX_VERSION=1.25.3 +RUN bash /opt/third_party/build.sh -n ${NGINX_VERSION} + +FROM golang:1.21.6-bullseye as build-init + +WORKDIR /go/src/app +COPY . . + +RUN go mod download +RUN CGO_ENABLED=0 go build -o /go/bin/init_module + +FROM gcr.io/distroless/static-debian11 as final +COPY --from=build-init /go/bin/init_module / +COPY --from=nginx /etc/nginx/modules /etc/nginx/modules + +CMD ["/init_module"] diff --git a/images/opentelemetry/rootfs/build.sh b/images/opentelemetry/rootfs/build.sh new file mode 100755 index 000000000..d46ab9fe5 --- /dev/null +++ b/images/opentelemetry/rootfs/build.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +# Copyright 2021 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail +set -x +# Check for recent changes: https://github.com/open-telemetry/opentelemetry-cpp/compare/v1.2.0...main +export OPENTELEMETRY_CPP_VERSION=${OPENTELEMETRY_CPP_VERSION:="v1.11.0"} +export INSTALL_DIR=/opt/third_party/install + +export NGINX_VERSION=${NGINX_VERSION:="1.25.3"} +# improve compilation times +CORES=$(($(grep -c ^processor /proc/cpuinfo) - 1)) + +rm -rf \ + /var/cache/debconf/* \ + /var/lib/apt/lists/* \ + /var/log/* \ + /tmp/* \ + /var/tmp/* + +export BUILD_PATH=/tmp/build +mkdir --verbose -p "$BUILD_PATH" + +Help() +{ + # Display Help + echo "Add description of the script functions here." + echo + echo "Syntax: scriptTemplate [-h|o|n|p|]" + echo "options:" + echo "h Print Help." + echo "o OpenTelemetry git tag" + echo "n install nginx" + echo "p prepare" + echo +} + +prepare() +{ + echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories + apk add \ + linux-headers \ + cmake \ + ninja \ + openssl \ + curl-dev \ + openssl-dev \ + gtest-dev \ + c-ares-dev \ + pcre-dev \ + curl \ + git \ + build-base \ + coreutils \ + build-base \ + openssl-dev \ + pkgconfig \ + c-ares-dev \ + re2-dev \ + grpc-dev \ + protobuf-dev \ + opentelemetry-cpp-dev + + git config --global http.version HTTP/1.1 + git config --global http.postBuffer 157286400 +} + +install_otel() +{ + cd ${BUILD_PATH} + export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+LD_LIBRARY_PATH:}${INSTALL_DIR}/lib:/usr/local" + export PATH="${PATH}:${INSTALL_DIR}/bin" + git clone --recurse-submodules -j ${CORES} --depth=1 -b \ + ${OPENTELEMETRY_CPP_VERSION} https://github.com/open-telemetry/opentelemetry-cpp.git opentelemetry-cpp-${OPENTELEMETRY_CPP_VERSION} + cd "opentelemetry-cpp-${OPENTELEMETRY_CPP_VERSION}" + mkdir -p .build + cd .build + + cmake -DCMAKE_BUILD_TYPE=Release \ + -G Ninja \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + -DWITH_ZIPKIN=OFF \ + -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} \ + -DBUILD_TESTING=OFF \ + -DWITH_BENCHMARK=OFF \ + -DWITH_FUNC_TESTS=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DWITH_OTLP_GRPC=ON \ + -DWITH_OTLP_HTTP=OFF \ + -DWITH_ABSEIL=ON \ + -DWITH_EXAMPLES=OFF \ + -DWITH_NO_DEPRECATED_CODE=ON \ + .. + cmake --build . -j ${CORES} --target install +} + +install_nginx() +{ + + # Check for recent changes: https://github.com/open-telemetry/opentelemetry-cpp-contrib/compare/2656a4...main + export OPENTELEMETRY_CONTRIB_COMMIT=aaa51e2297bcb34297f3c7aa44fa790497d2f7f3 + + mkdir -p /etc/nginx + cd "$BUILD_PATH" + + # TODO fix curl + # get_src 0528e793a97f942868616449d49326160f9cb67b2253fb2c4864603ac6ab09a9 \ + # "https://github.com/open-telemetry/opentelemetry-cpp-contrib/archive/$OPENTELEMETRY_CONTRIB_COMMIT.tar.gz" + + git clone https://github.com/open-telemetry/opentelemetry-cpp-contrib.git \ + opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT} + cd ${BUILD_PATH}/opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT} + git reset --hard ${OPENTELEMETRY_CONTRIB_COMMIT} + cd ${BUILD_PATH}/opentelemetry-cpp-contrib-${OPENTELEMETRY_CONTRIB_COMMIT}/instrumentation/nginx + mkdir -p build + cd build + cmake -DCMAKE_BUILD_TYPE=Release \ + -G Ninja \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} \ + -DBUILD_SHARED_LIBS=ON \ + -DNGINX_VERSION=${NGINX_VERSION} \ + .. + cmake --build . -j ${CORES} --target install + + mkdir -p /etc/nginx/modules + cp ${INSTALL_DIR}/otel_ngx_module.so /etc/nginx/modules/otel_ngx_module.so +} + +while getopts ":phn:" option; do + case $option in + h) # display Help + Help + exit;; + p) # prepare + prepare + exit;; + n) # install nginx + NGINX_VERSION=${OPTARG} + install_nginx + exit;; + \?) + Help + exit;; + esac +done diff --git a/images/opentelemetry/rootfs/go.mod b/images/opentelemetry/rootfs/go.mod new file mode 100644 index 000000000..9c183ef06 --- /dev/null +++ b/images/opentelemetry/rootfs/go.mod @@ -0,0 +1,3 @@ +module init-otel + +go 1.21 diff --git a/images/opentelemetry/rootfs/init_module.go b/images/opentelemetry/rootfs/init_module.go new file mode 100644 index 000000000..5d285052d --- /dev/null +++ b/images/opentelemetry/rootfs/init_module.go @@ -0,0 +1,103 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "io" + "os" + "path/filepath" +) + +func main() { + // Enable error handling for all operations + err := run() + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} + +func run() error { + // Create the target directory if it doesn't exist + targetDir := "/modules_mount/etc/nginx/modules/otel" + err := os.MkdirAll(targetDir, os.ModePerm) + if err != nil { + return fmt.Errorf("failed to create target directory: %w", err) + } + + // Copy files from source directory to target directory + sourceDir := "/etc/nginx/modules/" + err = filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Skip directories + if info.IsDir() { + return nil + } + + // Calculate the destination path + relPath, err := filepath.Rel(sourceDir, path) + if err != nil { + return err + } + destPath := filepath.Join(targetDir, relPath) + + // Create the destination directory if it doesn't exist + destDir := filepath.Dir(destPath) + err = os.MkdirAll(destDir, os.ModePerm) + if err != nil { + return err + } + + // Copy the file + err = copyFile(path, destPath) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return fmt.Errorf("failed to copy files: %w", err) + } + + return nil +} + +func copyFile(sourcePath, destPath string) error { + sourceFile, err := os.Open(sourcePath) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.Create(destPath) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + if err != nil { + return err + } + + return nil +} diff --git a/images/test-runner/Makefile b/images/test-runner/Makefile index 8adbf0b41..7e30d432f 100644 --- a/images/test-runner/Makefile +++ b/images/test-runner/Makefile @@ -50,7 +50,7 @@ image: --build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \ --build-arg GOLANG_VERSION=${GO_VERSION} \ --build-arg ETCD_VERSION=3.5.13-0 \ - --build-arg K8S_RELEASE=v1.32.2 \ + --build-arg K8S_RELEASE=v1.29.2 \ --build-arg RESTY_CLI_VERSION=0.27 \ --build-arg RESTY_CLI_SHA=e5f4f3128af49ba5c4d039d0554e5ae91bbe05866f60eccfa96d3653274bff90 \ --build-arg LUAROCKS_VERSION=3.8.0 \ @@ -59,7 +59,7 @@ image: --build-arg YAML_LINT_VERSION=1.33.0 \ --build-arg YAMALE_VERSION=4.0.4 \ --build-arg HELM_VERSION=3.14.4 \ - --build-arg GINKGO_VERSION=2.22.2 \ + --build-arg GINKGO_VERSION=2.19.0 \ --build-arg GOLINT_VERSION=latest \ -t ${IMAGE}:${TAG} rootfs @@ -71,7 +71,7 @@ build: ensure-buildx --build-arg BASE_IMAGE=${NGINX_BASE_IMAGE} \ --build-arg GOLANG_VERSION=${GO_VERSION} \ --build-arg ETCD_VERSION=3.5.13-0 \ - --build-arg K8S_RELEASE=v1.32.2 \ + --build-arg K8S_RELEASE=v1.29.2 \ --build-arg RESTY_CLI_VERSION=0.27 \ --build-arg RESTY_CLI_SHA=e5f4f3128af49ba5c4d039d0554e5ae91bbe05866f60eccfa96d3653274bff90 \ --build-arg LUAROCKS_VERSION=3.8.0 \ @@ -80,7 +80,7 @@ build: ensure-buildx --build-arg YAML_LINT_VERSION=1.33.0 \ --build-arg YAMALE_VERSION=4.0.4 \ --build-arg HELM_VERSION=3.14.4 \ - --build-arg GINKGO_VERSION=2.22.2 \ + --build-arg GINKGO_VERSION=2.19.0 \ --build-arg GOLINT_VERSION=latest \ -t ${IMAGE}:${TAG} rootfs diff --git a/images/test-runner/TAG b/images/test-runner/TAG index 46b105a30..3ce186fb7 100644 --- a/images/test-runner/TAG +++ b/images/test-runner/TAG @@ -1 +1 @@ -v2.0.0 +v0.0.8 diff --git a/images/test-runner/cloudbuild.yaml b/images/test-runner/cloudbuild.yaml index 93dce3ec9..b17de9b31 100644 --- a/images/test-runner/cloudbuild.yaml +++ b/images/test-runner/cloudbuild.yaml @@ -1,11 +1,17 @@ +timeout: 3600s options: - # Ignore Prow provided substitutions. substitution_option: ALLOW_LOOSE steps: - - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20250116-2a05ea7e3d - env: - - REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/ingress-nginx + - name: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90 entrypoint: bash + env: + - DOCKER_CLI_EXPERIMENTAL=enabled + - REGISTRY=gcr.io/k8s-staging-ingress-nginx + # default cloudbuild has HOME=/builder/home and docker buildx is in /root/.docker/cli-plugins/docker-buildx + # set the home to /root explicitly to if using docker buildx + - HOME=/root args: - - -c - - gcloud auth configure-docker && cd images/test-runner && make push + - -c + - | + gcloud auth configure-docker \ + && cd images/test-runner && make push diff --git a/images/test-runner/rootfs/Dockerfile b/images/test-runner/rootfs/Dockerfile index d871461bf..ff031182d 100644 --- a/images/test-runner/rootfs/Dockerfile +++ b/images/test-runner/rootfs/Dockerfile @@ -15,7 +15,7 @@ ARG BASE_IMAGE ARG GOLANG_VERSION ARG ETCD_VERSION -FROM golang:${GOLANG_VERSION}-alpine3.21 as GO +FROM golang:${GOLANG_VERSION}-alpine3.20 as GO FROM registry.k8s.io/etcd:${ETCD_VERSION} as etcd FROM ${BASE_IMAGE} @@ -48,7 +48,7 @@ RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH" COPY --from=etcd /usr/local/bin/etcd /usr/local/bin/etcd -RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories +RUN echo "@testing https://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories RUN apk update && apk upgrade && apk add --no-cache \ bash \ @@ -66,8 +66,8 @@ RUN apk update && apk upgrade && apk add --no-cache \ openssl \ cfssl@testing \ tzdata \ - libc6-compat \ - sqlite-dev + libc6-compat \ + sqlite-dev RUN go install -v github.com/onsi/ginkgo/v2/ginkgo@v${GINKGO_VERSION} \ && go install golang.org/x/lint/golint@${GOLINT_VERSION} diff --git a/internal/admission/controller/server.go b/internal/admission/controller/server.go index 74f55fd01..7fc61bcbb 100644 --- a/internal/admission/controller/server.go +++ b/internal/admission/controller/server.go @@ -47,7 +47,7 @@ type AdmissionControllerServer struct { AdmissionController AdmissionController } -// NewAdmissionControllerServer instantiates an admission controller server with +// NewAdmissionControllerServer instanciates an admission controller server with // a default codec func NewAdmissionControllerServer(ac AdmissionController) *AdmissionControllerServer { return &AdmissionControllerServer{ diff --git a/internal/ingress/annotations/annotations.go b/internal/ingress/annotations/annotations.go index e10cc9be1..302f0b4b1 100644 --- a/internal/ingress/annotations/annotations.go +++ b/internal/ingress/annotations/annotations.go @@ -19,10 +19,18 @@ package annotations import ( "dario.cat/mergo" + "k8s.io/ingress-nginx/internal/ingress/annotations/canary" + "k8s.io/ingress-nginx/internal/ingress/annotations/disableproxyintercepterrors" + "k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity" + "k8s.io/ingress-nginx/internal/ingress/annotations/opentelemetry" + "k8s.io/ingress-nginx/internal/ingress/annotations/proxyssl" + "k8s.io/ingress-nginx/internal/ingress/annotations/sslcipher" + "k8s.io/ingress-nginx/internal/ingress/annotations/streamsnippet" + "k8s.io/klog/v2" + apiv1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog/v2" "k8s.io/ingress-nginx/internal/ingress/annotations/alias" "k8s.io/ingress-nginx/internal/ingress/annotations/auth" @@ -30,27 +38,22 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/authreqglobal" "k8s.io/ingress-nginx/internal/ingress/annotations/authtls" "k8s.io/ingress-nginx/internal/ingress/annotations/backendprotocol" - "k8s.io/ingress-nginx/internal/ingress/annotations/canary" "k8s.io/ingress-nginx/internal/ingress/annotations/clientbodybuffersize" "k8s.io/ingress-nginx/internal/ingress/annotations/connection" "k8s.io/ingress-nginx/internal/ingress/annotations/cors" - "k8s.io/ingress-nginx/internal/ingress/annotations/customheaders" "k8s.io/ingress-nginx/internal/ingress/annotations/customhttperrors" "k8s.io/ingress-nginx/internal/ingress/annotations/defaultbackend" - "k8s.io/ingress-nginx/internal/ingress/annotations/disableproxyintercepterrors" "k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi" + "k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit" "k8s.io/ingress-nginx/internal/ingress/annotations/http2pushpreload" "k8s.io/ingress-nginx/internal/ingress/annotations/ipallowlist" "k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist" "k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing" "k8s.io/ingress-nginx/internal/ingress/annotations/log" "k8s.io/ingress-nginx/internal/ingress/annotations/mirror" - "k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity" - "k8s.io/ingress-nginx/internal/ingress/annotations/opentelemetry" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/portinredirect" "k8s.io/ingress-nginx/internal/ingress/annotations/proxy" - "k8s.io/ingress-nginx/internal/ingress/annotations/proxyssl" "k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit" "k8s.io/ingress-nginx/internal/ingress/annotations/redirect" "k8s.io/ingress-nginx/internal/ingress/annotations/rewrite" @@ -59,9 +62,7 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/serviceupstream" "k8s.io/ingress-nginx/internal/ingress/annotations/sessionaffinity" "k8s.io/ingress-nginx/internal/ingress/annotations/snippet" - "k8s.io/ingress-nginx/internal/ingress/annotations/sslcipher" "k8s.io/ingress-nginx/internal/ingress/annotations/sslpassthrough" - "k8s.io/ingress-nginx/internal/ingress/annotations/streamsnippet" "k8s.io/ingress-nginx/internal/ingress/annotations/upstreamhashby" "k8s.io/ingress-nginx/internal/ingress/annotations/upstreamvhost" "k8s.io/ingress-nginx/internal/ingress/annotations/xforwardedprefix" @@ -81,7 +82,6 @@ type Ingress struct { Canary canary.Config CertificateAuth authtls.Config ClientBodyBufferSize string - CustomHeaders customheaders.Config ConfigurationSnippet string Connection connection.Config CorsConfig cors.Config @@ -97,6 +97,7 @@ type Ingress struct { Proxy proxy.Config ProxySSL proxyssl.Config RateLimit ratelimit.Config + GlobalRateLimit globalratelimit.Config Redirect redirect.Config Rewrite rewrite.Config Satisfy string @@ -123,55 +124,51 @@ type Extractor struct { annotations map[string]parser.IngressAnnotation } -func NewAnnotationFactory(cfg resolver.Resolver) map[string]parser.IngressAnnotation { - return map[string]parser.IngressAnnotation{ - "Aliases": alias.NewParser(cfg), - "BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg), - "Canary": canary.NewParser(cfg), - "CertificateAuth": authtls.NewParser(cfg), - "ClientBodyBufferSize": clientbodybuffersize.NewParser(cfg), - "CustomHeaders": customheaders.NewParser(cfg), - "ConfigurationSnippet": snippet.NewParser(cfg), - "Connection": connection.NewParser(cfg), - "CorsConfig": cors.NewParser(cfg), - "CustomHTTPErrors": customhttperrors.NewParser(cfg), - "DisableProxyInterceptErrors": disableproxyintercepterrors.NewParser(cfg), - "DefaultBackend": defaultbackend.NewParser(cfg), - "FastCGI": fastcgi.NewParser(cfg), - "ExternalAuth": authreq.NewParser(cfg), - "EnableGlobalAuth": authreqglobal.NewParser(cfg), - "HTTP2PushPreload": http2pushpreload.NewParser(cfg), - "Opentelemetry": opentelemetry.NewParser(cfg), - "Proxy": proxy.NewParser(cfg), - "ProxySSL": proxyssl.NewParser(cfg), - "RateLimit": ratelimit.NewParser(cfg), - "Redirect": redirect.NewParser(cfg), - "Rewrite": rewrite.NewParser(cfg), - "Satisfy": satisfy.NewParser(cfg), - "ServerSnippet": serversnippet.NewParser(cfg), - "ServiceUpstream": serviceupstream.NewParser(cfg), - "SessionAffinity": sessionaffinity.NewParser(cfg), - "SSLPassthrough": sslpassthrough.NewParser(cfg), - "UsePortInRedirects": portinredirect.NewParser(cfg), - "UpstreamHashBy": upstreamhashby.NewParser(cfg), - "LoadBalancing": loadbalancing.NewParser(cfg), - "UpstreamVhost": upstreamvhost.NewParser(cfg), - "Allowlist": ipallowlist.NewParser(cfg), - "Denylist": ipdenylist.NewParser(cfg), - "XForwardedPrefix": xforwardedprefix.NewParser(cfg), - "SSLCipher": sslcipher.NewParser(cfg), - "Logs": log.NewParser(cfg), - "BackendProtocol": backendprotocol.NewParser(cfg), - "ModSecurity": modsecurity.NewParser(cfg), - "Mirror": mirror.NewParser(cfg), - "StreamSnippet": streamsnippet.NewParser(cfg), - } -} - // NewAnnotationExtractor creates a new annotations extractor func NewAnnotationExtractor(cfg resolver.Resolver) Extractor { return Extractor{ - NewAnnotationFactory(cfg), + map[string]parser.IngressAnnotation{ + "Aliases": alias.NewParser(cfg), + "BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg), + "Canary": canary.NewParser(cfg), + "CertificateAuth": authtls.NewParser(cfg), + "ClientBodyBufferSize": clientbodybuffersize.NewParser(cfg), + "ConfigurationSnippet": snippet.NewParser(cfg), + "Connection": connection.NewParser(cfg), + "CorsConfig": cors.NewParser(cfg), + "CustomHTTPErrors": customhttperrors.NewParser(cfg), + "DisableProxyInterceptErrors": disableproxyintercepterrors.NewParser(cfg), + "DefaultBackend": defaultbackend.NewParser(cfg), + "FastCGI": fastcgi.NewParser(cfg), + "ExternalAuth": authreq.NewParser(cfg), + "EnableGlobalAuth": authreqglobal.NewParser(cfg), + "HTTP2PushPreload": http2pushpreload.NewParser(cfg), + "Opentelemetry": opentelemetry.NewParser(cfg), + "Proxy": proxy.NewParser(cfg), + "ProxySSL": proxyssl.NewParser(cfg), + "RateLimit": ratelimit.NewParser(cfg), + "GlobalRateLimit": globalratelimit.NewParser(cfg), + "Redirect": redirect.NewParser(cfg), + "Rewrite": rewrite.NewParser(cfg), + "Satisfy": satisfy.NewParser(cfg), + "ServerSnippet": serversnippet.NewParser(cfg), + "ServiceUpstream": serviceupstream.NewParser(cfg), + "SessionAffinity": sessionaffinity.NewParser(cfg), + "SSLPassthrough": sslpassthrough.NewParser(cfg), + "UsePortInRedirects": portinredirect.NewParser(cfg), + "UpstreamHashBy": upstreamhashby.NewParser(cfg), + "LoadBalancing": loadbalancing.NewParser(cfg), + "UpstreamVhost": upstreamvhost.NewParser(cfg), + "Allowlist": ipallowlist.NewParser(cfg), + "Denylist": ipdenylist.NewParser(cfg), + "XForwardedPrefix": xforwardedprefix.NewParser(cfg), + "SSLCipher": sslcipher.NewParser(cfg), + "Logs": log.NewParser(cfg), + "BackendProtocol": backendprotocol.NewParser(cfg), + "ModSecurity": modsecurity.NewParser(cfg), + "Mirror": mirror.NewParser(cfg), + "StreamSnippet": streamsnippet.NewParser(cfg), + }, } } diff --git a/internal/ingress/annotations/annotations_test.go b/internal/ingress/annotations/annotations_test.go index 5df3cdc0e..0f4f8f7d7 100644 --- a/internal/ingress/annotations/annotations_test.go +++ b/internal/ingress/annotations/annotations_test.go @@ -43,20 +43,16 @@ var ( annotationAffinityCookieName = parser.GetAnnotationWithPrefix("session-cookie-name") annotationUpstreamHashBy = parser.GetAnnotationWithPrefix("upstream-hash-by") annotationCustomHTTPErrors = parser.GetAnnotationWithPrefix("custom-http-errors") - annotationCustomHeaders = parser.GetAnnotationWithPrefix("custom-headers") ) type mockCfg struct { resolver.Mock - MockSecrets map[string]*apiv1.Secret - MockServices map[string]*apiv1.Service - MockConfigMaps map[string]*apiv1.ConfigMap + MockSecrets map[string]*apiv1.Secret + MockServices map[string]*apiv1.Service } func (m mockCfg) GetDefaultBackend() defaults.Backend { - return defaults.Backend{ - AllowedResponseHeaders: []string{"Content-Type"}, - } + return defaults.Backend{} } func (m mockCfg) GetSecret(name string) (*apiv1.Secret, error) { @@ -67,10 +63,6 @@ func (m mockCfg) GetService(name string) (*apiv1.Service, error) { return m.MockServices[name], nil } -func (m mockCfg) GetConfigMap(name string) (*apiv1.ConfigMap, error) { - return m.MockConfigMaps[name], nil -} - func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) { secret, err := m.GetSecret(name) if err != nil { @@ -325,44 +317,3 @@ func TestCustomHTTPErrors(t *testing.T) { } } } - -func TestCustomResponseHeaders(t *testing.T) { - mockObj := mockCfg{} - mockObj.MockConfigMaps = map[string]*apiv1.ConfigMap{} - mockObj.MockConfigMaps["custom-headers"] = &apiv1.ConfigMap{Data: map[string]string{"Content-Type": "application/json"}} - mockObj.MockConfigMaps["empty-custom-headers"] = &apiv1.ConfigMap{Data: map[string]string{}} - - ec := NewAnnotationExtractor(mockObj) - ing := buildIngress() - fooAnns := []struct { - annotations map[string]string - headers map[string]string - }{ - {map[string]string{annotationCustomHeaders: "custom-headers"}, map[string]string{"Content-Type": "application/json"}}, - {map[string]string{annotationCustomHeaders: "empty-custom-headers"}, map[string]string{}}, - {nil, map[string]string{}}, - } - - for _, foo := range fooAnns { - ing.SetAnnotations(foo.annotations) - rann, err := ec.Extract(ing) - if err != nil { - t.Errorf("error should be null: %v", err) - } - r := rann.CustomHeaders.Headers - - // Check that expected headers were created - for i := range foo.headers { - if r[i] != foo.headers[i] { - t.Errorf("Returned %v but expected %v", r, foo.headers) - } - } - - // Check that no unexpected headers were created - for i := range r { - if r[i] != foo.headers[i] { - t.Errorf("Returned %v but expected %v", r, foo.headers) - } - } - } -} diff --git a/internal/ingress/annotations/authtls/main.go b/internal/ingress/annotations/authtls/main.go index de4d1cc1d..b331a215e 100644 --- a/internal/ingress/annotations/authtls/main.go +++ b/internal/ingress/annotations/authtls/main.go @@ -41,8 +41,8 @@ const ( ) var ( - authVerifyClientRegex = regexp.MustCompile(`^(on|off|optional|optional_no_ca)$`) - redirectRegex = regexp.MustCompile(`^((https?://)?[A-Za-z0-9\-.]+(:\d+)?)?(/[A-Za-z0-9\-_.]+)*/?$`) + authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`) + redirectRegex = regexp.MustCompile(`^((https?://)?[A-Za-z0-9\-.]*(:\d+)?/[A-Za-z0-9\-.]*)?$`) ) var authTLSAnnotations = parser.Annotation{ diff --git a/internal/ingress/annotations/cors/main.go b/internal/ingress/annotations/cors/main.go index cef4fb1b2..d6e92b34d 100644 --- a/internal/ingress/annotations/cors/main.go +++ b/internal/ingress/annotations/cors/main.go @@ -40,12 +40,12 @@ var ( // that could cause the Response to contain some internal value/variable (like returning $pid, $upstream_addr, etc) // Origin must contain a http/s Origin (including or not the port) or the value '*' // This Regex is composed of the following: - // * Sets a group that can be (https?://)?*?.something.com:port? OR null + // * Sets a group that can be (https?://)?*?.something.com:port? // * Allows this to be repeated as much as possible, and separated by comma // Otherwise it should be '*' - corsOriginRegexValidator = regexp.MustCompile(`^((((([a-z]+://)?(\*\.)?[A-Za-z0-9\-.]*(:\d+)?,?)|null)+)|\*)?$`) + corsOriginRegexValidator = regexp.MustCompile(`^((((https?://)?(\*\.)?[A-Za-z0-9\-.]*(:\d+)?,?)+)|\*)?$`) // corsOriginRegex defines the regex for validation inside Parse - corsOriginRegex = regexp.MustCompile(`^([a-z]+://(\*\.)?[A-Za-z0-9\-.]*(:\d+)?|\*|null)?$`) + corsOriginRegex = regexp.MustCompile(`^(https?://(\*\.)?[A-Za-z0-9\-.]*(:\d+)?|\*)?$`) // Method must contain valid methods list (PUT, GET, POST, BLA) // May contain or not spaces between each verb corsMethodsRegex = regexp.MustCompile(`^([A-Za-z]+,?\s?)+$`) @@ -78,9 +78,8 @@ var corsAnnotation = parser.Annotation{ Scope: parser.AnnotationScopeIngress, Risk: parser.AnnotationRiskMedium, Documentation: `This annotation controls what's the accepted Origin for CORS. - This is a multi-valued field, separated by ','. It must follow this format: protocol://origin-site.com, protocol://origin-site.com:port, null, or *. - It also supports single level wildcard subdomains and follows this format: https://*.foo.bar, http://*.bar.foo:8080 or myprotocol://*.abc.bar.foo:9000 - Protocol can be any lowercase string, like http, https, or mycustomprotocol.`, + This is a multi-valued field, separated by ','. It must follow this format: http(s)://origin-site.com or http(s)://origin-site.com:port + It also supports single level wildcard subdomains and follows this format: http(s)://*.foo.bar, http(s)://*.bar.foo:8080 or http(s)://*.abc.bar.foo:9000`, }, corsAllowHeadersAnnotation: { Validator: parser.ValidateRegex(parser.HeadersVariable, true), diff --git a/internal/ingress/annotations/cors/main_test.go b/internal/ingress/annotations/cors/main_test.go index 0b6b3671b..a69390a17 100644 --- a/internal/ingress/annotations/cors/main_test.go +++ b/internal/ingress/annotations/cors/main_test.go @@ -27,8 +27,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const enableAnnotation = "true" - func buildIngress() *networking.Ingress { defaultBackend := networking.IngressBackend{ Service: &networking.IngressServiceBackend{ @@ -78,11 +76,11 @@ func TestIngressCorsConfigValid(t *testing.T) { data := map[string]string{} // Valid - data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = enableAnnotation + data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = "true" data[parser.GetAnnotationWithPrefix(corsAllowHeadersAnnotation)] = "DNT,X-CustomHeader, Keep-Alive,User-Agent" data[parser.GetAnnotationWithPrefix(corsAllowCredentialsAnnotation)] = "false" data[parser.GetAnnotationWithPrefix(corsAllowMethodsAnnotation)] = "GET, PATCH" - data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "null, https://origin123.test.com:4443" + data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "https://origin123.test.com:4443" data[parser.GetAnnotationWithPrefix(corsExposeHeadersAnnotation)] = "*, X-CustomResponseHeader" data[parser.GetAnnotationWithPrefix(corsMaxAgeAnnotation)] = "600" ing.SetAnnotations(data) @@ -113,7 +111,7 @@ func TestIngressCorsConfigValid(t *testing.T) { t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsAllowMethodsAnnotation)], nginxCors.CorsAllowMethods) } - if !reflect.DeepEqual(nginxCors.CorsAllowOrigin, []string{"null", "https://origin123.test.com:4443"}) { + if nginxCors.CorsAllowOrigin[0] != "https://origin123.test.com:4443" { t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)], nginxCors.CorsAllowOrigin) } @@ -176,11 +174,11 @@ func TestIngressCorsConfigInvalid(t *testing.T) { } } -func TestIngressCorsConfigAllowOriginWithTrailingComma(t *testing.T) { +func TestIngresCorsConfigAllowOriginWithTrailingComma(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = enableAnnotation + data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = "true" // Include a trailing comma and an empty value between the commas. data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "https://origin123.test.com:4443, ,https://origin321.test.com:4443," @@ -205,63 +203,3 @@ func TestIngressCorsConfigAllowOriginWithTrailingComma(t *testing.T) { t.Errorf("expected %v but returned %v", expectedCorsAllowOrigins, nginxCors.CorsAllowOrigin) } } - -func TestIngressCorsConfigAllowOriginNull(t *testing.T) { - ing := buildIngress() - - data := map[string]string{} - data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = enableAnnotation - - // Include a trailing comma and an empty value between the commas. - data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "https://origin123.test.com:4443,null,https://origin321.test.com:4443" - ing.SetAnnotations(data) - - corst, err := NewParser(&resolver.Mock{}).Parse(ing) - if err != nil { - t.Errorf("error parsing annotations: %v", err) - } - - nginxCors, ok := corst.(*Config) - if !ok { - t.Errorf("expected a Config type but returned %t", corst) - } - - if !nginxCors.CorsEnabled { - t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)], nginxCors.CorsEnabled) - } - - expectedCorsAllowOrigins := []string{"https://origin123.test.com:4443", "null", "https://origin321.test.com:4443"} - if !reflect.DeepEqual(nginxCors.CorsAllowOrigin, expectedCorsAllowOrigins) { - t.Errorf("expected %v but returned %v", expectedCorsAllowOrigins, nginxCors.CorsAllowOrigin) - } -} - -func TestIngressCorsConfigAllowOriginWithNonHttpProtocol(t *testing.T) { - ing := buildIngress() - - data := map[string]string{} - data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = enableAnnotation - - // Include a trailing comma and an empty value between the commas. - data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "test://localhost" - ing.SetAnnotations(data) - - corst, err := NewParser(&resolver.Mock{}).Parse(ing) - if err != nil { - t.Errorf("error parsing annotations: %v", err) - } - - nginxCors, ok := corst.(*Config) - if !ok { - t.Errorf("expected a Config type but returned %t", corst) - } - - if !nginxCors.CorsEnabled { - t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)], nginxCors.CorsEnabled) - } - - expectedCorsAllowOrigins := []string{"test://localhost"} - if !reflect.DeepEqual(nginxCors.CorsAllowOrigin, expectedCorsAllowOrigins) { - t.Errorf("expected %v but returned %v", expectedCorsAllowOrigins, nginxCors.CorsAllowOrigin) - } -} diff --git a/internal/ingress/annotations/customheaders/main.go b/internal/ingress/annotations/customheaders/main.go deleted file mode 100644 index d48018d8c..000000000 --- a/internal/ingress/annotations/customheaders/main.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package customheaders - -import ( - "fmt" - "reflect" - "regexp" - "slices" - - "k8s.io/klog/v2" - - networking "k8s.io/api/networking/v1" - - "k8s.io/ingress-nginx/internal/ingress/annotations/parser" - ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" - "k8s.io/ingress-nginx/internal/ingress/resolver" -) - -// Config returns the custom response headers for an Ingress rule -type Config struct { - Headers map[string]string `json:"headers,omitempty"` -} - -// Equal tests for equality between two Config types -func (c1 *Config) Equal(c2 *Config) bool { - if c1 == c2 { - return true - } - if c1 == nil || c2 == nil { - return false - } - - return reflect.DeepEqual(c1.Headers, c2.Headers) -} - -var ( - headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`) - valueRegexp = regexp.MustCompile(`^[a-zA-Z\d_ :;.,\\/"'?!(){}\[\]@<>=\-+*#$&\x60|~^%]+$`) -) - -// ValidHeader checks is the provided string satisfies the header's name regex -func ValidHeader(header string) bool { - return headerRegexp.MatchString(header) -} - -// ValidValue checks is the provided string satisfies the value regex -func ValidValue(header string) bool { - return valueRegexp.MatchString(header) -} - -const ( - customHeadersConfigMapAnnotation = "custom-headers" -) - -var customHeadersAnnotation = parser.Annotation{ - Group: "backend", - Annotations: parser.AnnotationFields{ - customHeadersConfigMapAnnotation: { - Validator: parser.ValidateRegex(parser.BasicCharsRegex, true), - Scope: parser.AnnotationScopeLocation, - Risk: parser.AnnotationRiskMedium, - Documentation: `This annotation sets the name of a ConfigMap that specifies headers to pass to the client. - Only ConfigMaps on the same namespace are allowed`, - }, - }, -} - -type customHeaders struct { - r resolver.Resolver - annotationConfig parser.Annotation -} - -// NewParser creates a new custom response headers annotation parser -func NewParser(r resolver.Resolver) parser.IngressAnnotation { - return customHeaders{r: r, annotationConfig: customHeadersAnnotation} -} - -func (a customHeaders) GetDocumentation() parser.AnnotationFields { - return a.annotationConfig.Annotations -} - -// Parse parses the annotations contained in the ingress to use -// custom response headers -func (a customHeaders) Parse(ing *networking.Ingress) (interface{}, error) { - clientHeadersConfigMapName, err := parser.GetStringAnnotation(customHeadersConfigMapAnnotation, ing, a.annotationConfig.Annotations) - if err != nil { - klog.V(3).InfoS("client-headers annotation is undefined and will not be set") - } - - var headers map[string]string - defBackend := a.r.GetDefaultBackend() - - if clientHeadersConfigMapName != "" { - clientHeadersMapContents, err := a.r.GetConfigMap(clientHeadersConfigMapName) - if err != nil { - return nil, ing_errors.NewLocationDenied(fmt.Sprintf("unable to find configMap %q", clientHeadersConfigMapName)) - } - - for header, value := range clientHeadersMapContents.Data { - if !ValidHeader(header) { - return nil, ing_errors.NewLocationDenied("invalid header name in configmap") - } - if !ValidValue(value) { - return nil, ing_errors.NewLocationDenied("invalid header value in configmap") - } - if !slices.Contains(defBackend.AllowedResponseHeaders, header) { - return nil, ing_errors.NewLocationDenied(fmt.Sprintf("header %s is not allowed, defined allowed headers inside global-allowed-response-headers %v", header, defBackend.AllowedResponseHeaders)) - } - } - - headers = clientHeadersMapContents.Data - } - - return &Config{ - Headers: headers, - }, nil -} - -func (a customHeaders) Validate(anns map[string]string) error { - maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel) - return parser.CheckAnnotationRisk(anns, maxrisk, customHeadersAnnotation.Annotations) -} diff --git a/internal/ingress/annotations/customheaders/main_test.go b/internal/ingress/annotations/customheaders/main_test.go deleted file mode 100644 index 81c0b795a..000000000 --- a/internal/ingress/annotations/customheaders/main_test.go +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package customheaders - -import ( - "reflect" - "testing" - - api "k8s.io/api/core/v1" - networking "k8s.io/api/networking/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/ingress-nginx/internal/ingress/annotations/parser" - "k8s.io/ingress-nginx/internal/ingress/defaults" - "k8s.io/ingress-nginx/internal/ingress/resolver" -) - -func buildIngress() *networking.Ingress { - return &networking.Ingress{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "foo", - Namespace: api.NamespaceDefault, - }, - Spec: networking.IngressSpec{ - DefaultBackend: &networking.IngressBackend{ - Service: &networking.IngressServiceBackend{ - Name: "default-backend", - Port: networking.ServiceBackendPort{ - Number: 80, - }, - }, - }, - }, - } -} - -type mockBackend struct { - resolver.Mock -} - -// GetDefaultBackend returns the backend that must be used as default -func (m mockBackend) GetDefaultBackend() defaults.Backend { - return defaults.Backend{ - AllowedResponseHeaders: []string{"Content-Type", "Access-Control-Max-Age"}, - } -} - -func TestCustomHeadersParseInvalidAnnotations(t *testing.T) { - ing := buildIngress() - configMapResolver := mockBackend{} - configMapResolver.ConfigMaps = map[string]*api.ConfigMap{} - - _, err := NewParser(configMapResolver).Parse(ing) - if err != nil { - t.Errorf("expected error parsing ingress with custom-response-headers") - } - - data := map[string]string{} - data[parser.GetAnnotationWithPrefix("custom-headers")] = "custom-headers-configmap" - ing.SetAnnotations(data) - i, err := NewParser(&resolver.Mock{}).Parse(ing) - if err == nil { - t.Errorf("expected error parsing ingress with custom-response-headers") - } - if i != nil { - t.Errorf("expected %v but got %v", nil, i) - } -} - -func TestCustomHeadersParseAnnotations(t *testing.T) { - ing := buildIngress() - - data := map[string]string{} - data[parser.GetAnnotationWithPrefix("custom-headers")] = "custom-headers-configmap" - ing.SetAnnotations(data) - - configMapResolver := mockBackend{} - configMapResolver.ConfigMaps = map[string]*api.ConfigMap{} - - configMapResolver.ConfigMaps["custom-headers-configmap"] = &api.ConfigMap{Data: map[string]string{"Content-Type": "application/json", "Access-Control-Max-Age": "600"}} - - i, err := NewParser(configMapResolver).Parse(ing) - if err != nil { - t.Errorf("unexpected error parsing ingress with custom-response-headers: %s", err) - } - val, ok := i.(*Config) - if !ok { - t.Errorf("expected a *Config type") - } - - expectedResponseHeaders := map[string]string{} - expectedResponseHeaders["Content-Type"] = "application/json" - expectedResponseHeaders["Access-Control-Max-Age"] = "600" - - c := &Config{expectedResponseHeaders} - - if !reflect.DeepEqual(c, val) { - t.Errorf("expected %v but got %v", c, val) - } -} diff --git a/internal/ingress/annotations/globalratelimit/main.go b/internal/ingress/annotations/globalratelimit/main.go new file mode 100644 index 000000000..0aec29f66 --- /dev/null +++ b/internal/ingress/annotations/globalratelimit/main.go @@ -0,0 +1,179 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package globalratelimit + +import ( + "fmt" + "strings" + "time" + + networking "k8s.io/api/networking/v1" + "k8s.io/klog/v2" + + "k8s.io/ingress-nginx/internal/ingress/annotations/parser" + ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" + "k8s.io/ingress-nginx/internal/ingress/resolver" + "k8s.io/ingress-nginx/internal/net" + "k8s.io/ingress-nginx/pkg/util/sets" +) + +const defaultKey = "$remote_addr" + +const ( + globalRateLimitAnnotation = "global-rate-limit" + globalRateLimitWindowAnnotation = "global-rate-limit-window" + globalRateLimitKeyAnnotation = "global-rate-limit-key" + globalRateLimitIgnoredCidrsAnnotation = "global-rate-limit-ignored-cidrs" +) + +var globalRateLimitAnnotationConfig = parser.Annotation{ + Group: "ratelimit", + Annotations: parser.AnnotationFields{ + globalRateLimitAnnotation: { + Validator: parser.ValidateInt, + Scope: parser.AnnotationScopeIngress, + Risk: parser.AnnotationRiskLow, + Documentation: `This annotation configures maximum allowed number of requests per window`, + }, + globalRateLimitWindowAnnotation: { + Validator: parser.ValidateDuration, + Scope: parser.AnnotationScopeIngress, + Risk: parser.AnnotationRiskLow, + Documentation: `Configures a time window (i.e 1m) that the limit is applied`, + }, + globalRateLimitKeyAnnotation: { + Validator: parser.ValidateRegex(parser.NGINXVariable, true), + Scope: parser.AnnotationScopeIngress, + Risk: parser.AnnotationRiskHigh, + Documentation: `This annotation Configures a key for counting the samples. Defaults to $remote_addr. + You can also combine multiple NGINX variables here, like ${remote_addr}-${http_x_api_client} which would mean the limit will be applied to + requests coming from the same API client (indicated by X-API-Client HTTP request header) with the same source IP address`, + }, + globalRateLimitIgnoredCidrsAnnotation: { + Validator: parser.ValidateCIDRs, + Scope: parser.AnnotationScopeIngress, + Risk: parser.AnnotationRiskMedium, + Documentation: `This annotation defines a comma separated list of IPs and CIDRs to match client IP against. + When there's a match request is not considered for rate limiting.`, + }, + }, +} + +// Config encapsulates all global rate limit attributes +type Config struct { + Namespace string `json:"namespace"` + Limit int `json:"limit"` + WindowSize int `json:"window-size"` + Key string `json:"key"` + IgnoredCIDRs []string `json:"ignored-cidrs"` +} + +// Equal tests for equality between two Config types +func (l *Config) Equal(r *Config) bool { + if l.Namespace != r.Namespace { + return false + } + if l.Limit != r.Limit { + return false + } + if l.WindowSize != r.WindowSize { + return false + } + if l.Key != r.Key { + return false + } + if len(l.IgnoredCIDRs) != len(r.IgnoredCIDRs) || !sets.StringElementsMatch(l.IgnoredCIDRs, r.IgnoredCIDRs) { + return false + } + + return true +} + +type globalratelimit struct { + r resolver.Resolver + annotationConfig parser.Annotation +} + +// NewParser creates a new globalratelimit annotation parser +func NewParser(r resolver.Resolver) parser.IngressAnnotation { + return globalratelimit{ + r: r, + annotationConfig: globalRateLimitAnnotationConfig, + } +} + +// Parse extracts globalratelimit annotations from the given ingress +// and returns them structured as Config type +func (a globalratelimit) Parse(ing *networking.Ingress) (interface{}, error) { + config := &Config{} + + limit, err := parser.GetIntAnnotation(globalRateLimitAnnotation, ing, a.annotationConfig.Annotations) + if err != nil && ing_errors.IsInvalidContent(err) { + return nil, err + } + rawWindowSize, err := parser.GetStringAnnotation(globalRateLimitWindowAnnotation, ing, a.annotationConfig.Annotations) + if err != nil && ing_errors.IsValidationError(err) { + return config, ing_errors.LocationDeniedError{ + Reason: fmt.Errorf("failed to parse 'global-rate-limit-window' value: %w", err), + } + } + + if limit == 0 || rawWindowSize == "" { + return config, nil + } + + windowSize, err := time.ParseDuration(rawWindowSize) + if err != nil { + return config, ing_errors.LocationDeniedError{ + Reason: fmt.Errorf("failed to parse 'global-rate-limit-window' value: %w", err), + } + } + + key, err := parser.GetStringAnnotation(globalRateLimitKeyAnnotation, ing, a.annotationConfig.Annotations) + if err != nil { + klog.Warningf("invalid %s, defaulting to %s", globalRateLimitKeyAnnotation, defaultKey) + } + if key == "" { + key = defaultKey + } + + rawIgnoredCIDRs, err := parser.GetStringAnnotation(globalRateLimitIgnoredCidrsAnnotation, ing, a.annotationConfig.Annotations) + if err != nil && ing_errors.IsInvalidContent(err) { + return nil, err + } + ignoredCIDRs, err := net.ParseCIDRs(rawIgnoredCIDRs) + if err != nil { + return nil, err + } + + config.Namespace = strings.ReplaceAll(string(ing.UID), "-", "") + config.Limit = limit + config.WindowSize = int(windowSize.Seconds()) + config.Key = key + config.IgnoredCIDRs = ignoredCIDRs + + return config, nil +} + +func (a globalratelimit) GetDocumentation() parser.AnnotationFields { + return a.annotationConfig.Annotations +} + +func (a globalratelimit) Validate(anns map[string]string) error { + maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel) + return parser.CheckAnnotationRisk(anns, maxrisk, globalRateLimitAnnotationConfig.Annotations) +} diff --git a/internal/ingress/annotations/globalratelimit/main_test.go b/internal/ingress/annotations/globalratelimit/main_test.go new file mode 100644 index 000000000..b1a7ab71b --- /dev/null +++ b/internal/ingress/annotations/globalratelimit/main_test.go @@ -0,0 +1,211 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package globalratelimit + +import ( + "encoding/json" + "fmt" + "testing" + + api "k8s.io/api/core/v1" + networking "k8s.io/api/networking/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/ingress-nginx/internal/ingress/annotations/parser" + ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" + "k8s.io/ingress-nginx/internal/ingress/resolver" +) + +const ( + UID = "31285d47-b150-4dcf-bd6f-12c46d769f6e" + expectedUID = "31285d47b1504dcfbd6f12c46d769f6e" +) + +func buildIngress() *networking.Ingress { + defaultBackend := networking.IngressBackend{ + Service: &networking.IngressServiceBackend{ + Name: "default-backend", + Port: networking.ServiceBackendPort{ + Number: 80, + }, + }, + } + + return &networking.Ingress{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "foo", + Namespace: api.NamespaceDefault, + UID: UID, + }, + Spec: networking.IngressSpec{ + DefaultBackend: &networking.IngressBackend{ + Service: &networking.IngressServiceBackend{ + Name: "default-backend", + Port: networking.ServiceBackendPort{ + Number: 80, + }, + }, + }, + Rules: []networking.IngressRule{ + { + Host: "foo.bar.com", + IngressRuleValue: networking.IngressRuleValue{ + HTTP: &networking.HTTPIngressRuleValue{ + Paths: []networking.HTTPIngressPath{ + { + Path: "/foo", + Backend: defaultBackend, + }, + }, + }, + }, + }, + }, + }, + } +} + +type mockBackend struct { + resolver.Mock +} + +func TestGlobalRateLimiting(t *testing.T) { + ing := buildIngress() + + annRateLimit := parser.GetAnnotationWithPrefix("global-rate-limit") + annRateLimitWindow := parser.GetAnnotationWithPrefix("global-rate-limit-window") + annRateLimitKey := parser.GetAnnotationWithPrefix("global-rate-limit-key") + annRateLimitIgnoredCIDRs := parser.GetAnnotationWithPrefix("global-rate-limit-ignored-cidrs") + + testCases := []struct { + title string + annotations map[string]string + expectedConfig *Config + expectedErr error + }{ + { + "no annotation", + nil, + &Config{}, + nil, + }, + { + "minimum required annotations", + map[string]string{ + annRateLimit: "100", + annRateLimitWindow: "2m", + }, + &Config{ + Namespace: expectedUID, + Limit: 100, + WindowSize: 120, + Key: "$remote_addr", + IgnoredCIDRs: make([]string, 0), + }, + nil, + }, + { + "global-rate-limit-key annotation", + map[string]string{ + annRateLimit: "100", + annRateLimitWindow: "2m", + annRateLimitKey: "$http_x_api_user", + }, + &Config{ + Namespace: expectedUID, + Limit: 100, + WindowSize: 120, + Key: "$http_x_api_user", + IgnoredCIDRs: make([]string, 0), + }, + nil, + }, + { + "global-rate-limit-ignored-cidrs annotation", + map[string]string{ + annRateLimit: "100", + annRateLimitWindow: "2m", + annRateLimitKey: "$http_x_api_user", + annRateLimitIgnoredCIDRs: "127.0.0.1, 200.200.24.0/24", + }, + &Config{ + Namespace: expectedUID, + Limit: 100, + WindowSize: 120, + Key: "$http_x_api_user", + IgnoredCIDRs: []string{"127.0.0.1", "200.200.24.0/24"}, + }, + nil, + }, + { + "global-rate-limit-complex-key", + map[string]string{ + annRateLimit: "100", + annRateLimitWindow: "2m", + annRateLimitKey: "${http_x_api_user}${otherinfo}", + }, + &Config{ + Namespace: expectedUID, + Limit: 100, + WindowSize: 120, + Key: "${http_x_api_user}${otherinfo}", + IgnoredCIDRs: make([]string, 0), + }, + nil, + }, + { + "incorrect duration for window", + map[string]string{ + annRateLimit: "100", + annRateLimitWindow: "2mb", + annRateLimitKey: "$http_x_api_user", + }, + &Config{}, + ing_errors.ValidationError{ + Reason: fmt.Errorf("failed to parse 'global-rate-limit-window' value: annotation nginx.ingress.kubernetes.io/global-rate-limit-window contains invalid value"), + }, + }, + } + + for _, testCase := range testCases { + ing.SetAnnotations(testCase.annotations) + + i, actualErr := NewParser(mockBackend{}).Parse(ing) + if (testCase.expectedErr == nil || actualErr == nil) && testCase.expectedErr != actualErr { + t.Errorf("%s expected error '%v' but got '%v'", testCase.title, testCase.expectedErr, actualErr) + } else if testCase.expectedErr != nil && actualErr != nil && + testCase.expectedErr.Error() != actualErr.Error() { + t.Errorf("expected error '%v' but got '%v'", testCase.expectedErr, actualErr) + } + + actualConfig, ok := i.(*Config) + if !ok { + t.Errorf("expected Config type but got %T", i) + } + if !testCase.expectedConfig.Equal(actualConfig) { + expectedJSON, err := json.Marshal(testCase.expectedConfig) + if err != nil { + t.Errorf("failed to marshal expected config: %v", err) + } + actualJSON, err := json.Marshal(actualConfig) + if err != nil { + t.Errorf("failed to marshal actual config: %v", err) + } + t.Errorf("%v: expected config '%s' but got '%s'", testCase.title, expectedJSON, actualJSON) + } + } +} diff --git a/internal/ingress/annotations/loadbalancing/main.go b/internal/ingress/annotations/loadbalancing/main.go index 0e5ca8bd8..ee89d2c1b 100644 --- a/internal/ingress/annotations/loadbalancing/main.go +++ b/internal/ingress/annotations/loadbalancing/main.go @@ -23,22 +23,22 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -// LB Algorithms are defined in https://github.com/kubernetes/ingress-nginx/blob/d3e75b056f77be54e01bdb18675f1bb46caece31/rootfs/etc/nginx/lua/balancer.lua#L28 +// LB Alghorithms are defined in https://github.com/kubernetes/ingress-nginx/blob/d3e75b056f77be54e01bdb18675f1bb46caece31/rootfs/etc/nginx/lua/balancer.lua#L28 const ( - loadBalanceAlgorithmAnnotation = "load-balance" + loadBalanceAlghoritmAnnotation = "load-balance" ) -var loadBalanceAlgorithms = []string{"round_robin", "chash", "chashsubset", "sticky_balanced", "sticky_persistent", "ewma"} +var loadBalanceAlghoritms = []string{"round_robin", "chash", "chashsubset", "sticky_balanced", "sticky_persistent", "ewma"} var loadBalanceAnnotations = parser.Annotation{ Group: "backend", Annotations: parser.AnnotationFields{ - loadBalanceAlgorithmAnnotation: { - Validator: parser.ValidateOptions(loadBalanceAlgorithms, true, true), + loadBalanceAlghoritmAnnotation: { + Validator: parser.ValidateOptions(loadBalanceAlghoritms, true, true), Scope: parser.AnnotationScopeLocation, Risk: parser.AnnotationRiskLow, - Documentation: `This annotation allows setting the load balancing algorithm that should be used. If none is specified, defaults to + Documentation: `This annotation allows setting the load balancing alghorithm that should be used. If none is specified, defaults to the default configured by Ingress admin, otherwise to round_robin`, }, }, @@ -61,7 +61,7 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation { // used to indicate if the location/s contains a fragment of // configuration to be included inside the paths of the rules func (a loadbalancing) Parse(ing *networking.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(loadBalanceAlgorithmAnnotation, ing, a.annotationConfig.Annotations) + return parser.GetStringAnnotation(loadBalanceAlghoritmAnnotation, ing, a.annotationConfig.Annotations) } func (a loadbalancing) GetDocumentation() parser.AnnotationFields { diff --git a/internal/ingress/annotations/mirror/main_test.go b/internal/ingress/annotations/mirror/main_test.go index 805f1ef6d..1f6b44d61 100644 --- a/internal/ingress/annotations/mirror/main_test.go +++ b/internal/ingress/annotations/mirror/main_test.go @@ -90,7 +90,7 @@ func TestParse(t *testing.T) { Target: "http://some.test.env.com:2121/$someparam=1&$someotherparam=2", Host: "some.test.env.com", }}, - {map[string]string{backendURL: "http://some.test.env.com", host: "someInvalidParam.%^&*()_=!@#'\""}, &Config{ + {map[string]string{backendURL: "http://some.test.env.com", host: "someInvalidParm.%^&*()_=!@#'\""}, &Config{ Source: ngxURI, RequestBody: "on", Target: "http://some.test.env.com", diff --git a/internal/ingress/annotations/parser/main.go b/internal/ingress/annotations/parser/main.go index 3137afbfd..554ad9dde 100644 --- a/internal/ingress/annotations/parser/main.go +++ b/internal/ingress/annotations/parser/main.go @@ -210,21 +210,6 @@ func StringRiskToRisk(risk string) AnnotationRisk { } } -func (a AnnotationRisk) ToString() string { - switch a { - case AnnotationRiskCritical: - return "Critical" - case AnnotationRiskHigh: - return "High" - case AnnotationRiskMedium: - return "Medium" - case AnnotationRiskLow: - return "Low" - default: - return "Unknown" - } -} - func normalizeString(input string) string { trimmedContent := []string{} for _, line := range strings.Split(input, "\n") { diff --git a/internal/ingress/annotations/parser/validators.go b/internal/ingress/annotations/parser/validators.go index 3c724a311..ffb4d9ba9 100644 --- a/internal/ingress/annotations/parser/validators.go +++ b/internal/ingress/annotations/parser/validators.go @@ -44,7 +44,7 @@ var ( alphaNumericChars = `\-\.\_\~a-zA-Z0-9\/:` extendedAlphaNumeric = alphaNumericChars + ", " regexEnabledChars = regexp.QuoteMeta(`^$[](){}*+?|&=\`) - urlEnabledChars = regexp.QuoteMeta(`,:?&=`) + urlEnabledChars = regexp.QuoteMeta(`:?&=`) ) // IsValidRegex checks if the tested string can be used as a regex, but without any weird character. @@ -79,8 +79,6 @@ var ( // URLWithNginxVariableRegex defines a url that can contain nginx variables. // It is a risky operation URLWithNginxVariableRegex = regexp.MustCompile("^[" + extendedAlphaNumeric + urlEnabledChars + "$]*$") - // MaliciousRegex defines chars that are known to inject RCE - MaliciousRegex = regexp.MustCompile(`\r|\n`) ) // ValidateArrayOfServerName validates if all fields on a Server name annotation are @@ -115,10 +113,6 @@ func ValidateRegex(regex *regexp.Regexp, removeSpace bool) AnnotationValidator { if !regex.MatchString(s) { return fmt.Errorf("value %s is invalid", s) } - if MaliciousRegex.MatchString(s) { - return fmt.Errorf("value %s contains malicious string", s) - } - return nil } } diff --git a/internal/ingress/annotations/parser/validators_test.go b/internal/ingress/annotations/parser/validators_test.go index 49923ba76..ed8449452 100644 --- a/internal/ingress/annotations/parser/validators_test.go +++ b/internal/ingress/annotations/parser/validators_test.go @@ -55,21 +55,11 @@ func TestValidateArrayOfServerName(t *testing.T) { value: "*.so*mething.com,bla.com", wantErr: false, }, - { - name: "should allow comma separated query params", - value: "https://oauth.example/oauth2/auth?allowed_groups=gid1,gid2", - wantErr: false, - }, { name: "should deny names with weird characters", value: "something.com,lolo;xpto.com,nothing.com", wantErr: true, }, - { - name: "should deny names with malicous chars", - value: "http://something.com/#;\nournewinjection", - wantErr: true, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/ingress/annotations/proxy/main.go b/internal/ingress/annotations/proxy/main.go index aaa093eaf..9d2646261 100644 --- a/internal/ingress/annotations/proxy/main.go +++ b/internal/ingress/annotations/proxy/main.go @@ -31,7 +31,6 @@ const ( proxyReadTimeoutAnnotation = "proxy-read-timeout" proxyBuffersNumberAnnotation = "proxy-buffers-number" proxyBufferSizeAnnotation = "proxy-buffer-size" - proxyBusyBuffersSizeAnnotation = "proxy-busy-buffers-size" proxyCookiePathAnnotation = "proxy-cookie-path" proxyCookieDomainAnnotation = "proxy-cookie-domain" proxyBodySizeAnnotation = "proxy-body-size" @@ -83,12 +82,6 @@ var proxyAnnotations = parser.Annotation{ Documentation: `This annotation sets the size of the buffer proxy_buffer_size used for reading the first part of the response received from the proxied server. By default proxy buffer size is set as "4k".`, }, - proxyBusyBuffersSizeAnnotation: { - Validator: parser.ValidateRegex(parser.SizeRegex, true), - Scope: parser.AnnotationScopeLocation, - Risk: parser.AnnotationRiskLow, - Documentation: `This annotation limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read. By default proxy busy buffers size is set as "8k".`, - }, proxyCookiePathAnnotation: { Validator: parser.ValidateRegex(parser.URLIsValidRegex, true), Scope: parser.AnnotationScopeLocation, @@ -174,7 +167,6 @@ type Config struct { ReadTimeout int `json:"readTimeout"` BuffersNumber int `json:"buffersNumber"` BufferSize string `json:"bufferSize"` - BusyBuffersSize string `json:"busyBuffersSize"` CookieDomain string `json:"cookieDomain"` CookiePath string `json:"cookiePath"` NextUpstream string `json:"nextUpstream"` @@ -214,9 +206,6 @@ func (l1 *Config) Equal(l2 *Config) bool { if l1.BufferSize != l2.BufferSize { return false } - if l1.BusyBuffersSize != l2.BusyBuffersSize { - return false - } if l1.CookieDomain != l2.CookieDomain { return false } @@ -301,11 +290,6 @@ func (a proxy) Parse(ing *networking.Ingress) (interface{}, error) { config.BufferSize = defBackend.ProxyBufferSize } - config.BusyBuffersSize, err = parser.GetStringAnnotation(proxyBusyBuffersSizeAnnotation, ing, a.annotationConfig.Annotations) - if err != nil { - config.BusyBuffersSize = defBackend.ProxyBusyBuffersSize - } - config.CookiePath, err = parser.GetStringAnnotation(proxyCookiePathAnnotation, ing, a.annotationConfig.Annotations) if err != nil { config.CookiePath = defBackend.ProxyCookiePath diff --git a/internal/ingress/annotations/proxy/main_test.go b/internal/ingress/annotations/proxy/main_test.go index b6ce07fb2..9446ae970 100644 --- a/internal/ingress/annotations/proxy/main_test.go +++ b/internal/ingress/annotations/proxy/main_test.go @@ -88,7 +88,6 @@ func (m mockBackend) GetDefaultBackend() defaults.Backend { ProxyReadTimeout: 20, ProxyBuffersNumber: 4, ProxyBufferSize: "10k", - ProxyBusyBuffersSize: "15k", ProxyBodySize: "3k", ProxyNextUpstream: "error", ProxyNextUpstreamTimeout: 0, @@ -109,7 +108,6 @@ func TestProxy(t *testing.T) { data[parser.GetAnnotationWithPrefix("proxy-read-timeout")] = "3" data[parser.GetAnnotationWithPrefix("proxy-buffers-number")] = "8" data[parser.GetAnnotationWithPrefix("proxy-buffer-size")] = "1k" - data[parser.GetAnnotationWithPrefix("proxy-busy-buffers-size")] = "4k" data[parser.GetAnnotationWithPrefix("proxy-body-size")] = "2k" data[parser.GetAnnotationWithPrefix("proxy-next-upstream")] = off data[parser.GetAnnotationWithPrefix("proxy-next-upstream-timeout")] = "5" @@ -143,9 +141,6 @@ func TestProxy(t *testing.T) { if p.BufferSize != "1k" { t.Errorf("expected 1k as buffer-size but returned %v", p.BufferSize) } - if p.BusyBuffersSize != "4k" { - t.Errorf("expected 4k as busy-buffers-size but returned %v", p.BusyBuffersSize) - } if p.BodySize != "2k" { t.Errorf("expected 2k as body-size but returned %v", p.BodySize) } @@ -181,7 +176,6 @@ func TestProxyComplex(t *testing.T) { data[parser.GetAnnotationWithPrefix("proxy-read-timeout")] = "3" data[parser.GetAnnotationWithPrefix("proxy-buffers-number")] = "8" data[parser.GetAnnotationWithPrefix("proxy-buffer-size")] = "1k" - data[parser.GetAnnotationWithPrefix("proxy-busy-buffers-size")] = "4k" data[parser.GetAnnotationWithPrefix("proxy-body-size")] = "2k" data[parser.GetAnnotationWithPrefix("proxy-next-upstream")] = "error http_502" data[parser.GetAnnotationWithPrefix("proxy-next-upstream-timeout")] = "5" @@ -215,9 +209,6 @@ func TestProxyComplex(t *testing.T) { if p.BufferSize != "1k" { t.Errorf("expected 1k as buffer-size but returned %v", p.BufferSize) } - if p.BusyBuffersSize != "4k" { - t.Errorf("expected 4k as buffer-size but returned %v", p.BusyBuffersSize) - } if p.BodySize != "2k" { t.Errorf("expected 2k as body-size but returned %v", p.BodySize) } @@ -273,9 +264,6 @@ func TestProxyWithNoAnnotation(t *testing.T) { if p.BufferSize != "10k" { t.Errorf("expected 10k as buffer-size but returned %v", p.BufferSize) } - if p.BusyBuffersSize != "15k" { - t.Errorf("expected 15k as buffer-size but returned %v", p.BusyBuffersSize) - } if p.BodySize != "3k" { t.Errorf("expected 3k as body-size but returned %v", p.BodySize) } diff --git a/internal/ingress/annotations/redirect/redirect.go b/internal/ingress/annotations/redirect/redirect.go index edc3d279c..b58e35171 100644 --- a/internal/ingress/annotations/redirect/redirect.go +++ b/internal/ingress/annotations/redirect/redirect.go @@ -28,26 +28,20 @@ import ( "k8s.io/ingress-nginx/internal/ingress/resolver" ) -const ( - defaultPermanentRedirectCode = http.StatusMovedPermanently - defaultTemporalRedirectCode = http.StatusFound -) +const defaultPermanentRedirectCode = http.StatusMovedPermanently // Config returns the redirect configuration for an Ingress rule type Config struct { URL string `json:"url"` Code int `json:"code"` FromToWWW bool `json:"fromToWWW"` - Relative bool `json:"relative"` } const ( fromToWWWRedirAnnotation = "from-to-www-redirect" temporalRedirectAnnotation = "temporal-redirect" - temporalRedirectAnnotationCode = "temporal-redirect-code" permanentRedirectAnnotation = "permanent-redirect" permanentRedirectAnnotationCode = "permanent-redirect-code" - relativeRedirectsAnnotation = "relative-redirects" ) var redirectAnnotations = parser.Annotation{ @@ -57,7 +51,7 @@ var redirectAnnotations = parser.Annotation{ Validator: parser.ValidateBool, Scope: parser.AnnotationScopeLocation, Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options - Documentation: `In some scenarios, it is required to redirect from www.domain.com to domain.com or vice versa, which way the redirect is performed depends on the configured host value in the Ingress object.`, + Documentation: `In some scenarios is required to redirect from www.domain.com to domain.com or vice versa. To enable this feature use this annotation.`, }, temporalRedirectAnnotation: { Validator: parser.ValidateRegex(parser.URLIsValidRegex, false), @@ -66,12 +60,6 @@ var redirectAnnotations = parser.Annotation{ Documentation: `This annotation allows you to return a temporal redirect (Return Code 302) instead of sending data to the upstream. For example setting this annotation to https://www.google.com would redirect everything to Google with a Return Code of 302 (Moved Temporarily).`, }, - temporalRedirectAnnotationCode: { - Validator: parser.ValidateInt, - Scope: parser.AnnotationScopeLocation, - Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options - Documentation: `This annotation allows you to modify the status code used for temporal redirects.`, - }, permanentRedirectAnnotation: { Validator: parser.ValidateRegex(parser.URLIsValidRegex, false), Scope: parser.AnnotationScopeLocation, @@ -85,12 +73,6 @@ var redirectAnnotations = parser.Annotation{ Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options Documentation: `This annotation allows you to modify the status code used for permanent redirects.`, }, - relativeRedirectsAnnotation: { - Validator: parser.ValidateBool, - Scope: parser.AnnotationScopeLocation, - Risk: parser.AnnotationRiskLow, - Documentation: `If enabled, redirects issued by nginx will be relative. See https://nginx.org/en/docs/http/ngx_http_core_module.html#absolute_redirect`, - }, }, } @@ -117,35 +99,20 @@ func (r redirect) Parse(ing *networking.Ingress) (interface{}, error) { return nil, err } - rr, err := parser.GetBoolAnnotation(relativeRedirectsAnnotation, ing, r.annotationConfig.Annotations) - if err != nil && !errors.IsMissingAnnotations(err) { - return nil, err - } - tr, err := parser.GetStringAnnotation(temporalRedirectAnnotation, ing, r.annotationConfig.Annotations) if err != nil && !errors.IsMissingAnnotations(err) { return nil, err } if tr != "" { - trc, err := parser.GetIntAnnotation(temporalRedirectAnnotationCode, ing, r.annotationConfig.Annotations) - if err != nil && !errors.IsMissingAnnotations(err) { - return nil, err - } - - if trc < http.StatusMultipleChoices || trc > http.StatusTemporaryRedirect { - trc = defaultTemporalRedirectCode - } - if err := isValidURL(tr); err != nil { return nil, err } return &Config{ URL: tr, - Code: trc, + Code: http.StatusFound, FromToWWW: r3w, - Relative: rr, }, nil } @@ -168,13 +135,6 @@ func (r redirect) Parse(ing *networking.Ingress) (interface{}, error) { URL: pr, Code: prc, FromToWWW: r3w, - Relative: rr, - }, nil - } - - if rr { - return &Config{ - Relative: rr, }, nil } @@ -198,9 +158,6 @@ func (r1 *Config) Equal(r2 *Config) bool { if r1.FromToWWW != r2.FromToWWW { return false } - if r1.Relative != r2.Relative { - return false - } return true } diff --git a/internal/ingress/annotations/redirect/redirect_test.go b/internal/ingress/annotations/redirect/redirect_test.go index f4734ae5b..bd2f98211 100644 --- a/internal/ingress/annotations/redirect/redirect_test.go +++ b/internal/ingress/annotations/redirect/redirect_test.go @@ -103,7 +103,7 @@ func TestPermanentRedirectWithCustomCode(t *testing.T) { } } -func TestTemporalRedirectWithDefaultCode(t *testing.T) { +func TestTemporalRedirect(t *testing.T) { rp := NewParser(resolver.Mock{}) if rp == nil { t.Fatalf("Expected a parser.IngressAnnotation but returned nil") @@ -128,49 +128,10 @@ func TestTemporalRedirectWithDefaultCode(t *testing.T) { t.Errorf("Expected %v as redirect but returned %s", defRedirectURL, redirect.URL) } if redirect.Code != http.StatusFound { - t.Errorf("Expected %v as redirect to have a code %d but had %d", defRedirectURL, http.StatusFound, redirect.Code) + t.Errorf("Expected %v as redirect to have a code %d but had %d", defRedirectURL, defaultPermanentRedirectCode, redirect.Code) } -} - -func TestTemporalRedirectWithCustomCode(t *testing.T) { - rp := NewParser(resolver.Mock{}) - if rp == nil { - t.Fatalf("Expected a parser.IngressAnnotation but returned nil") - } - - testCases := map[string]struct { - input int - expectOutput int - }{ - "valid code": {http.StatusTemporaryRedirect, http.StatusTemporaryRedirect}, - "invalid code": {http.StatusTeapot, http.StatusFound}, - } - - for n, tc := range testCases { - t.Run(n, func(t *testing.T) { - ing := new(networking.Ingress) - - data := make(map[string]string, 2) - data[parser.GetAnnotationWithPrefix(fromToWWWRedirAnnotation)] = "true" - data[parser.GetAnnotationWithPrefix(temporalRedirectAnnotation)] = defRedirectURL - data[parser.GetAnnotationWithPrefix(temporalRedirectAnnotationCode)] = strconv.Itoa(tc.input) - ing.SetAnnotations(data) - - i, err := rp.Parse(ing) - if err != nil { - t.Errorf("Unexpected error with ingress: %v", err) - } - redirect, ok := i.(*Config) - if !ok { - t.Errorf("Expected a Redirect type") - } - if redirect.URL != defRedirectURL { - t.Errorf("Expected %v as redirect but returned %s", defRedirectURL, redirect.URL) - } - if redirect.Code != tc.expectOutput { - t.Errorf("Expected %v as redirect to have a code %d but had %d", defRedirectURL, tc.expectOutput, redirect.Code) - } - }) + if redirect.FromToWWW != true { + t.Errorf("Expected %v as redirect to have from-to-www as %v but got %v", defRedirectURL, true, redirect.FromToWWW) } } @@ -193,22 +154,3 @@ func TestIsValidURL(t *testing.T) { t.Errorf("expected nil but got %v", err) } } - -func TestParseAnnotations(t *testing.T) { - ing := new(networking.Ingress) - - data := map[string]string{} - data[parser.GetAnnotationWithPrefix(relativeRedirectsAnnotation)] = "true" - ing.SetAnnotations(data) - - _, err := NewParser(&resolver.Mock{}).Parse(ing) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - // test ingress using the annotation without a TLS section - _, err = NewParser(&resolver.Mock{}).Parse(ing) - if err != nil { - t.Errorf("unexpected error parsing ingress with relative-redirects") - } -} diff --git a/internal/ingress/annotations/serversnippet/main.go b/internal/ingress/annotations/serversnippet/main.go index bce764e69..aa15608d0 100644 --- a/internal/ingress/annotations/serversnippet/main.go +++ b/internal/ingress/annotations/serversnippet/main.go @@ -33,7 +33,7 @@ var serverSnippetAnnotations = parser.Annotation{ serverSnippetAnnotation: { Validator: parser.ValidateNull, Scope: parser.AnnotationScopeIngress, - Risk: parser.AnnotationRiskCritical, // Critical, this annotation is not validated at all and allows arbitrary configurations + Risk: parser.AnnotationRiskCritical, // Critical, this annotation is not validated at all and allows arbitrary configutations Documentation: `This annotation allows setting a custom NGINX configuration on a server block. This annotation does not contain any validation and it's usage is not recommended!`, }, }, diff --git a/internal/ingress/annotations/serviceupstream/main.go b/internal/ingress/annotations/serviceupstream/main.go index 7819d87d8..d1851bc7b 100644 --- a/internal/ingress/annotations/serviceupstream/main.go +++ b/internal/ingress/annotations/serviceupstream/main.go @@ -34,7 +34,7 @@ var serviceUpstreamAnnotations = parser.Annotation{ serviceUpstreamAnnotation: { Validator: parser.ValidateBool, Scope: parser.AnnotationScopeIngress, - Risk: parser.AnnotationRiskLow, // Critical, this annotation is not validated at all and allows arbitrary configurations + Risk: parser.AnnotationRiskLow, // Critical, this annotation is not validated at all and allows arbitrary configutations Documentation: `This annotation makes NGINX use Service's Cluster IP and Port instead of Endpoints as the backend endpoints`, }, }, diff --git a/internal/ingress/annotations/snippet/main.go b/internal/ingress/annotations/snippet/main.go index c2df84cdd..2406093c5 100644 --- a/internal/ingress/annotations/snippet/main.go +++ b/internal/ingress/annotations/snippet/main.go @@ -33,7 +33,7 @@ var configurationSnippetAnnotations = parser.Annotation{ configurationSnippetAnnotation: { Validator: parser.ValidateNull, Scope: parser.AnnotationScopeLocation, - Risk: parser.AnnotationRiskCritical, // Critical, this annotation is not validated at all and allows arbitrary configurations + Risk: parser.AnnotationRiskCritical, // Critical, this annotation is not validated at all and allows arbitrary configutations Documentation: `This annotation allows setting a custom NGINX configuration on a location block. This annotation does not contain any validation and it's usage is not recommended!`, }, }, diff --git a/internal/ingress/annotations/streamsnippet/main.go b/internal/ingress/annotations/streamsnippet/main.go index 7743d3fee..71ff3b140 100644 --- a/internal/ingress/annotations/streamsnippet/main.go +++ b/internal/ingress/annotations/streamsnippet/main.go @@ -33,7 +33,7 @@ var streamSnippetAnnotations = parser.Annotation{ streamSnippetAnnotation: { Validator: parser.ValidateNull, Scope: parser.AnnotationScopeIngress, - Risk: parser.AnnotationRiskCritical, // Critical, this annotation is not validated at all and allows arbitrary configurations + Risk: parser.AnnotationRiskCritical, // Critical, this annotation is not validated at all and allows arbitrary configutations Documentation: `This annotation allows setting a custom NGINX configuration on a stream block. This annotation does not contain any validation and it's usage is not recommended!`, }, }, diff --git a/internal/ingress/controller/config/config.go b/internal/ingress/controller/config/config.go index beac1405d..3098f5cba 100644 --- a/internal/ingress/controller/config/config.go +++ b/internal/ingress/controller/config/config.go @@ -20,9 +20,10 @@ import ( "strconv" "time" - apiv1 "k8s.io/api/core/v1" "k8s.io/klog/v2" + apiv1 "k8s.io/api/core/v1" + "k8s.io/ingress-nginx/internal/ingress/defaults" "k8s.io/ingress-nginx/pkg/apis/ingress" "k8s.io/ingress-nginx/pkg/util/runtime" @@ -119,7 +120,7 @@ type Configuration struct { // By default this is disabled AllowBackendServerHeader bool `json:"allow-backend-server-header"` - // AccessLogParams sets additional params for access_log + // AccessLogParams sets additionals params for access_log // http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log // By default it's empty AccessLogParams string `json:"access-log-params,omitempty"` @@ -318,6 +319,11 @@ type Configuration struct { NginxStatusIpv4Whitelist []string `json:"nginx-status-ipv4-whitelist,omitempty"` NginxStatusIpv6Whitelist []string `json:"nginx-status-ipv6-whitelist,omitempty"` + // Plugins configures plugins to use placed in the directory /etc/nginx/lua/plugins. + // Every plugin has to have main.lua in the root. Every plugin has to bundle all of its dependencies. + // The execution order follows the definition. + Plugins []string `json:"plugins,omitempty"` + // If UseProxyProtocol is enabled ProxyRealIPCIDR defines the default the IP/network address // of your external load balancer ProxyRealIPCIDR []string `json:"proxy-real-ip-cidr,omitempty"` @@ -418,7 +424,7 @@ type Configuration struct { // Example '60s' ProxyProtocolHeaderTimeout time.Duration `json:"proxy-protocol-header-timeout,omitempty"` - // Enables or disables the directive aio_write that writes files asynchronously + // Enables or disables the directive aio_write that writes files files asynchronously // https://nginx.org/en/docs/http/ngx_http_core_module.html#aio_write EnableAioWrite bool `json:"enable-aio-write,omitempty"` @@ -430,10 +436,6 @@ type Configuration struct { // By default this is disabled UseGeoIP2 bool `json:"use-geoip2,omitempty"` - // GeoIP2AutoReloadMinutes enables autoreload on geoip2 setting the interval in minutes - // By default this is disabled using 0 - GeoIP2AutoReloadMinutes int `json:"geoip2-autoreload-in-minutes,omitempty"` - // Enables or disables the use of the NGINX Brotli Module for compression // https://github.com/google/ngx_brotli EnableBrotli bool `json:"enable-brotli,omitempty"` @@ -472,13 +474,6 @@ type Configuration struct { // http://nginx.org/en/docs/ngx_core_module.html#worker_processes WorkerProcesses string `json:"worker-processes,omitempty"` - // Defines whether multiple concurrent reloads of worker processes should occur. - // Set this to false to prevent more than n x 2 workers to exist at any time, to avoid potential OOM situations and high CPU load - // With this setting on false, configuration changes in the queue will be re-queued with an exponential backoff, until the number of worker process is the expected value. - // By default new worker processes are spawned every time there's a change that cannot be applied dynamically with no upper limit to the number of running workers - // http://nginx.org/en/docs/ngx_core_module.html#worker_processes - WorkerSerialReloads bool `json:"enable-serial-reloads,omitempty"` - // Defines a timeout for a graceful shutdown of worker processes // http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout WorkerShutdownTimeout string `json:"worker-shutdown-timeout,omitempty"` @@ -549,10 +544,6 @@ type Configuration struct { // https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors DisableProxyInterceptErrors bool `json:"disable-proxy-intercept-errors,omitempty"` - // Disable absolute redirects and enables relative redirects. - // https://nginx.org/en/docs/http/ngx_http_core_module.html#absolute_redirect - RelativeRedirects bool `json:"relative-redirects"` - // Sets the ipv4 addresses on which the server will accept requests. BindAddressIpv4 []string `json:"bind-address-ipv4,omitempty"` @@ -616,7 +607,7 @@ type Configuration struct { // Default: 0.01 OtelSamplerRatio float32 `json:"otel-sampler-ratio"` - // OtelSamplerParentBased specifies the parent based sampler to be used for any traces created + // OtelSamplerParentBased specifies the parent based sampler to be use for any traces created // Default: true OtelSamplerParentBased bool `json:"otel-sampler-parent-based"` @@ -713,7 +704,7 @@ type Configuration struct { DefaultSSLCertificate *ingress.SSLCert `json:"-"` // ProxySSLLocationOnly controls whether the proxy-ssl parameters defined in the - // proxy-ssl-* annotations are applied on location level only in the nginx.conf file + // proxy-ssl-* annotations are applied on on location level only in the nginx.conf file // Default is that those are applied on server level, too ProxySSLLocationOnly bool `json:"proxy-ssl-location-only"` @@ -722,6 +713,31 @@ type Configuration struct { // Default: text/html DefaultType string `json:"default-type"` + // GlobalRateLimitMemcachedHost configures memcached host. + GlobalRateLimitMemcachedHost string `json:"global-rate-limit-memcached-host"` + + // GlobalRateLimitMemcachedPort configures memcached port. + GlobalRateLimitMemcachedPort int `json:"global-rate-limit-memcached-port"` + + // GlobalRateLimitMemcachedConnectTimeout configures timeout when connecting to memcached. + // The unit is millisecond. + GlobalRateLimitMemcachedConnectTimeout int `json:"global-rate-limit-memcached-connect-timeout"` + + // GlobalRateLimitMemcachedMaxIdleTimeout configured how long connections + // should be kept alive in idle state. The unit is millisecond. + GlobalRateLimitMemcachedMaxIdleTimeout int `json:"global-rate-limit-memcached-max-idle-timeout"` + + // GlobalRateLimitMemcachedPoolSize configures how many connections + // should be kept alive in the pool. + // Note that this is per NGINX worker. Make sure your memcached server can + // handle `MemcachedPoolSize * * ` + // simultaneous connections. + GlobalRateLimitMemcachedPoolSize int `json:"global-rate-limit-memcached-pool-size"` + + // GlobalRateLimitStatusCode determines the HTTP status code to return + // when limit is exceeding during global rate limiting. + GlobalRateLimitStatusCode int `json:"global-rate-limit-status-code"` + // DebugConnections Enables debugging log for selected client connections // http://nginx.org/en/docs/ngx_core_module.html#debug_connection // Default: "" @@ -732,11 +748,6 @@ type Configuration struct { // alphanumeric chars, "-", "_", "/".In case of additional characters, // like used on Rewrite configurations the user should use pathType as ImplementationSpecific StrictValidatePathType bool `json:"strict-validate-path-type"` - - // GRPCBufferSizeKb Sets the size of the buffer used for reading the response received - // from the gRPC server. The response is passed to the client synchronously, - // as soon as it is received. - GRPCBufferSizeKb int `json:"grpc-buffer-size-kb"` } // NewDefault returns the default nginx configuration @@ -755,10 +766,10 @@ func NewDefault() Configuration { cfg := Configuration{ AllowSnippetAnnotations: false, - AllowCrossNamespaceResources: false, + AllowCrossNamespaceResources: true, AllowBackendServerHeader: false, AnnotationValueWordBlocklist: "", - AnnotationsRiskLevel: "High", + AnnotationsRiskLevel: "Critical", AccessLogPath: "/var/log/nginx/access.log", AccessLogParams: "", EnableAccessLogForDefaultBackend: false, @@ -830,15 +841,12 @@ func NewDefault() Configuration { EnableAioWrite: true, UseGzip: false, UseGeoIP2: false, - GeoIP2AutoReloadMinutes: 0, WorkerProcesses: strconv.Itoa(runtime.NumCPU()), - WorkerSerialReloads: false, WorkerShutdownTimeout: "240s", VariablesHashBucketSize: 256, VariablesHashMaxSize: 2048, UseHTTP2: true, DisableProxyInterceptErrors: false, - RelativeRedirects: false, ProxyStreamTimeout: "600s", ProxyStreamNextUpstream: true, ProxyStreamNextUpstreamTimeout: "600s", @@ -850,7 +858,6 @@ func NewDefault() Configuration { ProxySendTimeout: 60, ProxyBuffersNumber: 4, ProxyBufferSize: "4k", - ProxyBusyBuffersSize: "8k", ProxyCookieDomain: "off", ProxyCookiePath: "off", ProxyNextUpstream: "error timeout", @@ -863,7 +870,6 @@ func NewDefault() Configuration { SSLRedirect: true, CustomHTTPErrors: []int{}, DisableProxyInterceptErrors: false, - RelativeRedirects: false, DenylistSourceRange: []string{}, WhitelistSourceRange: []string{}, SkipAccessLogURLs: []string{}, @@ -873,36 +879,39 @@ func NewDefault() Configuration { ProxyHTTPVersion: "1.1", ProxyMaxTempFileSize: "1024m", ServiceUpstream: false, - AllowedResponseHeaders: []string{}, }, - UpstreamKeepaliveConnections: 320, - UpstreamKeepaliveTime: "1h", - UpstreamKeepaliveTimeout: 60, - UpstreamKeepaliveRequests: 10000, - LimitConnZoneVariable: defaultLimitConnZoneVariable, - BindAddressIpv4: defBindAddress, - BindAddressIpv6: defBindAddress, - OpentelemetryTrustIncomingSpan: true, - OpentelemetryConfig: "/etc/ingress-controller/telemetry/opentelemetry.toml", - OtlpCollectorPort: "4317", - OtelServiceName: "nginx", - OtelSampler: "AlwaysOn", - OtelSamplerRatio: 0.01, - OtelSamplerParentBased: true, - OtelScheduleDelayMillis: 5000, - OtelMaxExportBatchSize: 512, - OtelMaxQueueSize: 2048, - LimitReqStatusCode: 503, - LimitConnStatusCode: 503, - SyslogPort: 514, - NoTLSRedirectLocations: "/.well-known/acme-challenge", - NoAuthLocations: "/.well-known/acme-challenge", - GlobalExternalAuth: defGlobalExternalAuth, - ProxySSLLocationOnly: false, - DefaultType: "text/html", - DebugConnections: []string{}, - StrictValidatePathType: true, - GRPCBufferSizeKb: 0, + UpstreamKeepaliveConnections: 320, + UpstreamKeepaliveTime: "1h", + UpstreamKeepaliveTimeout: 60, + UpstreamKeepaliveRequests: 10000, + LimitConnZoneVariable: defaultLimitConnZoneVariable, + BindAddressIpv4: defBindAddress, + BindAddressIpv6: defBindAddress, + OpentelemetryTrustIncomingSpan: true, + OpentelemetryConfig: "/etc/ingress-controller/telemetry/opentelemetry.toml", + OtlpCollectorPort: "4317", + OtelServiceName: "nginx", + OtelSampler: "AlwaysOn", + OtelSamplerRatio: 0.01, + OtelSamplerParentBased: true, + OtelScheduleDelayMillis: 5000, + OtelMaxExportBatchSize: 512, + OtelMaxQueueSize: 2048, + LimitReqStatusCode: 503, + LimitConnStatusCode: 503, + SyslogPort: 514, + NoTLSRedirectLocations: "/.well-known/acme-challenge", + NoAuthLocations: "/.well-known/acme-challenge", + GlobalExternalAuth: defGlobalExternalAuth, + ProxySSLLocationOnly: false, + DefaultType: "text/html", + GlobalRateLimitMemcachedPort: 11211, + GlobalRateLimitMemcachedConnectTimeout: 50, + GlobalRateLimitMemcachedMaxIdleTimeout: 10000, + GlobalRateLimitMemcachedPoolSize: 50, + GlobalRateLimitStatusCode: 429, + DebugConnections: []string{}, + StrictValidatePathType: false, // TODO: This will be true in future releases } if klog.V(5).Enabled() { diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index 652a80e49..0588791be 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -91,7 +91,6 @@ type Configuration struct { UpdateStatus bool UseNodeInternalIP bool ElectionID string - ElectionTTL time.Duration UpdateStatusOnShutdown bool HealthCheckHost string @@ -101,18 +100,13 @@ type Configuration struct { EnableSSLPassthrough bool - DisableLeaderElection bool - EnableProfiling bool - EnableMetrics bool - MetricsPerHost bool - MetricsPerUndefinedHost bool - MetricsBuckets *collectors.HistogramBuckets - MetricsBucketFactor float64 - MetricsMaxBuckets uint32 - ReportStatusClasses bool - ExcludeSocketMetrics []string + EnableMetrics bool + MetricsPerHost bool + MetricsBuckets *collectors.HistogramBuckets + ReportStatusClasses bool + ExcludeSocketMetrics []string FakeCertificate *ingress.SSLCert @@ -380,6 +374,10 @@ func (n *NGINXController) CheckIngress(ing *networking.Ingress) error { if !cfg.AllowSnippetAnnotations && strings.HasSuffix(key, "-snippet") { return fmt.Errorf("%s annotation cannot be used. Snippet directives are disabled by the Ingress administrator", key) } + + if cfg.GlobalRateLimitMemcachedHost == "" && strings.HasPrefix(key, fmt.Sprintf("%s/%s", parser.AnnotationsPrefix, "global-rate-limit")) { + return fmt.Errorf("'global-rate-limit*' annotations require 'global-rate-limit-memcached-host' settings configured in the global configmap") + } } k8s.SetDefaultNGINXPathType(ing) @@ -1255,7 +1253,6 @@ func (n *NGINXController) createServers(data []*ingress.Ingress, ReadTimeout: bdef.ProxyReadTimeout, BuffersNumber: bdef.ProxyBuffersNumber, BufferSize: bdef.ProxyBufferSize, - BusyBuffersSize: bdef.ProxyBusyBuffersSize, CookieDomain: bdef.ProxyCookieDomain, CookiePath: bdef.ProxyCookiePath, NextUpstream: bdef.ProxyNextUpstream, @@ -1504,7 +1501,6 @@ func (n *NGINXController) createServers(data []*ingress.Ingress, func locationApplyAnnotations(loc *ingress.Location, anns *annotations.Ingress) { loc.BasicDigestAuth = anns.BasicDigestAuth loc.ClientBodyBufferSize = anns.ClientBodyBufferSize - loc.CustomHeaders = anns.CustomHeaders loc.ConfigurationSnippet = anns.ConfigurationSnippet loc.CorsConfig = anns.CorsConfig loc.ExternalAuth = anns.ExternalAuth @@ -1514,6 +1510,7 @@ func locationApplyAnnotations(loc *ingress.Location, anns *annotations.Ingress) loc.Proxy = anns.Proxy loc.ProxySSL = anns.ProxySSL loc.RateLimit = anns.RateLimit + loc.GlobalRateLimit = anns.GlobalRateLimit loc.Redirect = anns.Redirect loc.Rewrite = anns.Rewrite loc.UpstreamVhost = anns.UpstreamVhost @@ -1593,11 +1590,7 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres altEqualsPri := false for _, loc := range servers[defServerName].Locations { - priUps, ok := upstreams[loc.Backend] - if !ok { - klog.Warningf("cannot find primary backend %s for location %s%s", loc.Backend, servers[defServerName].Hostname, loc.Path) - continue - } + priUps := upstreams[loc.Backend] altEqualsPri = altUps.Name == priUps.Name if altEqualsPri { klog.Warningf("alternative upstream %s in Ingress %s/%s is primary upstream in Other Ingress for location %s%s!", @@ -1656,11 +1649,7 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres // find matching paths for _, loc := range server.Locations { - priUps, ok := upstreams[loc.Backend] - if !ok { - klog.Warningf("cannot find primary backend %s for location %s%s", loc.Backend, server.Hostname, loc.Path) - continue - } + priUps := upstreams[loc.Backend] altEqualsPri = altUps.Name == priUps.Name if altEqualsPri { klog.Warningf("alternative upstream %s in Ingress %s/%s is primary upstream in Other Ingress for location %s%s!", diff --git a/internal/ingress/controller/controller_test.go b/internal/ingress/controller/controller_test.go index 9d3fea470..e257dd1f1 100644 --- a/internal/ingress/controller/controller_test.go +++ b/internal/ingress/controller/controller_test.go @@ -1292,74 +1292,6 @@ func TestMergeAlternativeBackends(t *testing.T) { }, }, }, - "alternative backend does not merge for missing upstream": { - &ingress.Ingress{ - Ingress: networking.Ingress{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "example", - }, - Spec: networking.IngressSpec{ - Rules: []networking.IngressRule{ - { - Host: "example.com", - IngressRuleValue: networking.IngressRuleValue{ - HTTP: &networking.HTTPIngressRuleValue{ - Paths: []networking.HTTPIngressPath{ - { - Path: "/", - PathType: &pathTypePrefix, - Backend: networking.IngressBackend{ - Service: &networking.IngressServiceBackend{ - Name: "http-svc-canary", - Port: networking.ServiceBackendPort{ - Number: 80, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - map[string]*ingress.Backend{ - "example-http-svc-canary-80": { - Name: "example-http-svc-canary-80", - NoServer: true, - TrafficShapingPolicy: ingress.TrafficShapingPolicy{ - Weight: 20, - }, - }, - }, - map[string]*ingress.Server{ - "example.com": { - Hostname: "example.com", - Locations: []*ingress.Location{ - { - Path: "/", - PathType: &pathTypePrefix, - Backend: "example-http-svc-80", - }, - }, - }, - }, - map[string]*ingress.Backend{}, - map[string]*ingress.Server{ - "example.com": { - Hostname: "example.com", - Locations: []*ingress.Location{ - { - Path: "/", - PathType: &pathTypePrefix, - Backend: "example-http-svc-80", - }, - }, - }, - }, - }, } for title, tc := range testCases { diff --git a/internal/ingress/controller/endpointslices.go b/internal/ingress/controller/endpointslices.go index ed46e2c85..4f98e3ce7 100644 --- a/internal/ingress/controller/endpointslices.go +++ b/internal/ingress/controller/endpointslices.go @@ -115,7 +115,7 @@ func getEndpointsFromSlices(s *corev1.Service, port *corev1.ServicePort, proto c useTopologyHints = false if zoneForHints != emptyZone { useTopologyHints = true - // check if all endpointslices have zone hints + // check if all endpointslices has zone hints for _, ep := range eps.Endpoints { if ep.Hints == nil || len(ep.Hints.ForZones) == 0 { useTopologyHints = false diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index 20fad5afb..e19ee8bb3 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -35,7 +35,6 @@ import ( "syscall" "text/template" "time" - "unicode" proxyproto "github.com/armon/go-proxyproto" "github.com/eapache/channels" @@ -88,10 +87,9 @@ func NewNGINXController(config *Configuration, mc metric.Collector) *NGINXContro n := &NGINXController{ isIPV6Enabled: ing_net.IsIPv6Enabled(), - resolver: h, - cfg: config, - syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.SyncRateLimit, 1), - workersReloading: false, + resolver: h, + cfg: config, + syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.SyncRateLimit, 1), recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{ Component: "nginx-ingress-controller", @@ -231,8 +229,6 @@ type NGINXController struct { syncRateLimiter flowcontrol.RateLimiter - workersReloading bool - // stopLock is used to enforce that only a single call to Stop send at // a given time. We allow stopping through an HTTP endpoint and // allowing concurrent stoppers leads to stack traces. @@ -277,29 +273,26 @@ func (n *NGINXController) Start() { // TODO: For now, as the the IngressClass logics has changed, is up to the // cluster admin to create different Leader Election IDs. // Should revisit this in a future + electionID := n.cfg.ElectionID - if !n.cfg.DisableLeaderElection { - electionID := n.cfg.ElectionID - setupLeaderElection(&leaderElectionConfig{ - Client: n.cfg.Client, - ElectionID: electionID, - ElectionTTL: n.cfg.ElectionTTL, - OnStartedLeading: func(stopCh chan struct{}) { - if n.syncStatus != nil { - go n.syncStatus.Run(stopCh) - } + setupLeaderElection(&leaderElectionConfig{ + Client: n.cfg.Client, + ElectionID: electionID, + OnStartedLeading: func(stopCh chan struct{}) { + if n.syncStatus != nil { + go n.syncStatus.Run(stopCh) + } - n.metricCollector.OnStartedLeading(electionID) - // manually update SSL expiration metrics - // (to not wait for a reload) - n.metricCollector.SetSSLExpireTime(n.runningConfig.Servers) - n.metricCollector.SetSSLInfo(n.runningConfig.Servers) - }, - OnStoppedLeading: func() { - n.metricCollector.OnStoppedLeading(electionID) - }, - }) - } + n.metricCollector.OnStartedLeading(electionID) + // manually update SSL expiration metrics + // (to not wait for a reload) + n.metricCollector.SetSSLExpireTime(n.runningConfig.Servers) + n.metricCollector.SetSSLInfo(n.runningConfig.Servers) + }, + OnStoppedLeading: func() { + n.metricCollector.OnStoppedLeading(electionID) + }, + }) cmd := n.command.ExecCommand() @@ -643,7 +636,8 @@ func (n *NGINXController) testTemplate(cfg []byte) error { if len(cfg) == 0 { return fmt.Errorf("invalid NGINX configuration (empty)") } - tmpfile, err := os.CreateTemp(filepath.Join(os.TempDir(), "nginx"), tempNginxPattern) + tmpDir := os.TempDir() + "/nginx" + tmpfile, err := os.CreateTemp(tmpDir, tempNginxPattern) if err != nil { return err } @@ -679,20 +673,11 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error { cfg := n.store.GetBackendConfiguration() cfg.Resolver = n.resolver - workerSerialReloads := cfg.WorkerSerialReloads - if workerSerialReloads && n.workersReloading { - return errors.New("worker reload already in progress, requeuing reload") - } - content, err := n.generateTemplate(cfg, ingressCfg) if err != nil { return err } - err = n.createLuaConfig(&cfg) - if err != nil { - return err - } err = createOpentelemetryCfg(&cfg) if err != nil { return err @@ -750,41 +735,9 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error { return fmt.Errorf("%v\n%v", err, string(o)) } - // Reload status checking runs in a separate goroutine to avoid blocking the sync queue - if workerSerialReloads { - go n.awaitWorkersReload() - } - return nil } -// awaitWorkersReload checks if the number of workers has returned to the expected count -func (n *NGINXController) awaitWorkersReload() { - n.workersReloading = true - defer func() { n.workersReloading = false }() - - expectedWorkers := n.store.GetBackendConfiguration().WorkerProcesses - var numWorkers string - klog.V(3).Infof("waiting for worker count to be equal to %s", expectedWorkers) - for numWorkers != expectedWorkers { - time.Sleep(time.Second) - o, err := exec.Command("/bin/sh", "-c", "pgrep worker | wc -l").Output() - if err != nil { - klog.ErrorS(err, numWorkers) - return - } - // cleanup any non-printable chars from shell output - numWorkers = strings.Map(func(r rune) rune { - if unicode.IsPrint(r) { - return r - } - return -1 - }, string(o)) - - klog.V(3).Infof("Currently running nginx worker processes: %s, expected %s", numWorkers, expectedWorkers) - } -} - // nginxHashBucketSize computes the correct NGINX hash_bucket_size for a hash // with the given longest key. func nginxHashBucketSize(longestString int) int { @@ -1082,40 +1035,14 @@ func createOpentelemetryCfg(cfg *ngx_config.Configuration) error { return os.WriteFile(cfg.OpentelemetryConfig, tmplBuf.Bytes(), file.ReadWriteByUser) } -func (n *NGINXController) createLuaConfig(cfg *ngx_config.Configuration) error { - luaconfigs := &ngx_template.LuaConfig{ - EnableMetrics: n.cfg.EnableMetrics, - ListenPorts: ngx_template.LuaListenPorts{ - HTTPSPort: strconv.Itoa(n.cfg.ListenPorts.HTTPS), - StatusPort: strconv.Itoa(nginx.StatusPort), - SSLProxyPort: strconv.Itoa(n.cfg.ListenPorts.SSLProxy), - }, - UseProxyProtocol: cfg.UseProxyProtocol, - UseForwardedHeaders: cfg.UseForwardedHeaders, - IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough, - HTTPRedirectCode: cfg.HTTPRedirectCode, - EnableOCSP: cfg.EnableOCSP, - MonitorBatchMaxSize: n.cfg.MonitorMaxBatchSize, - HSTS: cfg.HSTS, - HSTSMaxAge: cfg.HSTSMaxAge, - HSTSIncludeSubdomains: cfg.HSTSIncludeSubdomains, - HSTSPreload: cfg.HSTSPreload, - } - jsonCfg, err := json.Marshal(luaconfigs) - if err != nil { - return err - } - return os.WriteFile(luaCfgPath, jsonCfg, file.ReadWriteByUser) -} - func cleanTempNginxCfg() error { var files []string - err := filepath.Walk(filepath.Join(os.TempDir(), "nginx"), func(path string, info os.FileInfo, err error) error { + err := filepath.Walk(os.TempDir(), func(path string, info os.FileInfo, err error) error { if err != nil { return err } - if info.IsDir() && path != filepath.Join(os.TempDir(), "nginx") { + if info.IsDir() && os.TempDir() != path { return filepath.SkipDir } @@ -1134,7 +1061,7 @@ func cleanTempNginxCfg() error { } for _, file := range files { - err = os.Remove(file) + err := os.Remove(file) if err != nil { return err } diff --git a/internal/ingress/controller/nginx_test.go b/internal/ingress/controller/nginx_test.go index fc0a5b6d2..27180e066 100644 --- a/internal/ingress/controller/nginx_test.go +++ b/internal/ingress/controller/nginx_test.go @@ -361,11 +361,10 @@ func TestCleanTempNginxCfg(t *testing.T) { t.Fatal(err) } - tmpfile, err := os.CreateTemp(filepath.Join(os.TempDir(), "nginx"), tempNginxPattern) + tmpfile, err := os.CreateTemp("", tempNginxPattern) if err != nil { t.Fatal(err) } - expectedDeletedFile := tmpfile.Name() defer tmpfile.Close() dur, err := time.ParseDuration("-10m") @@ -379,11 +378,10 @@ func TestCleanTempNginxCfg(t *testing.T) { t.Fatal(err) } - tmpfile, err = os.CreateTemp(filepath.Join(os.TempDir(), "nginx"), tempNginxPattern) + tmpfile, err = os.CreateTemp("", tempNginxPattern) if err != nil { t.Fatal(err) } - expectedFile := tmpfile.Name() defer tmpfile.Close() err = cleanTempNginxCfg() @@ -393,8 +391,8 @@ func TestCleanTempNginxCfg(t *testing.T) { var files []string - err = filepath.Walk(filepath.Join(os.TempDir(), "nginx"), func(path string, info os.FileInfo, _ error) error { - if info.IsDir() && filepath.Join(os.TempDir(), "nginx") != path { + err = filepath.Walk(os.TempDir(), func(path string, info os.FileInfo, _ error) error { + if info.IsDir() && os.TempDir() != path { return filepath.SkipDir } @@ -407,22 +405,12 @@ func TestCleanTempNginxCfg(t *testing.T) { t.Fatal(err) } - // some other files can be created by other tests - var found bool - for _, file := range files { - if file == expectedDeletedFile { - t.Errorf("file %s should be deleted", file) - } - if file == expectedFile { - found = true - } - } - if !found { - t.Errorf("file %s should not be deleted", expectedFile) + if len(files) != 1 { + t.Errorf("expected one file but %d were found", len(files)) } } -//nolint:unparam // Ignore `network` always receives `"tcp"` error +//nolint:unparam // Ingnore `network` always receives `"tcp"` error func tryListen(network, address string) (l net.Listener, err error) { condFunc := func() (bool, error) { l, err = net.Listen(network, address) diff --git a/internal/ingress/controller/status.go b/internal/ingress/controller/status.go index 5a169e1c3..6bab7c2ad 100644 --- a/internal/ingress/controller/status.go +++ b/internal/ingress/controller/status.go @@ -36,8 +36,7 @@ import ( type leaderElectionConfig struct { Client clientset.Interface - ElectionID string - ElectionTTL time.Duration + ElectionID string OnStartedLeading func(chan struct{}) OnStoppedLeading func() @@ -108,11 +107,13 @@ func setupLeaderElection(config *leaderElectionConfig) { LockConfig: resourceLockConfig, } + ttl := 30 * time.Second + elector, err = leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{ Lock: lock, - LeaseDuration: config.ElectionTTL, - RenewDeadline: config.ElectionTTL / 2, - RetryPeriod: config.ElectionTTL / 4, + LeaseDuration: ttl, + RenewDeadline: ttl / 2, + RetryPeriod: ttl / 4, Callbacks: callbacks, }) diff --git a/internal/ingress/controller/store/endpointslice_test.go b/internal/ingress/controller/store/endpointslice_test.go index 0bdb3aa33..5d423a3a6 100644 --- a/internal/ingress/controller/store/endpointslice_test.go +++ b/internal/ingress/controller/store/endpointslice_test.go @@ -88,7 +88,7 @@ func TestEndpointSliceLister(t *testing.T) { } eps, err := el.MatchByKey(key) if err != nil { - t.Errorf("unexpected error %v", err) + t.Errorf("unexpeted error %v", err) } if err == nil && len(eps) != 1 { t.Errorf("expected one slice %v, error, got %d slices", endpointSlice, len(eps)) @@ -130,7 +130,7 @@ func TestEndpointSliceLister(t *testing.T) { } eps, err := el.MatchByKey(key) if err != nil { - t.Errorf("unexpected error %v", err) + t.Errorf("unexpeted error %v", err) } if len(eps) != 1 { t.Errorf("expected one slice %v, error, got %d slices", endpointSlice, len(eps)) diff --git a/internal/ingress/controller/store/store.go b/internal/ingress/controller/store/store.go index d4bd6136f..284f53209 100644 --- a/internal/ingress/controller/store/store.go +++ b/internal/ingress/controller/store/store.go @@ -240,8 +240,6 @@ type k8sStore struct { backendConfigMu *sync.RWMutex defaultSSLCertificate string - - recorder record.EventRecorder } // New creates a new object store to be used in the ingress controller. @@ -281,7 +279,6 @@ func New( recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{ Component: "nginx-ingress-controller", }) - store.recorder = recorder // k8sStore fulfills resolver.Resolver interface store.annotations = annotations.NewAnnotationExtractor(store) @@ -941,9 +938,6 @@ func (s *k8sStore) syncIngress(ing *networkingv1.Ingress) { klog.Error(err) return } - if parsed.Denied != nil { - s.recorder.Eventf(ing, corev1.EventTypeWarning, "AnnotationParsingFailed", fmt.Sprintf("Error parsing annotations: %v", *parsed.Denied)) - } err = s.listers.IngressWithAnnotation.Update(&ingress.Ingress{ Ingress: *copyIng, ParsedAnnotations: parsed, diff --git a/internal/ingress/controller/store/store_test.go b/internal/ingress/controller/store/store_test.go index 9c719af3b..317c0f36c 100644 --- a/internal/ingress/controller/store/store_test.go +++ b/internal/ingress/controller/store/store_test.go @@ -1208,13 +1208,13 @@ func TestStore(t *testing.T) { } }(updateCh) - namespaceSelector, err := labels.Parse("foo=bar") + namesapceSelector, err := labels.Parse("foo=bar") if err != nil { t.Errorf("unexpected error: %v", err) } storer := New( ns, - namespaceSelector, + namesapceSelector, fmt.Sprintf("%v/config", ns), fmt.Sprintf("%v/tcp", ns), fmt.Sprintf("%v/udp", ns), @@ -1274,7 +1274,7 @@ func TestStore(t *testing.T) { t.Errorf("expected 0 events of type Delete but %v occurred", del) } }) - // test add ingress with secret it doesn't exist and then add secret + // test add ingress with secret it doesn't exists and then add secret // check secret is generated on fs // check ocsp // check invalid secret (missing crt) diff --git a/internal/ingress/controller/template/configmap.go b/internal/ingress/controller/template/configmap.go index febf20be0..9dc019bcc 100644 --- a/internal/ingress/controller/template/configmap.go +++ b/internal/ingress/controller/template/configmap.go @@ -31,7 +31,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/ingress-nginx/internal/ingress/annotations/authreq" - "k8s.io/ingress-nginx/internal/ingress/annotations/customheaders" "k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/controller/config" ing_net "k8s.io/ingress-nginx/internal/net" @@ -55,7 +54,6 @@ const ( nginxStatusIpv6Whitelist = "nginx-status-ipv6-whitelist" proxyHeaderTimeout = "proxy-protocol-header-timeout" workerProcesses = "worker-processes" - globalAllowedResponseHeaders = "global-allowed-response-headers" globalAuthURL = "global-auth-url" globalAuthMethod = "global-auth-method" globalAuthSignin = "global-auth-signin" @@ -67,8 +65,8 @@ const ( globalAuthCacheDuration = "global-auth-cache-duration" globalAuthAlwaysSetCookie = "global-auth-always-set-cookie" luaSharedDictsKey = "lua-shared-dicts" + plugins = "plugins" debugConnections = "debug-connections" - workerSerialReloads = "enable-serial-reloads" ) var ( @@ -82,6 +80,7 @@ var ( "balancer_ewma_locks": 1024, "certificate_servers": 5120, "ocsp_response_cache": 5120, // keep this same as certificate_servers + "global_throttle_cache": 10240, } defaultGlobalAuthRedirectParam = "rd" ) @@ -116,7 +115,6 @@ func ReadConfig(src map[string]string) config.Configuration { blockUserAgentList := make([]string, 0) blockRefererList := make([]string, 0) responseHeaders := make([]string, 0) - allowedResponseHeaders := make([]string, 0) luaSharedDicts := make(map[string]int) debugConnectionsList := make([]string, 0) @@ -125,11 +123,8 @@ func ReadConfig(src map[string]string) config.Configuration { delete(conf, luaSharedDictsKey) lsd := splitAndTrimSpace(val, ",") for _, v := range lsd { - results := strings.SplitN(strings.ReplaceAll(v, " ", ""), ":", 2) - if len(results) != 2 { - klog.Errorf("Ignoring poorly formatted Lua dictionary %v", v) - continue - } + v = strings.ReplaceAll(v, " ", "") + results := strings.SplitN(v, ":", 2) dictName := results[0] size := dictStrToKb(results[1]) if size < 0 { @@ -253,22 +248,6 @@ func ReadConfig(src map[string]string) config.Configuration { } } - // Verify that the configured global external authorization response headers are valid. if not, set the default value - if val, ok := conf[globalAllowedResponseHeaders]; ok { - delete(conf, globalAllowedResponseHeaders) - - if val != "" { - harr := splitAndTrimSpace(val, ",") - for _, header := range harr { - if !customheaders.ValidHeader(header) { - klog.Warningf("Global allowed response headers denied - %s.", header) - } else { - allowedResponseHeaders = append(allowedResponseHeaders, header) - } - } - } - } - // Verify that the configured global external authorization method is a valid HTTP method. if not, set the default value if val, ok := conf[globalAuthMethod]; ok { delete(conf, globalAuthMethod) @@ -406,15 +385,9 @@ func ReadConfig(src map[string]string) config.Configuration { delete(conf, workerProcesses) } - if val, ok := conf[workerSerialReloads]; ok { - boolVal, err := strconv.ParseBool(val) - if err != nil { - to.WorkerSerialReloads = false - klog.Warningf("failed to parse enable-serial-reloads setting, valid values are true or false, found %s", val) - } else { - to.WorkerSerialReloads = boolVal - } - delete(conf, workerSerialReloads) + if val, ok := conf[plugins]; ok { + to.Plugins = splitAndTrimSpace(val, ",") + delete(conf, plugins) } if val, ok := conf[debugConnections]; ok { @@ -449,7 +422,6 @@ func ReadConfig(src map[string]string) config.Configuration { to.ProxyStreamResponses = streamResponses to.DisableIpv6DNS = !ing_net.IsIPv6Enabled() to.LuaSharedDicts = luaSharedDicts - to.Backend.AllowedResponseHeaders = allowedResponseHeaders decoderConfig := &mapstructure.DecoderConfig{ Metadata: nil, diff --git a/internal/ingress/controller/template/configmap_test.go b/internal/ingress/controller/template/configmap_test.go index 6c7468303..dad841694 100644 --- a/internal/ingress/controller/template/configmap_test.go +++ b/internal/ingress/controller/template/configmap_test.go @@ -390,11 +390,6 @@ func TestLuaSharedDictsParsing(t *testing.T) { entry: map[string]string{"lua-shared-dicts": "configuration_data: 10, my_random_dict:15 , another_example:2"}, expect: map[string]int{"configuration_data": 10240, "my_random_dict": 15360, "another_example": 2048}, }, - { - name: "invalid format", - entry: map[string]string{"lua-shared-dicts": "mydict: 10, invalid_dict 100"}, - expect: map[string]int{"mydict": 10240}, - }, { name: "invalid size value should be ignored", entry: map[string]string{"lua-shared-dicts": "mydict: 10, invalid_dict: 1a, bad_mb_dict:10mb"}, diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index ed052e4ec..c70406cf0 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -136,13 +136,6 @@ func cleanConf(in, out *bytes.Buffer) error { case ' ', '\t': needOutput = lineStarted case '\r': - rest := in.Bytes() - if len(rest) > 0 { - if rest[0] != '\n' { - c = ' ' - needOutput = lineStarted - } - } case '\n': needOutput = !(!lineStarted && emptyLineWritten) nextLineStarted = false @@ -157,13 +150,6 @@ func cleanConf(in, out *bytes.Buffer) error { case stateComment: switch c { case '\r': - rest := in.Bytes() - if len(rest) > 0 { - if rest[0] != '\n' { - c = ' ' - needOutput = lineStarted - } - } case '\n': needOutput = true nextLineStarted = false @@ -194,41 +180,6 @@ func cleanConf(in, out *bytes.Buffer) error { } } -/* LuaConfig defines the structure that will be written as a config for lua scripts -The json format should follow what's expected by lua: - use_forwarded_headers = %t, - use_proxy_protocol = %t, - is_ssl_passthrough_enabled = %t, - http_redirect_code = %v, - listen_ports = { ssl_proxy = "%v", https = "%v" }, - - hsts = %t, - hsts_max_age = %v, - hsts_include_subdomains = %t, - hsts_preload = %t, -*/ - -type LuaConfig struct { - EnableMetrics bool `json:"enable_metrics"` - ListenPorts LuaListenPorts `json:"listen_ports"` - UseForwardedHeaders bool `json:"use_forwarded_headers"` - UseProxyProtocol bool `json:"use_proxy_protocol"` - IsSSLPassthroughEnabled bool `json:"is_ssl_passthrough_enabled"` - HTTPRedirectCode int `json:"http_redirect_code"` - EnableOCSP bool `json:"enable_ocsp"` - MonitorBatchMaxSize int `json:"monitor_batch_max_size"` - HSTS bool `json:"hsts"` - HSTSMaxAge string `json:"hsts_max_age"` - HSTSIncludeSubdomains bool `json:"hsts_include_subdomains"` - HSTSPreload bool `json:"hsts_preload"` -} - -type LuaListenPorts struct { - HTTPSPort string `json:"https"` - StatusPort string `json:"status_port"` - SSLProxyPort string `json:"ssl_proxy"` -} - // Write populates a buffer using a template with NGINX configuration // and the servers and upstreams created by Ingress rules func (t *Template) Write(conf *config.TemplateConfig) ([]byte, error) { @@ -291,6 +242,7 @@ var funcMap = text_template.FuncMap{ "filterRateLimits": filterRateLimits, "buildRateLimitZones": buildRateLimitZones, "buildRateLimit": buildRateLimit, + "configForLua": configForLua, "locationConfigForLua": locationConfigForLua, "buildResolvers": buildResolvers, "buildUpstreamName": buildUpstreamName, @@ -417,6 +369,54 @@ func luaConfigurationRequestBodySize(c interface{}) string { return dictKbToStr(size) } +// configForLua returns some general configuration as Lua table represented as string +func configForLua(input interface{}) string { + all, ok := input.(config.TemplateConfig) + if !ok { + klog.Errorf("expected a 'config.TemplateConfig' type but %T was given", input) + return "{}" + } + + return fmt.Sprintf(`{ + use_forwarded_headers = %t, + use_proxy_protocol = %t, + is_ssl_passthrough_enabled = %t, + http_redirect_code = %v, + listen_ports = { ssl_proxy = "%v", https = "%v" }, + + hsts = %t, + hsts_max_age = %v, + hsts_include_subdomains = %t, + hsts_preload = %t, + + global_throttle = { + memcached = { + host = "%v", port = %d, connect_timeout = %d, max_idle_timeout = %d, pool_size = %d, + }, + status_code = %d, + } + }`, + all.Cfg.UseForwardedHeaders, + all.Cfg.UseProxyProtocol, + all.IsSSLPassthroughEnabled, + all.Cfg.HTTPRedirectCode, + all.ListenPorts.SSLProxy, + all.ListenPorts.HTTPS, + + all.Cfg.HSTS, + all.Cfg.HSTSMaxAge, + all.Cfg.HSTSIncludeSubdomains, + all.Cfg.HSTSPreload, + + all.Cfg.GlobalRateLimitMemcachedHost, + all.Cfg.GlobalRateLimitMemcachedPort, + all.Cfg.GlobalRateLimitMemcachedConnectTimeout, + all.Cfg.GlobalRateLimitMemcachedMaxIdleTimeout, + all.Cfg.GlobalRateLimitMemcachedPoolSize, + all.Cfg.GlobalRateLimitStatusCode, + ) +} + // locationConfigForLua formats some location specific configuration into Lua table represented as string func locationConfigForLua(l, a interface{}) string { location, ok := l.(*ingress.Location) @@ -431,26 +431,30 @@ func locationConfigForLua(l, a interface{}) string { return "{}" } - /* Lua expects the following vars - force_ssl_redirect = string_to_bool(ngx.var.force_ssl_redirect), - ssl_redirect = string_to_bool(ngx.var.ssl_redirect), - force_no_ssl_redirect = string_to_bool(ngx.var.force_no_ssl_redirect), - preserve_trailing_slash = string_to_bool(ngx.var.preserve_trailing_slash), - use_port_in_redirects = string_to_bool(ngx.var.use_port_in_redirects), - */ + ignoredCIDRs, err := convertGoSliceIntoLuaTable(location.GlobalRateLimit.IgnoredCIDRs, false) + if err != nil { + klog.Errorf("failed to convert %v into Lua table: %q", location.GlobalRateLimit.IgnoredCIDRs, err) + ignoredCIDRs = "{}" + } - return fmt.Sprintf(` - set $force_ssl_redirect "%t"; - set $ssl_redirect "%t"; - set $force_no_ssl_redirect "%t"; - set $preserve_trailing_slash "%t"; - set $use_port_in_redirects "%t"; - `, + return fmt.Sprintf(`{ + force_ssl_redirect = %t, + ssl_redirect = %t, + force_no_ssl_redirect = %t, + preserve_trailing_slash = %t, + use_port_in_redirects = %t, + global_throttle = { namespace = "%v", limit = %d, window_size = %d, key = %v, ignored_cidrs = %v }, + }`, location.Rewrite.ForceSSLRedirect, location.Rewrite.SSLRedirect, isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations), location.Rewrite.PreserveTrailingSlash, location.UsePortInRedirects, + location.GlobalRateLimit.Namespace, + location.GlobalRateLimit.Limit, + location.GlobalRateLimit.WindowSize, + parseComplexNginxVarIntoLuaTable(location.GlobalRateLimit.Key), + ignoredCIDRs, ) } @@ -602,12 +606,17 @@ func buildAuthResponseHeaders(proxySetHeader string, headers []string, lua bool) return res } -func buildAuthUpstreamLuaHeaders(headers []string) string { +func buildAuthUpstreamLuaHeaders(headers []string) []string { + res := []string{} + if len(headers) == 0 { - return "" + return res } - return strings.Join(headers, ",") + for i, h := range headers { + res = append(res, fmt.Sprintf("ngx.var.authHeader%d = res.header['%s']", i, h)) + } + return res } func buildAuthProxySetHeaders(headers map[string]string) []string { @@ -1667,6 +1676,54 @@ func buildServerName(hostname string) string { return `~^(?[\w-]+)\.` + strings.Join(parts, "\\.") + `$` } +// parseComplexNginxVarIntoLuaTable parses things like "$my${complex}ngx\$var" into +// [["$var", "complex", "my", "ngx"]]. In other words, 2nd and 3rd elements +// in the result are actual NGINX variable names, whereas first and 4th elements +// are string literals. +func parseComplexNginxVarIntoLuaTable(ngxVar string) string { + r := regexp.MustCompile(`(\\\$[0-9a-zA-Z_]+)|\$\{([0-9a-zA-Z_]+)\}|\$([0-9a-zA-Z_]+)|(\$|[^$\\]+)`) + matches := r.FindAllStringSubmatch(ngxVar, -1) + components := make([][]string, len(matches)) + for i, match := range matches { + components[i] = match[1:] + } + + luaTable, err := convertGoSliceIntoLuaTable(components, true) + if err != nil { + klog.Errorf("unexpected error: %v", err) + luaTable = "{}" + } + return luaTable +} + +func convertGoSliceIntoLuaTable(goSliceInterface interface{}, emptyStringAsNil bool) (string, error) { + goSlice := reflect.ValueOf(goSliceInterface) + kind := goSlice.Kind() + + switch kind { + case reflect.String: + if emptyStringAsNil && goSlice.Interface().(string) == "" { + return "nil", nil + } + return fmt.Sprintf(`"%v"`, goSlice.Interface()), nil + case reflect.Int, reflect.Bool: + return fmt.Sprintf(`%v`, goSlice.Interface()), nil + case reflect.Slice, reflect.Array: + luaTable := "{ " + for i := 0; i < goSlice.Len(); i++ { + luaEl, err := convertGoSliceIntoLuaTable(goSlice.Index(i).Interface(), emptyStringAsNil) + if err != nil { + return "", err + } + luaTable = luaTable + luaEl + ", " + } + luaTable += "}" + return luaTable, nil + default: + return "", fmt.Errorf("could not process type: %s", kind) + } +} + func buildOriginRegex(origin string) string { origin = regexp.QuoteMeta(origin) origin = strings.Replace(origin, "\\*", `[A-Za-z0-9\-]+`, 1) diff --git a/internal/ingress/controller/template/template_test.go b/internal/ingress/controller/template/template_test.go index 6553f5daf..3089e3b32 100644 --- a/internal/ingress/controller/template/template_test.go +++ b/internal/ingress/controller/template/template_test.go @@ -537,7 +537,10 @@ func TestBuildAuthResponseHeaders(t *testing.T) { func TestBuildAuthResponseLua(t *testing.T) { externalAuthResponseHeaders := []string{"h1", "H-With-Caps-And-Dashes"} - expected := "h1,H-With-Caps-And-Dashes" + expected := []string{ + "ngx.var.authHeader0 = res.header['h1']", + "ngx.var.authHeader1 = res.header['H-With-Caps-And-Dashes']", + } headers := buildAuthUpstreamLuaHeaders(externalAuthResponseHeaders) @@ -1923,6 +1926,89 @@ func TestBuildServerName(t *testing.T) { } } +func TestParseComplexNginxVarIntoLuaTable(t *testing.T) { + testCases := []struct { + ngxVar string + expectedLuaTable string + }{ + {"foo", `{ { nil, nil, nil, "foo", }, }`}, + {"$foo", `{ { nil, nil, "foo", nil, }, }`}, + {"${foo}", `{ { nil, "foo", nil, nil, }, }`}, + {"\\$foo", `{ { "\$foo", nil, nil, nil, }, }`}, + { + "foo\\$bar$baz${daz}xiyar$pomidor", + `{ { nil, nil, nil, "foo", }, { "\$bar", nil, nil, nil, }, { nil, nil, "baz", nil, }, ` + + `{ nil, "daz", nil, nil, }, { nil, nil, nil, "xiyar", }, { nil, nil, "pomidor", nil, }, }`, + }, + } + + for _, testCase := range testCases { + actualLuaTable := parseComplexNginxVarIntoLuaTable(testCase.ngxVar) + if actualLuaTable != testCase.expectedLuaTable { + t.Errorf("expected %v but returned %v", testCase.expectedLuaTable, actualLuaTable) + } + } +} + +func TestConvertGoSliceIntoLuaTablet(t *testing.T) { + testCases := []struct { + title string + goSlice interface{} + emptyStringAsNil bool + expectedLuaTable string + expectedErr error + }{ + { + "flat string slice", + []string{"one", "two", "three"}, + false, + `{ "one", "two", "three", }`, + nil, + }, + { + "nested string slice", + [][]string{{"one", "", "three"}, {"foo", "bar"}}, + false, + `{ { "one", "", "three", }, { "foo", "bar", }, }`, + nil, + }, + { + "converts empty string to nil when enabled", + [][]string{{"one", "", "three"}, {"foo", "bar"}}, + true, + `{ { "one", nil, "three", }, { "foo", "bar", }, }`, + nil, + }, + { + "boolean slice", + []bool{true, true, false}, + false, + `{ true, true, false, }`, + nil, + }, + { + "integer slice", + []int{4, 3, 6}, + false, + `{ 4, 3, 6, }`, + nil, + }, + } + + for _, testCase := range testCases { + actualLuaTable, err := convertGoSliceIntoLuaTable(testCase.goSlice, testCase.emptyStringAsNil) + if testCase.expectedErr != nil && err != nil && testCase.expectedErr.Error() != err.Error() { + t.Errorf("expected error '%v' but returned '%v'", testCase.expectedErr, err) + } + if testCase.expectedErr == nil && err != nil { + t.Errorf("expected error to be nil but returned '%v'", err) + } + if testCase.expectedLuaTable != actualLuaTable { + t.Errorf("%v: expected '%v' but returned '%v'", testCase.title, testCase.expectedLuaTable, actualLuaTable) + } + } +} + func TestCleanConf(t *testing.T) { testDataDir, err := getTestDataDir() if err != nil { diff --git a/internal/ingress/controller/util.go b/internal/ingress/controller/util.go index 975fb822a..8851f323f 100644 --- a/internal/ingress/controller/util.go +++ b/internal/ingress/controller/util.go @@ -98,9 +98,8 @@ func rlimitMaxNumFiles() int { } const ( - defBinary = "/usr/bin/nginx" - cfgPath = "/etc/nginx/nginx.conf" - luaCfgPath = "/etc/nginx/lua/cfg.json" + defBinary = "/usr/bin/nginx" + cfgPath = "/etc/nginx/nginx.conf" ) // NginxExecTester defines the interface to execute @@ -130,7 +129,7 @@ func NewNginxCommand() NginxCommand { return command } -// ExecCommand instantiates an exec.Cmd object to call nginx program +// ExecCommand instanciates an exec.Cmd object to call nginx program func (nc NginxCommand) ExecCommand(args ...string) *exec.Cmd { cmdArgs := []string{} diff --git a/internal/ingress/defaults/main.go b/internal/ingress/defaults/main.go index bec1b08e2..2bb58c858 100644 --- a/internal/ingress/defaults/main.go +++ b/internal/ingress/defaults/main.go @@ -69,11 +69,6 @@ type Backend struct { // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) ProxyBufferSize string `json:"proxy-buffer-size"` - // Limits the total size of buffers that can be busy sending a response to the client while - // the response is not yet fully read. - // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_busy_buffers_size - ProxyBusyBuffersSize string `json:"proxy-busy-buffers-size"` - // Sets a text that should be changed in the path attribute of the “Set-Cookie” header fields of // a proxied server response. // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_path @@ -130,11 +125,6 @@ type Backend struct { // Default: false UsePortInRedirects bool `json:"use-port-in-redirects"` - // Enables or disables relative redirects. By default nginx uses absolute redirects. - // http://nginx.org/en/docs/http/ngx_http_core_module.html#absolute_redirect - // Default: false - RelativeRedirects bool `json:"relative-redirects"` - // Enable stickiness by client-server mapping based on a NGINX variable, text or a combination of both. // A consistent hashing method will be used which ensures only a few keys would be remapped to different // servers on upstream group changes @@ -186,9 +176,6 @@ type Backend struct { // By default, the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration. // It disables that behavior and instead uses a single upstream in NGINX, the service's Cluster IP and port. ServiceUpstream bool `json:"service-upstream"` - - // AllowedResponseHeaders allows to define allow response headers for custom header annotation - AllowedResponseHeaders []string `json:"global-allowed-response-headers"` } type SecurityConfiguration struct { diff --git a/internal/ingress/metric/collectors/controller.go b/internal/ingress/metric/collectors/controller.go index 0df04c1d0..4ee84bc56 100644 --- a/internal/ingress/metric/collectors/controller.go +++ b/internal/ingress/metric/collectors/controller.go @@ -225,7 +225,7 @@ func (cm *Controller) IncCheckErrorCount(namespace, name string) { cm.checkIngressOperationErrors.MustCurryWith(cm.constLabels).With(labels).Inc() } -// IncOrphanIngress sets the orphaned ingress gauge to one +// IncOrphanIngress sets the the orphaned ingress gauge to one func (cm *Controller) IncOrphanIngress(namespace, name, orphanityType string) { labels := prometheus.Labels{ "namespace": namespace, @@ -235,7 +235,7 @@ func (cm *Controller) IncOrphanIngress(namespace, name, orphanityType string) { cm.OrphanIngress.MustCurryWith(cm.constLabels).With(labels).Set(1.0) } -// DecOrphanIngress sets the orphaned ingress gauge to zero (all services has their endpoints) +// DecOrphanIngress sets the the orphaned ingress gauge to zero (all services has their endpoints) func (cm *Controller) DecOrphanIngress(namespace, name, orphanityType string) { labels := prometheus.Labels{ "namespace": namespace, @@ -305,14 +305,13 @@ func (cm *Controller) SetSSLExpireTime(servers []*ingress.Server) { } labels["host"] = s.Hostname labels["secret_name"] = s.SSLCert.Name - labels["namespace"] = s.SSLCert.Namespace labels["identifier"] = s.SSLCert.Identifier() cm.sslExpireTime.With(labels).Set(float64(s.SSLCert.ExpireTime.Unix())) } } -// SetSSLInfo creates a metric with all certificate information +// SetSSLInfo creates a metric with all certificates informations func (cm *Controller) SetSSLInfo(servers []*ingress.Server) { for _, s := range servers { if s.SSLCert == nil || s.SSLCert.Certificate == nil || s.SSLCert.Certificate.SerialNumber == nil { diff --git a/internal/ingress/metric/collectors/controller_test.go b/internal/ingress/metric/collectors/controller_test.go index a77293c20..7c7ea8a67 100644 --- a/internal/ingress/metric/collectors/controller_test.go +++ b/internal/ingress/metric/collectors/controller_test.go @@ -88,8 +88,6 @@ func TestControllerCounters(t *testing.T) { Hostname: "demo", SSLCert: &ingress.SSLCert{ ExpireTime: t1, - Name: "secret-name", - Namespace: "secret-namespace", Certificate: &x509.Certificate{ PublicKeyAlgorithm: x509.ECDSA, Issuer: pkix.Name{ @@ -113,7 +111,7 @@ func TestControllerCounters(t *testing.T) { want: ` # HELP nginx_ingress_controller_ssl_expire_time_seconds Number of seconds since 1970 to the SSL Certificate expire.\n An example to check if this certificate will expire in 10 days is: "nginx_ingress_controller_ssl_expire_time_seconds < (time() + (10 * 24 * 3600))" # TYPE nginx_ingress_controller_ssl_expire_time_seconds gauge - nginx_ingress_controller_ssl_expire_time_seconds{class="nginx",host="demo",identifier="abcd1234-100",namespace="secret-namespace",secret_name="secret-name"} 1.351807721e+09 + nginx_ingress_controller_ssl_expire_time_seconds{class="nginx",host="demo",identifier="abcd1234-100",namespace="default",secret_name=""} 1.351807721e+09 `, metrics: []string{"nginx_ingress_controller_ssl_expire_time_seconds"}, }, diff --git a/internal/ingress/metric/collectors/process.go b/internal/ingress/metric/collectors/process.go index 85e8066b5..8c489de03 100644 --- a/internal/ingress/metric/collectors/process.go +++ b/internal/ingress/metric/collectors/process.go @@ -112,7 +112,7 @@ func NewNGINXProcess(pod, namespace, ingressClass string) (NGINXProcessCollector p := &namedProcess{ scrapeChan: make(chan scrapeRequest), - Grouper: proc.NewGrouper(nm, true, false, false, 0, false, false), + Grouper: proc.NewGrouper(nm, true, false, false, 0, false), fs: fs, } diff --git a/internal/ingress/metric/collectors/socket.go b/internal/ingress/metric/collectors/socket.go index 0bdd816ae..248f23f63 100644 --- a/internal/ingress/metric/collectors/socket.go +++ b/internal/ingress/metric/collectors/socket.go @@ -64,10 +64,11 @@ type metricMapping map[string]prometheus.Collector type SocketCollector struct { prometheus.Collector - connectTime *prometheus.HistogramVec - headerTime *prometheus.HistogramVec - requestTime *prometheus.HistogramVec - responseTime *prometheus.HistogramVec + upstreamLatency *prometheus.SummaryVec // TODO: DEPRECATED, remove + connectTime *prometheus.HistogramVec + headerTime *prometheus.HistogramVec + requestTime *prometheus.HistogramVec + responseTime *prometheus.HistogramVec requestLength *prometheus.HistogramVec responseLength *prometheus.HistogramVec @@ -81,9 +82,8 @@ type SocketCollector struct { hosts sets.Set[string] - metricsPerHost bool - metricsPerUndefinedHost bool - reportStatusClasses bool + metricsPerHost bool + reportStatusClasses bool } var requestTags = []string{ @@ -98,9 +98,13 @@ var requestTags = []string{ "canary", } +// DefObjectives was removed in https://github.com/prometheus/client_golang/pull/262 +// updating the library to latest version changed the output of the metrics +var defObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001} + // NewSocketCollector creates a new SocketCollector instance using // the ingress watch namespace and class used by the controller -func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPerUndefinedHost, reportStatusClasses bool, buckets HistogramBuckets, bucketFactor float64, maxBuckets uint32, excludeMetrics []string) (*SocketCollector, error) { +func NewSocketCollector(pod, namespace, class string, metricsPerHost, reportStatusClasses bool, buckets HistogramBuckets, excludeMetrics []string) (*SocketCollector, error) { socket := "/tmp/nginx/prometheus-nginx.socket" // unix sockets must be unlink()ed before being used //nolint:errcheck // Ignore unlink error @@ -140,19 +144,16 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer sc := &SocketCollector{ listener: listener, - metricsPerHost: metricsPerHost, - metricsPerUndefinedHost: metricsPerUndefinedHost, - reportStatusClasses: reportStatusClasses, + metricsPerHost: metricsPerHost, + reportStatusClasses: reportStatusClasses, connectTime: histogramMetric( &prometheus.HistogramOpts{ - Name: "connect_duration_seconds", - Help: "The time spent on establishing a connection with the upstream server", - Namespace: PrometheusNamespace, - ConstLabels: constLabels, - Buckets: buckets.TimeBuckets, - NativeHistogramBucketFactor: bucketFactor, - NativeHistogramMaxBucketNumber: maxBuckets, + Name: "connect_duration_seconds", + Help: "The time spent on establishing a connection with the upstream server", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Buckets: buckets.TimeBuckets, }, requestTags, em, @@ -161,13 +162,11 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer headerTime: histogramMetric( &prometheus.HistogramOpts{ - Name: "header_duration_seconds", - Help: "The time spent on receiving first header from the upstream server", - Namespace: PrometheusNamespace, - ConstLabels: constLabels, - Buckets: buckets.TimeBuckets, - NativeHistogramBucketFactor: bucketFactor, - NativeHistogramMaxBucketNumber: maxBuckets, + Name: "header_duration_seconds", + Help: "The time spent on receiving first header from the upstream server", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Buckets: buckets.TimeBuckets, }, requestTags, em, @@ -175,13 +174,11 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer ), responseTime: histogramMetric( &prometheus.HistogramOpts{ - Name: "response_duration_seconds", - Help: "The time spent on receiving the response from the upstream server", - Namespace: PrometheusNamespace, - ConstLabels: constLabels, - Buckets: buckets.TimeBuckets, - NativeHistogramBucketFactor: bucketFactor, - NativeHistogramMaxBucketNumber: maxBuckets, + Name: "response_duration_seconds", + Help: "The time spent on receiving the response from the upstream server", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Buckets: buckets.TimeBuckets, }, requestTags, em, @@ -190,13 +187,11 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer requestTime: histogramMetric( &prometheus.HistogramOpts{ - Name: "request_duration_seconds", - Help: "The request processing time in milliseconds", - Namespace: PrometheusNamespace, - ConstLabels: constLabels, - Buckets: buckets.TimeBuckets, - NativeHistogramBucketFactor: bucketFactor, - NativeHistogramMaxBucketNumber: maxBuckets, + Name: "request_duration_seconds", + Help: "The request processing time in milliseconds", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Buckets: buckets.TimeBuckets, }, requestTags, em, @@ -205,13 +200,11 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer responseLength: histogramMetric( &prometheus.HistogramOpts{ - Name: "response_size", - Help: "The response length (including request line, header, and request body)", - Namespace: PrometheusNamespace, - ConstLabels: constLabels, - Buckets: buckets.LengthBuckets, - NativeHistogramBucketFactor: bucketFactor, - NativeHistogramMaxBucketNumber: maxBuckets, + Name: "response_size", + Help: "The response length (including request line, header, and request body)", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Buckets: buckets.LengthBuckets, }, requestTags, em, @@ -220,13 +213,11 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer requestLength: histogramMetric( &prometheus.HistogramOpts{ - Name: "request_size", - Help: "The request length (including request line, header, and request body)", - Namespace: PrometheusNamespace, - ConstLabels: constLabels, - Buckets: buckets.LengthBuckets, - NativeHistogramBucketFactor: bucketFactor, - NativeHistogramMaxBucketNumber: maxBuckets, + Name: "request_size", + Help: "The request length (including request line, header, and request body)", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Buckets: buckets.LengthBuckets, }, requestTags, em, @@ -257,6 +248,19 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost, metricsPer em, mm, ), + + upstreamLatency: summaryMetric( + &prometheus.SummaryOpts{ + Name: "ingress_upstream_latency_seconds", + Help: "DEPRECATED Upstream service latency per Ingress", + Namespace: PrometheusNamespace, + ConstLabels: constLabels, + Objectives: defObjectives, + }, + []string{"ingress", "namespace", "service", "canary"}, + em, + mm, + ), } sc.metricMapping = mm @@ -271,6 +275,18 @@ func containsMetric(excludeMetrics map[string]struct{}, name string) bool { return false } +func summaryMetric(opts *prometheus.SummaryOpts, requestTags []string, excludeMetrics map[string]struct{}, metricMapping metricMapping) *prometheus.SummaryVec { + if containsMetric(excludeMetrics, opts.Name) { + return nil + } + m := prometheus.NewSummaryVec( + *opts, + requestTags, + ) + metricMapping[prometheus.BuildFQName(PrometheusNamespace, "", opts.Name)] = m + return m +} + func counterMetric(opts *prometheus.CounterOpts, requestTags []string, excludeMetrics map[string]struct{}, metricMapping metricMapping) *prometheus.CounterVec { if containsMetric(excludeMetrics, opts.Name) { return nil @@ -308,8 +324,8 @@ func (sc *SocketCollector) handleMessage(msg []byte) { for i := range statsBatch { stats := &statsBatch[i] - if sc.metricsPerHost && !sc.hosts.Has(stats.Host) && !sc.metricsPerUndefinedHost { - klog.V(3).InfoS("Skipping metric for host not explicitly defined in an ingress", "host", stats.Host) + if sc.metricsPerHost && !sc.hosts.Has(stats.Host) { + klog.V(3).InfoS("Skipping metric for host not being served", "host", stats.Host) continue } @@ -342,6 +358,13 @@ func (sc *SocketCollector) handleMessage(msg []byte) { collectorLabels["host"] = stats.Host } + latencyLabels := prometheus.Labels{ + "namespace": stats.Namespace, + "ingress": stats.Ingress, + "service": stats.Service, + "canary": stats.Canary, + } + if sc.requests != nil { requestsMetric, err := sc.requests.GetMetricWith(collectorLabels) if err != nil { @@ -360,6 +383,15 @@ func (sc *SocketCollector) handleMessage(msg []byte) { connectTimeMetric.Observe(stats.Latency) } } + + if sc.upstreamLatency != nil { + latencyMetric, err := sc.upstreamLatency.GetMetricWith(latencyLabels) + if err != nil { + klog.ErrorS(err, "Error fetching latency metric") + } else { + latencyMetric.Observe(stats.Latency) + } + } } if stats.HeaderTime != -1 && sc.headerTime != nil { diff --git a/internal/ingress/metric/collectors/socket_test.go b/internal/ingress/metric/collectors/socket_test.go index 3a1f29f35..2113b4725 100644 --- a/internal/ingress/metric/collectors/socket_test.go +++ b/internal/ingress/metric/collectors/socket_test.go @@ -83,19 +83,15 @@ func TestCollector(t *testing.T) { prometheus.ExponentialBuckets(10, 10, 7), } - bucketFactor := 1.1 - maxBuckets := uint32(100) - cases := []struct { - name string - data []string - metrics []string - metricsPerUndefinedHost bool - useStatusClasses bool - excludeMetrics []string - wantBefore string - removeIngresses []string - wantAfter string + name string + data []string + metrics []string + useStatusClasses bool + excludeMetrics []string + wantBefore string + removeIngresses []string + wantAfter string }{ { name: "invalid metric object should not increase prometheus metrics", @@ -592,69 +588,13 @@ func TestCollector(t *testing.T) { nginx_ingress_controller_response_duration_seconds_count{canary="",controller_class="ingress",controller_namespace="default",controller_pod="pod",host="testshop.com",ingress="web-yml",method="GET",namespace="test-app-production",path="/admin",service="test-app",status="2xx"} 1 `, }, - { - name: "metrics with a host should not be dropped when the host is not in the hosts slice but metricsPerUndefinedHost is true", - data: []string{`[{ - "host":"wildcard.testshop.com", - "status":"200", - "bytesSent":150.0, - "method":"GET", - "path":"/admin", - "requestLength":300.0, - "requestTime":60.0, - "upstreamLatency":1.0, - "upstreamHeaderTime":5.0, - "upstreamName":"test-upstream", - "upstreamIP":"1.1.1.1:8080", - "upstreamResponseTime":200, - "upstreamStatus":"220", - "namespace":"test-app-production", - "ingress":"web-yml", - "service":"test-app", - "canary":"" - }]`}, - excludeMetrics: []string{"response_duration_seconds2", "test.*", "nginx_ingress_.*", "response_duration_secon"}, - metrics: []string{"nginx_ingress_controller_requests"}, - metricsPerUndefinedHost: true, - useStatusClasses: true, - wantBefore: ` - # HELP nginx_ingress_controller_requests The total number of client requests - # TYPE nginx_ingress_controller_requests counter - nginx_ingress_controller_requests{canary="",controller_class="ingress",controller_namespace="default",controller_pod="pod",host="wildcard.testshop.com",ingress="web-yml",method="GET",namespace="test-app-production",path="/admin",service="test-app",status="2xx"} 1 - `, - }, - { - name: "metrics with a host should be dropped when the host is not in the hosts slice", - data: []string{`[{ - "host":"wildcard.testshop.com", - "status":"200", - "bytesSent":150.0, - "method":"GET", - "path":"/admin", - "requestLength":300.0, - "requestTime":60.0, - "upstreamLatency":1.0, - "upstreamHeaderTime":5.0, - "upstreamName":"test-upstream", - "upstreamIP":"1.1.1.1:8080", - "upstreamResponseTime":200, - "upstreamStatus":"220", - "namespace":"test-app-production", - "ingress":"web-yml", - "service":"test-app", - "canary":"" - }]`}, - excludeMetrics: []string{"response_duration_seconds2", "test.*", "nginx_ingress_.*", "response_duration_secon"}, - metrics: []string{"nginx_ingress_controller_requests"}, - useStatusClasses: true, - }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { registry := prometheus.NewPedanticRegistry() - sc, err := NewSocketCollector("pod", "default", "ingress", true, c.metricsPerUndefinedHost, c.useStatusClasses, buckets, bucketFactor, maxBuckets, c.excludeMetrics) + sc, err := NewSocketCollector("pod", "default", "ingress", true, c.useStatusClasses, buckets, c.excludeMetrics) if err != nil { t.Errorf("%v: unexpected error creating new SocketCollector: %v", c.name, err) } diff --git a/internal/ingress/metric/main.go b/internal/ingress/metric/main.go index 9ed401d19..93c31622c 100644 --- a/internal/ingress/metric/main.go +++ b/internal/ingress/metric/main.go @@ -71,7 +71,7 @@ type collector struct { } // NewCollector creates a new metric collector the for ingress controller -func NewCollector(metricsPerHost, metricsPerUndefinedHost, reportStatusClasses bool, registry *prometheus.Registry, ingressclass string, buckets collectors.HistogramBuckets, bucketFactor float64, maxBuckets uint32, excludedSocketMetrics []string) (Collector, error) { +func NewCollector(metricsPerHost, reportStatusClasses bool, registry *prometheus.Registry, ingressclass string, buckets collectors.HistogramBuckets, excludedSocketMetrics []string) (Collector, error) { podNamespace := os.Getenv("POD_NAMESPACE") if podNamespace == "" { podNamespace = "default" @@ -89,7 +89,7 @@ func NewCollector(metricsPerHost, metricsPerUndefinedHost, reportStatusClasses b return nil, err } - s, err := collectors.NewSocketCollector(podName, podNamespace, ingressclass, metricsPerHost, metricsPerUndefinedHost, reportStatusClasses, buckets, bucketFactor, maxBuckets, excludedSocketMetrics) + s, err := collectors.NewSocketCollector(podName, podNamespace, ingressclass, metricsPerHost, reportStatusClasses, buckets, excludedSocketMetrics) if err != nil { return nil, err } diff --git a/internal/ingress/resolver/main.go b/internal/ingress/resolver/main.go index 259f44e49..7d17f4e16 100644 --- a/internal/ingress/resolver/main.go +++ b/internal/ingress/resolver/main.go @@ -29,10 +29,10 @@ type Resolver interface { // GetSecurityConfiguration returns the configuration options from Ingress GetSecurityConfiguration() defaults.SecurityConfiguration - // GetConfigMap searches for configmap containing the namespace and name using the character / + // GetConfigMap searches for configmap containing the namespace and name usting the character / GetConfigMap(string) (*apiv1.ConfigMap, error) - // GetSecret searches for secrets containing the namespace and name using the character / + // GetSecret searches for secrets containing the namespace and name using a the character / GetSecret(string) (*apiv1.Secret, error) // GetAuthCertificate resolves a given secret name into an SSL certificate and CRL. @@ -42,7 +42,7 @@ type Resolver interface { // ca.crl: contains the revocation list used for authentication GetAuthCertificate(string) (*AuthSSLCert, error) - // GetService searches for services containing the namespace and name using the character / + // GetService searches for services containing the namespace and name using a the character / GetService(string) (*apiv1.Service, error) } diff --git a/internal/ingress/resolver/mock.go b/internal/ingress/resolver/mock.go index 3abfe7eda..679c3b13c 100644 --- a/internal/ingress/resolver/mock.go +++ b/internal/ingress/resolver/mock.go @@ -39,7 +39,7 @@ func (m Mock) GetDefaultBackend() defaults.Backend { func (m Mock) GetSecurityConfiguration() defaults.SecurityConfiguration { defRisk := m.AnnotationsRiskLevel if defRisk == "" { - defRisk = "High" + defRisk = "Critical" } return defaults.SecurityConfiguration{ AnnotationsRiskLevel: defRisk, @@ -47,7 +47,7 @@ func (m Mock) GetSecurityConfiguration() defaults.SecurityConfiguration { } } -// GetSecret searches for secrets containing the namespace and name using the character / +// GetSecret searches for secrets contenating the namespace and name using a the character / func (m Mock) GetSecret(string) (*apiv1.Secret, error) { return nil, nil } @@ -60,12 +60,12 @@ func (m Mock) GetAuthCertificate(string) (*AuthSSLCert, error) { return nil, nil } -// GetService searches for services containing the namespace and name using the character / +// GetService searches for services contenating the namespace and name using a the character / func (m Mock) GetService(string) (*apiv1.Service, error) { return nil, nil } -// GetConfigMap searches for configMaps containing the namespace and name using the character / +// GetConfigMap searches for configMaps contenating the namespace and name using a the character / func (m Mock) GetConfigMap(name string) (*apiv1.ConfigMap, error) { if v, ok := m.ConfigMaps[name]; ok { return v, nil diff --git a/internal/net/ssl/ssl.go b/internal/net/ssl/ssl.go index 0592303bc..f8bac2377 100644 --- a/internal/net/ssl/ssl.go +++ b/internal/net/ssl/ssl.go @@ -442,7 +442,7 @@ func getFakeHostSSLCert(host string) (cert, key []byte) { // fullChainCert checks if a certificate file contains issues in the intermediate CA chain // Returns a new certificate with the intermediate certificates. -// If the certificate does not contain issues with the chain it returns an empty byte array +// If the certificate does not contains issues with the chain it return an empty byte array func fullChainCert(in []byte) ([]byte, error) { cert, err := certUtil.DecodeCertificate(in) if err != nil { @@ -523,7 +523,7 @@ func (tl *TLSListener) GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, e return tl.certificate, tl.err } -// TLSConfig instantiates a TLS configuration, always providing an up to date certificate +// TLSConfig instanciates a TLS configuration, always providing an up to date certificate func (tl *TLSListener) TLSConfig() *tls.Config { return &tls.Config{ GetCertificate: tl.GetCertificate, diff --git a/internal/task/queue.go b/internal/task/queue.go index 8753bed34..f92f2a501 100644 --- a/internal/task/queue.go +++ b/internal/task/queue.go @@ -36,7 +36,7 @@ var keyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc // which timestamp is older than the last successful get operation. type Queue struct { // queue is the work queue the worker polls - queue workqueue.TypedRateLimitingInterface[any] + queue workqueue.RateLimitingInterface // sync is called for each item in the queue sync func(interface{}) error // workerDone is closed when the worker exits @@ -172,7 +172,7 @@ func NewTaskQueue(syncFn func(interface{}) error) *Queue { // NewCustomTaskQueue creates a new custom task queue with the given sync function. func NewCustomTaskQueue(syncFn func(interface{}) error, fn func(interface{}) (interface{}, error)) *Queue { q := &Queue{ - queue: workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[any]()), + queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), sync: syncFn, workerDone: make(chan bool), fn: fn, diff --git a/magefiles/go.mod b/magefiles/go.mod index f11ab740e..d41baf17e 100644 --- a/magefiles/go.mod +++ b/magefiles/go.mod @@ -1,6 +1,6 @@ module k8s.io/ingress-nginx/magefiles -go 1.23.6 +go 1.21 require ( github.com/blang/semver/v4 v4.0.0 @@ -28,7 +28,7 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/stretchr/testify v1.9.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.21.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/magefiles/go.sum b/magefiles/go.sum index 8684d4701..16bc8460f 100644 --- a/magefiles/go.sum +++ b/magefiles/go.sum @@ -89,8 +89,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -121,16 +121,16 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= diff --git a/magefiles/steps/helm.go b/magefiles/steps/helm.go index 73c9b0b3b..245f5e1c0 100644 --- a/magefiles/steps/helm.go +++ b/magefiles/steps/helm.go @@ -170,7 +170,7 @@ func runHelmDocs() error { if err != nil { return err } - err = sh.RunV("helm-docs", "--chart-search-root", "${PWD}/charts") + err = sh.RunV("helm-docs", "--chart-search-root=${PWD}/charts") if err != nil { return err } @@ -181,7 +181,7 @@ func installHelmDocs() error { utils.Info("HELM Install HelmDocs") g0 := sh.RunCmd("go") - err := g0("install", "github.com/norwoodj/helm-docs/cmd/helm-docs@latest") + err := g0("install", "github.com/norwoodj/helm-docs/cmd/helm-docs@v1.11.0") if err != nil { return err } diff --git a/magefiles/utils/helm.go b/magefiles/utils/helm.go index cb8acae57..dea68caab 100644 --- a/magefiles/utils/helm.go +++ b/magefiles/utils/helm.go @@ -31,6 +31,7 @@ type IngressChartValue struct { RunAsUser int `yaml:"runAsUser"` AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"` } `yaml:"image"` + ExistingPsp string `yaml:"existingPsp"` ContainerName string `yaml:"containerName"` ContainerPort struct { HTTP int `yaml:"http"` @@ -207,6 +208,13 @@ type IngressChartValue struct { ExtraVolumes []interface{} `yaml:"extraVolumes"` ExtraInitContainers []interface{} `yaml:"extraInitContainers"` ExtraModules []interface{} `yaml:"extraModules"` + Opentelemetry struct { + Enabled bool `yaml:"enabled"` + Image string `yaml:"image"` + ContainerSecurityContext struct { + AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"` + } `yaml:"containerSecurityContext"` + } `yaml:"opentelemetry"` AdmissionWebhooks struct { Annotations struct{} `yaml:"annotations"` Enabled bool `yaml:"enabled"` @@ -218,6 +226,7 @@ type IngressChartValue struct { NamespaceSelector struct{} `yaml:"namespaceSelector"` ObjectSelector struct{} `yaml:"objectSelector"` Labels struct{} `yaml:"labels"` + ExistingPsp string `yaml:"existingPsp"` NetworkPolicyEnabled bool `yaml:"networkPolicyEnabled"` Service struct { Annotations struct{} `yaml:"annotations"` @@ -320,6 +329,7 @@ type IngressChartValue struct { ReadOnlyRootFilesystem bool `yaml:"readOnlyRootFilesystem"` AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"` } `yaml:"image"` + ExistingPsp string `yaml:"existingPsp"` ExtraArgs struct{} `yaml:"extraArgs"` ServiceAccount struct { Create bool `yaml:"create"` @@ -378,6 +388,9 @@ type IngressChartValue struct { Create bool `yaml:"create"` Scope bool `yaml:"scope"` } `yaml:"rbac"` + PodSecurityPolicy struct { + Enabled bool `yaml:"enabled"` + } `yaml:"podSecurityPolicy"` ServiceAccount struct { Create bool `yaml:"create"` Name string `yaml:"name"` diff --git a/mkdocs.yml b/mkdocs.yml index b59546c9c..cbc2988ce 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,7 +50,6 @@ theme: - navigation.tabs.sticky - navigation.instant - navigation.sections - - content.code.copy palette: primary: "teal" @@ -84,7 +83,6 @@ nav: - Introduction: "user-guide/nginx-configuration/index.md" - Basic usage: "user-guide/basic-usage.md" - Annotations: "user-guide/nginx-configuration/annotations.md" - - Annotations Risks: "user-guide/nginx-configuration/annotations-risk.md" - ConfigMap: "user-guide/nginx-configuration/configmap.md" - Custom NGINX template: "user-guide/nginx-configuration/custom-template.md" - Log format: "user-guide/nginx-configuration/log-format.md" @@ -125,6 +123,7 @@ nav: - Rewrite: "examples/rewrite/README.md" - Static IPs: "examples/static-ip/README.md" - TLS termination: "examples/tls-termination/README.md" + - Pod Security Policy (PSP): "examples/psp/README.md" - Open Policy Agent rules: "examples/openpolicyagent/README.md" - Canary Deployments: "examples/canary/README.md" - Developer Guide: diff --git a/pkg/apis/ingress/types.go b/pkg/apis/ingress/types.go index ccdd49fe9..ca5df56c9 100644 --- a/pkg/apis/ingress/types.go +++ b/pkg/apis/ingress/types.go @@ -27,8 +27,8 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/authtls" "k8s.io/ingress-nginx/internal/ingress/annotations/connection" "k8s.io/ingress-nginx/internal/ingress/annotations/cors" - "k8s.io/ingress-nginx/internal/ingress/annotations/customheaders" "k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi" + "k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit" "k8s.io/ingress-nginx/internal/ingress/annotations/ipallowlist" "k8s.io/ingress-nginx/internal/ingress/annotations/ipdenylist" "k8s.io/ingress-nginx/internal/ingress/annotations/log" @@ -198,10 +198,10 @@ type Server struct { Aliases []string `json:"aliases,omitempty"` // RedirectFromToWWW returns if a redirect to/from prefix www is required RedirectFromToWWW bool `json:"redirectFromToWWW,omitempty"` - // CertificateAuth indicates this server requires mutual authentication + // CertificateAuth indicates the this server requires mutual authentication // +optional CertificateAuth authtls.Config `json:"certificateAuth"` - // ProxySSL indicates this server uses client certificate to access backends + // ProxySSL indicates the this server uses client certificate to access backends // +optional ProxySSL proxyssl.Config `json:"proxySSL"` // ServerSnippet returns the snippet of server @@ -219,7 +219,7 @@ type Server struct { // Location describes an URI inside a server. // Also contains additional information about annotations in the Ingress. // -// In some cases when more than one annotation is defined a particular order in the execution +// In some cases when more than one annotations is defined a particular order in the execution // is required. // The chain in the execution order of annotations should be: // - Denylist @@ -263,8 +263,7 @@ type Location struct { BasicDigestAuth auth.Config `json:"basicDigestAuth,omitempty"` // Denied returns an error when this location cannot not be allowed // Requesting a denied location should return HTTP code 403. - Denied *string `json:"denied,omitempty"` - CustomHeaders customheaders.Config `json:"customHeaders,omitempty"` + Denied *string `json:"denied,omitempty"` // CorsConfig returns the Cors Configuration for the ingress rule // +optional CorsConfig cors.Config `json:"corsConfig,omitempty"` @@ -284,6 +283,10 @@ type Location struct { // The Redirect annotation precedes RateLimit // +optional RateLimit ratelimit.Config `json:"rateLimit,omitempty"` + // GlobalRateLimit similar to RateLimit + // but this is applied globally across multiple replicas. + // +optional + GlobalRateLimit globalratelimit.Config `json:"globalRateLimit,omitempty"` // Redirect describes a temporal o permanent redirection this location. // +optional Redirect redirect.Config `json:"redirect,omitempty"` @@ -342,7 +345,7 @@ type Location struct { // CustomHTTPErrors specifies the error codes that should be intercepted. // +optional CustomHTTPErrors []int `json:"custom-http-errors"` - // ProxyInterceptErrors disables error interception when using CustomHTTPErrors + // ProxyInterceptErrors disables error intecepting when using CustomHTTPErrors // e.g. custom 404 and 503 when service-a does not exist or is not available // but service-a can return 404 and 503 error codes without intercept // +optional diff --git a/pkg/apis/ingress/types_equals.go b/pkg/apis/ingress/types_equals.go index 6fba3bd45..eeed9a06e 100644 --- a/pkg/apis/ingress/types_equals.go +++ b/pkg/apis/ingress/types_equals.go @@ -390,6 +390,9 @@ func (l1 *Location) Equal(l2 *Location) bool { if !(&l1.RateLimit).Equal(&l2.RateLimit) { return false } + if !(&l1.GlobalRateLimit).Equal(&l2.GlobalRateLimit) { + return false + } if !(&l1.Redirect).Equal(&l2.Redirect) { return false } @@ -467,10 +470,6 @@ func (l1 *Location) Equal(l2 *Location) bool { return false } - if !l1.CustomHeaders.Equal(&l2.CustomHeaders) { - return false - } - return true } diff --git a/pkg/flags/flags.go b/pkg/flags/flags.go index ce24160fd..d3bc4ee86 100644 --- a/pkg/flags/flags.go +++ b/pkg/flags/flags.go @@ -17,7 +17,6 @@ limitations under the License. package flags import ( - "errors" "flag" "fmt" "net" @@ -133,9 +132,6 @@ Requires setting the publish-service parameter to a valid Service reference.`) electionID = flags.String("election-id", "ingress-controller-leader", `Election id to use for Ingress status updates.`) - electionTTL = flags.Duration("election-ttl", 30*time.Second, - `Duration a leader election is valid before it's getting re-elected`) - updateStatusOnShutdown = flags.Bool("update-status-on-shutdown", true, `Update the load-balancer status of Ingress objects when the controller shuts down. Requires the update-status parameter.`) @@ -150,17 +146,14 @@ Requires the update-status parameter.`) enableSSLPassthrough = flags.Bool("enable-ssl-passthrough", false, `Enable SSL Passthrough.`) - disableLeaderElection = flags.Bool("disable-leader-election", false, - `Disable Leader Election on NGINX Controller.`) - disableServiceExternalName = flags.Bool("disable-svc-external-name", false, `Disable support for Services of type ExternalName.`) annotationsPrefix = flags.String("annotations-prefix", parser.DefaultAnnotationsPrefix, `Prefix of the Ingress annotations specific to the NGINX controller.`) - enableAnnotationValidation = flags.Bool("enable-annotation-validation", true, - `If true, will enable the annotation validation feature. Defaults to true`) + enableAnnotationValidation = flags.Bool("enable-annotation-validation", false, + `If true, will enable the annotation validation feature. This value will be defaulted to true on a future release`) enableSSLChainCompletion = flags.Bool("enable-ssl-chain-completion", false, `Autocomplete SSL certificate chains with missing intermediate CA certificates. @@ -174,20 +167,16 @@ extension for this to succeed.`) `Customized address (or addresses, separated by comma) to set as the load-balancer status of Ingress objects this controller satisfies. Requires the update-status parameter.`) - enableMetrics = flags.Bool("enable-metrics", false, + enableMetrics = flags.Bool("enable-metrics", true, `Enables the collection of NGINX metrics.`) metricsPerHost = flags.Bool("metrics-per-host", true, `Export metrics per-host.`) - metricsPerUndefinedHost = flags.Bool("metrics-per-undefined-host", false, - `Export metrics per-host even if the host is not defined in an ingress. Requires --metrics-per-host to be set to true.`) reportStatusClasses = flags.Bool("report-status-classes", false, `Use status classes (2xx, 3xx, 4xx and 5xx) instead of status codes in metrics.`) timeBuckets = flags.Float64Slice("time-buckets", prometheus.DefBuckets, "Set of buckets which will be used for prometheus histogram metrics such as RequestTime, ResponseTime.") lengthBuckets = flags.Float64Slice("length-buckets", prometheus.LinearBuckets(10, 10, 10), "Set of buckets which will be used for prometheus histogram metrics such as RequestLength, ResponseLength.") sizeBuckets = flags.Float64Slice("size-buckets", prometheus.ExponentialBuckets(10, 10, 7), "Set of buckets which will be used for prometheus histogram metrics such as BytesSent.") - bucketFactor = flags.Float64("bucket-factor", 0, "Bucket factor for native histograms. Value must be > 1 for enabling native histograms.") - maxBuckets = flags.Uint32("max-buckets", 100, "Maximum number of buckets for native histograms.") excludeSocketMetrics = flags.StringSlice("exclude-socket-metrics", []string{}, "et of socket request metrics to exclude which won't be exported nor being calculated. E.g. 'nginx_ingress_controller_success,nginx_ingress_controller_header_duration_seconds'.") monitorMaxBatchSize = flags.Int("monitor-max-batch-size", 10000, "Max batch size of NGINX metrics.") @@ -237,7 +226,7 @@ Takes the form ":port". If not provided, no admission controller is starte flags.StringVar(&nginx.MaxmindMirror, "maxmind-mirror", "", `Maxmind mirror url (example: http://geoip.local/databases.`) flags.StringVar(&nginx.MaxmindLicenseKey, "maxmind-license-key", "", `Maxmind license key to download GeoLite2 Databases. -https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geolite2-databases/ .`) +https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases .`) flags.StringVar(&nginx.MaxmindEditionIDs, "maxmind-edition-ids", "GeoLite2-City,GeoLite2-ASN", `Maxmind edition ids to download GeoLite2 Databases.`) flags.IntVar(&nginx.MaxmindRetriesCount, "maxmind-retries-count", 1, "Number of attempts to download the GeoIP DB.") flags.DurationVar(&nginx.MaxmindRetriesTimeout, "maxmind-retries-timeout", time.Second*0, "Maxmind downloading delay between 1st and 2nd attempt, 0s - do not retry to download if something went wrong.") @@ -322,14 +311,6 @@ https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geol } } - if *metricsPerUndefinedHost && !*metricsPerHost { - return false, nil, errors.New("--metrics-per-undefined-host=true must be passed with --metrics-per-host=true") - } - - if *electionTTL <= 0 { - *electionTTL = 30 * time.Second - } - histogramBuckets := &collectors.HistogramBuckets{ TimeBuckets: *timeBuckets, LengthBuckets: *lengthBuckets, @@ -343,20 +324,15 @@ https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geol KubeConfigFile: *kubeConfigFile, UpdateStatus: *updateStatus, ElectionID: *electionID, - ElectionTTL: *electionTTL, EnableProfiling: *profiling, EnableMetrics: *enableMetrics, MetricsPerHost: *metricsPerHost, - MetricsPerUndefinedHost: *metricsPerUndefinedHost, MetricsBuckets: histogramBuckets, - MetricsBucketFactor: *bucketFactor, - MetricsMaxBuckets: *maxBuckets, ReportStatusClasses: *reportStatusClasses, ExcludeSocketMetrics: *excludeSocketMetrics, MonitorMaxBatchSize: *monitorMaxBatchSize, DisableServiceExternalName: *disableServiceExternalName, EnableSSLPassthrough: *enableSSLPassthrough, - DisableLeaderElection: *disableLeaderElection, ResyncPeriod: *resyncPeriod, DefaultService: *defaultSvc, Namespace: *watchNamespace, diff --git a/pkg/flags/flags_test.go b/pkg/flags/flags_test.go index fdf153021..bffe2b16d 100644 --- a/pkg/flags/flags_test.go +++ b/pkg/flags/flags_test.go @@ -19,7 +19,6 @@ package flags import ( "os" "testing" - "time" ) func TestNoMandatoryFlag(t *testing.T) { @@ -110,131 +109,3 @@ func TestMaxmindRetryDownload(t *testing.T) { t.Fatalf("Expected an error parsing flags but none returned") } } - -func TestDisableLeaderElectionFlag(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--disable-leader-election", "--http-port", "80", "--https-port", "443"} - - _, conf, err := ParseFlags() - if err != nil { - t.Fatalf("Unexpected error parsing default flags: %v", err) - } - - if !conf.DisableLeaderElection { - t.Fatalf("Expected --disable-leader-election and conf.DisableLeaderElection as true, but found: %v", conf.DisableLeaderElection) - } -} - -func TestIfLeaderElectionDisabledFlagIsFalse(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443"} - - _, conf, err := ParseFlags() - if err != nil { - t.Fatalf("Unexpected error parsing default flags: %v", err) - } - - if conf.DisableLeaderElection { - t.Fatalf("Expected --disable-leader-election and conf.DisableLeaderElection as false, but found: %v", conf.DisableLeaderElection) - } -} - -func TestLeaderElectionTTLDefaultValue(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443"} - - _, conf, err := ParseFlags() - if err != nil { - t.Fatalf("Unexpected error parsing default flags: %v", err) - } - - if conf.ElectionTTL != 30*time.Second { - t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 30s, but found: %v", conf.ElectionTTL) - } -} - -func TestLeaderElectionTTLParseValueInSeconds(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443", "--election-ttl", "10s"} - - _, conf, err := ParseFlags() - if err != nil { - t.Fatalf("Unexpected error parsing default flags: %v", err) - } - - if conf.ElectionTTL != 10*time.Second { - t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 10s, but found: %v", conf.ElectionTTL) - } -} - -func TestLeaderElectionTTLParseValueInMinutes(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443", "--election-ttl", "10m"} - - _, conf, err := ParseFlags() - if err != nil { - t.Fatalf("Unexpected error parsing default flags: %v", err) - } - - if conf.ElectionTTL != 10*time.Minute { - t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 10m, but found: %v", conf.ElectionTTL) - } -} - -func TestLeaderElectionTTLParseValueInHours(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443", "--election-ttl", "1h"} - - _, conf, err := ParseFlags() - if err != nil { - t.Fatalf("Unexpected error parsing default flags: %v", err) - } - - if conf.ElectionTTL != 1*time.Hour { - t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 1h, but found: %v", conf.ElectionTTL) - } -} - -func TestMetricsPerUndefinedHost(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--metrics-per-undefined-host=true"} - - _, _, err := ParseFlags() - if err != nil { - t.Fatalf("Expected no error but got: %s", err) - } -} - -func TestMetricsPerUndefinedHostWithMetricsPerHostFalse(t *testing.T) { - ResetForTesting(func() { t.Fatal("Parsing failed") }) - - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--metrics-per-host=false", "--metrics-per-undefined-host=true"} - - _, _, err := ParseFlags() - if err == nil { - t.Fatalf("Expected an error parsing flags but none returned") - } -} diff --git a/pkg/util/runtime/cpu_linux.go b/pkg/util/runtime/cpu_linux.go index 7db609053..cfc49d924 100644 --- a/pkg/util/runtime/cpu_linux.go +++ b/pkg/util/runtime/cpu_linux.go @@ -36,42 +36,15 @@ import ( // // https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt func NumCPU() int { - return NumCPUWithCustomPath("") -} - -func NumCPUWithCustomPath(path string) int { cpus := runtime.NumCPU() - cgroupVersionCheckPath := path - - if cgroupVersionCheckPath == "" { - cgroupVersionCheckPath = "/sys/fs/cgroup/" + cgroupPath, err := libcontainercgroups.FindCgroupMountpoint("", "cpu") + if err != nil { + return cpus } - cgroupVersion := GetCgroupVersion(cgroupVersionCheckPath) - cpuQuota := int64(-1) - cpuPeriod := int64(-1) - - if cgroupVersion == 1 { - cgroupPath := "" - if path == "" { - cgroupPathRd, err := libcontainercgroups.FindCgroupMountpoint("", "cpu") - if err != nil { - return cpus - } - cgroupPath = cgroupPathRd - } else { - cgroupPath = path - } - cpuQuota = readCgroupFileToInt64(cgroupPath, "cpu.cfs_quota_us") - cpuPeriod = readCgroupFileToInt64(cgroupPath, "cpu.cfs_period_us") - } else if cgroupVersion == 2 { - cgroupPath := "/sys/fs/cgroup/" - if path != "" { - cgroupPath = path - } - cpuQuota, cpuPeriod = readCgroup2FileToInt64Tuple(cgroupPath, "cpu.max") - } + cpuQuota := readCgroupFileToInt64(cgroupPath, "cpu.cfs_quota_us") + cpuPeriod := readCgroupFileToInt64(cgroupPath, "cpu.cfs_period_us") if cpuQuota == -1 || cpuPeriod == -1 { return cpus @@ -80,66 +53,16 @@ func NumCPUWithCustomPath(path string) int { return int(math.Ceil(float64(cpuQuota) / float64(cpuPeriod))) } -func GetCgroupVersion(cgroupPath string) int64 { - // /sys/fs/cgroup/cgroup.controllers will not exist with cgroupsv1 - if _, err := os.Stat(filepath.Join(cgroupPath, "cgroup.controllers")); err == nil { - return 2 - } - - return 1 -} - -func readCgroup2StringToInt64Tuple(cgroupString string) (quota, period int64) { - // file contents looks like: $MAX $PERIOD - // $MAX can have value "max" indicating no limit - // it is possible for $PERIOD to be unset - - values := strings.Fields(cgroupString) - - if values[0] == "max" { - return -1, -1 - } - - cpuQuota, err := strconv.ParseInt(values[0], 10, 64) - if err != nil { - return -1, -1 - } - - if len(values) == 1 { - return cpuQuota, 100000 - } - - cpuPeriod, err := strconv.ParseInt(values[1], 10, 64) - if err != nil { - return -1, -1 - } - - return cpuQuota, cpuPeriod -} - -func readCgroup2FileToInt64Tuple(cgroupPath, cgroupFile string) (quota, period int64) { - contents, err := os.ReadFile(filepath.Join(cgroupPath, cgroupFile)) - if err != nil { - return -1, -1 - } - - return readCgroup2StringToInt64Tuple(string(contents)) -} - -func readCgroupStringToInt64(contents string) int64 { - strValue := strings.TrimSpace(contents) - if value, err := strconv.ParseInt(strValue, 10, 64); err == nil { - return value - } - - return -1 -} - func readCgroupFileToInt64(cgroupPath, cgroupFile string) int64 { contents, err := os.ReadFile(filepath.Join(cgroupPath, cgroupFile)) if err != nil { return -1 } - return readCgroupStringToInt64(string(contents)) + strValue := strings.TrimSpace(string(contents)) + if value, err := strconv.ParseInt(strValue, 10, 64); err == nil { + return value + } + + return -1 } diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index 9b7753b5d..a04cfe3de 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -59,7 +59,7 @@ RUN bash -xeu -c ' \ ); \ for dir in "${writeDirs[@]}"; do \ mkdir -p ${dir}; \ - chown -R www-data:www-data ${dir}; \ + chown -R www-data.www-data ${dir}; \ done' \ # LD_LIBRARY_PATH does not work so below is needed for opentelemetry/other modules # Put libs of newer modules under `/modules_mount//lib` and add that path below diff --git a/rootfs/Dockerfile-chroot b/rootfs/Dockerfile-chroot index 481b311e2..c06db2252 100644 --- a/rootfs/Dockerfile-chroot +++ b/rootfs/Dockerfile-chroot @@ -23,7 +23,7 @@ RUN apk update \ && apk upgrade \ && /chroot.sh -FROM alpine:3.21 +FROM alpine:3.20.0 ARG TARGETARCH ARG VERSION @@ -78,7 +78,7 @@ RUN bash -xeu -c ' \ ); \ for dir in "${writeDirs[@]}"; do \ mkdir -p ${dir}; \ - chown -R www-data:www-data ${dir}; \ + chown -R www-data.www-data ${dir}; \ done' \ # LD_LIBRARY_PATH does not work so below is needed for opentelemetry/other modules # Put libs of newer modules under `/modules_mount//lib` and add that path below @@ -103,7 +103,7 @@ RUN ln -sf /chroot/etc/nginx /etc/nginx \ && touch /chroot/var/log/nginx/access.log \ && chown www-data:www-data /chroot/var/log/nginx/access.log \ && echo "" > /chroot/etc/resolv.conf \ - && chown -R www-data:www-data /chroot/var/log/nginx /chroot/etc/resolv.conf \ + && chown -R www-data.www-data /chroot/var/log/nginx /chroot/etc/resolv.conf \ && mknod -m 0666 /chroot/dev/null c 1 3 \ && mknod -m 0666 /chroot/dev/random c 1 8 \ && mknod -m 0666 /chroot/dev/urandom c 1 9 \ diff --git a/rootfs/chroot.sh b/rootfs/chroot.sh index 4875ae535..38547b69c 100755 --- a/rootfs/chroot.sh +++ b/rootfs/chroot.sh @@ -39,7 +39,7 @@ writeDirs=( \ for dir in "${writeDirs[@]}"; do mkdir -p ${dir}; - chown -R www-data:www-data ${dir}; + chown -R www-data.www-data ${dir}; done mkdir -p /chroot/lib /chroot/proc /chroot/usr /chroot/bin /chroot/dev /chroot/run @@ -47,5 +47,4 @@ cp /etc/passwd /etc/group /etc/hosts /chroot/etc/ cp -a /usr/* /chroot/usr/ cp -a /etc/nginx/* /chroot/etc/nginx/ cp -a /etc/ingress-controller/* /chroot/etc/ingress-controller/ -cp /lib/ld-musl-* /chroot/lib/ -cp /usr/lib/libcrypto* /usr/lib/libssl* /usr/lib/libz* /chroot/usr/lib/ +cp /lib/ld-musl-* /lib/libcrypto* /lib/libssl* /lib/libz* /chroot/lib/ diff --git a/rootfs/etc/nginx/lua/global_throttle.lua b/rootfs/etc/nginx/lua/global_throttle.lua new file mode 100644 index 000000000..bea8cfd17 --- /dev/null +++ b/rootfs/etc/nginx/lua/global_throttle.lua @@ -0,0 +1,131 @@ +local resty_global_throttle = require("resty.global_throttle") +local resty_ipmatcher = require("resty.ipmatcher") +local util = require("util") + +local ngx = ngx +local ngx_exit = ngx.exit +local ngx_log = ngx.log +local ngx_ERR = ngx.ERR +local ngx_INFO = ngx.INFO + +local _M = {} + +local DECISION_CACHE = ngx.shared.global_throttle_cache + +-- it does not make sense to cache decision for too little time +-- the benefit of caching likely is negated if we cache for too little time +-- Lua Shared Dict's time resolution for expiry is 0.001. +local CACHE_THRESHOLD = 0.001 + +local DEFAULT_RAW_KEY = "remote_addr" + +local function should_ignore_request(ignored_cidrs) + if not ignored_cidrs or #ignored_cidrs == 0 then + return false + end + + local ignored_cidrs_matcher, err = resty_ipmatcher.new(ignored_cidrs) + if not ignored_cidrs_matcher then + ngx_log(ngx_ERR, "failed to initialize resty-ipmatcher: ", err) + return false + end + + local is_ignored + is_ignored, err = ignored_cidrs_matcher:match(ngx.var.remote_addr) + if err then + ngx_log(ngx_ERR, "failed to match ip: '", + ngx.var.remote_addr, "': ", err) + return false + end + + return is_ignored +end + +local function is_enabled(config, location_config) + if config.memcached.host == "" or config.memcached.port == 0 then + return false + end + if location_config.limit == 0 or + location_config.window_size == 0 then + return false + end + + if should_ignore_request(location_config.ignored_cidrs) then + return false + end + + return true +end + +local function get_namespaced_key_value(namespace, key_value) + return namespace .. key_value +end + +function _M.throttle(config, location_config) + if not is_enabled(config, location_config) then + return + end + + local key_value = util.generate_var_value(location_config.key) + if not key_value or key_value == "" then + key_value = ngx.var[DEFAULT_RAW_KEY] + end + + local namespaced_key_value = + get_namespaced_key_value(location_config.namespace, key_value) + + local is_limit_exceeding = DECISION_CACHE:get(namespaced_key_value) + if is_limit_exceeding then + ngx.var.global_rate_limit_exceeding = "c" + return ngx_exit(config.status_code) + end + + local my_throttle, err = resty_global_throttle.new( + location_config.namespace, + location_config.limit, + location_config.window_size, + { + provider = "memcached", + host = config.memcached.host, + port = config.memcached.port, + connect_timeout = config.memcached.connect_timeout, + max_idle_timeout = config.memcached.max_idle_timeout, + pool_size = config.memcached.pool_size, + } + ) + if err then + ngx.log(ngx.ERR, "faled to initialize resty_global_throttle: ", err) + -- fail open + return + end + + local desired_delay, estimated_final_count + estimated_final_count, desired_delay, err = my_throttle:process(key_value) + if err then + ngx.log(ngx.ERR, "error while processing key: ", err) + -- fail open + return + end + + if desired_delay then + if desired_delay > CACHE_THRESHOLD then + local ok + ok, err = + DECISION_CACHE:safe_add(namespaced_key_value, true, desired_delay) + if not ok then + if err ~= "exists" then + ngx_log(ngx_ERR, "failed to cache decision: ", err) + end + end + end + + ngx.var.global_rate_limit_exceeding = "y" + ngx_log(ngx_INFO, "limit is exceeding for ", + location_config.namespace, "/", key_value, + " with estimated_final_count: ", estimated_final_count) + + return ngx_exit(config.status_code) + end +end + +return _M diff --git a/rootfs/etc/nginx/lua/lua_ingress.lua b/rootfs/etc/nginx/lua/lua_ingress.lua index a513928cf..49e0f5b05 100644 --- a/rootfs/etc/nginx/lua/lua_ingress.lua +++ b/rootfs/etc/nginx/lua/lua_ingress.lua @@ -1,8 +1,8 @@ local ngx_re_split = require("ngx.re").split -local string_to_bool = require("util").string_to_bool local certificate_configured_for_current_request = require("certificate").configured_for_current_request +local global_throttle = require("global_throttle") local ngx = ngx local io = io @@ -109,16 +109,7 @@ end -- rewrite gets called in every location context. -- This is where we do variable assignments to be used in subsequent -- phases or redirection -function _M.rewrite() - - local location_config = { - force_ssl_redirect = string_to_bool(ngx.var.force_ssl_redirect), - ssl_redirect = string_to_bool(ngx.var.ssl_redirect), - force_no_ssl_redirect = string_to_bool(ngx.var.force_no_ssl_redirect), - preserve_trailing_slash = string_to_bool(ngx.var.preserve_trailing_slash), - use_port_in_redirects = string_to_bool(ngx.var.use_port_in_redirects), - } - +function _M.rewrite(location_config) ngx.var.pass_access_scheme = ngx.var.scheme ngx.var.best_http_host = ngx.var.http_host or ngx.var.host @@ -173,6 +164,7 @@ function _M.rewrite() return ngx_redirect(uri, config.http_redirect_code) end + global_throttle.throttle(config.global_throttle, location_config.global_throttle) end function _M.header() diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_balancer.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_balancer.lua deleted file mode 100644 index 977d3e964..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_balancer.lua +++ /dev/null @@ -1,2 +0,0 @@ -local balancer = require("balancer") -balancer.balance() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_balancer_tcp_udp.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_balancer_tcp_udp.lua deleted file mode 100644 index 0442df7d8..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_balancer_tcp_udp.lua +++ /dev/null @@ -1,2 +0,0 @@ -local tcp_udp_balancer = require("tcp_udp_balancer") -tcp_udp_balancer.balance() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_certificate.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_certificate.lua deleted file mode 100644 index d33d2171b..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_certificate.lua +++ /dev/null @@ -1,2 +0,0 @@ -local certificate = require("certificate") -certificate.call() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_configuration.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_configuration.lua deleted file mode 100644 index 7864f40ef..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_configuration.lua +++ /dev/null @@ -1,2 +0,0 @@ -local configuration = require("configuration") -configuration.call() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_content_tcp_udp.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_content_tcp_udp.lua deleted file mode 100644 index ed81e7ff3..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_content_tcp_udp.lua +++ /dev/null @@ -1,2 +0,0 @@ -local tcp_udp_configuration = require("tcp_udp_configuration") -tcp_udp_configuration.call() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_external_auth.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_external_auth.lua deleted file mode 100644 index 6c68cf07c..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_external_auth.lua +++ /dev/null @@ -1,30 +0,0 @@ -local auth_path = ngx.var.auth_path -local auth_keepalive_share_vars = ngx.var.auth_keepalive_share_vars -local auth_response_headers = ngx.var.auth_response_headers -local ngx_re_split = require("ngx.re").split -local ipairs = ipairs -local ngx_log = ngx.log -local ngx_ERR = ngx.ERR - -local res = ngx.location.capture(auth_path, { - method = ngx.HTTP_GET, body = '', - share_all_vars = auth_keepalive_share_vars }) - -if res.status == ngx.HTTP_OK then - local header_parts, err = ngx_re_split(auth_response_headers, ",") - if err then - ngx_log(ngx_ERR, err) - return - end - ngx.var.auth_cookie = res.header['Set-Cookie'] - for i, header_name in ipairs(header_parts) do - local varname = "authHeader" .. tostring(i) - ngx.var[varname] = res.header[header_name] - end - return -end - -if res.status == ngx.HTTP_UNAUTHORIZED or res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) -end -ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_init_tcp_udp.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_init_tcp_udp.lua deleted file mode 100644 index 926ab7a03..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_init_tcp_udp.lua +++ /dev/null @@ -1,2 +0,0 @@ -local tcp_udp_balancer = require("tcp_udp_balancer") -tcp_udp_balancer.init_worker() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_is_dynamic_lb_initialized.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_is_dynamic_lb_initialized.lua deleted file mode 100644 index ade3114b1..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_is_dynamic_lb_initialized.lua +++ /dev/null @@ -1,9 +0,0 @@ -local configuration = require("configuration") -local backend_data = configuration.get_backends_data() -if not backend_data then - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - return -end - -ngx.say("OK") -ngx.exit(ngx.HTTP_OK) \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_log.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_log.lua deleted file mode 100644 index 8f3d57be6..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_log.lua +++ /dev/null @@ -1,2 +0,0 @@ -local monitor = require("monitor") -monitor.call() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_log_block.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_log_block.lua deleted file mode 100644 index 72f6a6430..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_log_block.lua +++ /dev/null @@ -1,11 +0,0 @@ -local balancer = require("balancer") -local monitor = require("monitor") - -local luaconfig = ngx.shared.luaconfig -local enablemetrics = luaconfig:get("enablemetrics") - -balancer.log() - -if enablemetrics then - monitor.call() -end \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_rewrite_auth.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_rewrite_auth.lua deleted file mode 100644 index 0d16faba0..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_rewrite_auth.lua +++ /dev/null @@ -1 +0,0 @@ -ngx.var.cache_key = ngx.encode_base64(ngx.sha1_bin(ngx.var.tmp_cache_key)) \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_conf_srv_hdr_filter.lua b/rootfs/etc/nginx/lua/nginx/ngx_conf_srv_hdr_filter.lua deleted file mode 100644 index 311a9b433..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_conf_srv_hdr_filter.lua +++ /dev/null @@ -1,2 +0,0 @@ -local lua_ingress = require("lua_ingress") -lua_ingress.header() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_rewrite.lua b/rootfs/etc/nginx/lua/nginx/ngx_rewrite.lua deleted file mode 100644 index 66fdd6d55..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_rewrite.lua +++ /dev/null @@ -1,5 +0,0 @@ -local lua_ingress = require("lua_ingress") -local balancer = require("balancer") - -lua_ingress.rewrite() -balancer.rewrite() \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/nginx/ngx_srv_redirect.lua b/rootfs/etc/nginx/lua/nginx/ngx_srv_redirect.lua deleted file mode 100644 index 4b9445d00..000000000 --- a/rootfs/etc/nginx/lua/nginx/ngx_srv_redirect.lua +++ /dev/null @@ -1,24 +0,0 @@ -local request_uri = ngx.var.request_uri -local redirect_to = ngx.arg[1] - -local luaconfig = ngx.shared.luaconfig -local use_forwarded_headers = luaconfig:get("use_forwarded_headers") - -if string.sub(request_uri, -1) == "/" then - request_uri = string.sub(request_uri, 1, -2) -end - -local redirectScheme = ngx.var.scheme -local redirectPort = ngx.var.server_port - -if use_forwarded_headers then - if ngx.var.http_x_forwarded_proto then - redirectScheme = ngx.var.http_x_forwarded_proto - end - if ngx.var.http_x_forwarded_port then - redirectPort = ngx.var.http_x_forwarded_port - end -end - -return string.format("%s://%s:%s%s", redirectScheme, - redirect_to, redirectPort, request_uri) \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/ngx_conf_init.lua b/rootfs/etc/nginx/lua/ngx_conf_init.lua deleted file mode 100644 index 9789386ac..000000000 --- a/rootfs/etc/nginx/lua/ngx_conf_init.lua +++ /dev/null @@ -1,53 +0,0 @@ -local cjson = require("cjson.safe") - -collectgarbage("collect") -local f = io.open("/etc/nginx/lua/cfg.json", "r") -local content = f:read("*a") -f:close() -local configfile = cjson.decode(content) - -local luaconfig = ngx.shared.luaconfig -luaconfig:set("enablemetrics", configfile.enable_metrics) -luaconfig:set("use_forwarded_headers", configfile.use_forwarded_headers) --- init modules -local ok, res -ok, res = pcall(require, "lua_ingress") -if not ok then - error("require failed: " .. tostring(res)) -else - lua_ingress = res - lua_ingress.set_config(configfile) -end -ok, res = pcall(require, "configuration") -if not ok then - error("require failed: " .. tostring(res)) -else - configuration = res - if not configfile.listen_ports.status_port then - error("required status port not found") - end - configuration.prohibited_localhost_port = configfile.listen_ports.status_port -end -ok, res = pcall(require, "balancer") -if not ok then - error("require failed: " .. tostring(res)) -else - balancer = res -end -if configfile.enable_metrics then - ok, res = pcall(require, "monitor") - if not ok then - error("require failed: " .. tostring(res)) - else - monitor = res - end -end -ok, res = pcall(require, "certificate") -if not ok then - error("require failed: " .. tostring(res)) -else - certificate = res - if configfile.enable_ocsp then - certificate.is_ocsp_stapling_enabled = configfile.enable_ocsp - end -end \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/ngx_conf_init_stream.lua b/rootfs/etc/nginx/lua/ngx_conf_init_stream.lua deleted file mode 100644 index a78062d0a..000000000 --- a/rootfs/etc/nginx/lua/ngx_conf_init_stream.lua +++ /dev/null @@ -1,30 +0,0 @@ -local cjson = require("cjson.safe") -collectgarbage("collect") -local f = io.open("/etc/nginx/lua/cfg.json", "r") -local content = f:read("*a") -f:close() -local configfile = cjson.decode(content) --- init modules -local ok, res -ok, res = pcall(require, "configuration") -if not ok then - error("require failed: " .. tostring(res)) -else - configuration = res -end -ok, res = pcall(require, "tcp_udp_configuration") -if not ok then - error("require failed: " .. tostring(res)) -else - tcp_udp_configuration = res - if not configfile.listen_ports.status_port then - error("required status port not found") - end - tcp_udp_configuration.prohibited_localhost_port = configfile.listen_ports.status_port -end -ok, res = pcall(require, "tcp_udp_balancer") -if not ok then - error("require failed: " .. tostring(res)) -else - tcp_udp_balancer = res -end diff --git a/rootfs/etc/nginx/lua/ngx_conf_init_worker.lua b/rootfs/etc/nginx/lua/ngx_conf_init_worker.lua deleted file mode 100644 index cba866136..000000000 --- a/rootfs/etc/nginx/lua/ngx_conf_init_worker.lua +++ /dev/null @@ -1,15 +0,0 @@ -local cjson = require("cjson.safe") - -local f = io.open("/etc/nginx/lua/cfg.json", "r") -local content = f:read("*a") -f:close() -local configfile = cjson.decode(content) - -local lua_ingress = require("lua_ingress") -local balancer = require("balancer") -local monitor = require("monitor") -lua_ingress.init_worker() -balancer.init_worker() -if configfile.enable_metrics and configfile.monitor_batch_max_size then - monitor.init_worker(configfile.monitor_batch_max_size) -end \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/plugins.lua b/rootfs/etc/nginx/lua/plugins.lua new file mode 100644 index 000000000..55e208a32 --- /dev/null +++ b/rootfs/etc/nginx/lua/plugins.lua @@ -0,0 +1,61 @@ +local require = require +local ngx = ngx +local ipairs = ipairs +local string_format = string.format +local ngx_log = ngx.log +local INFO = ngx.INFO +local ERR = ngx.ERR +local pcall = pcall + +local _M = {} +local MAX_NUMBER_OF_PLUGINS = 20 +local plugins = {} + +local function load_plugin(name) + local path = string_format("plugins.%s.main", name) + + local ok, plugin = pcall(require, path) + if not ok then + ngx_log(ERR, string_format("error loading plugin \"%s\": %s", path, plugin)) + return + end + local index = #plugins + if (plugin.name == nil or plugin.name == '') then + plugin.name = name + end + plugins[index + 1] = plugin +end + +function _M.init(names) + local count = 0 + for _, name in ipairs(names) do + if count >= MAX_NUMBER_OF_PLUGINS then + ngx_log(ERR, "the total number of plugins exceed the maximum number: ", MAX_NUMBER_OF_PLUGINS) + break + end + load_plugin(name) + count = count + 1 -- ignore loading failure, just count the total + end +end + +function _M.run() + local phase = ngx.get_phase() + + for _, plugin in ipairs(plugins) do + if plugin[phase] then + ngx_log(INFO, string_format("running plugin \"%s\" in phase \"%s\"", plugin.name, phase)) + + -- TODO: consider sandboxing this, should we? + -- probably yes, at least prohibit plugin from accessing env vars etc + -- but since the plugins are going to be installed by ingress-nginx + -- operator they can be assumed to be safe also + local ok, err = pcall(plugin[phase]) + if not ok then + ngx_log(ERR, string_format("error while running plugin \"%s\" in phase \"%s\": %s", + plugin.name, phase, err)) + end + end + end +end + +return _M diff --git a/rootfs/etc/nginx/lua/plugins/README.md b/rootfs/etc/nginx/lua/plugins/README.md new file mode 100644 index 000000000..64f4912f0 --- /dev/null +++ b/rootfs/etc/nginx/lua/plugins/README.md @@ -0,0 +1,36 @@ +# Custom Lua plugins + +ingress-nginx uses [https://github.com/openresty/lua-nginx-module](https://github.com/openresty/lua-nginx-module) to run custom Lua code +within Nginx workers. It is recommended to familiarize yourself with that ecosystem before deploying your custom Lua based ingress-nginx plugin. + +### Writing a plugin + +Every ingress-nginx Lua plugin is expected to have `main.lua` file and all of its dependencies. +`main.lua` is the entry point of the plugin. The plugin manager uses convention over configuration +strategy and automatically runs functions defined in `main.lua` in the corresponding Nginx phase based on their name. + +Nginx has different [request processing phases](https://nginx.org/en/docs/dev/development_guide.html#http_phases). +By defining functions with the following names, you can run your custom Lua code in the corresponding Nginx phase: + + - `init_worker`: useful for initializing some data per Nginx worker process + - `rewrite`: useful for modifying request, changing headers, redirection, dropping request, doing authentication etc + - `header_filter`: this is called when backend response header is received, it is useful for modifying response headers + - `body_filter`: this is called when response body is received, it is useful for logging response body + - `log`: this is called when request processing is completed and a response is delivered to the client + +Check this [`hello_world`](https://github.com/kubernetes/ingress-nginx/tree/main/rootfs/etc/nginx/lua/plugins/hello_world) plugin as a simple example or refer to [OpenID Connect integration](https://github.com/ElvinEfendi/ingress-nginx-openidc/tree/master/rootfs/etc/nginx/lua/plugins/openidc) for more advanced usage. + +Do not forget to write tests for your plugin. + +### Installing a plugin + +There are two options: + + - mount your plugin into `/etc/nginx/lua/plugins/` in the ingress-nginx pod + - build your own ingress-nginx image like it is done in the [example](https://github.com/ElvinEfendi/ingress-nginx-openidc/tree/master/rootfs/etc/nginx/lua/plugins/openidc) and install your plugin during image build + +Mounting is the quickest option. + +### Enabling plugins + +Once your plugin is ready you need to use [`plugins` configuration setting](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#plugins) to activate it. Let's say you want to activate `hello_world` and `open_idc` plugins, then you set `plugins` setting to `"hello_world, open_idc"`. _Note_ that the plugins will be executed in the given order. diff --git a/rootfs/etc/nginx/lua/plugins/hello_world/main.lua b/rootfs/etc/nginx/lua/plugins/hello_world/main.lua new file mode 100644 index 000000000..03316c3ee --- /dev/null +++ b/rootfs/etc/nginx/lua/plugins/hello_world/main.lua @@ -0,0 +1,13 @@ +local ngx = ngx + +local _M = {} + +function _M.rewrite() + local ua = ngx.var.http_user_agent + + if ua == "hello" then + ngx.req.set_header("x-hello-world", "1") + end +end + +return _M diff --git a/rootfs/etc/nginx/lua/plugins/hello_world/test/main_test.lua b/rootfs/etc/nginx/lua/plugins/hello_world/test/main_test.lua new file mode 100644 index 000000000..5eda52259 --- /dev/null +++ b/rootfs/etc/nginx/lua/plugins/hello_world/test/main_test.lua @@ -0,0 +1,24 @@ + +local main = require("plugins.hello_world.main") + +-- The unit tests are run within a timer phase in a headless Nginx process. +-- Since `set_header` and `ngx.var.http_` API are disabled in this phase we have to stub it +-- to avoid `API disabled in the current context` error. + +describe("main", function() + describe("rewrite", function() + it("sets x-hello-world header to 1 when user agent is hello", function() + ngx.var = { http_user_agent = "hello" } + stub(ngx.req, "set_header") + main.rewrite() + assert.stub(ngx.req.set_header).was_called_with("x-hello-world", "1") + end) + + it("does not set x-hello-world header to 1 when user agent is not hello", function() + ngx.var = { http_user_agent = "not-hello" } + stub(ngx.req, "set_header") + main.rewrite() + assert.stub(ngx.req.set_header).was_not_called_with("x-hello-world", "1") + end) + end) +end) diff --git a/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua b/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua index 70723143b..80d0c0d0e 100644 --- a/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua +++ b/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua @@ -357,7 +357,7 @@ describe("Sticky", function() for _ = 1, 100 do local new_upstream = sticky_balancer_instance:balance() if change_on_failure == false then - -- upstream should be the same in spite of error, if change_on_failure option is false + -- upstream should be the same inspite of error, if change_on_failure option is false assert.equal(new_upstream, old_upstream) else -- upstream should change after error, if change_on_failure option is true diff --git a/rootfs/etc/nginx/lua/test/global_throttle_test.lua b/rootfs/etc/nginx/lua/test/global_throttle_test.lua new file mode 100644 index 000000000..b8db740ad --- /dev/null +++ b/rootfs/etc/nginx/lua/test/global_throttle_test.lua @@ -0,0 +1,258 @@ +local util = require("util") + +local function assert_request_rejected(config, location_config, opts) + stub(ngx, "exit") + + local global_throttle = require_without_cache("global_throttle") + assert.has_no.errors(function() + global_throttle.throttle(config, location_config) + end) + + assert.stub(ngx.exit).was_called_with(config.status_code) + if opts.with_cache then + assert.are.same("c", ngx.var.global_rate_limit_exceeding) + else + assert.are.same("y", ngx.var.global_rate_limit_exceeding) + end +end + +local function assert_request_not_rejected(config, location_config) + stub(ngx, "exit") + local cache_safe_add_spy = spy.on(ngx.shared.global_throttle_cache, "safe_add") + + local global_throttle = require_without_cache("global_throttle") + assert.has_no.errors(function() + global_throttle.throttle(config, location_config) + end) + + assert.stub(ngx.exit).was_not_called() + assert.is_nil(ngx.var.global_rate_limit_exceeding) + assert.spy(cache_safe_add_spy).was_not_called() +end + +local function assert_short_circuits(f) + local cache_get_spy = spy.on(ngx.shared.global_throttle_cache, "get") + + local resty_global_throttle = require_without_cache("resty.global_throttle") + local resty_global_throttle_new_spy = spy.on(resty_global_throttle, "new") + + local global_throttle = require_without_cache("global_throttle") + + f(global_throttle) + + assert.spy(resty_global_throttle_new_spy).was_not_called() + assert.spy(cache_get_spy).was_not_called() +end + +local function assert_fails_open(config, location_config, ...) + stub(ngx, "exit") + stub(ngx, "log") + + local global_throttle = require_without_cache("global_throttle") + + assert.has_no.errors(function() + global_throttle.throttle(config, location_config) + end) + + assert.stub(ngx.exit).was_not_called() + assert.stub(ngx.log).was_called_with(ngx.ERR, ...) + assert.is_nil(ngx.var.global_rate_limit_exceeding) +end + +local function stub_resty_global_throttle_process(ret1, ret2, ret3, f) + local resty_global_throttle = require_without_cache("resty.global_throttle") + local resty_global_throttle_mock = { + process = function(self, key) return ret1, ret2, ret3 end + } + stub(resty_global_throttle, "new", resty_global_throttle_mock) + + f() + + assert.stub(resty_global_throttle.new).was_called() +end + +local function cache_rejection_decision(namespace, key_value, desired_delay) + local namespaced_key_value = namespace .. key_value + local ok, err = ngx.shared.global_throttle_cache:safe_add(namespaced_key_value, true, desired_delay) + assert.is_nil(err) + assert.is_true(ok) + assert.is_true(ngx.shared.global_throttle_cache:get(namespaced_key_value)) +end + +describe("global_throttle", function() + local snapshot + + local NAMESPACE = "31285d47b1504dcfbd6f12c46d769f6e" + local LOCATION_CONFIG = { + namespace = NAMESPACE, + limit = 10, + window_size = 60, + key = {}, + ignored_cidrs = {}, + } + local CONFIG = { + memcached = { + host = "memc.default.svc.cluster.local", port = 11211, + connect_timeout = 50, max_idle_timeout = 10000, pool_size = 50, + }, + status_code = 429, + } + + before_each(function() + snapshot = assert:snapshot() + + ngx.var = { remote_addr = "127.0.0.1", global_rate_limit_exceeding = nil } + end) + + after_each(function() + snapshot:revert() + + ngx.shared.global_throttle_cache:flush_all() + reset_ngx() + end) + + it("short circuits when memcached is not configured", function() + assert_short_circuits(function(global_throttle) + assert.has_no.errors(function() + global_throttle.throttle({ memcached = { host = "", port = 0 } }, LOCATION_CONFIG) + end) + end) + end) + + it("short circuits when limit or window_size is not configured", function() + assert_short_circuits(function(global_throttle) + local location_config_copy = util.deepcopy(LOCATION_CONFIG) + location_config_copy.limit = 0 + assert.has_no.errors(function() + global_throttle.throttle(CONFIG, location_config_copy) + end) + end) + + assert_short_circuits(function(global_throttle) + local location_config_copy = util.deepcopy(LOCATION_CONFIG) + location_config_copy.window_size = 0 + assert.has_no.errors(function() + global_throttle.throttle(CONFIG, location_config_copy) + end) + end) + end) + + it("short circuits when remote_addr is in ignored_cidrs", function() + local global_throttle = require_without_cache("global_throttle") + local location_config = util.deepcopy(LOCATION_CONFIG) + location_config.ignored_cidrs = { ngx.var.remote_addr } + assert_short_circuits(function(global_throttle) + assert.has_no.errors(function() + global_throttle.throttle(CONFIG, location_config) + end) + end) + end) + + it("rejects when exceeding limit has already been cached", function() + local key_value = "foo" + local location_config = util.deepcopy(LOCATION_CONFIG) + location_config.key = { { nil, nil, nil, key_value } } + cache_rejection_decision(NAMESPACE, key_value, 0.5) + + assert_request_rejected(CONFIG, location_config, { with_cache = true }) + end) + + describe("when resty_global_throttle fails", function() + it("fails open in case of initialization error", function() + local too_long_namespace = "" + for i=1,36,1 do + too_long_namespace = too_long_namespace .. "a" + end + + local location_config = util.deepcopy(LOCATION_CONFIG) + location_config.namespace = too_long_namespace + + assert_fails_open(CONFIG, location_config, "faled to initialize resty_global_throttle: ", "'namespace' can be at most 35 characters") + end) + + it("fails open in case of key processing error", function() + stub_resty_global_throttle_process(nil, nil, "failed to process", function() + assert_fails_open(CONFIG, LOCATION_CONFIG, "error while processing key: ", "failed to process") + end) + end) + end) + + it("initializes resty_global_throttle with the right parameters", function() + local resty_global_throttle = require_without_cache("resty.global_throttle") + local resty_global_throttle_original_new = resty_global_throttle.new + resty_global_throttle.new = function(namespace, limit, window_size, store_opts) + local o, err = resty_global_throttle_original_new(namespace, limit, window_size, store_opts) + if not o then + return nil, err + end + o.process = function(self, key) return 1, nil, nil end + + local expected = LOCATION_CONFIG + assert.are.same(expected.namespace, namespace) + assert.are.same(expected.limit, limit) + assert.are.same(expected.window_size, window_size) + + assert.are.same("memcached", store_opts.provider) + assert.are.same(CONFIG.memcached.host, store_opts.host) + assert.are.same(CONFIG.memcached.port, store_opts.port) + assert.are.same(CONFIG.memcached.connect_timeout, store_opts.connect_timeout) + assert.are.same(CONFIG.memcached.max_idle_timeout, store_opts.max_idle_timeout) + assert.are.same(CONFIG.memcached.pool_size, store_opts.pool_size) + + return o, nil + end + local resty_global_throttle_new_spy = spy.on(resty_global_throttle, "new") + + local global_throttle = require_without_cache("global_throttle") + + assert.has_no.errors(function() + global_throttle.throttle(CONFIG, LOCATION_CONFIG) + end) + + assert.spy(resty_global_throttle_new_spy).was_called() + end) + + it("rejects request and caches decision when limit is exceeding after processing a key", function() + local desired_delay = 0.015 + + stub_resty_global_throttle_process(LOCATION_CONFIG.limit + 1, desired_delay, nil, function() + assert_request_rejected(CONFIG, LOCATION_CONFIG, { with_cache = false }) + + local cache_key = LOCATION_CONFIG.namespace .. ngx.var.remote_addr + assert.is_true(ngx.shared.global_throttle_cache:get(cache_key)) + + -- we assume it won't take more than this after caching + -- until we execute the assertion below + local delta = 0.001 + local ttl = ngx.shared.global_throttle_cache:ttl(cache_key) + assert.is_true(ttl > desired_delay - delta) + assert.is_true(ttl <= desired_delay) + end) + end) + + it("rejects request and skip caching of decision when limit is exceeding after processing a key but desired delay is lower than the threshold", function() + local desired_delay = 0.0009 + + stub_resty_global_throttle_process(LOCATION_CONFIG.limit, desired_delay, nil, function() + assert_request_rejected(CONFIG, LOCATION_CONFIG, { with_cache = false }) + + local cache_key = LOCATION_CONFIG.namespace .. ngx.var.remote_addr + assert.is_nil(ngx.shared.global_throttle_cache:get(cache_key)) + end) + end) + + it("allows the request when limit is not exceeding after processing a key", function() + stub_resty_global_throttle_process(LOCATION_CONFIG.limit - 3, nil, nil, + function() + assert_request_not_rejected(CONFIG, LOCATION_CONFIG) + end + ) + end) + + it("rejects with custom status code", function() + cache_rejection_decision(NAMESPACE, ngx.var.remote_addr, 0.3) + local config = util.deepcopy(CONFIG) + config.status_code = 503 + assert_request_rejected(config, LOCATION_CONFIG, { with_cache = true }) + end) +end) diff --git a/rootfs/etc/nginx/lua/test/plugins_test.lua b/rootfs/etc/nginx/lua/test/plugins_test.lua new file mode 100644 index 000000000..d7f789d0f --- /dev/null +++ b/rootfs/etc/nginx/lua/test/plugins_test.lua @@ -0,0 +1,23 @@ +describe("plugins", function() + describe("#run", function() + it("runs the plugins in the given order", function() + ngx.get_phase = function() return "rewrite" end + local plugins = require("plugins") + local called_plugins = {} + local plugins_to_mock = {"plugins.pluginfirst.main", "plugins.pluginsecond.main", "plugins.pluginthird.main"} + for i=1, 3, 1 + do + package.loaded[plugins_to_mock[i]] = { + rewrite = function() + called_plugins[#called_plugins + 1] = plugins_to_mock[i] + end + } + end + assert.has_no.errors(function() + plugins.init({"pluginfirst", "pluginsecond", "pluginthird"}) + end) + assert.has_no.errors(plugins.run) + assert.are.same(plugins_to_mock, called_plugins) + end) + end) +end) \ No newline at end of file diff --git a/rootfs/etc/nginx/lua/util.lua b/rootfs/etc/nginx/lua/util.lua index 1e4cd7c01..7389f3226 100644 --- a/rootfs/etc/nginx/lua/util.lua +++ b/rootfs/etc/nginx/lua/util.lua @@ -146,10 +146,6 @@ function _M.is_blank(str) return str == nil or string_len(str) == 0 end -function _M.string_to_bool(str) - return str == "true" -end - -- this implementation is taken from: -- https://github.com/luafun/luafun/blob/master/fun.lua#L33 -- SHA: 04c99f9c393e54a604adde4b25b794f48104e0d0 diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 6b8e750b0..d58be2880 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -68,11 +68,71 @@ http { {{ buildLuaSharedDictionaries $cfg $servers }} - lua_shared_dict luaconfig 5m; + init_by_lua_block { + collectgarbage("collect") - init_by_lua_file /etc/nginx/lua/ngx_conf_init.lua; + -- init modules + local ok, res - init_worker_by_lua_file /etc/nginx/lua/ngx_conf_init_worker.lua; + ok, res = pcall(require, "lua_ingress") + if not ok then + error("require failed: " .. tostring(res)) + else + lua_ingress = res + lua_ingress.set_config({{ configForLua $all }}) + end + + ok, res = pcall(require, "configuration") + if not ok then + error("require failed: " .. tostring(res)) + else + configuration = res + configuration.prohibited_localhost_port = '{{ .StatusPort }}' + end + + ok, res = pcall(require, "balancer") + if not ok then + error("require failed: " .. tostring(res)) + else + balancer = res + end + + {{ if $all.EnableMetrics }} + ok, res = pcall(require, "monitor") + if not ok then + error("require failed: " .. tostring(res)) + else + monitor = res + end + {{ end }} + + ok, res = pcall(require, "certificate") + if not ok then + error("require failed: " .. tostring(res)) + else + certificate = res + certificate.is_ocsp_stapling_enabled = {{ $cfg.EnableOCSP }} + end + + ok, res = pcall(require, "plugins") + if not ok then + error("require failed: " .. tostring(res)) + else + plugins = res + end + -- load all plugins that'll be used here + plugins.init({ {{ range $idx, $plugin := $cfg.Plugins }}{{ if $idx }},{{ end }}{{ $plugin | quote }}{{ end }} }) + } + + init_worker_by_lua_block { + lua_ingress.init_worker() + balancer.init_worker() + {{ if $all.EnableMetrics }} + monitor.init_worker({{ $all.MonitorMaxBatchSize }}) + {{ end }} + + plugins.run() + } {{/* Enable the real_ip module only if we use either X-Forwarded headers or Proxy Protocol. */}} {{/* we use the value of the real IP for the geo_ip module */}} @@ -112,9 +172,6 @@ http { {{ range $index, $file := $all.MaxmindEditionFiles }} {{ if eq $file "GeoLite2-Country.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoLite2-Country.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_country_code source=$remote_addr country iso_code; $geoip2_country_name source=$remote_addr country names en; $geoip2_country_geoname_id source=$remote_addr country geoname_id; @@ -126,9 +183,6 @@ http { {{ if eq $file "GeoIP2-Country.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoIP2-Country.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_country_code source=$remote_addr country iso_code; $geoip2_country_name source=$remote_addr country names en; $geoip2_country_geoname_id source=$remote_addr country geoname_id; @@ -140,9 +194,6 @@ http { {{ if eq $file "GeoLite2-City.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoLite2-City.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_city_country_code source=$remote_addr country iso_code; $geoip2_city_country_name source=$remote_addr country names en; $geoip2_city_country_geoname_id source=$remote_addr country geoname_id; @@ -166,9 +217,6 @@ http { {{ if eq $file "GeoIP2-City.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoIP2-City.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_city_country_code source=$remote_addr country iso_code; $geoip2_city_country_name source=$remote_addr country names en; $geoip2_city_country_geoname_id source=$remote_addr country geoname_id; @@ -192,9 +240,6 @@ http { {{ if eq $file "GeoLite2-ASN.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoLite2-ASN.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_asn source=$remote_addr autonomous_system_number; $geoip2_org source=$remote_addr autonomous_system_organization; } @@ -202,9 +247,6 @@ http { {{ if eq $file "GeoIP2-ASN.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoIP2-ASN.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_asn source=$remote_addr autonomous_system_number; $geoip2_org source=$remote_addr autonomous_system_organization; } @@ -212,9 +254,6 @@ http { {{ if eq $file "GeoIP2-ISP.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoIP2-ISP.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_isp source=$remote_addr isp; $geoip2_isp_org source=$remote_addr organization; $geoip2_asn source=$remote_addr default=0 autonomous_system_number; @@ -229,9 +268,6 @@ http { {{ if eq $file "GeoIP2-Anonymous-IP.mmdb" }} geoip2 /etc/ingress-controller/geoip/GeoIP2-Anonymous-IP.mmdb { - {{ if (gt $cfg.GeoIP2AutoReloadMinutes 0) }} - auto_reload {{ $cfg.GeoIP2AutoReloadMinutes }}m; - {{ end }} $geoip2_is_anon source=$remote_addr is_anonymous; $geoip2_is_anonymous source=$remote_addr default=0 is_anonymous; $geoip2_is_anonymous_vpn source=$remote_addr default=0 is_anonymous_vpn; @@ -271,10 +307,6 @@ http { client_body_buffer_size {{ $cfg.ClientBodyBufferSize }}; client_body_timeout {{ $cfg.ClientBodyTimeout }}s; - {{ if gt $cfg.GRPCBufferSizeKb 0 }} - grpc_buffer_size {{ $cfg.GRPCBufferSizeKb }}k; - {{ end }} - {{ if and (ne $cfg.HTTP2MaxHeaderSize "") (ne $cfg.HTTP2MaxFieldSize "") }} http2_max_field_size {{ $cfg.HTTP2MaxFieldSize }}; http2_max_header_size {{ $cfg.HTTP2MaxHeaderSize }}; @@ -459,10 +491,6 @@ http { proxy_intercept_errors on; {{ end }} - {{ if $cfg.RelativeRedirects }} - absolute_redirect off; - {{ end }} - {{ range $errCode := $cfg.CustomHTTPErrors }} error_page {{ $errCode }} = @custom_upstream-default-backend_{{ $errCode }};{{ end }} @@ -494,7 +522,9 @@ http { server 0.0.0.1; # placeholder - balancer_by_lua_file /etc/nginx/lua/nginx/ngx_conf_balancer.lua; + balancer_by_lua_block { + balancer.balance() + } {{ if (gt $cfg.UpstreamKeepaliveConnections 0) }} keepalive {{ $cfg.UpstreamKeepaliveConnections }}; @@ -559,7 +589,9 @@ http { {{ buildHTTPListener $all $redirect.From }} {{ buildHTTPSListener $all $redirect.From }} - ssl_certificate_by_lua_file /etc/nginx/lua/nginx/ngx_conf_certificate.lua; + ssl_certificate_by_lua_block { + certificate.call() + } {{ if gt (len $cfg.BlockUserAgents) 0 }} if ($block_ua) { @@ -572,7 +604,30 @@ http { } {{ end }} - set_by_lua_file $redirect_to /etc/nginx/lua/nginx/ngx_srv_redirect.lua {{ $redirect.To }}; + set_by_lua_block $redirect_to { + local request_uri = ngx.var.request_uri + if string.sub(request_uri, -1) == "/" then + request_uri = string.sub(request_uri, 1, -2) + end + + {{ if $cfg.UseForwardedHeaders }} + local redirectScheme + if not ngx.var.http_x_forwarded_proto then + redirectScheme = ngx.var.scheme + else + redirectScheme = ngx.var.http_x_forwarded_proto + end + {{ else }} + local redirectScheme = ngx.var.scheme + {{ end }} + + {{ if ne $all.ListenPorts.HTTPS 443 }} + {{ $redirect_port := (printf ":%v" $all.ListenPorts.HTTPS) }} + return string.format("%s://%s%s%s", redirectScheme, "{{ $redirect.To }}", "{{ $redirect_port }}", request_uri) + {{ else }} + return string.format("%s://%s%s", redirectScheme, "{{ $redirect.To }}", request_uri) + {{ end }} + } return {{ $all.Cfg.HTTPRedirectCode }} $redirect_to; } @@ -667,7 +722,17 @@ http { } location /is-dynamic-lb-initialized { - content_by_lua_file /etc/nginx/lua/nginx/ngx_conf_is_dynamic_lb_initialized.lua; + content_by_lua_block { + local configuration = require("configuration") + local backend_data = configuration.get_backends_data() + if not backend_data then + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + return + end + + ngx.say("OK") + ngx.exit(ngx.HTTP_OK) + } } location {{ .StatusPath }} { @@ -679,11 +744,15 @@ http { client_body_buffer_size {{ luaConfigurationRequestBodySize $cfg }}; proxy_buffering off; - content_by_lua_file /etc/nginx/lua/nginx/ngx_conf_configuration.lua; + content_by_lua_block { + configuration.call() + } } location / { - return 404; + content_by_lua_block { + ngx.exit(ngx.HTTP_NOT_FOUND) + } } } } @@ -695,9 +764,39 @@ stream { {{ buildResolvers $cfg.Resolver $cfg.DisableIpv6DNS }} - init_by_lua_file /etc/nginx/lua/ngx_conf_init_stream.lua; + init_by_lua_block { + collectgarbage("collect") - init_worker_by_lua_file /etc/nginx/lua/nginx/ngx_conf_init_tcp_udp.lua; + -- init modules + local ok, res + + ok, res = pcall(require, "configuration") + if not ok then + error("require failed: " .. tostring(res)) + else + configuration = res + end + + ok, res = pcall(require, "tcp_udp_configuration") + if not ok then + error("require failed: " .. tostring(res)) + else + tcp_udp_configuration = res + tcp_udp_configuration.prohibited_localhost_port = '{{ .StatusPort }}' + + end + + ok, res = pcall(require, "tcp_udp_balancer") + if not ok then + error("require failed: " .. tostring(res)) + else + tcp_udp_balancer = res + end + } + + init_worker_by_lua_block { + tcp_udp_balancer.init_worker() + } lua_add_variable $proxy_upstream_name; @@ -719,7 +818,10 @@ stream { upstream upstream_balancer { server 0.0.0.1:1234; # placeholder - balancer_by_lua_file /etc/nginx/lua/nginx/ngx_conf_balancer_tcp_udp.lua; + + balancer_by_lua_block { + tcp_udp_balancer.balance() + } } server { @@ -727,7 +829,9 @@ stream { access_log off; - content_by_lua_file /etc/nginx/lua/nginx/ngx_conf_content_tcp_udp.lua; + content_by_lua_block { + tcp_udp_configuration.call() + } } # TCP services @@ -827,9 +931,11 @@ stream { rewrite (.*) / break; proxy_pass http://upstream_balancer; - {{ if $enableMetrics }} - log_by_lua_file /etc/nginx/lua/nginx/ngx_conf_log.lua; - {{ end }} + log_by_lua_block { + {{ if $enableMetrics }} + monitor.call() + {{ end }} + } } {{ end }} {{ end }} @@ -889,7 +995,9 @@ stream { ssl_reject_handshake {{ if $all.Cfg.SSLRejectHandshake }}on{{ else }}off{{ end }}; {{ end }} - ssl_certificate_by_lua_file /etc/nginx/lua/nginx/ngx_conf_certificate.lua; + ssl_certificate_by_lua_block { + certificate.call() + } {{ if not (empty $server.AuthTLSError) }} # {{ $server.AuthTLSError }} @@ -990,7 +1098,9 @@ stream { set $tmp_cache_key '{{ $server.Hostname }}{{ $authPath }}{{ $externalAuth.AuthCacheKey }}'; set $cache_key ''; - rewrite_by_lua_file /etc/nginx/lua/nginx/ngx_conf_rewrite_auth.lua; + rewrite_by_lua_block { + ngx.var.cache_key = ngx.encode_base64(ngx.sha1_bin(ngx.var.tmp_cache_key)) + } proxy_cache auth_cache; @@ -1041,7 +1151,6 @@ stream { {{ end }} proxy_buffer_size {{ $location.Proxy.BufferSize }}; proxy_buffers {{ $location.Proxy.BuffersNumber }} {{ $location.Proxy.BufferSize }}; - proxy_busy_buffers_size {{ $location.Proxy.BusyBuffersSize }}; proxy_request_buffering {{ $location.Proxy.RequestBuffering }}; proxy_ssl_server_name on; @@ -1116,6 +1225,7 @@ stream { set $service_name {{ $ing.Service | quote }}; set $service_port {{ $ing.ServicePort | quote }}; set $location_path {{ $ing.Path | escapeLiteralDollar | quote }}; + set $global_rate_limit_exceeding n; {{ buildOpentelemetryForLocation $all.Cfg.EnableOpentelemetry $all.Cfg.OpentelemetryTrustIncomingSpan $location }} @@ -1124,13 +1234,35 @@ stream { mirror_request_body {{ $location.Mirror.RequestBody }}; {{ end }} - {{ locationConfigForLua $location $all }} + rewrite_by_lua_block { + lua_ingress.rewrite({{ locationConfigForLua $location $all }}) + balancer.rewrite() + plugins.run() + } - rewrite_by_lua_file /etc/nginx/lua/nginx/ngx_rewrite.lua; + # be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any + # will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)` + # other authentication method such as basic auth or external auth useless - all requests will be allowed. + #access_by_lua_block { + #} - header_filter_by_lua_file /etc/nginx/lua/nginx/ngx_conf_srv_hdr_filter.lua; + header_filter_by_lua_block { + lua_ingress.header() + plugins.run() + } - log_by_lua_file /etc/nginx/lua/nginx/ngx_conf_log_block.lua; + body_filter_by_lua_block { + plugins.run() + } + + log_by_lua_block { + balancer.log() + {{ if $all.EnableMetrics }} + monitor.call() + {{ end }} + + plugins.run() + } {{ if not $location.Logs.Access }} access_log off; @@ -1190,10 +1322,20 @@ stream { {{- end }} # `auth_request` module does not support HTTP keepalives in upstream block: # https://trac.nginx.org/nginx/ticket/1579 - set $auth_path '{{ $authPath }}'; - set $auth_keepalive_share_vars {{ $externalAuth.KeepaliveShareVars }}; - set $auth_response_headers '{{ buildAuthUpstreamLuaHeaders $externalAuth.ResponseHeaders }}'; - access_by_lua_file /etc/nginx/lua/nginx/ngx_conf_external_auth.lua; + access_by_lua_block { + local res = ngx.location.capture('{{ $authPath }}', { method = ngx.HTTP_GET, body = '', share_all_vars = {{ $externalAuth.KeepaliveShareVars }} }) + if res.status == ngx.HTTP_OK then + ngx.var.auth_cookie = res.header['Set-Cookie'] + {{- range $line := buildAuthUpstreamLuaHeaders $externalAuth.ResponseHeaders }} + {{ $line }} + {{- end }} + return + end + if res.status == ngx.HTTP_UNAUTHORIZED or res.status == ngx.HTTP_FORBIDDEN then + ngx.exit(res.status) + end + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + } {{ else }} auth_request {{ $authPath }}; auth_request_set $auth_cookie $upstream_http_set_cookie; @@ -1297,7 +1439,6 @@ stream { proxy_buffering {{ $location.Proxy.ProxyBuffering }}; proxy_buffer_size {{ $location.Proxy.BufferSize }}; proxy_buffers {{ $location.Proxy.BuffersNumber }} {{ $location.Proxy.BufferSize }}; - proxy_busy_buffers_size {{ $location.Proxy.BusyBuffersSize }}; {{ if isValidByteSize $location.Proxy.ProxyMaxTempFileSize true }} proxy_max_temp_file_size {{ $location.Proxy.ProxyMaxTempFileSize }}; {{ end }} @@ -1312,13 +1453,6 @@ stream { proxy_next_upstream_timeout {{ $location.Proxy.NextUpstreamTimeout }}; proxy_next_upstream_tries {{ $location.Proxy.NextUpstreamTries }}; - {{ if or (eq $location.BackendProtocol "GRPC") (eq $location.BackendProtocol "GRPCS") }} - # Grpc settings - grpc_connect_timeout {{ $location.Proxy.ConnectTimeout }}s; - grpc_send_timeout {{ $location.Proxy.SendTimeout }}s; - grpc_read_timeout {{ $location.Proxy.ReadTimeout }}s; - {{ end }} - {{/* Add any additional configuration defined */}} {{ $location.ConfigurationSnippet }} @@ -1327,13 +1461,6 @@ stream { {{ $all.Cfg.LocationSnippet }} {{ end }} - {{ if $location.CustomHeaders }} - # Custom Response Headers - {{ range $k, $v := $location.CustomHeaders.Headers }} - more_set_headers {{ printf "%s: %s" $k $v | escapeLiteralDollar | quote }}; - {{ end }} - {{ end }} - {{/* if we are sending the request to a custom default backend, we add the required headers */}} {{ if (hasPrefix $location.Backend "custom-default-backend-") }} proxy_set_header X-Code 503; @@ -1349,10 +1476,6 @@ stream { satisfy {{ $location.Satisfy }}; {{ end }} - {{ if $location.Redirect.Relative }} - absolute_redirect off; - {{ end }} - {{/* if a location-specific error override is set, add the proxy_intercept here */}} {{ if and $location.CustomHTTPErrors (not $location.DisableProxyInterceptErrors) }} # Custom error pages per ingress diff --git a/test/data/cleanConf.expected.conf b/test/data/cleanConf.expected.conf index 9c0513b37..7c4a16824 100644 --- a/test/data/cleanConf.expected.conf +++ b/test/data/cleanConf.expected.conf @@ -67,6 +67,8 @@ http { balancer.init_worker() monitor.init_worker(10000) + + plugins.run() } map $request_uri $loggable { @@ -118,6 +120,7 @@ http { use_port_in_redirects = false, }) balancer.rewrite() + plugins.run() } # be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any @@ -127,6 +130,7 @@ http { header_filter_by_lua_block { lua_ingress.header() + plugins.run() } } diff --git a/test/data/cleanConf.src.conf b/test/data/cleanConf.src.conf index 6da578106..89954cf0d 100644 --- a/test/data/cleanConf.src.conf +++ b/test/data/cleanConf.src.conf @@ -86,8 +86,11 @@ lua_shared_dict ocsp_response_cache 5M; init_worker_by_lua_block { lua_ingress.init_worker() balancer.init_worker() - + monitor.init_worker(10000) + + + plugins.run() } @@ -161,6 +164,7 @@ lua_shared_dict ocsp_response_cache 5M; use_port_in_redirects = false, }) balancer.rewrite() + plugins.run() } # be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any @@ -170,6 +174,7 @@ lua_shared_dict ocsp_response_cache 5M; header_filter_by_lua_block { lua_ingress.header() + plugins.run() } diff --git a/test/e2e-image/Dockerfile b/test/e2e-image/Dockerfile index c16545e43..7bd7c9c1c 100644 --- a/test/e2e-image/Dockerfile +++ b/test/e2e-image/Dockerfile @@ -1,7 +1,7 @@ ARG E2E_BASE_IMAGE FROM ${E2E_BASE_IMAGE} AS BASE -FROM alpine:3.21 +FROM alpine:3.20.0 RUN apk update \ && apk upgrade && apk add -U --no-cache \ diff --git a/test/e2e-image/Makefile b/test/e2e-image/Makefile index f72651f48..a76c65d10 100644 --- a/test/e2e-image/Makefile +++ b/test/e2e-image/Makefile @@ -1,6 +1,6 @@ DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -E2E_BASE_IMAGE ?= "registry.k8s.io/ingress-nginx/e2e-test-runner:v20250112-a188f4eb@sha256:043038b1e30e5a0b64f3f919f096c5c9488ac3f617ac094b07fb9db8215f9441" +E2E_BASE_IMAGE ?= "registry.k8s.io/ingress-nginx/e2e-test-runner:v20240717-1fe74b5f@sha256:fce2ca5e683708cf76c6ba759f351fd7a592c5a56841491cf2d08784154ebf75" image: echo "..entered Makefile in /test/e2e-image" diff --git a/test/e2e-image/namespace-overlays/disableleaderelection/values.yaml b/test/e2e-image/namespace-overlays/disableleaderelection/values.yaml deleted file mode 100644 index f312a9fb4..000000000 --- a/test/e2e-image/namespace-overlays/disableleaderelection/values.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# TODO: remove the need to use fullnameOverride -fullnameOverride: nginx-ingress -controller: - image: - repository: ingress-controller/controller - chroot: true - tag: 1.0.0-dev - digest: - digestChroot: - scope: - # Necessary to allow the ingress controller to get the topology information from the nodes - enabled: false - config: - worker-processes: "1" - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 1 - livenessProbe: - initialDelaySeconds: 3 - periodSeconds: 1 - service: - type: NodePort - extraArgs: - # e2e tests do not require information about ingress status - update-status: "false" - terminationGracePeriodSeconds: 1 - admissionWebhooks: - enabled: false - - disableLeaderElection: true - -rbac: - create: true - scope: false diff --git a/test/e2e/HTTPBUN_IMAGE b/test/e2e/HTTPBUN_IMAGE index 491b333c7..7e83b49fe 100644 --- a/test/e2e/HTTPBUN_IMAGE +++ b/test/e2e/HTTPBUN_IMAGE @@ -1 +1 @@ -registry.k8s.io/ingress-nginx/httpbun:v1.1.1@sha256:4569515d9b74470c915566a010792e7202b6769443fb1f3bb1b1e87376028634 +registry.k8s.io/ingress-nginx/e2e-test-httpbun:v20231011-8b53cabe0 diff --git a/test/e2e/admission/admission.go b/test/e2e/admission/admission.go index 873e6719d..c41105e2d 100644 --- a/test/e2e/admission/admission.go +++ b/test/e2e/admission/admission.go @@ -44,6 +44,33 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller", f.NewSlowEchoDeployment() }) + ginkgo.It("reject ingress with global-rate-limit annotations when memcached is not configured", func() { + host := admissionTestHost + + annotations := map[string]string{ + "nginx.ingress.kubernetes.io/global-rate-limit": "100", + "nginx.ingress.kubernetes.io/global-rate-limit-window": "1m", + } + ing := framework.NewSingleIngress("first-ingress", "/", host, f.Namespace, framework.EchoService, 80, annotations) + + ginkgo.By("rejects ingress when memcached is not configured") + + _, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), ing, metav1.CreateOptions{}) + assert.NotNil(ginkgo.GinkgoT(), err, "creating ingress with global throttle annotations when memcached is not configured") + + ginkgo.By("accepts ingress when memcached is not configured") + + f.UpdateNginxConfigMapData("global-rate-limit-memcached-host", "memc.default.svc.cluster.local") + + _, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), ing, metav1.CreateOptions{}) + assert.Nil(ginkgo.GinkgoT(), err, "creating ingress with global throttle annotations when memcached is configured") + + f.WaitForNginxServer(host, + func(server string) bool { + return strings.Contains(server, fmt.Sprintf("server_name %v", host)) + }) + }) + ginkgo.It("should not allow overlaps of host and paths without canary annotations", func() { host := admissionTestHost @@ -100,8 +127,14 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller", }) ginkgo.It("should return an error if there is an error validating the ingress definition", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := admissionTestHost @@ -208,8 +241,14 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller", }) ginkgo.It("should return an error if the Ingress V1 definition contains invalid annotations", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() out, err := createIngress(f.Namespace, invalidV1Ingress) assert.Empty(ginkgo.GinkgoT(), out) @@ -222,8 +261,14 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller", }) ginkgo.It("should not return an error for an invalid Ingress when it has unknown class", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() out, err := createIngress(f.Namespace, invalidV1IngressWithOtherClass) assert.Equal(ginkgo.GinkgoT(), "ingress.networking.k8s.io/extensions-invalid-other created\n", out) assert.Nil(ginkgo.GinkgoT(), err, "creating an invalid ingress with unknown class using kubectl") diff --git a/test/e2e/annotations/auth.go b/test/e2e/annotations/auth.go index ddda1dce5..ea33fdf32 100644 --- a/test/e2e/annotations/auth.go +++ b/test/e2e/annotations/auth.go @@ -277,8 +277,14 @@ var _ = framework.DescribeAnnotation("auth-*", func() { "nginx.ingress.kubernetes.io/auth-snippet": ` proxy_set_header My-Custom-Header 42;`, } - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) f.EnsureIngress(ing) @@ -291,8 +297,15 @@ var _ = framework.DescribeAnnotation("auth-*", func() { ginkgo.It(`should not set snippet "proxy_set_header My-Custom-Header 42;" when external auth is not configured`, func() { host := authHost - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() annotations := map[string]string{ "nginx.ingress.kubernetes.io/auth-snippet": ` @@ -653,7 +666,7 @@ http { func(server string) bool { return strings.Contains(server, `upstream auth-external-auth`) && strings.Contains(server, `keepalive 10;`) && - strings.Contains(server, `set $auth_keepalive_share_vars false;`) + strings.Contains(server, `share_all_vars = false`) }) }) @@ -673,7 +686,7 @@ http { func(server string) bool { return strings.Contains(server, `upstream auth-external-auth`) && strings.Contains(server, `keepalive 10;`) && - strings.Contains(server, `set $auth_keepalive_share_vars true;`) + strings.Contains(server, `share_all_vars = true`) }) }) }) diff --git a/test/e2e/annotations/cors.go b/test/e2e/annotations/cors.go index 58f4445f7..a14a5761f 100644 --- a/test/e2e/annotations/cors.go +++ b/test/e2e/annotations/cors.go @@ -669,33 +669,4 @@ var _ = framework.DescribeAnnotation("cors-*", func() { Headers(). NotContainsKey("Access-Control-Allow-Origin") }) - - ginkgo.It("should allow - origins with non-http[s] protocols", func() { - host := corsHost - origin := "test://localhost" - origin2 := "tauri://localhost:3000" - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/enable-cors": "true", - "nginx.ingress.kubernetes.io/cors-allow-origin": "test://localhost, tauri://localhost:3000", - } - - ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - WithHeader("Origin", origin). - Expect(). - Status(http.StatusOK).Headers(). - ValueEqual("Access-Control-Allow-Origin", []string{"test://localhost"}) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - WithHeader("Origin", origin2). - Expect(). - Status(http.StatusOK).Headers(). - ValueEqual("Access-Control-Allow-Origin", []string{"tauri://localhost:3000"}) - }) }) diff --git a/test/e2e/annotations/customheaders.go b/test/e2e/annotations/customheaders.go deleted file mode 100644 index 274ce8278..000000000 --- a/test/e2e/annotations/customheaders.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package annotations - -import ( - "fmt" - "net/http" - "strings" - - "github.com/onsi/ginkgo/v2" - - "k8s.io/ingress-nginx/test/e2e/framework" -) - -const ( - customHeaderHost = "custom-headers" -) - -var _ = framework.DescribeAnnotation("custom-headers-*", func() { - f := framework.NewDefaultFramework("custom-headers") - - ginkgo.BeforeEach(func() { - f.NewEchoDeployment() - }) - - ginkgo.It("should return status code 200 when no custom-headers is configured", func() { - ing := framework.NewSingleIngress(customHeaderHost, "/", customHeaderHost, f.Namespace, framework.EchoService, 80, nil) - f.EnsureIngress(ing) - - f.WaitForNginxServer(customHeaderHost, - func(server string) bool { - return strings.Contains(server, "server_name custom-headers") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", customHeaderHost). - Expect(). - Status(http.StatusOK). - Body().Contains(fmt.Sprintf("host=%v", customHeaderHost)) - }) - - ginkgo.It("should return status code 503 when custom-headers is configured with an invalid secret", func() { - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/custom-headers": f.Namespace + "/custom-headers", - } - - ing := framework.NewSingleIngress(customHeaderHost, "/", customHeaderHost, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.WaitForNginxServer(customHeaderHost, - func(server string) bool { - return strings.Contains(server, "server_name custom-headers") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", customHeaderHost). - Expect(). - Status(http.StatusServiceUnavailable). - Body().Contains("503 Service Temporarily Unavailable") - }) - - ginkgo.It(`should set "more_set_headers 'My-Custom-Header' '42';" when custom-headers are set`, func() { - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/custom-headers": f.Namespace + "/custom-headers", - } - - f.CreateConfigMap("custom-headers", map[string]string{ - "My-Custom-Header": "42", - "My-Custom-Header-Dollar": "$remote_addr", - }) - f.UpdateNginxConfigMapData("global-allowed-response-headers", "My-Custom-Header,My-Custom-Header-Dollar") - - ing := framework.NewSingleIngress(customHeaderHost, "/", customHeaderHost, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.WaitForNginxServer(customHeaderHost, - func(server string) bool { - return strings.Contains(server, `more_set_headers "My-Custom-Header: 42";`) - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", customHeaderHost). - Expect(). - Status(http.StatusOK). - Header("My-Custom-Header").Contains("42") - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", customHeaderHost). - Expect(). - Status(http.StatusOK). - Header("My-Custom-Header-Dollar").Contains("$remote_addr") - }) -}) diff --git a/test/e2e/annotations/fromtowwwredirect.go b/test/e2e/annotations/fromtowwwredirect.go index a3fb3b9b5..b69cce93e 100644 --- a/test/e2e/annotations/fromtowwwredirect.go +++ b/test/e2e/annotations/fromtowwwredirect.go @@ -58,12 +58,18 @@ var _ = framework.DescribeAnnotation("from-to-www-redirect", func() { WithHeader("Host", fmt.Sprintf("%s.%s", "www", host)). Expect(). Status(http.StatusPermanentRedirect). - Header("Location").Equal("http://fromtowwwredirect.bar.com:80/foo") + Header("Location").Equal("http://fromtowwwredirect.bar.com/foo") }) ginkgo.It("should redirect from www HTTPS to HTTPS", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() ginkgo.By("setting up server for redirect from www") @@ -101,7 +107,7 @@ var _ = framework.DescribeAnnotation("from-to-www-redirect", func() { WithHeader("Host", toHost). Expect(). Status(http.StatusPermanentRedirect). - Header("Location").Equal(fmt.Sprintf("https://%v:443", fromHost)) + Header("Location").Equal(fmt.Sprintf("https://%v", fromHost)) ginkgo.By("sending request to domain should not redirect to www") f.HTTPTestClientWithTLSConfig(&tls.Config{ diff --git a/test/e2e/annotations/globalratelimit.go b/test/e2e/annotations/globalratelimit.go new file mode 100644 index 000000000..96be467fe --- /dev/null +++ b/test/e2e/annotations/globalratelimit.go @@ -0,0 +1,88 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package annotations + +import ( + "fmt" + "net/http" + "strings" + + "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/assert" + + "k8s.io/ingress-nginx/test/e2e/framework" +) + +var _ = framework.DescribeAnnotation("annotation-global-rate-limit", func() { + f := framework.NewDefaultFramework("global-rate-limit") + host := "global-rate-limit-annotation" + + ginkgo.BeforeEach(func() { + f.NewEchoDeployment() + }) + + ginkgo.It("generates correct configuration", func() { + annotations := make(map[string]string) + annotations["nginx.ingress.kubernetes.io/global-rate-limit"] = "5" + annotations["nginx.ingress.kubernetes.io/global-rate-limit-window"] = "2m" + + // We need to allow { and } characters for this annotation to work + f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "load_module, lua_package, _by_lua, location, root") + // Sleep a while just to guarantee that the configmap is applied + framework.Sleep() + + ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) + ing = f.EnsureIngress(ing) + namespace := strings.ReplaceAll(string(ing.UID), "-", "") + + serverConfig := "" + f.WaitForNginxServer(host, func(server string) bool { + serverConfig = server + return true + }) + assert.Contains(ginkgo.GinkgoT(), serverConfig, + fmt.Sprintf(`global_throttle = { namespace = "%v", `+ + `limit = 5, window_size = 120, key = { { nil, nil, "remote_addr", nil, }, }, `+ + `ignored_cidrs = { } }`, + namespace)) + + f.HTTPTestClient().GET("/").WithHeader("Host", host).Expect().Status(http.StatusOK) + + ginkgo.By("regenerating the correct configuration after update") + annotations["nginx.ingress.kubernetes.io/global-rate-limit-key"] = "${remote_addr}${http_x_api_client}" + annotations["nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs"] = "192.168.1.1, 234.234.234.0/24" + ing.SetAnnotations(annotations) + + f.WaitForReload(func() { + ing = f.UpdateIngress(ing) + }) + + serverConfig = "" + f.WaitForNginxServer(host, func(server string) bool { + serverConfig = server + return true + }) + assert.Contains(ginkgo.GinkgoT(), serverConfig, + fmt.Sprintf(`global_throttle = { namespace = "%v", `+ + `limit = 5, window_size = 120, `+ + `key = { { nil, "remote_addr", nil, nil, }, { nil, "http_x_api_client", nil, nil, }, }, `+ + `ignored_cidrs = { "192.168.1.1", "234.234.234.0/24", } }`, + namespace)) + + f.HTTPTestClient().GET("/").WithHeader("Host", host).Expect().Status(http.StatusOK) + }) +}) diff --git a/test/e2e/annotations/grpc.go b/test/e2e/annotations/grpc.go index 2a9c5a983..c7228cd0e 100644 --- a/test/e2e/annotations/grpc.go +++ b/test/e2e/annotations/grpc.go @@ -22,13 +22,11 @@ import ( "fmt" "strings" - delaypb "github.com/Anddd7/pb/grpcbin" pb "github.com/moul/pb/grpcbin/go-grpc" "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" "google.golang.org/grpc" "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -37,10 +35,7 @@ import ( "k8s.io/ingress-nginx/test/e2e/framework" ) -const ( - echoHost = "echo" - host = "grpc" -) +const echoHost = "echo" var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() { f := framework.NewDefaultFramework("grpc", framework.WithHTTPBunEnabled()) @@ -48,6 +43,8 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() { ginkgo.It("should use grpc_pass in the configuration file", func() { f.NewGRPCFortuneTellerDeployment() + host := "grpc" + annotations := map[string]string{ "nginx.ingress.kubernetes.io/backend-protocol": "GRPC", } @@ -193,8 +190,14 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() { ginkgo.It("should return OK for service with backend protocol GRPCS", func() { f.NewGRPCBinDeployment() - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := echoHost @@ -256,89 +259,4 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() { metadata := res.GetMetadata() assert.Equal(ginkgo.GinkgoT(), metadata["content-type"].Values[0], "application/grpc") }) - - ginkgo.It("should return OK when request not exceed timeout", func() { - f.NewGRPCBinDelayDeployment() - - proxyTimeout := "10" - ingressName := "grpcbin-delay" - - annotations := make(map[string]string) - annotations["nginx.ingress.kubernetes.io/backend-protocol"] = "GRPC" - annotations["nginx.ingress.kubernetes.io/proxy-connect-timeout"] = proxyTimeout - annotations["nginx.ingress.kubernetes.io/proxy-send-timeout"] = proxyTimeout - annotations["nginx.ingress.kubernetes.io/proxy-read-timeout"] = proxyTimeout - - ing := framework.NewSingleIngress(host, "/", host, f.Namespace, ingressName, 50051, annotations) - - f.EnsureIngress(ing) - - f.WaitForNginxServer(host, - func(server string) bool { - return strings.Contains(server, fmt.Sprintf("grpc_connect_timeout %ss;", proxyTimeout)) && - strings.Contains(server, fmt.Sprintf("grpc_send_timeout %ss;", proxyTimeout)) && - strings.Contains(server, fmt.Sprintf("grpc_read_timeout %ss;", proxyTimeout)) - }) - - conn, err := grpc.NewClient( - f.GetNginxIP()+":80", - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithAuthority(host), - ) - assert.Nil(ginkgo.GinkgoT(), err, "error creating a connection") - defer conn.Close() - - client := delaypb.NewGrpcbinServiceClient(conn) - - res, err := client.Unary(context.Background(), &delaypb.UnaryRequest{ - Data: "hello", - }) - assert.Nil(ginkgo.GinkgoT(), err) - - metadata := res.GetResponseAttributes().RequestHeaders - assert.Equal(ginkgo.GinkgoT(), metadata["content-type"], "application/grpc") - assert.Equal(ginkgo.GinkgoT(), metadata[":authority"], host) - }) - - ginkgo.It("should return Error when request exceed timeout", func() { - f.NewGRPCBinDelayDeployment() - - proxyTimeout := "10" - ingressName := "grpcbin-delay" - - annotations := make(map[string]string) - annotations["nginx.ingress.kubernetes.io/backend-protocol"] = "GRPC" - annotations["nginx.ingress.kubernetes.io/proxy-connect-timeout"] = proxyTimeout - annotations["nginx.ingress.kubernetes.io/proxy-send-timeout"] = proxyTimeout - annotations["nginx.ingress.kubernetes.io/proxy-read-timeout"] = proxyTimeout - - ing := framework.NewSingleIngress(host, "/", host, f.Namespace, ingressName, 50051, annotations) - - f.EnsureIngress(ing) - - f.WaitForNginxServer(host, - func(server string) bool { - return strings.Contains(server, fmt.Sprintf("grpc_connect_timeout %ss;", proxyTimeout)) && - strings.Contains(server, fmt.Sprintf("grpc_send_timeout %ss;", proxyTimeout)) && - strings.Contains(server, fmt.Sprintf("grpc_read_timeout %ss;", proxyTimeout)) - }) - - conn, err := grpc.NewClient( - f.GetNginxIP()+":80", - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithAuthority(host), - ) - assert.Nil(ginkgo.GinkgoT(), err, "error creating a connection") - defer conn.Close() - - client := delaypb.NewGrpcbinServiceClient(conn) - - _, err = client.Unary(context.Background(), &delaypb.UnaryRequest{ - Data: "hello", - RequestAttributes: &delaypb.RequestAttributes{ - Delay: 15, - }, - }) - assert.Error(ginkgo.GinkgoT(), err) - }) }) diff --git a/test/e2e/annotations/modsecurity/modsecurity.go b/test/e2e/annotations/modsecurity/modsecurity.go index 730fc76e7..a3e7d80ba 100644 --- a/test/e2e/annotations/modsecurity/modsecurity.go +++ b/test/e2e/annotations/modsecurity/modsecurity.go @@ -100,8 +100,14 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { }) ginkgo.It("should enable modsecurity with snippet", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := modSecurityFooHost nameSpace := f.Namespace @@ -167,8 +173,14 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { }) ginkgo.It("should enable modsecurity with snippet and block requests", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := modSecurityFooHost nameSpace := f.Namespace @@ -200,8 +212,14 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { }) ginkgo.It("should enable modsecurity globally and with modsecurity-snippet block requests", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := modSecurityFooHost nameSpace := f.Namespace @@ -233,11 +251,16 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { }) ginkgo.It("should enable modsecurity when enable-owasp-modsecurity-crs is set to true", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() - - f.UpdateNginxConfigMapData("enable-modsecurity", "true") - f.UpdateNginxConfigMapData("enable-owasp-modsecurity-crs", "true") + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + "enable-modsecurity": "true", + "enable-owasp-modsecurity-crs": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := modSecurityFooHost nameSpace := f.Namespace @@ -267,8 +290,6 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { }) ginkgo.It("should enable modsecurity through the config map", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() host := modSecurityFooHost nameSpace := f.Namespace @@ -289,9 +310,17 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { f.EnsureIngress(ing) expectedComment := "SecRuleEngine On" - f.UpdateNginxConfigMapData("enable-modsecurity", "true") - f.UpdateNginxConfigMapData("enable-owasp-modsecurity-crs", "true") - f.UpdateNginxConfigMapData("modsecurity-snippet", expectedComment) + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + "enable-modsecurity": "true", + "enable-owasp-modsecurity-crs": "true", + "modsecurity-snippet": expectedComment, + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() f.WaitForNginxServer(host, func(server string) bool { @@ -310,9 +339,6 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { host := modSecurityFooHost nameSpace := f.Namespace - f.UpdateNginxConfigMapData("annotations-risk-level", "Critical") // To enable snippet configurations - defer f.UpdateNginxConfigMapData("annotations-risk-level", "High") - snippet := `SecRequestBodyAccess On SecAuditEngine RelevantOnly SecAuditLogParts ABIJDEFHZ @@ -352,9 +378,14 @@ var _ = framework.DescribeAnnotation("modsecurity owasp", func() { }) ginkgo.It("should disable default modsecurity conf setting when modsecurity-snippet is specified", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() - + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := modSecurityFooHost nameSpace := f.Namespace diff --git a/test/e2e/annotations/proxy.go b/test/e2e/annotations/proxy.go index 8e9866021..235b828e7 100644 --- a/test/e2e/annotations/proxy.go +++ b/test/e2e/annotations/proxy.go @@ -160,13 +160,11 @@ var _ = framework.DescribeAnnotation("proxy-*", func() { proxyBuffering := "on" proxyBuffersNumber := "8" proxyBufferSize := "8k" - proxyBusyBuffersSize := "16k" annotations := make(map[string]string) annotations["nginx.ingress.kubernetes.io/proxy-buffering"] = proxyBuffering annotations["nginx.ingress.kubernetes.io/proxy-buffers-number"] = proxyBuffersNumber annotations["nginx.ingress.kubernetes.io/proxy-buffer-size"] = proxyBufferSize - annotations["nginx.ingress.kubernetes.io/proxy-busy-buffers-size"] = proxyBusyBuffersSize ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) f.EnsureIngress(ing) @@ -176,7 +174,6 @@ var _ = framework.DescribeAnnotation("proxy-*", func() { return strings.Contains(server, fmt.Sprintf("proxy_buffering %s;", proxyBuffering)) && strings.Contains(server, fmt.Sprintf("proxy_buffer_size %s;", proxyBufferSize)) && strings.Contains(server, fmt.Sprintf("proxy_buffers %s %s;", proxyBuffersNumber, proxyBufferSize)) && - strings.Contains(server, fmt.Sprintf("proxy_busy_buffers_size %s;", proxyBusyBuffersSize)) && strings.Contains(server, fmt.Sprintf("proxy_request_buffering %s;", proxyBuffering)) }) }) diff --git a/test/e2e/annotations/relativeredirects.go b/test/e2e/annotations/relativeredirects.go deleted file mode 100644 index 430b357e4..000000000 --- a/test/e2e/annotations/relativeredirects.go +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package annotations - -import ( - "fmt" - "net/http" - "strings" - - "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" - "k8s.io/ingress-nginx/test/e2e/framework" -) - -const ( - relativeRedirectsHostname = "rr.foo.com" - relativeRedirectsRedirectPath = "/something" - relativeRedirectsRelativeRedirectURL = "/new-location" -) - -var _ = framework.DescribeAnnotation("relative-redirects", func() { - f := framework.NewDefaultFramework("relative-redirects") - - ginkgo.BeforeEach(func() { - f.NewHttpbunDeployment() - f.NewEchoDeployment() - }) - - ginkgo.It("configures Nginx correctly", func() { - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/relative-redirects": "true", - } - - ing := framework.NewSingleIngress(relativeRedirectsHostname, "/", relativeRedirectsHostname, f.Namespace, framework.HTTPBunService, 80, annotations) - f.EnsureIngress(ing) - - var serverConfig string - f.WaitForNginxServer(relativeRedirectsHostname, func(srvCfg string) bool { - serverConfig = srvCfg - return strings.Contains(serverConfig, fmt.Sprintf("server_name %s", relativeRedirectsHostname)) - }) - - ginkgo.By("turning off absolute_redirect directive") - assert.Contains(ginkgo.GinkgoT(), serverConfig, "absolute_redirect off;") - }) - - ginkgo.It("should respond with absolute URL in Location", func() { - absoluteRedirectURL := fmt.Sprintf("http://%s%s", relativeRedirectsHostname, relativeRedirectsRelativeRedirectURL) - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/permanent-redirect": relativeRedirectsRelativeRedirectURL, - "nginx.ingress.kubernetes.io/relative-redirects": "false", - } - - ginkgo.By("setup ingress") - ing := framework.NewSingleIngress(relativeRedirectsHostname, relativeRedirectsRedirectPath, relativeRedirectsHostname, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.WaitForNginxServer(relativeRedirectsHostname, func(srvCfg string) bool { - return strings.Contains(srvCfg, fmt.Sprintf("server_name %s", relativeRedirectsHostname)) - }) - - ginkgo.By("sending request to redirected URL path") - f.HTTPTestClient(). - GET(relativeRedirectsRedirectPath). - WithHeader("Host", relativeRedirectsHostname). - Expect(). - Status(http.StatusMovedPermanently). - Header("Location").Equal(absoluteRedirectURL) - }) - - ginkgo.It("should respond with relative URL in Location", func() { - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/permanent-redirect": relativeRedirectsRelativeRedirectURL, - "nginx.ingress.kubernetes.io/relative-redirects": "true", - } - - ginkgo.By("setup ingress") - ing := framework.NewSingleIngress(relativeRedirectsHostname, relativeRedirectsRedirectPath, relativeRedirectsHostname, f.Namespace, framework.EchoService, 80, annotations) - f.EnsureIngress(ing) - - f.WaitForNginxServer(relativeRedirectsHostname, func(srvCfg string) bool { - return strings.Contains(srvCfg, fmt.Sprintf("server_name %s", relativeRedirectsHostname)) - }) - - ginkgo.By("sending request to redirected URL path") - f.HTTPTestClient(). - GET(relativeRedirectsRedirectPath). - WithHeader("Host", relativeRedirectsHostname). - Expect(). - Status(http.StatusMovedPermanently). - Header("Location").Equal(relativeRedirectsRelativeRedirectURL) - }) -}) diff --git a/test/e2e/annotations/serversnippet.go b/test/e2e/annotations/serversnippet.go index c94960a3d..1195b728a 100644 --- a/test/e2e/annotations/serversnippet.go +++ b/test/e2e/annotations/serversnippet.go @@ -33,8 +33,14 @@ var _ = framework.DescribeAnnotation("server-snippet", func() { }) ginkgo.It(`add valid directives to server via server snippet`, func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "serversnippet.foo.com" annotations := map[string]string{ @@ -62,8 +68,14 @@ var _ = framework.DescribeAnnotation("server-snippet", func() { }) ginkgo.It(`drops server snippet if disabled by the administrator`, func() { - f.UpdateNginxConfigMapData("annotations-risk-level", "Critical") // To enable snippet configurations - defer f.UpdateNginxConfigMapData("annotations-risk-level", "High") + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "noserversnippet.foo.com" annotations := map[string]string{ @@ -73,6 +85,11 @@ var _ = framework.DescribeAnnotation("server-snippet", func() { } ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) + f.UpdateNginxConfigMapData("allow-snippet-annotations", "false") + defer func() { + // Return to the original value + f.UpdateNginxConfigMapData("allow-snippet-annotations", "true") + }() // Sleep a while just to guarantee that the configmap is applied framework.Sleep() f.EnsureIngress(ing) diff --git a/test/e2e/annotations/snippet.go b/test/e2e/annotations/snippet.go index 9e3160dcc..0c6148a4f 100644 --- a/test/e2e/annotations/snippet.go +++ b/test/e2e/annotations/snippet.go @@ -33,8 +33,15 @@ var _ = framework.DescribeAnnotation("configuration-snippet", func() { ginkgo.It("set snippet more_set_headers in all locations", func() { host := "configurationsnippet.foo.com" - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() annotations := map[string]string{ "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`, @@ -64,8 +71,6 @@ var _ = framework.DescribeAnnotation("configuration-snippet", func() { }) ginkgo.It("drops snippet more_set_header in all locations if disabled by admin", func() { - f.UpdateNginxConfigMapData("annotations-risk-level", "Critical") // To enable snippet configurations - defer f.UpdateNginxConfigMapData("annotations-risk-level", "High") host := "noconfigurationsnippet.foo.com" annotations := map[string]string{ "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`, diff --git a/test/e2e/annotations/streamsnippet.go b/test/e2e/annotations/streamsnippet.go index f91cdc34e..432537b4a 100644 --- a/test/e2e/annotations/streamsnippet.go +++ b/test/e2e/annotations/streamsnippet.go @@ -39,8 +39,14 @@ var _ = framework.DescribeSetting("stream-snippet", func() { }) ginkgo.It("should add value of stream-snippet to nginx config", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "foo.com" diff --git a/test/e2e/cgroups/cgroups.go b/test/e2e/cgroups/cgroups.go deleted file mode 100644 index eab194324..000000000 --- a/test/e2e/cgroups/cgroups.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cgroups - -import ( - "log" - "os" - "path/filepath" - - "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" - - "k8s.io/ingress-nginx/test/e2e/framework" - - "k8s.io/ingress-nginx/pkg/util/runtime" -) - -var _ = framework.IngressNginxDescribeSerial("[CGroups] cgroups", func() { - f := framework.NewDefaultFramework("cgroups") - - ginkgo.BeforeEach(func() { - f.NewEchoDeployment() - f.NewSlowEchoDeployment() - }) - - ginkgo.It("detects cgroups version v1", func() { - cgroupPath := "/testing/sys/fs/cgroup/" - if err := os.MkdirAll(cgroupPath, os.ModePerm); err != nil { - log.Fatal(err) - } - - quotaFile, err := os.Create(filepath.Join(cgroupPath, "cpu.cfs_quota_us")) - if err != nil { - log.Fatal(err) - } - - periodFile, err := os.Create(filepath.Join(cgroupPath, "cpu.cfs_period_us")) - if err != nil { - log.Fatal(err) - } - - _, err = quotaFile.WriteString("4") - if err != nil { - log.Fatal(err) - } - - err = quotaFile.Sync() - if err != nil { - log.Fatal(err) - } - - _, err = periodFile.WriteString("2") - if err != nil { - log.Fatal(err) - } - - err = periodFile.Sync() - if err != nil { - log.Fatal(err) - } - - assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(cgroupPath), int64(1)) - assert.Equal(ginkgo.GinkgoT(), runtime.NumCPUWithCustomPath(cgroupPath), 2) - - os.Remove(filepath.Join(cgroupPath, "cpu.cfs_quota_us")) - os.Remove(filepath.Join(cgroupPath, "cpu.cfs_period_us")) - }) - - ginkgo.It("detect cgroups version v2", func() { - cgroupPath := "/testing/sys/fs/cgroup/" - if err := os.MkdirAll(cgroupPath, os.ModePerm); err != nil { - log.Fatal(err) - } - - _, err := os.Create(filepath.Join(cgroupPath, "cgroup.controllers")) - if err != nil { - log.Fatal(err) - } - - file, err := os.Create(filepath.Join(cgroupPath, "cpu.max")) - if err != nil { - log.Fatal(err) - } - - _, err = file.WriteString("4 2") - if err != nil { - log.Fatal(err) - } - - err = file.Sync() - if err != nil { - log.Fatal(err) - } - - assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(cgroupPath), int64(2)) - assert.Equal(ginkgo.GinkgoT(), runtime.NumCPUWithCustomPath(cgroupPath), 2) - - os.Remove(filepath.Join(cgroupPath, "cpu.max")) - os.Remove(filepath.Join(cgroupPath, "cgroup.controllers")) - }) -}) diff --git a/test/e2e/disableleaderelection/disable_leader.go b/test/e2e/disableleaderelection/disable_leader.go deleted file mode 100644 index fd7369dfb..000000000 --- a/test/e2e/disableleaderelection/disable_leader.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2024 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package disableleaderelection - -import ( - "net/http" - "strings" - - "github.com/onsi/ginkgo/v2" - - "k8s.io/ingress-nginx/test/e2e/framework" -) - -var _ = framework.IngressNginxDescribe("[Disable Leader] Routing works when leader election was disabled", func() { - f := framework.NewDefaultFramework("disableleaderelection") - - ginkgo.BeforeEach(func() { - f.NewEchoDeployment() - }) - - ginkgo.It("should create multiple ingress routings rules when leader election has disabled", func() { - host1 := "leader.election.disabled.com" - host2 := "leader.election.disabled2.com" - - ing1 := framework.NewSingleIngress(host1, "/foo", host1, f.Namespace, framework.EchoService, 80, nil) - f.EnsureIngress(ing1) - - ing2 := framework.NewSingleIngress(host2, "/ping", host2, f.Namespace, framework.EchoService, 80, nil) - f.EnsureIngress(ing2) - - f.WaitForNginxServer(host1, - func(server string) bool { - return strings.Contains(server, host1) && - strings.Contains(server, "location /foo") - }) - - f.WaitForNginxServer(host2, - func(server string) bool { - return strings.Contains(server, host2) && - strings.Contains(server, "location /ping") - }) - - f.HTTPTestClient(). - GET("/foo"). - WithHeader("Host", host1). - Expect(). - Status(http.StatusOK) - - f.HTTPTestClient(). - GET("/bar"). - WithHeader("Host", host1). - Expect(). - Status(http.StatusNotFound) - - f.HTTPTestClient(). - GET("/foo"). - WithHeader("Host", host2). - Expect(). - Status(http.StatusNotFound) - - f.HTTPTestClient(). - GET("/ping"). - WithHeader("Host", host2). - Expect(). - Status(http.StatusOK) - - f.HTTPTestClient(). - GET("/pong"). - WithHeader("Host", host2). - Expect(). - Status(http.StatusNotFound) - - f.HTTPTestClient(). - GET("/ping"). - WithHeader("Host", host1). - Expect(). - Status(http.StatusNotFound) - }) -}) diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 9bf005164..25d714f88 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -32,10 +32,8 @@ import ( _ "k8s.io/ingress-nginx/test/e2e/admission" _ "k8s.io/ingress-nginx/test/e2e/annotations" _ "k8s.io/ingress-nginx/test/e2e/annotations/modsecurity" - _ "k8s.io/ingress-nginx/test/e2e/cgroups" _ "k8s.io/ingress-nginx/test/e2e/dbg" _ "k8s.io/ingress-nginx/test/e2e/defaultbackend" - _ "k8s.io/ingress-nginx/test/e2e/disableleaderelection" _ "k8s.io/ingress-nginx/test/e2e/endpointslices" _ "k8s.io/ingress-nginx/test/e2e/gracefulshutdown" _ "k8s.io/ingress-nginx/test/e2e/ingress" diff --git a/test/e2e/endpointslices/topology.go b/test/e2e/endpointslices/topology.go index 70f7ff86b..38c5f8b76 100644 --- a/test/e2e/endpointslices/topology.go +++ b/test/e2e/endpointslices/topology.go @@ -84,7 +84,7 @@ var _ = framework.IngressNginxDescribeSerial("[TopologyHints] topology aware rou } if gotHints { - // we have 2 replicas, if there is just one backend it means that we are routing according slices hints to same zone as controller is + // we have 2 replics, if there is just one backend it means that we are routing according slices hints to same zone as controller is assert.Equal(ginkgo.GinkgoT(), 1, gotBackends) } else { // two replicas should have two endpoints without topology hints diff --git a/test/e2e/framework/deployment.go b/test/e2e/framework/deployment.go index f213e2e98..08a5353b2 100644 --- a/test/e2e/framework/deployment.go +++ b/test/e2e/framework/deployment.go @@ -43,11 +43,11 @@ const HTTPBunService = "httpbun" // NipService name of external service using nip.io const NIPService = "external-nip" -// HTTPBunImage is the default image that is used to deploy HTTPBun with the framework +// HTTPBunImage is the default image that is used to deploy HTTPBun with the framwork var HTTPBunImage = os.Getenv("HTTPBUN_IMAGE") // EchoImage is the default image to be used by the echo service -const EchoImage = "registry.k8s.io/ingress-nginx/e2e-test-echo:v1.1.1@sha256:a1e0152e2eeab26e3f6fd3986f3d82b17bc7711717cae5392dcd18dd447ba6ef" //#nosec G101 +const EchoImage = "registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:4938d1d91a2b7d19454460a8c1b010b89f6ff92d2987fd889ac3e8fc3b70d91a" //#nosec G101 // TODO: change all Deployment functions to use these options // in order to reduce complexity and have a unified API across the diff --git a/test/e2e/framework/exec.go b/test/e2e/framework/exec.go index 8d528c37a..580a8f58e 100644 --- a/test/e2e/framework/exec.go +++ b/test/e2e/framework/exec.go @@ -117,7 +117,11 @@ func (f *Framework) newIngressController(namespace, namespaceOverlay string) err isChroot = "false" } - cmd := exec.Command("./wait-for-nginx.sh", namespace, namespaceOverlay, isChroot) + enableAnnotationValidations, ok := os.LookupEnv("ENABLE_VALIDATIONS") + if !ok { + enableAnnotationValidations = "false" + } + cmd := exec.Command("./wait-for-nginx.sh", namespace, namespaceOverlay, isChroot, enableAnnotationValidations) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("unexpected error waiting for ingress controller deployment: %v.\nLogs:\n%v", err, string(out)) diff --git a/test/e2e/framework/fastcgi_helloserver.go b/test/e2e/framework/fastcgi_helloserver.go index c414c4da3..73f9ef340 100644 --- a/test/e2e/framework/fastcgi_helloserver.go +++ b/test/e2e/framework/fastcgi_helloserver.go @@ -59,7 +59,7 @@ func (f *Framework) NewNewFastCGIHelloServerDeploymentWithReplicas(replicas int3 Containers: []corev1.Container{ { Name: "fastcgi-helloserver", - Image: "registry.k8s.io/ingress-nginx/fastcgi-helloserver:v1.1.1@sha256:6af4d8c7745c6727aab759db616a58fd68d784d07ce7a32d1ad149c331fd9a6f", + Image: "registry.k8s.io/ingress-nginx/e2e-test-fastcgi-helloserver@sha256:0e08c836cc58f1ea862578de99b13bc4264fe071e816f96dc1d79857bfba7473", Env: []corev1.EnvVar{}, Ports: []corev1.ContainerPort{ { diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 204da7df0..b71d84baa 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -16,7 +16,6 @@ package framework import ( "context" "crypto/tls" - "encoding/json" "fmt" "net" "net/http" @@ -101,7 +100,7 @@ func NewDefaultFramework(baseName string, opts ...func(*Framework)) *Framework { } // NewSimpleFramework makes a new framework that allows the usage of a namespace -// for arbitrary tests. +// for arbitraty tests. func NewSimpleFramework(baseName string, opts ...func(*Framework)) *Framework { defer ginkgo.GinkgoRecover() @@ -284,15 +283,6 @@ func (f *Framework) WaitForNginxConfiguration(matcher func(cfg string) bool) { Sleep(1 * time.Second) } -// WaitForLuaConfiguration waits until the nginx configuration contains a particular configuration -// `cfg` passed to matcher is normalized by replacing all tabs and spaces with single space. -func (f *Framework) WaitForLuaConfiguration(matcher func(jsonCfg map[string]interface{}) bool) { - //nolint:staticcheck // TODO: will replace it since wait.Poll is deprecated - err := wait.Poll(Poll, DefaultTimeout, f.matchLuaConditions(matcher)) - assert.Nil(ginkgo.GinkgoT(), err, "waiting for nginx lua configuration condition/s") - Sleep(1 * time.Second) -} - // WaitForNginxCustomConfiguration waits until the nginx configuration given part (from, to) contains a particular configuration func (f *Framework) WaitForNginxCustomConfiguration(from, to string, matcher func(cfg string) bool) { //nolint:staticcheck // TODO: will replace it since wait.Poll is deprecated @@ -336,29 +326,6 @@ func (f *Framework) matchNginxConditions(name string, matcher func(cfg string) b } } -func (f *Framework) matchLuaConditions(matcher func(jsonCfg map[string]interface{}) bool) wait.ConditionFunc { - return func() (bool, error) { - cmd := "cat /etc/nginx/lua/cfg.json" - - o, err := f.ExecCommand(f.pod, cmd) - if err != nil { - return false, nil - } - - if klog.V(10).Enabled() && o != "" { - klog.InfoS("Lua", "configuration", o) - } - - luaConfig := make(map[string]interface{}) // Use unstructured so we can walk through JSON - if err := json.Unmarshal([]byte(o), &luaConfig); err != nil { - return false, err - } - - // passes the lua interface to the function - return matcher(luaConfig), nil - } -} - func (f *Framework) matchNginxCustomConditions(from, to string, matcher func(cfg string) bool) wait.ConditionFunc { return func() (bool, error) { cmd := fmt.Sprintf("cat /etc/nginx/nginx.conf| awk '/%v/,/%v/'", from, to) @@ -416,20 +383,6 @@ func (f *Framework) SetNginxConfigMapData(cmData map[string]string) { f.WaitForReload(fn) } -// SetNginxConfigMapData sets ingress-nginx's nginx-ingress-controller configMap data -func (f *Framework) AllowSnippetConfiguration() func() { - f.SetNginxConfigMapData(map[string]string{ - "allow-snippet-annotations": "true", - "annotations-risk-level": "Critical", // To enable snippet configurations - }) - return func() { - f.SetNginxConfigMapData(map[string]string{ - "allow-snippet-annotations": "false", - "annotations-risk-level": "High", - }) - } -} - // CreateConfigMap creates a new configmap in the current namespace func (f *Framework) CreateConfigMap(name string, data map[string]string) { _, err := f.KubeClientSet.CoreV1().ConfigMaps(f.Namespace).Create(context.TODO(), &v1.ConfigMap{ diff --git a/test/e2e/framework/grpc_delay.go b/test/e2e/framework/grpc_delay.go deleted file mode 100644 index 58d10b2e9..000000000 --- a/test/e2e/framework/grpc_delay.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright 2024 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package framework - -import ( - "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/util/intstr" -) - -// NewGRPCBinDelayDeployment creates a new single replica -// deployment of the grpcbin image in a particular namespace -func (f *Framework) NewGRPCBinDelayDeployment() { - f.NewNewGRPCBinDelayDeploymentWithReplicas(1) -} - -// NewNewGRPCBinDelayDeploymentWithReplicas creates a new deployment of the -// grpcbin image in a particular namespace. Number of replicas is configurable -func (f *Framework) NewNewGRPCBinDelayDeploymentWithReplicas(replicas int32) { - name := "grpcbin-delay" - - deployment := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: f.Namespace, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: NewInt32(replicas), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": name, - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app": name, - }, - }, - Spec: corev1.PodSpec{ - TerminationGracePeriodSeconds: NewInt64(0), - Containers: []corev1.Container{ - { - Name: name, - Image: "ghcr.io/anddd7/grpcbin:v1.0.6", - Env: []corev1.EnvVar{}, - Ports: []corev1.ContainerPort{ - { - Name: "grpc", - ContainerPort: 50051, - }, - }, - }, - }, - }, - }, - }, - } - - d := f.EnsureDeployment(deployment) - - err := waitForPodsReady(f.KubeClientSet, DefaultTimeout, int(replicas), f.Namespace, &metav1.ListOptions{ - LabelSelector: fields.SelectorFromSet(fields.Set(d.Spec.Template.ObjectMeta.Labels)).String(), - }) - assert.Nil(ginkgo.GinkgoT(), err, "failed to wait for to become ready") - - service := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: f.Namespace, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "grpc", - Port: 50051, - TargetPort: intstr.FromInt(50051), - Protocol: "TCP", - }, - }, - Selector: map[string]string{ - "app": name, - }, - }, - } - - f.EnsureService(service) - - err = WaitForEndpoints(f.KubeClientSet, DefaultTimeout, name, f.Namespace, int(replicas)) - assert.Nil(ginkgo.GinkgoT(), err, "waiting for endpoints to become ready") -} diff --git a/test/e2e/gracefulshutdown/shutdown.go b/test/e2e/gracefulshutdown/shutdown.go index e9883338f..604143da8 100644 --- a/test/e2e/gracefulshutdown/shutdown.go +++ b/test/e2e/gracefulshutdown/shutdown.go @@ -37,7 +37,7 @@ var _ = framework.IngressNginxDescribe("[Shutdown] ingress controller", func() { f.NewSlowEchoDeployment() }) - ginkgo.It("should shutdown in less than 60 seconds without pending connections", func() { + ginkgo.It("should shutdown in less than 60 secons without pending connections", func() { f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.SlowEchoService, 80, nil)) f.WaitForNginxServer(host, diff --git a/test/e2e/ingress/multiple_rules.go b/test/e2e/ingress/multiple_rules.go index 9247dc1d3..f44b2f8dd 100644 --- a/test/e2e/ingress/multiple_rules.go +++ b/test/e2e/ingress/multiple_rules.go @@ -36,8 +36,14 @@ var _ = framework.IngressNginxDescribe("single ingress - multiple hosts", func() }) ginkgo.It("should set the correct $service_name NGINX variable", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() annotations := map[string]string{ "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "service-name: $service_name";`, diff --git a/test/e2e/ingress/pathtype_exact.go b/test/e2e/ingress/pathtype_exact.go index 2660e32a4..d0564cbf6 100644 --- a/test/e2e/ingress/pathtype_exact.go +++ b/test/e2e/ingress/pathtype_exact.go @@ -35,8 +35,14 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] exact", func() { }) ginkgo.It("should choose exact location for /exact", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "exact.path" diff --git a/test/e2e/ingress/pathtype_mixed.go b/test/e2e/ingress/pathtype_mixed.go index 3212089c9..e7bf2532e 100644 --- a/test/e2e/ingress/pathtype_mixed.go +++ b/test/e2e/ingress/pathtype_mixed.go @@ -37,8 +37,14 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] mix Exact and Prefi exactPathType := networking.PathTypeExact ginkgo.It("should choose the correct location", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "mixed.path" diff --git a/test/e2e/lua/dynamic_configuration.go b/test/e2e/lua/dynamic_configuration.go index a5e2196ce..8ec1ef839 100644 --- a/test/e2e/lua/dynamic_configuration.go +++ b/test/e2e/lua/dynamic_configuration.go @@ -48,7 +48,12 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic configuration", func() { ginkgo.It("configures balancer Lua middleware correctly", func() { f.WaitForNginxConfiguration(func(cfg string) bool { - return strings.Contains(cfg, "balancer_by_lua_file /etc/nginx/lua/nginx/ngx_conf_balancer.lua") + return strings.Contains(cfg, "balancer.init_worker()") && strings.Contains(cfg, "balancer.balance()") + }) + + host := "foo.com" + f.WaitForNginxServer(host, func(server string) bool { + return strings.Contains(server, "balancer.rewrite()") && strings.Contains(server, "balancer.log()") }) }) diff --git a/test/e2e/metrics/metrics.go b/test/e2e/metrics/metrics.go index bec09bb37..907b53732 100644 --- a/test/e2e/metrics/metrics.go +++ b/test/e2e/metrics/metrics.go @@ -36,7 +36,6 @@ const waitForMetrics = 2 * time.Second var _ = framework.IngressNginxDescribe("[metrics] exported prometheus metrics", func() { f := framework.NewDefaultFramework("metrics") host := "foo.com" - wildcardHost := "wildcard." + host ginkgo.BeforeEach(func() { f.NewEchoDeployment() @@ -92,50 +91,4 @@ var _ = framework.IngressNginxDescribe("[metrics] exported prometheus metrics", assert.Nil(ginkgo.GinkgoT(), err) assert.NotNil(ginkgo.GinkgoT(), mf) }) - ginkgo.It("request metrics per undefined host are present when flag is set", func() { - err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error { - args := deployment.Spec.Template.Spec.Containers[0].Args - args = append(args, "--metrics-per-undefined-host=true") - deployment.Spec.Template.Spec.Containers[0].Args = args - _, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) - return err - }) - assert.Nil(ginkgo.GinkgoT(), err, "updating deployment") - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", wildcardHost). - Expect(). - Status(http.StatusNotFound) - time.Sleep(waitForMetrics) - - ip := f.GetNginxPodIP() - reqMetrics, err := f.GetMetric("nginx_ingress_controller_requests", ip) - assert.Nil(ginkgo.GinkgoT(), err) - assert.NotNil(ginkgo.GinkgoT(), reqMetrics.Metric) - assert.Len(ginkgo.GinkgoT(), reqMetrics.Metric, 1) - - containedLabel := false - for _, label := range reqMetrics.Metric[0].Label { - if *label.Name == "host" && *label.Value == wildcardHost { - containedLabel = true - break - } - } - - assert.Truef(ginkgo.GinkgoT(), containedLabel, "expected reqMetrics to contain label with \"name\"=\"host\" \"value\"=%q, but it did not: %s", wildcardHost, reqMetrics.String()) - }) - ginkgo.It("request metrics per undefined host are not present when flag is not set", func() { - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", wildcardHost). - Expect(). - Status(http.StatusNotFound) - time.Sleep(waitForMetrics) - - ip := f.GetNginxPodIP() - reqMetrics, err := f.GetMetric("nginx_ingress_controller_requests", ip) - assert.EqualError(ginkgo.GinkgoT(), err, "there is no metric with name nginx_ingress_controller_requests") - assert.Nil(ginkgo.GinkgoT(), reqMetrics) - }) }) diff --git a/test/e2e/run-chart-test.sh b/test/e2e/run-chart-test.sh index 7e3f2fe9b..1f8a2ffc7 100755 --- a/test/e2e/run-chart-test.sh +++ b/test/e2e/run-chart-test.sh @@ -62,7 +62,7 @@ export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}" if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then echo "[dev-env] creating Kubernetes cluster with kind" - export K8S_VERSION=${K8S_VERSION:-v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027} + export K8S_VERSION=${K8S_VERSION:-v1.29.2@sha256:51a1434a5397193442f0be2a297b488b6c919ce8a3931be0ce822606ea5ca245} kind create cluster \ --verbosity=${KIND_LOG_LEVEL} \ @@ -78,7 +78,7 @@ fi if [ "${SKIP_IMAGE_CREATION:-false}" = "false" ]; then if ! command -v ginkgo &> /dev/null; then - go install github.com/onsi/ginkgo/v2/ginkgo@v2.22.2 + go install github.com/onsi/ginkgo/v2/ginkgo@v2.19.0 fi echo "[dev-env] building image" make -C ${DIR}/../../ clean-image build image @@ -91,28 +91,25 @@ echo "[dev-env] copying docker images to cluster..." kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes=${KIND_WORKERS} ${REGISTRY}/controller:${TAG} if [ "${SKIP_CERT_MANAGER_CREATION:-false}" = "false" ]; then - echo "[dev-env] deploying cert-manager..." - - # Get OS & platform for downloading cmctl. - os="$(uname -o | tr "[:upper:]" "[:lower:]" | sed "s/gnu\///")" - platform="$(uname -m | sed "s/aarch64/arm64/;s/x86_64/amd64/")" - - # Download cmctl. Cannot validate checksum as OS & platform may vary. - curl --fail --location "https://github.com/cert-manager/cmctl/releases/download/v2.1.1/cmctl_${os}_${platform}.tar.gz" | tar --extract --gzip cmctl - - # Install cert-manager. - ./cmctl x install - ./cmctl check api --wait 1m + curl -fsSL -o cmctl.tar.gz https://github.com/cert-manager/cert-manager/releases/download/v1.11.1/cmctl-linux-amd64.tar.gz + tar xzf cmctl.tar.gz + chmod +x cmctl + ./cmctl help + echo "[dev-env] apply cert-manager ..." + kubectl apply --wait -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml + kubectl wait --timeout=30s --for=condition=available deployment/cert-manager -n cert-manager + kubectl get validatingwebhookconfigurations cert-manager-webhook -ojson | jq '.webhooks[].clientConfig' + kubectl get endpoints -n cert-manager cert-manager-webhook + ./cmctl check api --wait=2m fi echo "[dev-env] running helm chart e2e tests..." -docker run \ - --name ct \ - --volume "${KUBECONFIG}:/root/.kube/config:ro" \ - --volume "${DIR}/../../:/workdir" \ - --network host \ - --workdir /workdir \ - --entrypoint ct \ - --rm \ - registry.k8s.io/ingress-nginx/e2e-test-runner:v20250112-a188f4eb@sha256:043038b1e30e5a0b64f3f919f096c5c9488ac3f617ac094b07fb9db8215f9441 \ - install --charts charts/ingress-nginx +docker run --rm --interactive --network host \ + --name ct \ + --volume $KUBECONFIG:/root/.kube/config \ + --volume "${DIR}/../../":/workdir \ + --workdir /workdir \ + registry.k8s.io/ingress-nginx/e2e-test-runner:v20240717-1fe74b5f@sha256:fce2ca5e683708cf76c6ba759f351fd7a592c5a56841491cf2d08784154ebf75 \ + ct install \ + --charts charts/ingress-nginx \ + --helm-extra-args "--timeout 60s" diff --git a/test/e2e/run-e2e-suite.sh b/test/e2e/run-e2e-suite.sh index 909368e96..9333ee61f 100755 --- a/test/e2e/run-e2e-suite.sh +++ b/test/e2e/run-e2e-suite.sh @@ -78,6 +78,7 @@ kubectl run --rm \ --env="E2E_NODES=${E2E_NODES}" \ --env="FOCUS=${FOCUS}" \ --env="IS_CHROOT=${IS_CHROOT:-false}"\ + --env="ENABLE_VALIDATIONS=${ENABLE_VALIDATIONS:-false}"\ --env="SKIP_OPENTELEMETRY_TESTS=${SKIP_OPENTELEMETRY_TESTS:-false}"\ --env="E2E_CHECK_LEAKS=${E2E_CHECK_LEAKS}" \ --env="NGINX_BASE_IMAGE=${NGINX_BASE_IMAGE}" \ diff --git a/test/e2e/run-kind-e2e.sh b/test/e2e/run-kind-e2e.sh index e41d31afd..640632a1b 100755 --- a/test/e2e/run-kind-e2e.sh +++ b/test/e2e/run-kind-e2e.sh @@ -39,6 +39,7 @@ fi KIND_LOG_LEVEL="1" IS_CHROOT="${IS_CHROOT:-false}" +ENABLE_VALIDATIONS="${ENABLE_VALIDATIONS:-false}" export KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ingress-nginx-dev} DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # Use 1.0.0-dev to make sure we use the latest configuration in the helm template @@ -63,7 +64,7 @@ echo "Running e2e with nginx base image ${NGINX_BASE_IMAGE}" if [ "${SKIP_CLUSTER_CREATION}" = "false" ]; then echo "[dev-env] creating Kubernetes cluster with kind" - export K8S_VERSION=${K8S_VERSION:-v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027} + export K8S_VERSION=${K8S_VERSION:-v1.29.2@sha256:51a1434a5397193442f0be2a297b488b6c919ce8a3931be0ce822606ea5ca245} # delete the cluster if it exists if kind get clusters | grep "${KIND_CLUSTER_NAME}"; then @@ -95,7 +96,7 @@ fi if [ "${SKIP_E2E_IMAGE_CREATION}" = "false" ]; then if ! command -v ginkgo &> /dev/null; then - go install github.com/onsi/ginkgo/v2/ginkgo@v2.22.2 + go install github.com/onsi/ginkgo/v2/ginkgo@v2.19.0 fi echo "[dev-env] .. done building controller images" diff --git a/test/e2e/settings/badannotationvalues.go b/test/e2e/settings/badannotationvalues.go index aa9906909..f61b5bada 100644 --- a/test/e2e/settings/badannotationvalues.go +++ b/test/e2e/settings/badannotationvalues.go @@ -34,8 +34,14 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() { }) ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is an invalid character in some annotation", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "invalid-value-test" annotations := map[string]string{ @@ -44,6 +50,7 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() { } ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) + f.UpdateNginxConfigMapData("allow-snippet-annotations", "true") f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "something_forbidden,otherthing_forbidden,{") f.EnsureIngress(ing) @@ -66,8 +73,14 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() { }) ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is a forbidden word in some annotation", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "forbidden-value-test" @@ -80,6 +93,7 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() { } ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) + f.UpdateNginxConfigMapData("allow-snippet-annotations", "true") f.UpdateNginxConfigMapData("annotation-value-word-blocklist", "something_forbidden,otherthing_forbidden,content_by_lua_block") // Sleep a while just to guarantee that the configmap is applied framework.Sleep() @@ -103,9 +117,14 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() { }) ginkgo.It("[BAD_ANNOTATIONS] should allow an ingress if there is a default blocklist config in place", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() - + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() hostValid := "custom-allowed-value-test" annotationsValid := map[string]string{ "nginx.ingress.kubernetes.io/configuration-snippet": ` @@ -136,8 +155,14 @@ var _ = framework.DescribeAnnotation("Bad annotation values", func() { }) ginkgo.It("[BAD_ANNOTATIONS] should drop an ingress if there is a custom blocklist config in place and allow others to pass", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() host := "custom-forbidden-value-test" annotations := map[string]string{ diff --git a/test/e2e/settings/geoip2.go b/test/e2e/settings/geoip2.go index 9c6d59dc5..7da26d810 100644 --- a/test/e2e/settings/geoip2.go +++ b/test/e2e/settings/geoip2.go @@ -69,9 +69,15 @@ var _ = framework.DescribeSetting("Geoip2", func() { ginkgo.It("should only allow requests from specific countries", func() { ginkgo.Skip("GeoIP test are temporarily disabled") - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() - f.UpdateNginxConfigMapData("use-geoip2", "true") + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + "use-geoip2": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() httpSnippetAllowingOnlyAustralia := `map $geoip2_city_country_code $blocked_country { default 1; @@ -118,52 +124,4 @@ var _ = framework.DescribeSetting("Geoip2", func() { Expect(). Status(http.StatusOK) }) - - ginkgo.It("should up and running nginx controller using autoreload flag", func() { - edition := "GeoLite2-Country" - - err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error { - args := deployment.Spec.Template.Spec.Containers[0].Args - args = append(args, "--maxmind-edition-ids="+edition) - deployment.Spec.Template.Spec.Containers[0].Args = args - _, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) - return err - }) - assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags") - - filename := fmt.Sprintf("/etc/ingress-controller/geoip/%s.mmdb", edition) - exec, err := f.ExecIngressPod(fmt.Sprintf(`sh -c "mkdir -p '%s' && wget -O '%s' '%s' 2>&1"`, filepath.Dir(filename), filename, testdataURL)) - framework.Logf(exec) - assert.Nil(ginkgo.GinkgoT(), err, fmt.Sprintln("error downloading test geoip2 db", filename)) - - f.SetNginxConfigMapData(map[string]string{ - "use-geoip2": "true", - "geoip2-autoreload-in-minutes": "5", - }) - - // Check Configmap Autoreload Patterns - f.WaitForNginxConfiguration( - func(cfg string) bool { - return strings.Contains(cfg, fmt.Sprintf("geoip2 %s", filename)) && - strings.Contains(cfg, "auto_reload 5m;") - }, - ) - - // Check if Nginx could up, running and routing with auto_reload configs - host := "ping.com" - ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil) - f.EnsureIngress(ing) - - f.WaitForNginxServer(host, - func(server string) bool { - return strings.Contains(server, host) && - strings.Contains(server, "location /") - }) - - f.HTTPTestClient(). - GET("/"). - WithHeader("Host", host). - Expect(). - Status(http.StatusOK) - }) }) diff --git a/test/e2e/settings/global_external_auth.go b/test/e2e/settings/global_external_auth.go index f589a63e9..741e6f955 100644 --- a/test/e2e/settings/global_external_auth.go +++ b/test/e2e/settings/global_external_auth.go @@ -32,8 +32,8 @@ import ( ) const ( - disable = "false" - noAuthLocationSetting = "no-auth-locations" + disable = "false" + noAuthLocaltionSetting = "no-auth-locations" ) var _ = framework.DescribeSetting("[Security] global-auth-url", func() { @@ -51,7 +51,7 @@ var _ = framework.DescribeSetting("[Security] global-auth-url", func() { fooPath := "/foo" barPath := "/bar" - noAuthSetting := noAuthLocationSetting + noAuthSetting := noAuthLocaltionSetting noAuthLocations := barPath enableGlobalExternalAuthAnnotation := "nginx.ingress.kubernetes.io/enable-global-auth" diff --git a/test/e2e/settings/globalratelimit.go b/test/e2e/settings/globalratelimit.go new file mode 100644 index 000000000..e266350ad --- /dev/null +++ b/test/e2e/settings/globalratelimit.go @@ -0,0 +1,96 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package settings + +import ( + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/assert" + "k8s.io/ingress-nginx/test/e2e/framework" +) + +var _ = framework.DescribeSetting("settings-global-rate-limit", func() { + f := framework.NewDefaultFramework("global-rate-limit") + host := "global-rate-limit" + + ginkgo.BeforeEach(func() { + f.NewEchoDeployment() + }) + + ginkgo.It("generates correct NGINX configuration", func() { + annotations := make(map[string]string) + ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations) + f.EnsureIngress(ing) + + ginkgo.By("generating correct defaults") + + ngxCfg := "" + f.WaitForNginxConfiguration(func(cfg string) bool { + if strings.Contains(cfg, "global_throttle") { + ngxCfg = cfg + return true + } + return false + }) + + assert.Contains(ginkgo.GinkgoT(), ngxCfg, fmt.Sprintf(`global_throttle = { `+ + `memcached = { host = "%v", port = %d, connect_timeout = %d, max_idle_timeout = %d, `+ + `pool_size = %d, }, status_code = %d, }`, + "", 11211, 50, 10000, 50, 429)) + + f.HTTPTestClient().GET("/").WithHeader("Host", host).Expect().Status(http.StatusOK) + + ginkgo.By("applying customizations") + + memcachedHost := "memc.default.svc.cluster.local" + memcachedPort := 11211 + memcachedConnectTimeout := 100 + memcachedMaxIdleTimeout := 5000 + memcachedPoolSize := 100 + statusCode := 503 + + f.SetNginxConfigMapData(map[string]string{ + "global-rate-limit-memcached-host": memcachedHost, + "global-rate-limit-memcached-port": strconv.Itoa(memcachedPort), + "global-rate-limit-memcached-connect-timeout": strconv.Itoa(memcachedConnectTimeout), + "global-rate-limit-memcached-max-idle-timeout": strconv.Itoa(memcachedMaxIdleTimeout), + "global-rate-limit-memcached-pool-size": strconv.Itoa(memcachedPoolSize), + "global-rate-limit-status-code": strconv.Itoa(statusCode), + }) + + ngxCfg = "" + f.WaitForNginxConfiguration(func(cfg string) bool { + if strings.Contains(cfg, "global_throttle") { + ngxCfg = cfg + return true + } + return false + }) + + assert.Contains(ginkgo.GinkgoT(), ngxCfg, fmt.Sprintf(`global_throttle = { `+ + `memcached = { host = "%v", port = %d, connect_timeout = %d, max_idle_timeout = %d, `+ + `pool_size = %d, }, status_code = %d, }`, + memcachedHost, memcachedPort, memcachedConnectTimeout, memcachedMaxIdleTimeout, + memcachedPoolSize, statusCode)) + + f.HTTPTestClient().GET("/").WithHeader("Host", host).Expect().Status(http.StatusOK) + }) +}) diff --git a/test/e2e/settings/grpc.go b/test/e2e/settings/grpc.go deleted file mode 100644 index ae3175034..000000000 --- a/test/e2e/settings/grpc.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2024 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package settings - -import ( - "context" - "crypto/tls" - "fmt" - "strings" - - pb "github.com/moul/pb/grpcbin/go-grpc" - "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - - "k8s.io/ingress-nginx/test/e2e/framework" -) - -const echoHost = "echo" - -var _ = framework.DescribeSetting("GRPC", func() { - f := framework.NewDefaultFramework("grpc-buffersize", framework.WithHTTPBunEnabled()) - - ginkgo.It("should set the correct GRPC Buffer Size", func() { - f.SetNginxConfigMapData(map[string]string{ - "grpc-buffer-size-kb": "8", - }) - - f.WaitForNginxConfiguration( - func(cfg string) bool { - return strings.Contains(cfg, "grpc_buffer_size 8k") - }) - - f.NewGRPCBinDeployment() - - host := echoHost - - svc := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "grpcbin-test", - Namespace: f.Namespace, - }, - Spec: corev1.ServiceSpec{ - ExternalName: fmt.Sprintf("grpcbin.%v.svc.cluster.local", f.Namespace), - Type: corev1.ServiceTypeExternalName, - Ports: []corev1.ServicePort{ - { - Name: host, - Port: 9000, - TargetPort: intstr.FromInt(9000), - Protocol: "TCP", - }, - }, - }, - } - f.EnsureService(svc) - - annotations := map[string]string{ - "nginx.ingress.kubernetes.io/backend-protocol": "GRPC", - } - - ing := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, "grpcbin-test", 9000, annotations) - - f.EnsureIngress(ing) - - f.WaitForNginxServer(host, - func(server string) bool { - return strings.Contains(server, "grpc_pass grpc://upstream_balancer;") - }) - - conn, err := grpc.NewClient(f.GetNginxIP()+":443", - grpc.WithTransportCredentials( - credentials.NewTLS(&tls.Config{ - ServerName: echoHost, - InsecureSkipVerify: true, //nolint:gosec // Ignore certificate validation in testing - }), - ), - ) - assert.Nil(ginkgo.GinkgoT(), err, "error creating a connection") - defer conn.Close() - - client := pb.NewGRPCBinClient(conn) - ctx := context.Background() - - res, err := client.HeadersUnary(ctx, &pb.EmptyMessage{}) - assert.Nil(ginkgo.GinkgoT(), err) - - metadata := res.GetMetadata() - assert.Equal(ginkgo.GinkgoT(), metadata["content-type"].Values[0], "application/grpc") - assert.Equal(ginkgo.GinkgoT(), metadata[":authority"].Values[0], host) - }) -}) diff --git a/test/e2e/settings/no_tls_redirect_locations.go b/test/e2e/settings/no_tls_redirect_locations.go index 18fd09e26..8339eb23e 100644 --- a/test/e2e/settings/no_tls_redirect_locations.go +++ b/test/e2e/settings/no_tls_redirect_locations.go @@ -33,7 +33,7 @@ var _ = framework.DescribeSetting("Add no tls redirect locations", func() { f.EnsureIngress(ing) f.WaitForNginxConfiguration(func(server string) bool { - return strings.Contains(server, "set $force_no_ssl_redirect \"false\"") + return !strings.Contains(server, "force_no_ssl_redirect = true,") }) wlKey := "no-tls-redirect-locations" @@ -42,7 +42,7 @@ var _ = framework.DescribeSetting("Add no tls redirect locations", func() { f.UpdateNginxConfigMapData(wlKey, wlValue) f.WaitForNginxConfiguration(func(server string) bool { - return strings.Contains(server, "set $force_no_ssl_redirect \"true\"") + return strings.Contains(server, "force_no_ssl_redirect = true,") }) }) }) diff --git a/test/e2e/settings/ocsp/ocsp.go b/test/e2e/settings/ocsp/ocsp.go index b2d50292a..21cda3008 100644 --- a/test/e2e/settings/ocsp/ocsp.go +++ b/test/e2e/settings/ocsp/ocsp.go @@ -34,7 +34,6 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/ingress-nginx/test/e2e/framework" @@ -108,9 +107,8 @@ var _ = framework.DescribeSetting("OCSP", func() { err = framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, "ocspserve", f.Namespace, 1) assert.Nil(ginkgo.GinkgoT(), err, "waiting for endpoints to become ready") - f.WaitForLuaConfiguration(func(jsonCfg map[string]interface{}) bool { - val, ok, err := unstructured.NestedBool(jsonCfg, "enable_ocsp") - return err == nil && ok && val + f.WaitForNginxConfiguration(func(cfg string) bool { + return strings.Contains(cfg, "certificate.is_ocsp_stapling_enabled = true") }) f.WaitForNginxServer(host, @@ -297,7 +295,7 @@ func ocspserveDeployment(namespace string) (*appsv1.Deployment, *corev1.Service) Containers: []corev1.Container{ { Name: name, - Image: "registry.k8s.io/ingress-nginx/cfssl:v1.1.1@sha256:bcd576c6d0a01d4710969195e804c02da62b71b5c35c6816df9b7584d5445437", + Image: "registry.k8s.io/ingress-nginx/e2e-test-cfssl@sha256:48869cf72b0ceb1d8c82029f85961e423daf3ff8a04f4a455150000f90a90606", Command: []string{ "/bin/bash", "-c", diff --git a/test/e2e/settings/plugins.go b/test/e2e/settings/plugins.go new file mode 100644 index 000000000..659acd42c --- /dev/null +++ b/test/e2e/settings/plugins.go @@ -0,0 +1,55 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package settings + +import ( + "fmt" + "net/http" + "strings" + + "github.com/onsi/ginkgo/v2" + "k8s.io/ingress-nginx/test/e2e/framework" +) + +var _ = framework.IngressNginxDescribe("plugins", func() { + f := framework.NewDefaultFramework("plugins") + + ginkgo.BeforeEach(func() { + f.NewEchoDeployment() + }) + + ginkgo.It("should exist a x-hello-world header", func() { + f.UpdateNginxConfigMapData("plugins", "hello_world, invalid") + + host := "example.com" + f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil)) + + f.WaitForNginxConfiguration( + func(server string) bool { + return strings.Contains(server, fmt.Sprintf("server_name %v", host)) && + strings.Contains(server, `plugins.init({ "hello_world","invalid" })`) + }) + + f.HTTPTestClient(). + GET("/"). + WithHeader("Host", host). + WithHeader("User-Agent", "hello"). + Expect(). + Status(http.StatusOK). + Body().Contains("x-hello-world=1") + }) +}) diff --git a/test/e2e/settings/proxy_host.go b/test/e2e/settings/proxy_host.go index bb5dc9c01..35aafc53d 100644 --- a/test/e2e/settings/proxy_host.go +++ b/test/e2e/settings/proxy_host.go @@ -34,9 +34,14 @@ var _ = framework.IngressNginxDescribe("Dynamic $proxy_host", func() { }) ginkgo.It("should exist a proxy_host", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() - + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() upstreamName := fmt.Sprintf("%v-%v-80", f.Namespace, framework.EchoService) annotations := map[string]string{ "nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Custom-Header: $proxy_host"`, @@ -58,8 +63,14 @@ var _ = framework.IngressNginxDescribe("Dynamic $proxy_host", func() { }) ginkgo.It("should exist a proxy_host using the upstream-vhost annotation value", func() { - disableSnippet := f.AllowSnippetConfiguration() - defer disableSnippet() + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "true", + }) + defer func() { + f.SetNginxConfigMapData(map[string]string{ + "allow-snippet-annotations": "false", + }) + }() upstreamName := fmt.Sprintf("%v-%v-80", f.Namespace, framework.EchoService) upstreamVHost := "different.host" diff --git a/test/e2e/settings/server_snippet.go b/test/e2e/settings/server_snippet.go index 1e2084bd8..8ddf10fd9 100644 --- a/test/e2e/settings/server_snippet.go +++ b/test/e2e/settings/server_snippet.go @@ -38,7 +38,6 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() { f.SetNginxConfigMapData(map[string]string{ "allow-snippet-annotations": "true", - "annotations-risk-level": "Critical", "server-snippet": ` more_set_headers "Globalfoo: Foooo";`, }) @@ -46,7 +45,6 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() { defer func() { f.SetNginxConfigMapData(map[string]string{ "allow-snippet-annotations": "false", - "annotations-risk-level": "High", }) }() annotations := map[string]string{ @@ -103,7 +101,6 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() { f.SetNginxConfigMapData(map[string]string{ "allow-snippet-annotations": "false", - "annotations-risk-level": "Critical", // To allow Configuration Snippet "server-snippet": ` more_set_headers "Globalfoo: Foooo";`, }) @@ -111,7 +108,6 @@ var _ = framework.DescribeSetting("configmap server-snippet", func() { defer func() { f.SetNginxConfigMapData(map[string]string{ "allow-snippet-annotations": "false", - "annotations-risk-level": "High", }) }() annotations := map[string]string{ diff --git a/test/e2e/settings/tls.go b/test/e2e/settings/tls.go index 1ebf358c1..51f760df8 100644 --- a/test/e2e/settings/tls.go +++ b/test/e2e/settings/tls.go @@ -25,11 +25,10 @@ import ( "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/ingress-nginx/test/e2e/framework" ) -var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers", func() { +var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", func() { f := framework.NewDefaultFramework("settings-tls") host := "settings-tls" @@ -110,9 +109,8 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers", fu ginkgo.It("setting max-age parameter", func() { f.UpdateNginxConfigMapData(hstsMaxAge, "86400") - f.WaitForLuaConfiguration(func(jsonCfg map[string]interface{}) bool { - val, ok, err := unstructured.NestedString(jsonCfg, "hsts_max_age") - return err == nil && ok && val == "86400" + f.WaitForNginxConfiguration(func(server string) bool { + return strings.Contains(server, `hsts_max_age = 86400,`) }) f.HTTPTestClientWithTLSConfig(tlsConfig). @@ -130,9 +128,8 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers", fu hstsIncludeSubdomains: "false", }) - f.WaitForLuaConfiguration(func(jsonCfg map[string]interface{}) bool { - val, ok, err := unstructured.NestedBool(jsonCfg, "hsts_include_subdomains") - return err == nil && ok && !val + f.WaitForNginxConfiguration(func(server string) bool { + return strings.Contains(server, `hsts_include_subdomains = false,`) }) f.HTTPTestClientWithTLSConfig(tlsConfig). @@ -151,9 +148,8 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers", fu hstsIncludeSubdomains: "false", }) - f.WaitForLuaConfiguration(func(jsonCfg map[string]interface{}) bool { - val, ok, err := unstructured.NestedBool(jsonCfg, "hsts_preload") - return err == nil && ok && val + f.WaitForNginxConfiguration(func(server string) bool { + return strings.Contains(server, `hsts_preload = true,`) }) f.HTTPTestClientWithTLSConfig(tlsConfig). diff --git a/test/e2e/settings/validations/validations.go b/test/e2e/settings/validations/validations.go index 881de39b4..ac95a453a 100644 --- a/test/e2e/settings/validations/validations.go +++ b/test/e2e/settings/validations/validations.go @@ -48,8 +48,8 @@ var _ = framework.IngressNginxDescribeSerial("annotation validations", func() { framework.Sleep() annotations := map[string]string{ - "nginx.ingress.kubernetes.io/default-backend": "bla", // low risk - "nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk + "nginx.ingress.kubernetes.io/default-backend": "default/bla", // low risk + "nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk } ginkgo.By("allow ingress with low/medium risk annotations") @@ -82,8 +82,8 @@ var _ = framework.IngressNginxDescribeSerial("annotation validations", func() { framework.Sleep() annotations := map[string]string{ - "nginx.ingress.kubernetes.io/default-backend": "bla", // low risk - "nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk + "nginx.ingress.kubernetes.io/default-backend": "default/bla", // low risk + "nginx.ingress.kubernetes.io/denylist-source-range": "1.1.1.1/32", // medium risk } ginkgo.By("allow ingress with low/medium risk annotations") diff --git a/test/e2e/wait-for-nginx.sh b/test/e2e/wait-for-nginx.sh index 73023aba1..ac0584962 100755 --- a/test/e2e/wait-for-nginx.sh +++ b/test/e2e/wait-for-nginx.sh @@ -24,6 +24,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export NAMESPACE=$1 export NAMESPACE_OVERLAY=$2 export IS_CHROOT=$3 +export ENABLE_VALIDATIONS=$4 echo "deploying NGINX Ingress controller in namespace $NAMESPACE" @@ -58,6 +59,7 @@ else # TODO: remove the need to use fullnameOverride fullnameOverride: nginx-ingress controller: + enableAnnotationValidations: ${ENABLE_VALIDATIONS} image: repository: ingress-controller/controller chroot: ${IS_CHROOT} diff --git a/test/k6/loadtest.js b/test/k6/loadtest.js index 51801765e..2396948fc 100644 --- a/test/k6/loadtest.js +++ b/test/k6/loadtest.js @@ -1,6 +1,6 @@ // This is a loadtest under development // Test here is spec'd to have 100virtual-users -// Other specs currently similar to smoketest +// Other specs currently similar to smoktest // But loadtest needs testplan that likely uses auth & data-transfer import http from 'k6/http'; @@ -35,7 +35,7 @@ export default function () { const req3 = { params: { headers: { - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' }, }, method: 'POST', diff --git a/test/k6/smoketest.js b/test/k6/smoketest.js index 12691b63a..8fe9e950a 100644 --- a/test/k6/smoketest.js +++ b/test/k6/smoketest.js @@ -1,4 +1,4 @@ -// smoketest.js edited after copy/pasting from https://k6.io docs +// smotest.js edited after copy/pasting from https://k6.io docs // Using this like loadtest because of limited cpu/memory/other import http from 'k6/http'; @@ -22,7 +22,7 @@ export const options = { }; export default function () { - // docs of k6 say this is how to add host header + // docs of k6 say this is how to adds host header // needed as ingress is created with this host value const params = { headers: {'host': 'test.ingress-nginx-controller.ga'}, @@ -39,7 +39,7 @@ export default function () { const req3 = { params: { headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json' }, }, method: 'POST', diff --git a/test/manifests/configuration-a.json b/test/manifests/configuration-a.json index f9599d77c..ba513c616 100644 --- a/test/manifests/configuration-a.json +++ b/test/manifests/configuration-a.json @@ -302,12 +302,7 @@ "validationDepth": 0 }, "use-port-in-redirects": false, - "configuration-snippet": "", - "customHeaders": { - "headers": { - "Server": "HAL9000" - } - } + "configuration-snippet": "" }] }, { "hostname": "dev.mycompany.com", diff --git a/test/manifests/configuration-b.json b/test/manifests/configuration-b.json index d2e71bb29..9e40785b4 100644 --- a/test/manifests/configuration-b.json +++ b/test/manifests/configuration-b.json @@ -302,12 +302,7 @@ "validationDepth": 0 }, "use-port-in-redirects": false, - "configuration-snippet": "", - "customHeaders": { - "headers": { - "Server": "HAL9000" - } - } + "configuration-snippet": "" }] }, { "hostname": "dev.mycompany.com", diff --git a/test/test-lua.sh b/test/test-lua.sh index e7ee5843e..fc60023f8 100755 --- a/test/test-lua.sh +++ b/test/test-lua.sh @@ -36,11 +36,12 @@ SHDICT_ARGS=( "--shdict" "high_throughput_tracker 1M" "--shdict" "balancer_ewma_last_touched_at 1M" "--shdict" "balancer_ewma_locks 512k" + "--shdict" "global_throttle_cache 5M" "./rootfs/etc/nginx/lua/test/run.lua" ) if [ $# -eq 0 ]; then - resty "${SHDICT_ARGS[@]}" ./rootfs/etc/nginx/lua/test/ ${BUSTED_ARGS} + resty "${SHDICT_ARGS[@]}" ./rootfs/etc/nginx/lua/test/ ./rootfs/etc/nginx/lua/plugins/**/test ${BUSTED_ARGS} else resty "${SHDICT_ARGS[@]}" $@ ${BUSTED_ARGS} fi