Repository: kubernetes/ingress-nginx
Pull request #9090 (2022-09-26 16:59:01)

fix chroot module mount path
<!--- Provide a general summary of your changes in the Title above --->
<!--- Please don't @-mention people in PR or commit messages (do so in an additional comment). --->

## What this PR does / why we need it:
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

modules mounted via volume have wrong path as they are not copied to the chroot directory.
This PR fixes the mount path when chroot is used.

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] CVE Report (Scanner found CVE and adding report)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation only

## Which issue/s this PR fixes
<!--
(optional, in `fixes #<issue number>` format, will close that issue when PR gets merged):

fixes #
-->
related to #9016 step 1
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
loaded module:
![image](https://user-images.githubusercontent.com/71217171/192336081-50e589c8-8f89-4d34-8b5b-f4b7624cd3dc.png)

pod status:
![image](https://user-images.githubusercontent.com/71217171/192336227-fcac51c2-3bf1-493a-9d58-831c0ff10b92.png)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I've read the [CONTRIBUTION](https://github.com/kubernetes/ingress-nginx/blob/main/CONTRIBUTING.md) guide
- [ ] I have added unit and/or e2e tests to cover my changes.
- [ ] All new and existing tests passed.
- [ ] Added Release Notes.

## Does my pull request need a release note?
Any user-visible or operator-visible change qualifies for a release note. This could be a:

- CLI change
- API change
- UI change
- configuration schema change
- behavioral change
- change in non-functional attributes such as efficiency or availability, availability of a new platform
- a warning about a deprecation
- fix of a previous Known Issue
- fix of a vulnerability (CVE)

No release notes are required for changes to the following:

- Tests
- Build infrastructure
- Fixes for unreleased bugs

For more tips on writing good release notes, check out the [Release Notes Handbook](https://github.com/kubernetes/sig-release/tree/master/release-team/role-handbooks/release-notes)

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->
```release-note
fix chroot module mount path
```


k8s-ci-robot: @esigo: This issue is currently awaiting triage.

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

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


<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: Hi @esigo. Thanks for your PR.

I'm waiting for a [kubernetes](https://github.com/orgs/kubernetes/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fingress-nginx).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#" title="Author self-approved">esigo</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign tao12345666333 for approval by writing `/assign @tao12345666333` in a comment. For more information see:[The Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fingress-nginx).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/ingress-nginx/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["tao12345666333"]} -->
longwuyuan: /ok-to-test
Thanks
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#" title="Author self-approved">esigo</a>*, *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#issuecomment-1259178085" title="LGTM">longwuyuan</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign tao12345666333 for approval by writing `/assign @tao12345666333` in a comment. For more information see:[The Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fingress-nginx).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/ingress-nginx/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["tao12345666333"]} -->
rikatz: /approve
Please fix the release notes field in the PR, then this can be unhold

thanks
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#pullrequestreview-1121616273" title="Approved">cpanato</a>*, *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#" title="Author self-approved">esigo</a>*, *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#issuecomment-1259178085" title="LGTM">longwuyuan</a>*, *<a href="https://github.com/kubernetes/ingress-nginx/pull/9090#issuecomment-1259294007" title="Approved">rikatz</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fingress-nginx).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes/ingress-nginx/blob/main/OWNERS)~~ [rikatz]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/charts/ingress-nginx/templates/controller-deployment.yaml b/charts/ingress-nginx/templates/controller-deployment.yaml
index 5ad186794..c193f776c 100644
--- a/charts/ingress-nginx/templates/controller-deployment.yaml
+++ b/charts/ingress-nginx/templates/controller-deployment.yaml
@@ -147,7 +147,11 @@ spec:
           volumeMounts:
           {{- if .Values.controller.extraModules }}
             - name: modules
+            {{ if .Values.controller.image.chroot }}
+              mountPath: /chroot/modules_mount
+            {{ else }}
               mountPath: /modules_mount
+            {{ end }}
           {{- end }}
           {{- if .Values.controller.customTemplate.configMapName }}
             - mountPath: /etc/nginx/template
diff --git a/cmd/plugin/request/request.go b/cmd/plugin/request/request.go
index cae90e9d2..fd47564a9 100644
--- a/cmd/plugin/request/request.go
+++ b/cmd/plugin/request/request.go
@@ -22,11 +22,13 @@ import (
 
 	appsv1 "k8s.io/api/apps/v1"
 	apiv1 "k8s.io/api/core/v1"
+	discoveryv1 "k8s.io/api/discovery/v1"
 	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 	appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
 	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+	discoveryv1client "k8s.io/client-go/kubernetes/typed/discovery/v1"
 	typednetworking "k8s.io/client-go/kubernetes/typed/networking/v1"
 
 	"k8s.io/ingress-nginx/cmd/plugin/util"
@@ -129,55 +131,61 @@ func GetIngressDefinitions(flags *genericclioptions.ConfigFlags, namespace strin
 	return pods.Items, nil
 }
 
-// GetNumEndpoints counts the number of endpoints for the service with the given name
+// GetNumEndpoints counts the number of endpointslices adresses for the service with the given name
 func GetNumEndpoints(flags *genericclioptions.ConfigFlags, namespace string, serviceName string) (*int, error) {
-	endpoints, err := GetEndpointsByName(flags, namespace, serviceName)
+	epss, err := GetEndpointSlicesByName(flags, namespace, serviceName)
 	if err != nil {
 		return nil, err
 	}
 
-	if endpoints == nil {
+	if len(epss) == 0 {
 		return nil, nil
 	}
 
 	ret := 0
-	for _, subset := range endpoints.Subsets {
-		ret += len(subset.Addresses)
+	for _, eps := range epss {
+		for _, ep := range eps.Endpoints {
+			ret += len(ep.Addresses)
+		}
 	}
 	return &ret, nil
 }
 
-// GetEndpointsByName returns the endpoints for the service with the given name
-func GetEndpointsByName(flags *genericclioptions.ConfigFlags, namespace string, name string) (*apiv1.Endpoints, error) {
-	allEndpoints, err := getEndpoints(flags, namespace)
+// GetEndpointSlicesByName returns the endpointSlices for the service with the given name
+func GetEndpointSlicesByName(flags *genericclioptions.ConfigFlags, namespace string, name string) ([]discoveryv1.EndpointSlice, error) {
+	allEndpointsSlices, err := getEndpointSlices(flags, namespace)
 	if err != nil {
 		return nil, err
 	}
-
-	for _, endpoints := range allEndpoints {
-		if endpoints.Name == name {
-			return &endpoints, nil
+	var eps []discoveryv1.EndpointSlice
+	for _, slice := range allEndpointsSlices {
+		if svcName, ok := slice.ObjectMeta.GetLabels()[discoveryv1.LabelServiceName]; ok {
+			if svcName == name {
+				eps = append(eps, slice)
+			}
 		}
 	}
 
-	return nil, nil
+	return eps, nil
 }
 
-var endpointsCache = make(map[string]*[]apiv1.Endpoints)
+var endpointSlicesCache = make(map[string]*[]discoveryv1.EndpointSlice)
+
+func getEndpointSlices(flags *genericclioptions.ConfigFlags, namespace string) ([]discoveryv1.EndpointSlice, error) {
+	cachedEndpointSlices, ok := endpointSlicesCache[namespace]
 
-func getEndpoints(flags *genericclioptions.ConfigFlags, namespace string) ([]apiv1.Endpoints, error) {
-	cachedEndpoints, ok := endpointsCache[namespace]
 	if ok {
-		return *cachedEndpoints, nil
+		return *cachedEndpointSlices, nil
 	}
 
 	if namespace != "" {
-		tryAllNamespacesEndpointsCache(flags)
+		tryAllNamespacesEndpointSlicesCache(flags)
 	}
 
-	cachedEndpoints = tryFilteringEndpointsFromAllNamespacesCache(flags, namespace)
-	if cachedEndpoints != nil {
-		return *cachedEndpoints, nil
+	cachedEndpointSlices = tryFilteringEndpointSlicesFromAllNamespacesCache(flags, namespace)
+
+	if cachedEndpointSlices != nil {
+		return *cachedEndpointSlices, nil
 	}
 
 	rawConfig, err := flags.ToRESTConfig()
@@ -185,42 +193,41 @@ func getEndpoints(flags *genericclioptions.ConfigFlags, namespace string) ([]api
 		return nil, err
 	}
 
-	api, err := corev1.NewForConfig(rawConfig)
+	api, err := discoveryv1client.NewForConfig(rawConfig)
 	if err != nil {
 		return nil, err
 	}
-
-	endpointsList, err := api.Endpoints(namespace).List(context.TODO(), metav1.ListOptions{})
+	endpointSlicesList, err := api.EndpointSlices(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
-	endpoints := endpointsList.Items
+	endpointSlices := endpointSlicesList.Items
 
-	endpointsCache[namespace] = &endpoints
-	return endpoints, nil
+	endpointSlicesCache[namespace] = &endpointSlices
+	return endpointSlices, nil
 }
 
-func tryAllNamespacesEndpointsCache(flags *genericclioptions.ConfigFlags) {
-	_, ok := endpointsCache[""]
+func tryAllNamespacesEndpointSlicesCache(flags *genericclioptions.ConfigFlags) {
+	_, ok := endpointSlicesCache[""]
 	if !ok {
-		_, err := getEndpoints(flags, "")
+		_, err := getEndpointSlices(flags, "")
 		if err != nil {
-			endpointsCache[""] = nil
+			endpointSlicesCache[""] = nil
 		}
 	}
 }
 
-func tryFilteringEndpointsFromAllNamespacesCache(flags *genericclioptions.ConfigFlags, namespace string) *[]apiv1.Endpoints {
-	allEndpoints := endpointsCache[""]
-	if allEndpoints != nil {
-		endpoints := make([]apiv1.Endpoints, 0)
-		for _, thisEndpoints := range *allEndpoints {
-			if thisEndpoints.Namespace == namespace {
-				endpoints = append(endpoints, thisEndpoints)
+func tryFilteringEndpointSlicesFromAllNamespacesCache(flags *genericclioptions.ConfigFlags, namespace string) *[]discoveryv1.EndpointSlice {
+	allEndpointSlices := endpointSlicesCache[""]
+	if allEndpointSlices != nil {
+		endpointSlices := make([]discoveryv1.EndpointSlice, 0)
+		for _, slice := range *allEndpointSlices {
+			if slice.Namespace == namespace {
+				endpointSlices = append(endpointSlices, slice)
 			}
 		}
-		endpointsCache[namespace] = &endpoints
-		return &endpoints
+		endpointSlicesCache[namespace] = &endpointSlices
+		return &endpointSlices
 	}
 	return nil
 }
diff --git a/docs/developer-guide/getting-started.md b/docs/developer-guide/getting-started.md
index 8d500f147..fbf251790 100644
--- a/docs/developer-guide/getting-started.md
+++ b/docs/developer-guide/getting-started.md
@@ -88,3 +88,6 @@ and then publish such version with
 ```console
 docker push $REGISTRY/controller:$TAG
 ```
+
+### New Contributor Tips
+New contributors can refer to the [new contributor tips](https://github.com/kubernetes/ingress-nginx/blob/main/NEW_CONTRIBUTOR.md) which will be updated with examples and tips.
diff --git a/docs/examples/affinity/cookie/README.md b/docs/examples/affinity/cookie/README.md
index 891f828a2..1920d132b 100644
--- a/docs/examples/affinity/cookie/README.md
+++ b/docs/examples/affinity/cookie/README.md
@@ -14,6 +14,7 @@ Session affinity can be configured using the following annotations:
 |nginx.ingress.kubernetes.io/session-cookie-name|Name of the cookie that will be created|string (defaults to `INGRESSCOOKIE`)|
 |nginx.ingress.kubernetes.io/session-cookie-secure|Set the cookie as secure regardless the protocol of the incoming request|`"true"` or `"false"`|
 |nginx.ingress.kubernetes.io/session-cookie-path|Path that will be set on the cookie (required if your [Ingress paths][ingress-paths] use regular expressions)|string (defaults to the currently [matched path][ingress-paths])|
+|nginx.ingress.kubernetes.io/session-cookie-domain|Domain that will be set on the cookie|string|
 |nginx.ingress.kubernetes.io/session-cookie-samesite|`SameSite` attribute to apply to the cookie|Browser accepted values are `None`, `Lax`, and `Strict`|
 |nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none|Will omit `SameSite=None` attribute for older browsers which reject the more-recently defined `SameSite=None` value|`"true"` or `"false"`
 |nginx.ingress.kubernetes.io/session-cookie-max-age|Time until the cookie expires, corresponds to the `Max-Age` cookie directive|number of seconds|
diff --git a/docs/user-guide/nginx-configuration/annotations.md b/docs/user-guide/nginx-configuration/annotations.md
index 199d156be..131320bf7 100755
--- a/docs/user-guide/nginx-configuration/annotations.md
+++ b/docs/user-guide/nginx-configuration/annotations.md
@@ -98,6 +98,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
 |[nginx.ingress.kubernetes.io/service-upstream](#service-upstream)|"true" or "false"|
 |[nginx.ingress.kubernetes.io/session-cookie-name](#cookie-affinity)|string|
 |[nginx.ingress.kubernetes.io/session-cookie-path](#cookie-affinity)|string|
+|[nginx.ingress.kubernetes.io/session-cookie-domain](#cookie-affinity)|string|
 |[nginx.ingress.kubernetes.io/session-cookie-change-on-failure](#cookie-affinity)|"true" or "false"|
 |[nginx.ingress.kubernetes.io/session-cookie-samesite](#cookie-affinity)|string|
 |[nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none](#cookie-affinity)|"true" or "false"|
@@ -189,6 +190,8 @@ If you use the ``cookie`` affinity type you can also specify the name of the coo
 
 The NGINX annotation `nginx.ingress.kubernetes.io/session-cookie-path` defines the path that will be set on the cookie. This is optional unless the annotation `nginx.ingress.kubernetes.io/use-regex` is set to true; Session cookie paths do not support regex.
 
+Use `nginx.ingress.kubernetes.io/session-cookie-domain` to set the `Domain` attribute of the sticky cookie.
+
 Use `nginx.ingress.kubernetes.io/session-cookie-samesite` to apply a `SameSite` attribute to the sticky cookie. Browser accepted values are `None`, `Lax`, and `Strict`. Some browsers reject cookies with `SameSite=None`, including those created before the `SameSite=None` specification (e.g. Chrome 5X). Other browsers mistakenly treat `SameSite=None` cookies as `SameSite=Strict` (e.g. Safari running on OSX 14). To omit `SameSite=None` from browsers with these incompatibilities, add the annotation `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none: "true"`.
 
 ### Authentication
diff --git a/go.mod b/go.mod
index ca896babd..471e7749e 100644
--- a/go.mod
+++ b/go.mod
@@ -30,14 +30,14 @@ require (
 	google.golang.org/grpc v1.49.0
 	gopkg.in/go-playground/pool.v3 v3.1.1
 	gopkg.in/mcuadros/go-syslog.v2 v2.3.0
-	k8s.io/api v0.25.1
+	k8s.io/api v0.25.2
 	k8s.io/apiextensions-apiserver v0.23.5
-	k8s.io/apimachinery v0.25.1
+	k8s.io/apimachinery v0.25.2
 	k8s.io/apiserver v0.25.0
 	k8s.io/cli-runtime v0.25.0
-	k8s.io/client-go v0.25.1
+	k8s.io/client-go v0.25.2
 	k8s.io/code-generator v0.23.5
-	k8s.io/component-base v0.25.1
+	k8s.io/component-base v0.25.2
 	k8s.io/klog/v2 v2.80.1
 	pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
 	sigs.k8s.io/controller-runtime v0.11.2
diff --git a/go.sum b/go.sum
index 8127cfbf4..65fb4ee78 100644
--- a/go.sum
+++ b/go.sum
@@ -1134,26 +1134,26 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
-k8s.io/api v0.25.1 h1:yL7du50yc93k17nH/Xe9jujAYrcDkI/i5DL1jPz4E3M=
-k8s.io/api v0.25.1/go.mod h1:hh4itDvrWSJsmeUc28rIFNri8MatNAAxJjKcQmhX6TU=
+k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8=
+k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0=
 k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI=
 k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
 k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
-k8s.io/apimachinery v0.25.1 h1:t0XrnmCEHVgJlR2arwO8Awp9ylluDic706WePaYCBTI=
-k8s.io/apimachinery v0.25.1/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA=
+k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs=
+k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA=
 k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw=
 k8s.io/apiserver v0.25.0 h1:8kl2ifbNffD440MyvHtPaIz1mw4mGKVgWqM0nL+oyu4=
 k8s.io/apiserver v0.25.0/go.mod h1:BKwsE+PTC+aZK+6OJQDPr0v6uS91/HWxX7evElAH6xo=
 k8s.io/cli-runtime v0.25.0 h1:XBnTc2Fi+w818jcJGzhiJKQuXl8479sZ4FhtV5hVJ1Q=
 k8s.io/cli-runtime v0.25.0/go.mod h1:bHOI5ZZInRHhbq12OdUiYZQN8ml8aKZLwQgt9QlLINw=
 k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
-k8s.io/client-go v0.25.1 h1:uFj4AJKtE1/ckcSKz8IhgAuZTdRXZDKev8g387ndD58=
-k8s.io/client-go v0.25.1/go.mod h1:rdFWTLV/uj2C74zGbQzOsmXPUtMAjSf7ajil4iJUNKo=
+k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo=
+k8s.io/client-go v0.25.2/go.mod h1:i7cNU7N+yGQmJkewcRD2+Vuj4iz7b30kI8OcL3horQ4=
 k8s.io/code-generator v0.23.5 h1:xn3a6J5pUL49AoH6SPrOFtnB5cvdMl76f/bEY176R3c=
 k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
 k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
-k8s.io/component-base v0.25.1 h1:Wmj33QwddVwsJFJWmXlf24Nu8do2bGHLabXHrKz7Org=
-k8s.io/component-base v0.25.1/go.mod h1:j78+TFdsKM8RXHfM88oeAdZu2v9qMZdQZOfg0LGW+q4=
+k8s.io/component-base v0.25.2 h1:Nve/ZyHLUBHz1rqwkjXm/Re6IniNa5k7KgzxZpTfSQY=
+k8s.io/component-base v0.25.2/go.mod h1:90W21YMr+Yjg7MX+DohmZLzjsBtaxQDDwaX4YxDkl60=
 k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA=
 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=
diff --git a/images/nginx/rootfs/build.sh b/images/nginx/rootfs/build.sh
index f3efb3663..75d765e78 100755
--- a/images/nginx/rootfs/build.sh
+++ b/images/nginx/rootfs/build.sh
@@ -60,10 +60,10 @@ export DATADOG_CPP_VERSION=1.3.2
 export MODSECURITY_VERSION=1.0.2
 
 # Check for recent changes: https://github.com/SpiderLabs/ModSecurity/compare/v3.0.5...v3/master
-export MODSECURITY_LIB_VERSION=v3.0.5
+export MODSECURITY_LIB_VERSION=v3.0.8
 
 # Check for recent changes: https://github.com/coreruleset/coreruleset/compare/v3.3.2...v3.3/master
-export OWASP_MODSECURITY_CRS_VERSION=v3.3.2
+export OWASP_MODSECURITY_CRS_VERSION=v3.3.4
 
 # Check for recent changes: https://github.com/openresty/lua-nginx-module/compare/v0.10.20...master
 export LUA_NGX_VERSION=b721656a9127255003b696b42ccc871c7ec18d59
@@ -548,6 +548,7 @@ 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
+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
diff --git a/internal/ingress/annotations/sessionaffinity/main.go b/internal/ingress/annotations/sessionaffinity/main.go
index 9c4d1d2bc..98a0d64f8 100644
--- a/internal/ingress/annotations/sessionaffinity/main.go
+++ b/internal/ingress/annotations/sessionaffinity/main.go
@@ -52,6 +52,9 @@ const (
 	// This is used to control the cookie path when use-regex is set to true
 	annotationAffinityCookiePath = "session-cookie-path"
 
+	// This is used to control the cookie Domain
+	annotationAffinityCookieDomain = "session-cookie-domain"
+
 	// This is used to control the SameSite attribute of the cookie
 	annotationAffinityCookieSameSite = "session-cookie-samesite"
 
@@ -87,6 +90,8 @@ type Cookie struct {
 	MaxAge string `json:"maxage"`
 	// The path that a cookie will be set on
 	Path string `json:"path"`
+	// The domain that a cookie will be set on
+	Domain string `json:"domain"`
 	// Flag that allows cookie regeneration on request failure
 	ChangeOnFailure bool `json:"changeonfailure"`
 	// Secure flag to be set
@@ -127,6 +132,11 @@ func (a affinity) cookieAffinityParse(ing *networking.Ingress) *Cookie {
 		klog.V(3).InfoS("Invalid or no annotation value found. Ignoring", "ingress", klog.KObj(ing), "annotation", annotationAffinityCookiePath)
 	}
 
+	cookie.Domain, err = parser.GetStringAnnotation(annotationAffinityCookieDomain, ing)
+	if err != nil {
+		klog.V(3).InfoS("Invalid or no annotation value found. Ignoring", "ingress", klog.KObj(ing), "annotation", annotationAffinityCookieDomain)
+	}
+
 	cookie.SameSite, err = parser.GetStringAnnotation(annotationAffinityCookieSameSite, ing)
 	if err != nil {
 		klog.V(3).InfoS("Invalid or no annotation value found. Ignoring", "ingress", klog.KObj(ing), "annotation", annotationAffinityCookieSameSite)
diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go
index 84da5eb30..f60f7a053 100644
--- a/internal/ingress/controller/controller.go
+++ b/internal/ingress/controller/controller.go
@@ -767,6 +767,7 @@ func (n *NGINXController) getBackendServers(ingresses []*ingress.Ingress) ([]*in
 					ups.SessionAffinity.CookieSessionAffinity.MaxAge = anns.SessionAffinity.Cookie.MaxAge
 					ups.SessionAffinity.CookieSessionAffinity.Secure = anns.SessionAffinity.Cookie.Secure
 					ups.SessionAffinity.CookieSessionAffinity.Path = cookiePath
+					ups.SessionAffinity.CookieSessionAffinity.Domain = anns.SessionAffinity.Cookie.Domain
 					ups.SessionAffinity.CookieSessionAffinity.SameSite = anns.SessionAffinity.Cookie.SameSite
 					ups.SessionAffinity.CookieSessionAffinity.ConditionalSameSiteNone = anns.SessionAffinity.Cookie.ConditionalSameSiteNone
 					ups.SessionAffinity.CookieSessionAffinity.ChangeOnFailure = anns.SessionAffinity.Cookie.ChangeOnFailure
diff --git a/pkg/apis/ingress/types.go b/pkg/apis/ingress/types.go
index 8460ee684..7c1c825b7 100644
--- a/pkg/apis/ingress/types.go
+++ b/pkg/apis/ingress/types.go
@@ -159,6 +159,7 @@ type CookieSessionAffinity struct {
 	Locations               map[string][]string `json:"locations,omitempty"`
 	Secure                  bool                `json:"secure,omitempty"`
 	Path                    string              `json:"path,omitempty"`
+	Domain                  string              `json:"domain,omitempty"`
 	SameSite                string              `json:"samesite,omitempty"`
 	ConditionalSameSiteNone bool                `json:"conditional_samesite_none,omitempty"`
 	ChangeOnFailure         bool                `json:"change_on_failure,omitempty"`
diff --git a/pkg/apis/ingress/types_equals.go b/pkg/apis/ingress/types_equals.go
index 1ba80d07e..a954a253b 100644
--- a/pkg/apis/ingress/types_equals.go
+++ b/pkg/apis/ingress/types_equals.go
@@ -173,6 +173,9 @@ func (csa1 *CookieSessionAffinity) Equal(csa2 *CookieSessionAffinity) bool {
 	if csa1.Path != csa2.Path {
 		return false
 	}
+	if csa1.Domain != csa2.Domain {
+		return false
+	}
 	if csa1.Expires != csa2.Expires {
 		return false
 	}
@@ -192,7 +195,7 @@ func (csa1 *CookieSessionAffinity) Equal(csa2 *CookieSessionAffinity) bool {
 	return true
 }
 
-//Equal checks the equality between UpstreamByConfig types
+// Equal checks the equality between UpstreamByConfig types
 func (u1 *UpstreamHashByConfig) Equal(u2 *UpstreamHashByConfig) bool {
 	if u1 == u2 {
 		return true
diff --git a/rootfs/Dockerfile-chroot b/rootfs/Dockerfile-chroot
index 64b222890..4805909d5 100644
--- a/rootfs/Dockerfile-chroot
+++ b/rootfs/Dockerfile-chroot
@@ -84,7 +84,7 @@ RUN bash -xeu -c ' \
   # LD_LIBRARY_PATH does not work so below is needed for  opentelemetry/other modules
   # Put libs of newer modules under `/modules_mount/<other>/lib` and add that path below
   # Could get complicated arch specific paths become a need
-  && echo "/lib:/usr/lib:/usr/local/lib:/modules_mount/otel/lib" > /etc/ld-musl-x86_64.path
+  && echo "/lib:/usr/lib:/usr/local/lib:/modules_mount/etc/nginx/modules/otel" > /chroot/etc/ld-musl-x86_64.path
 
 RUN apk add --no-cache libcap \
   && setcap    cap_sys_chroot,cap_net_bind_service=+ep /nginx-ingress-controller \
@@ -113,6 +113,10 @@ RUN  ln -sf /chroot/etc/nginx /etc/nginx \
   && mknod -m 0666 /chroot/dev/zero c 1 5 \
   && mknod -m 0666 /chroot/dev/tty c 5 0
 
+RUN mkdir -p /chroot/modules_mount \
+  && mkdir -p modules_mount \
+  && ln -s /modules_mount /chroot/modules_mount
+
 USER www-data
 
 EXPOSE 80 443
diff --git a/rootfs/etc/nginx/lua/balancer/sticky.lua b/rootfs/etc/nginx/lua/balancer/sticky.lua
index 3440d86bd..9d0a54116 100644
--- a/rootfs/etc/nginx/lua/balancer/sticky.lua
+++ b/rootfs/etc/nginx/lua/balancer/sticky.lua
@@ -110,6 +110,10 @@ function _M.set_cookie(self, value)
     cookie_data.max_age = tonumber(self.cookie_session_affinity.maxage)
   end
 
+  if self.cookie_session_affinity.domain and self.cookie_session_affinity.domain ~= "" then
+    cookie_data.domain = self.cookie_session_affinity.domain
+  end
+
   local ok
   ok, err = cookie:set(cookie_data)
   if not ok then


Test patch:
diff --git a/internal/ingress/annotations/sessionaffinity/main_test.go b/internal/ingress/annotations/sessionaffinity/main_test.go
index 65d11ac2d..cffe57fec 100644
--- a/internal/ingress/annotations/sessionaffinity/main_test.go
+++ b/internal/ingress/annotations/sessionaffinity/main_test.go
@@ -78,6 +78,7 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieExpires)] = "4500"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieMaxAge)] = "3000"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookiePath)] = "/foo"
+	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieDomain)] = "foo.bar"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieChangeOnFailure)] = "true"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieSecure)] = "true"
 	ing.SetAnnotations(data)
@@ -112,6 +113,10 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
 		t.Errorf("expected /foo as session-cookie-path but returned %v", nginxAffinity.Cookie.Path)
 	}
 
+	if nginxAffinity.Cookie.Domain != "foo.bar" {
+		t.Errorf("expected foo.bar as session-cookie-domain but returned %v", nginxAffinity.Cookie.Domain)
+	}
+
 	if !nginxAffinity.Cookie.ChangeOnFailure {
 		t.Errorf("expected change of failure parameter set to true but returned %v", nginxAffinity.Cookie.ChangeOnFailure)
 	}
diff --git a/test/e2e/annotations/affinity.go b/test/e2e/annotations/affinity.go
index 6a0a0bf48..3e1e9e969 100644
--- a/test/e2e/annotations/affinity.go
+++ b/test/e2e/annotations/affinity.go
@@ -222,6 +222,51 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
 			Header("Set-Cookie").Contains(fmt.Sprintf("Expires=%s", expected)).Contains("Max-Age=259200")
 	})
 
+	ginkgo.It("should set cookie with domain", func() {
+		host := "cookiedomain.foo.com"
+		annotations := make(map[string]string)
+		annotations["nginx.ingress.kubernetes.io/affinity"] = "cookie"
+		annotations["nginx.ingress.kubernetes.io/session-cookie-name"] = "DomainCookie"
+		annotations["nginx.ingress.kubernetes.io/session-cookie-domain"] = "foo.bar"
+
+		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
+		f.EnsureIngress(ing)
+
+		f.WaitForNginxServer(host,
+			func(server string) bool {
+				return strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
+			})
+
+		f.HTTPTestClient().
+			GET("/").
+			WithHeader("Host", host).
+			Expect().
+			Status(http.StatusOK).
+			Header("Set-Cookie").Contains("Domain=foo.bar")
+	})
+
+	ginkgo.It("should not set cookie without domain annotation", func() {
+		host := "cookienodomain.foo.com"
+		annotations := make(map[string]string)
+		annotations["nginx.ingress.kubernetes.io/affinity"] = "cookie"
+		annotations["nginx.ingress.kubernetes.io/session-cookie-name"] = "NoDomainCookie"
+
+		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
+		f.EnsureIngress(ing)
+
+		f.WaitForNginxServer(host,
+			func(server string) bool {
+				return strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
+			})
+
+		f.HTTPTestClient().
+			GET("/").
+			WithHeader("Host", host).
+			Expect().
+			Status(http.StatusOK).
+			Header("Set-Cookie").NotContains("; Domain")
+	})
+
 	ginkgo.It("should work with use-regex annotation and session-cookie-path", func() {
 		host := "useregex.foo.com"
 		annotations := make(map[string]string)