Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add NTLM support to VirtualServer and VirtualServerRoute upstreams #1908

Merged
merged 6 commits into from
Aug 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,8 @@ spec:
type: string
next-upstream-tries:
type: integer
ntlm:
type: boolean
port:
type: integer
queue:
Expand Down
2 changes: 2 additions & 0 deletions deployments/common/crds/k8s.nginx.org_virtualservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ spec:
type: string
next-upstream-tries:
type: integer
ntlm:
type: boolean
port:
type: integer
queue:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,8 @@ spec:
type: string
next-upstream-tries:
type: integer
ntlm:
type: boolean
port:
type: integer
queue:
Expand Down
2 changes: 2 additions & 0 deletions deployments/helm-chart/crds/k8s.nginx.org_virtualservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ spec:
type: string
next-upstream-tries:
type: integer
ntlm:
type: boolean
port:
type: integer
queue:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ tls:
|``buffering`` | Enables buffering of responses from the upstream server. See the [proxy_buffering](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering) directive. The default is set in the ``proxy-buffering`` ConfigMap key. | ``boolean`` | No |
|``buffers`` | Configures the buffers used for reading a response from the upstream server for a single connection. | [buffers](#upstream-buffers) | No |
|``buffer-size`` | Sets the size of the buffer used for reading the first part of a response received from the upstream server. See the [proxy_buffer_size](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) directive. The default is set in the ``proxy-buffer-size`` ConfigMap key. | ``string`` | No |
|``ntlm`` | Allows proxying requests with NTLM Authentication. See the [ntlm](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ntlm) directive. In order for NTLM authentication to work, it is necessary to enable keepalive connections to upstream servers using the ``keepalive`` field. Note: this feature is supported only in NGINX Plus.| ``boolean`` | No |
{{% /table %}}

### Upstream.Buffers
Expand Down
1 change: 1 addition & 0 deletions internal/configs/version2/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Upstream struct {
Queue *Queue
SessionCookie *SessionCookie
UpstreamLabels UpstreamLabels
NTLM bool
}

// UpstreamServer defines an upstream server.
Expand Down
2 changes: 2 additions & 0 deletions internal/configs/version2/nginx-plus.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ upstream {{ $u.Name }} {
sticky cookie {{ .Name }}{{ if .Expires }} expires={{ .Expires }}{{ end }}{{ if .Domain }} domain={{ .Domain }}{{ end }}{{ if .HTTPOnly }} httponly{{ end }}{{ if .Secure }} secure{{ end }}{{ if .Path }} path={{ .Path }}{{ end }};
{{ end }}
{{ end }}

{{ if $u.NTLM }}ntlm;{{ end }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so easy!

}
{{ end }}

Expand Down
1 change: 1 addition & 0 deletions internal/configs/version2/templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var virtualServerCfg = VirtualServerConfig{
UpstreamZoneSize: "256k",
Queue: &Queue{Size: 10, Timeout: "60s"},
SessionCookie: &SessionCookie{Enable: true, Name: "test", Path: "/tea", Expires: "25s"},
NTLM: true,
},
{
Name: "coffee-v1",
Expand Down
1 change: 1 addition & 0 deletions internal/configs/virtualserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@ func (vsc *virtualServerConfigurator) generateUpstream(
ups.SlowStart = vsc.generateSlowStartForPlus(owner, upstream, lbMethod)
ups.Queue = generateQueueForPlus(upstream.Queue, "60s")
ups.SessionCookie = generateSessionCookie(upstream.SessionCookie)
ups.NTLM = upstream.NTLM
}

return ups
Expand Down
45 changes: 45 additions & 0 deletions internal/configs/virtualserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3597,6 +3597,51 @@ func TestGenerateUpstreamForExternalNameService(t *testing.T) {
}
}

func TestGenerateUpstreamWithNTLM(t *testing.T) {
name := "test-upstream"
upstream := conf_v1.Upstream{Service: name, Port: 80, NTLM: true}
endpoints := []string{
"192.168.10.10:8080",
}
cfgParams := ConfigParams{
LBMethod: "random",
MaxFails: 1,
MaxConns: 0,
FailTimeout: "10s",
Keepalive: 21,
UpstreamZoneSize: "256k",
}

expected := version2.Upstream{
Name: "test-upstream",
UpstreamLabels: version2.UpstreamLabels{
Service: "test-upstream",
},
Servers: []version2.UpstreamServer{
{
Address: "192.168.10.10:8080",
},
},
MaxFails: 1,
MaxConns: 0,
FailTimeout: "10s",
LBMethod: "random",
Keepalive: 21,
UpstreamZoneSize: "256k",
NTLM: true,
}

vsc := newVirtualServerConfigurator(&cfgParams, true, false, &StaticConfigParams{})
result := vsc.generateUpstream(nil, name, upstream, false, endpoints)
if !reflect.DeepEqual(result, expected) {
t.Errorf("generateUpstream() returned %v but expected %v", result, expected)
}

if len(vsc.warnings) != 0 {
t.Errorf("generateUpstream returned warnings for %v", upstream)
}
}

func TestGenerateProxyPass(t *testing.T) {
tests := []struct {
tlsEnabled bool
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/configuration/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type Upstream struct {
Queue *UpstreamQueue `json:"queue"`
SessionCookie *SessionCookie `json:"sessionCookie"`
UseClusterIP bool `json:"use-cluster-ip"`
NTLM bool `json:"ntlm"`
}

// UpstreamBuffers defines Buffer Configuration for an Upstream.
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/configuration/validation/virtualserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,10 @@ func rejectPlusResourcesInOSS(upstream v1.Upstream, idxPath *field.Path, isPlus
allErrs = append(allErrs, field.Forbidden(idxPath.Child("queue"), "queue is only supported in NGINX Plus"))
}

if upstream.NTLM {
allErrs = append(allErrs, field.Forbidden(idxPath.Child("ntlm"), "NTLM is only supported in NGINX Plus"))
}

return allErrs
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/configuration/validation/virtualserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2571,6 +2571,11 @@ func TestRejectPlusResourcesInOSS(t *testing.T) {
Queue: &v1.UpstreamQueue{},
},
},
{
upstream: &v1.Upstream{
NTLM: true,
},
},
}

for _, test := range tests {
Expand Down
7 changes: 4 additions & 3 deletions tests/suite/test_virtual_server_upstream_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,14 @@ class TestOptionsSpecificForPlus:
"healthCheck": {"enable": True, "port": 8080},
"slow-start": "3h",
"queue": {"size": 100},
"ntlm": True,
"sessionCookie": {"enable": True,
"name": "TestCookie",
"path": "/some-valid/path",
"expires": "max",
"domain": "virtual-server-route.example.com", "httpOnly": True, "secure": True}},
["health_check uri=/ port=8080 interval=5s jitter=0s", "fails=1 passes=1;",
"slow_start=3h", "queue 100 timeout=60s;",
"slow_start=3h", "queue 100 timeout=60s;", "ntlm;",
"sticky cookie TestCookie expires=max domain=virtual-server-route.example.com httponly secure path=/some-valid/path;"]),
({"lb-method": "least_conn",
"healthCheck": {"enable": True, "path": "/health",
Expand All @@ -318,12 +319,12 @@ class TestOptionsSpecificForPlus:
"connect-timeout": "35s", "read-timeout": "45s", "send-timeout": "55s",
"headers": [{"name": "Host", "value": "virtual-server.example.com"}]},
"queue": {"size": 1000, "timeout": "66s"},
"slow-start": "0s"},
"slow-start": "0s", "ntlm": True},
["health_check uri=/health port=8080 interval=15s jitter=3", "fails=2 passes=2 match=",
"proxy_pass https://vs", "status 200;",
"proxy_connect_timeout 35s;", "proxy_read_timeout 45s;", "proxy_send_timeout 55s;",
'proxy_set_header Host "virtual-server.example.com";',
"slow_start=0s", "queue 1000 timeout=66s;"])
"slow_start=0s", "queue 1000 timeout=66s;", "ntlm;"])

])
def test_config_and_events(self, kube_apis, ingress_controller_prerequisites,
Expand Down