Repository: kubernetes/ingress-nginx
Pull request #7561 (2021-08-28 19:59:41)

Add doc ref for preserve-trailing-slash annotation

<!--- 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:

Fixes issue #7555.  Adds reference for `nginx.ingress.kubernetes.io/preserve-trailing-slash` annotation which was missing.

<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## 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)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Which issue/s this PR fixes
<!--
(optional, in `fixes #<issue number>` format, will close that issue when PR gets merged):

fixes #7555 
-->

## 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. -->
N/A. This is purely a documentation change.

## 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! -->
NOTE: I am in the process of getting my organization to sign the corporate SLA.

- [x] My change requires a change to the documentation.
- [x] 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 tests to cover my changes.
- [ ] All new and existing tests passed.


k8s-ci-robot: @fredthomsen: 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: Welcome @fredthomsen! <br><br>It looks like this is your first PR to <a href='https://github.com/kubernetes/ingress-nginx'>kubernetes/ingress-nginx</a> 🎉. Please refer to our [pull request process documentation](https://git.k8s.io/community/contributors/guide/pull-requests.md) to help your PR have a smooth ride to approval. <br><br>You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. [Here is the bot commands documentation](https://go.k8s.io/bot-commands). <br><br>You can also check if kubernetes/ingress-nginx has [its own contribution guidelines](https://github.com/kubernetes/ingress-nginx/tree/master/CONTRIBUTING.md). <br><br>You may want to refer to our [testing guide](https://git.k8s.io/community/contributors/devel/sig-testing/testing.md) if you run into trouble with your tests not passing. <br><br>If you are having difficulty getting your pull request seen, please follow the [recommended escalation practices](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#why-is-my-pull-request-not-getting-reviewed). Also, for tips and tricks in the contribution process you may want to read the [Kubernetes contributor cheat sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md). We want to make sure your contribution gets all the attention it needs! <br><br>Thank you, and welcome to Kubernetes. :smiley:
k8s-ci-robot: Hi @fredthomsen. 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: Thanks for your pull request. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please follow instructions at <https://git.k8s.io/community/CLA.md#the-contributor-license-agreement> to sign the CLA.**

It may take a couple minutes for the CLA signature to be fully registered; after that, please reply here with a new comment and we'll verify.  Thanks.

---

- If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address.  Check your existing CLA data and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
- If you signed the CLA as a corporation, please sign in with your organization's credentials at <https://identity.linuxfoundation.org/projects/cncf> to be authorized.
- If you have done the above and are still having issues with the CLA being reported as unsigned, please log a ticket with the Linux Foundation Helpdesk: <https://support.linuxfoundation.org/>
- Should you encounter any issues with the Linux Foundation Helpdesk, send a message to the backup e-mail support address at: login-issues@jira.linuxfoundation.org

<!-- need_sender_cla -->

<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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</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/7561#" title="Author self-approved">fredthomsen</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **dcbw** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @dcbw` in a comment when ready.

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":["dcbw"]} -->
fredthomsen: I signed it

Patch:
diff --git a/charts/ingress-nginx/templates/controller-service-internal.yaml b/charts/ingress-nginx/templates/controller-service-internal.yaml
index 09c942eb2..599449836 100644
--- a/charts/ingress-nginx/templates/controller-service-internal.yaml
+++ b/charts/ingress-nginx/templates/controller-service-internal.yaml
@@ -51,6 +51,28 @@ spec:
       nodePort: {{ .Values.controller.service.nodePorts.https }}
     {{- end }}
   {{- end }}
+  {{- range $key, $value := .Values.tcp }}
+    - name: {{ $key }}-tcp
+      port: {{ $key }}
+      protocol: TCP
+      targetPort: {{ $key }}-tcp
+    {{- if $.Values.controller.service.nodePorts.tcp }}
+    {{- if index $.Values.controller.service.nodePorts.tcp $key }}
+      nodePort: {{ index $.Values.controller.service.nodePorts.tcp $key }}
+    {{- end }}
+    {{- end }}
+  {{- end }}
+  {{- range $key, $value := .Values.udp }}
+    - name: {{ $key }}-udp
+      port: {{ $key }}
+      protocol: UDP
+      targetPort: {{ $key }}-udp
+    {{- if $.Values.controller.service.nodePorts.udp }}
+    {{- if index $.Values.controller.service.nodePorts.udp $key }}
+      nodePort: {{ index $.Values.controller.service.nodePorts.udp $key }}
+    {{- end }}
+    {{- end }}
+  {{- end }}
   selector:
     {{- include "ingress-nginx.selectorLabels" . | nindent 4 }}
     app.kubernetes.io/component: controller
diff --git a/deploy/static/provider/aws/deploy-tls-termination.yaml b/deploy/static/provider/aws/deploy-tls-termination.yaml
index bf442df89..3085270d8 100644
--- a/deploy/static/provider/aws/deploy-tls-termination.yaml
+++ b/deploy/static/provider/aws/deploy-tls-termination.yaml
@@ -37,7 +37,7 @@ metadata:
   name: ingress-nginx-controller
   namespace: ingress-nginx
 data:
-  http-snippet:|
+  http-snippet: |
     server{
       listen 2443;
       return 308 https://$host$request_uri;
diff --git a/deploy/static/provider/kind/deploy.yaml b/deploy/static/provider/kind/deploy.yaml
index 88c512162..4bd7e42c3 100644
--- a/deploy/static/provider/kind/deploy.yaml
+++ b/deploy/static/provider/kind/deploy.yaml
@@ -339,6 +339,7 @@ spec:
             - --validating-webhook-certificate=/usr/local/certificates/cert
             - --validating-webhook-key=/usr/local/certificates/key
             - --publish-status-address=localhost
+            - --watch-ingress-without-class
           securityContext:
             capabilities:
               drop:
diff --git a/docs/examples/affinity/cookie/README.md b/docs/examples/affinity/cookie/README.md
index 4f93fc0f8..b567c44c0 100644
--- a/docs/examples/affinity/cookie/README.md
+++ b/docs/examples/affinity/cookie/README.md
@@ -12,6 +12,7 @@ Session affinity can be configured using the following annotations:
 |nginx.ingress.kubernetes.io/affinity-mode|The affinity mode defines how sticky a session is. Use `balanced` to redistribute some sessions when scaling pods or `persistent` for maximum stickiness.|`balanced` (default) or `persistent`|
 |nginx.ingress.kubernetes.io/affinity-canary-behavior|Defines session affinity behavior of canaries. By default the behavior is `sticky`, and canaries respect session affinity configuration. Set this to `legacy` to restore original canary behavior, when session affinity parameters were not respected.|`sticky` (default) or `legacy`|
 |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-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"`
diff --git a/docs/examples/affinity/cookie/ingress-samesite.yaml b/docs/examples/affinity/cookie/ingress-samesite.yaml
index b3f8f4b20..edfa1b653 100644
--- a/docs/examples/affinity/cookie/ingress-samesite.yaml
+++ b/docs/examples/affinity/cookie/ingress-samesite.yaml
@@ -5,6 +5,7 @@ metadata:
   annotations:
     nginx.ingress.kubernetes.io/affinity: "cookie"
     nginx.ingress.kubernetes.io/session-cookie-name: "SSNONE"
+    nginx.ingress.kubernetes.io/session-cookie-secure: "true"
     nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
     nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
     nginx.ingress.kubernetes.io/session-cookie-samesite: "None"
diff --git a/docs/user-guide/nginx-configuration/annotations.md b/docs/user-guide/nginx-configuration/annotations.md
index 67bc10c58..e9fefebf1 100755
--- a/docs/user-guide/nginx-configuration/annotations.md
+++ b/docs/user-guide/nginx-configuration/annotations.md
@@ -64,6 +64,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
 |[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/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|
 |[nginx.ingress.kubernetes.io/proxy-cookie-path](#proxy-cookie-path)|string|
@@ -591,6 +592,8 @@ When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to
 even when there is no TLS certificate available.
 This can be achieved by using the `nginx.ingress.kubernetes.io/force-ssl-redirect: "true"` annotation in the particular resource.
 
+To preserve the trailing slash in the URI with `ssl-redirect`, set `nginx.ingress.kubernetes.io/preserve-trailing-slash: "true"` annotation for that particular resource.
+
 ### Redirect from/to www
 
 In some scenarios is required to redirect from `www.domain.com` to `domain.com` or vice versa.
diff --git a/internal/ingress/annotations/sessionaffinity/main.go b/internal/ingress/annotations/sessionaffinity/main.go
index 358be1442..9c4d1d2bc 100644
--- a/internal/ingress/annotations/sessionaffinity/main.go
+++ b/internal/ingress/annotations/sessionaffinity/main.go
@@ -37,6 +37,10 @@ const (
 
 	defaultAffinityCookieName = "INGRESSCOOKIE"
 
+	// This is used to force the Secure flag on the cookie even if the
+	// incoming request is not secured. (https://github.com/kubernetes/ingress-nginx/issues/6812)
+	annotationAffinityCookieSecure = "session-cookie-secure"
+
 	// This is used to control the cookie expires, its value is a number of seconds until the
 	// cookie expires
 	annotationAffinityCookieExpires = "session-cookie-expires"
@@ -85,6 +89,8 @@ type Cookie struct {
 	Path string `json:"path"`
 	// Flag that allows cookie regeneration on request failure
 	ChangeOnFailure bool `json:"changeonfailure"`
+	// Secure flag to be set
+	Secure bool `json:"secure"`
 	// SameSite attribute value
 	SameSite string `json:"samesite"`
 	// Flag that conditionally applies SameSite=None attribute on cookie if user agent accepts it.
@@ -126,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", annotationAffinityCookieSameSite)
 	}
 
+	cookie.Secure, err = parser.GetBoolAnnotation(annotationAffinityCookieSecure, ing)
+	if err != nil {
+		klog.V(3).InfoS("Invalid or no annotation value found. Ignoring", "ingress", klog.KObj(ing), "annotation", annotationAffinityCookieSecure)
+	}
+
 	cookie.ConditionalSameSiteNone, err = parser.GetBoolAnnotation(annotationAffinityCookieConditionalSameSiteNone, ing)
 	if err != nil {
 		klog.V(3).InfoS("Invalid or no annotation value found. Ignoring", "ingress", klog.KObj(ing), "annotation", annotationAffinityCookieConditionalSameSiteNone)
diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go
index 72a1afa63..1fd22079b 100644
--- a/internal/ingress/controller/controller.go
+++ b/internal/ingress/controller/controller.go
@@ -667,6 +667,7 @@ func (n *NGINXController) getBackendServers(ingresses []*ingress.Ingress) ([]*in
 					ups.SessionAffinity.CookieSessionAffinity.Name = anns.SessionAffinity.Cookie.Name
 					ups.SessionAffinity.CookieSessionAffinity.Expires = anns.SessionAffinity.Cookie.Expires
 					ups.SessionAffinity.CookieSessionAffinity.MaxAge = anns.SessionAffinity.Cookie.MaxAge
+					ups.SessionAffinity.CookieSessionAffinity.Secure = anns.SessionAffinity.Cookie.Secure
 					ups.SessionAffinity.CookieSessionAffinity.Path = cookiePath
 					ups.SessionAffinity.CookieSessionAffinity.SameSite = anns.SessionAffinity.Cookie.SameSite
 					ups.SessionAffinity.CookieSessionAffinity.ConditionalSameSiteNone = anns.SessionAffinity.Cookie.ConditionalSameSiteNone
diff --git a/internal/ingress/types.go b/internal/ingress/types.go
index a1cbdf685..033fa9cc4 100644
--- a/internal/ingress/types.go
+++ b/internal/ingress/types.go
@@ -155,6 +155,7 @@ type CookieSessionAffinity struct {
 	Expires                 string              `json:"expires,omitempty"`
 	MaxAge                  string              `json:"maxage,omitempty"`
 	Locations               map[string][]string `json:"locations,omitempty"`
+	Secure                  bool                `json:"secure,omitempty"`
 	Path                    string              `json:"path,omitempty"`
 	SameSite                string              `json:"samesite,omitempty"`
 	ConditionalSameSiteNone bool                `json:"conditional_samesite_none,omitempty"`
diff --git a/internal/ingress/types_equals.go b/internal/ingress/types_equals.go
index 87af2bcfc..18ffa9042 100644
--- a/internal/ingress/types_equals.go
+++ b/internal/ingress/types_equals.go
@@ -182,6 +182,9 @@ func (csa1 *CookieSessionAffinity) Equal(csa2 *CookieSessionAffinity) bool {
 	if csa1.SameSite != csa2.SameSite {
 		return false
 	}
+	if csa1.Secure != csa2.Secure {
+		return false
+	}
 	if csa1.ConditionalSameSiteNone != csa2.ConditionalSameSiteNone {
 		return false
 	}
diff --git a/rootfs/etc/nginx/lua/balancer/sticky.lua b/rootfs/etc/nginx/lua/balancer/sticky.lua
index 63f3c6785..3440d86bd 100644
--- a/rootfs/etc/nginx/lua/balancer/sticky.lua
+++ b/rootfs/etc/nginx/lua/balancer/sticky.lua
@@ -87,13 +87,18 @@ function _M.set_cookie(self, value)
     end
   end
 
+  local cookie_secure = self.cookie_session_affinity.secure
+  if cookie_secure == nil then
+    cookie_secure = ngx.var.https == "on"
+  end
+
   local cookie_data = {
     key = self:cookie_name(),
     value = value .. COOKIE_VALUE_DELIMITER .. self.backend_key,
     path = cookie_path,
     httponly = true,
     samesite = cookie_samesite,
-    secure = ngx.var.https == "on",
+    secure = cookie_secure,
   }
 
   if self.cookie_session_affinity.expires and self.cookie_session_affinity.expires ~= "" then


Test patch:
diff --git a/internal/ingress/annotations/sessionaffinity/main_test.go b/internal/ingress/annotations/sessionaffinity/main_test.go
index 98f0a1eb6..65d11ac2d 100644
--- a/internal/ingress/annotations/sessionaffinity/main_test.go
+++ b/internal/ingress/annotations/sessionaffinity/main_test.go
@@ -79,6 +79,7 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieMaxAge)] = "3000"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookiePath)] = "/foo"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieChangeOnFailure)] = "true"
+	data[parser.GetAnnotationWithPrefix(annotationAffinityCookieSecure)] = "true"
 	ing.SetAnnotations(data)
 
 	affin, _ := NewParser(&resolver.Mock{}).Parse(ing)
@@ -114,4 +115,8 @@ func TestIngressAffinityCookieConfig(t *testing.T) {
 	if !nginxAffinity.Cookie.ChangeOnFailure {
 		t.Errorf("expected change of failure parameter set to true but returned %v", nginxAffinity.Cookie.ChangeOnFailure)
 	}
+
+	if !nginxAffinity.Cookie.Secure {
+		t.Errorf("expected secure parameter set to true but returned %v", nginxAffinity.Cookie.Secure)
+	}
 }
diff --git a/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua b/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua
index a0c0ae54f..80d0c0d0e 100644
--- a/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua
+++ b/rootfs/etc/nginx/lua/test/balancer/sticky_test.lua
@@ -422,7 +422,7 @@ describe("Sticky", function()
       cookie.new = mocked_cookie_new
     end)
 
-    local function test_set_cookie_with(sticky_balancer_type, samesite, conditional_samesite_none, expected_path, expected_samesite)
+    local function test_set_cookie_with(sticky_balancer_type, samesite, conditional_samesite_none, expected_path, expected_samesite, secure, expected_secure)
       local s = {}
       cookie.new = function(self)
         local cookie_instance = {
@@ -432,7 +432,7 @@ describe("Sticky", function()
             assert.equal(payload.samesite, expected_samesite)
             assert.equal(payload.domain, nil)
             assert.equal(payload.httponly, true)
-            assert.equal(payload.secure, false)
+            assert.equal(payload.secure, expected_secure)
             return true, nil
           end,
           get = function(k) return false end,
@@ -445,57 +445,61 @@ describe("Sticky", function()
       b.sessionAffinityConfig.cookieSessionAffinity.locations["test.com"] = {"/"}
       b.sessionAffinityConfig.cookieSessionAffinity.samesite = samesite
       b.sessionAffinityConfig.cookieSessionAffinity.conditional_samesite_none = conditional_samesite_none
+      b.sessionAffinityConfig.cookieSessionAffinity.secure = secure
       local sticky_balancer_instance = sticky_balancer_type:new(b)
       assert.has_no.errors(function() sticky_balancer_instance:balance() end)
       assert.spy(s).was_called()
     end
 
-    it("returns a cookie with SameSite=Strict when user specifies samesite strict", function()
-      test_set_cookie_with(sticky_balanced, "Strict", false, "/", "Strict")
+    it("returns a secure cookie with SameSite=Strict when user specifies samesite strict and secure=true", function()
+      test_set_cookie_with(sticky_balanced, "Lax", false, "/", "Lax", true, true)
     end)
     it("returns a cookie with SameSite=Strict when user specifies samesite strict and conditional samesite none", function()
-      test_set_cookie_with(sticky_balanced, "Strict", true, "/", "Strict")
+      test_set_cookie_with(sticky_balanced, "Strict", true, "/", "Strict", nil, false)
     end)
     it("returns a cookie with SameSite=Lax when user specifies samesite lax", function()
-      test_set_cookie_with(sticky_balanced, "Lax", false, "/", "Lax")
+      test_set_cookie_with(sticky_balanced, "Lax", false, "/", "Lax", nil, false)
     end)
     it("returns a cookie with SameSite=Lax when user specifies samesite lax and conditional samesite none", function()
-      test_set_cookie_with(sticky_balanced, "Lax", true, "/", "Lax")
+      test_set_cookie_with(sticky_balanced, "Lax", true, "/", "Lax", nil, false)
     end)
     it("returns a cookie with SameSite=None when user specifies samesite None", function()
-      test_set_cookie_with(sticky_balanced, "None", false, "/", "None")
+      test_set_cookie_with(sticky_balanced, "None", false, "/", "None", nil, false)
     end)
     it("returns a cookie with SameSite=None when user specifies samesite None and conditional samesite none with supported user agent", function()
       mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.2704.103 Safari/537.36"} })
-      test_set_cookie_with(sticky_balanced, "None", true, "/", "None")
+      test_set_cookie_with(sticky_balanced, "None", true, "/", "None", nil, false)
     end)
     it("returns a cookie without SameSite=None when user specifies samesite None and conditional samesite none with unsupported user agent", function()
       mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} })
-      test_set_cookie_with(sticky_balanced, "None", true, "/", nil)
+      test_set_cookie_with(sticky_balanced, "None", true, "/", nil, nil, false)
     end)
 
+    it("returns a secure cookie with SameSite=Strict when user specifies samesite strict and secure=true", function()
+      test_set_cookie_with(sticky_persistent, "Lax", false, "/", "Lax", true, true)
+    end)
     it("returns a cookie with SameSite=Strict when user specifies samesite strict", function()
-      test_set_cookie_with(sticky_persistent, "Strict", false, "/", "Strict")
+      test_set_cookie_with(sticky_persistent, "Strict", false, "/", "Strict", nil, false)
     end)
     it("returns a cookie with SameSite=Strict when user specifies samesite strict and conditional samesite none", function()
-      test_set_cookie_with(sticky_persistent, "Strict", true, "/", "Strict")
+      test_set_cookie_with(sticky_persistent, "Strict", true, "/", "Strict", nil, false)
     end)
     it("returns a cookie with SameSite=Lax when user specifies samesite lax", function()
-      test_set_cookie_with(sticky_persistent, "Lax", false, "/", "Lax")
+      test_set_cookie_with(sticky_persistent, "Lax", false, "/", "Lax", nil, false)
     end)
     it("returns a cookie with SameSite=Lax when user specifies samesite lax and conditional samesite none", function()
-      test_set_cookie_with(sticky_persistent, "Lax", true, "/", "Lax")
+      test_set_cookie_with(sticky_persistent, "Lax", true, "/", "Lax", nil, false)
     end)
     it("returns a cookie with SameSite=None when user specifies samesite None", function()
-      test_set_cookie_with(sticky_persistent, "None", false, "/", "None")
+      test_set_cookie_with(sticky_persistent, "None", false, "/", "None", nil, false)
     end)
     it("returns a cookie with SameSite=None when user specifies samesite None and conditional samesite none with supported user agent", function()
       mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.2704.103 Safari/537.36"} })
-      test_set_cookie_with(sticky_persistent, "None", true, "/", "None")
+      test_set_cookie_with(sticky_persistent, "None", true, "/", "None", nil, false)
     end)
     it("returns a cookie without SameSite=None when user specifies samesite None and conditional samesite none with unsupported user agent", function()
       mock_ngx({ var = { location_path = "/", host = "test.com" , http_user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} })
-      test_set_cookie_with(sticky_persistent, "None", true, "/", nil)
+      test_set_cookie_with(sticky_persistent, "None", true, "/", nil, nil, false)
     end)
   end)