Skip to content

Commit

Permalink
Merge pull request #3343 from abaruni/auth-snippet
Browse files Browse the repository at this point in the history
Auth snippet
  • Loading branch information
k8s-ci-robot authored Nov 6, 2018
2 parents ecf605b + b511333 commit d53b492
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 11 deletions.
10 changes: 10 additions & 0 deletions docs/user-guide/nginx-configuration/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|[nginx.ingress.kubernetes.io/auth-tls-error-page](#client-certificate-authentication)|string|
|[nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream](#client-certificate-authentication)|"true" or "false"|
|[nginx.ingress.kubernetes.io/auth-url](#external-authentication)|string|
|[nginx.ingress.kubernetes.io/auth-snippet](#external-authentication)|string|
|[nginx.ingress.kubernetes.io/backend-protocol](#backend-protocol)|string|HTTP,HTTPS,GRPC,GRPCS,AJP|
|[nginx.ingress.kubernetes.io/base-url-scheme](#rewrite)|string|
|[nginx.ingress.kubernetes.io/client-body-buffer-size](#client-body-buffer-size)|string|
Expand Down Expand Up @@ -326,6 +327,15 @@ Additionally it is possible to set:
`<Response_Header_1, ..., Response_Header_n>` to specify headers to pass to backend once authentication request completes.
* `nginx.ingress.kubernetes.io/auth-request-redirect`:
`<Request_Redirect_URL>` to specify the X-Auth-Request-Redirect header value.
* `nginx.ingress.kubernetes.io/auth-snippet`:
`<Auth_Snippet>` to specify a custom snippet to use with external authentication, e.g.

```yaml
nginx.ingress.kubernetes.io/auth-url: http://foo.com/external-auth
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header Foo-Header 42;
```
> Note: `nginx.ingress.kubernetes.io/auth-snippet` is an optional annotation. However, it may only be used in conjunction with `nginx.ingress.kubernetes.io/auth-url` and will be ignored if `nginx.ingress.kubernetes.io/auth-url` is not set

!!! example
Please check the [external-auth](../../examples/auth/external-auth/README.md) example.
Expand Down
17 changes: 16 additions & 1 deletion internal/ingress/annotations/authreq/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"regexp"
"strings"

"github.com/golang/glog"

extensions "k8s.io/api/extensions/v1beta1"

"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
Expand All @@ -37,6 +39,7 @@ type Config struct {
Method string `json:"method"`
ResponseHeaders []string `json:"responseHeaders,omitempty"`
RequestRedirect string `json:"requestRedirect"`
AuthSnippet string `json:"authSnippet"`
}

// Equal tests for equality between two Config types
Expand Down Expand Up @@ -74,6 +77,9 @@ func (e1 *Config) Equal(e2 *Config) bool {
if e1.RequestRedirect != e2.RequestRedirect {
return false
}
if e1.AuthSnippet != e2.AuthSnippet {
return false
}

return true
}
Expand Down Expand Up @@ -141,7 +147,15 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
}

// Optional Parameters
signIn, _ := parser.GetStringAnnotation("auth-signin", ing)
signIn, err := parser.GetStringAnnotation("auth-signin", ing)
if err != nil {
glog.Warning("auth-signin annotation is undefined and will not be set")
}

authSnippet, err := parser.GetStringAnnotation("auth-snippet", ing)
if err != nil {
glog.Warning("auth-snippet annotation is undefined and will not be set")
}

responseHeaders := []string{}
hstr, _ := parser.GetStringAnnotation("auth-response-headers", ing)
Expand All @@ -167,5 +181,6 @@ func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
Method: authMethod,
ResponseHeaders: responseHeaders,
RequestRedirect: requestRedirect,
AuthSnippet: authSnippet,
}, nil
}
24 changes: 15 additions & 9 deletions internal/ingress/annotations/authreq/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,31 @@ func TestAnnotations(t *testing.T) {
signinURL string
method string
requestRedirect string
authSnippet string
expErr bool
}{
{"empty", "", "", "", "", true},
{"no scheme", "bar", "bar", "", "", true},
{"invalid host", "http://", "http://", "", "", true},
{"invalid host (multiple dots)", "http://foo..bar.com", "http://foo..bar.com", "", "", true},
{"valid URL", "http://bar.foo.com/external-auth", "http://bar.foo.com/external-auth", "", "", false},
{"valid URL - send body", "http://foo.com/external-auth", "http://foo.com/external-auth", "POST", "", false},
{"valid URL - send body", "http://foo.com/external-auth", "http://foo.com/external-auth", "GET", "", false},
{"valid URL - request redirect", "http://foo.com/external-auth", "http://foo.com/external-auth", "GET", "http://foo.com/redirect-me", false},
{"empty", "", "", "", "", "", true},
{"no scheme", "bar", "bar", "", "", "", true},
{"invalid host", "http://", "http://", "", "", "", true},
{"invalid host (multiple dots)", "http://foo..bar.com", "http://foo..bar.com", "", "", "", true},
{"valid URL", "http://bar.foo.com/external-auth", "http://bar.foo.com/external-auth", "", "", "", false},
{"valid URL - send body", "http://foo.com/external-auth", "http://foo.com/external-auth", "POST", "", "", false},
{"valid URL - send body", "http://foo.com/external-auth", "http://foo.com/external-auth", "GET", "", "", false},
{"valid URL - request redirect", "http://foo.com/external-auth", "http://foo.com/external-auth", "GET", "http://foo.com/redirect-me", "", false},
{"auth snippet", "http://foo.com/external-auth", "http://foo.com/external-auth", "", "", "proxy_set_header My-Custom-Header 42;", false},
}

for _, test := range tests {
data[parser.GetAnnotationWithPrefix("auth-url")] = test.url
data[parser.GetAnnotationWithPrefix("auth-signin")] = test.signinURL
data[parser.GetAnnotationWithPrefix("auth-method")] = fmt.Sprintf("%v", test.method)
data[parser.GetAnnotationWithPrefix("auth-request-redirect")] = test.requestRedirect
data[parser.GetAnnotationWithPrefix("auth-snippet")] = test.authSnippet

i, err := NewParser(&resolver.Mock{}).Parse(ing)
if test.expErr {
if err == nil {
t.Errorf("%v: expected error but retuned nil", test.title)
t.Errorf("%v: expected error but returned nil", test.title)
}
continue
}
Expand All @@ -118,6 +121,9 @@ func TestAnnotations(t *testing.T) {
if u.RequestRedirect != test.requestRedirect {
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.requestRedirect, u.RequestRedirect)
}
if u.AuthSnippet != test.authSnippet {
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.authSnippet, u.AuthSnippet)
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions rootfs/etc/nginx/template/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,10 @@ stream {
proxy_set_header ssl-client-issuer-dn $ssl_client_i_dn;
{{ end }}

{{ if not (empty $location.ExternalAuth.AuthSnippet) }}
{{ $location.ExternalAuth.AuthSnippet }}
{{ end }}

set $target {{ $location.ExternalAuth.URL }};
proxy_pass $target;
}
Expand Down
36 changes: 35 additions & 1 deletion test/e2e/annotations/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/parnurzeal/gorequest"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -234,6 +233,41 @@ var _ = framework.IngressNginxDescribe("Annotations - Auth", func() {
Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
})

It(`should set snippet "proxy_set_header My-Custom-Header 42;" when external auth is configured`, func() {
host := "auth"

annotations := map[string]string{
"nginx.ingress.kubernetes.io/auth-url": "http://foo.bar/basic-auth/user/password",
"nginx.ingress.kubernetes.io/auth-snippet": `
proxy_set_header My-Custom-Header 42;`,
}

ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
f.EnsureIngress(ing)

f.WaitForNginxServer(host,
func(server string) bool {
return Expect(server).Should(ContainSubstring(`proxy_set_header My-Custom-Header 42;`))
})
})

It(`should not set snippet "proxy_set_header My-Custom-Header 42;" when external auth is not configured`, func() {
host := "auth"

annotations := map[string]string{
"nginx.ingress.kubernetes.io/auth-snippet": `
proxy_set_header My-Custom-Header 42;`,
}

ing := framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "http-svc", 80, &annotations)
f.EnsureIngress(ing)

f.WaitForNginxServer(host,
func(server string) bool {
return Expect(server).ShouldNot(ContainSubstring(`proxy_set_header My-Custom-Header 42;`))
})
})

Context("when external authentication is configured", func() {
host := "auth"

Expand Down

0 comments on commit d53b492

Please sign in to comment.