Skip to content
This repository was archived by the owner on Apr 17, 2019. It is now read-only.

Commit 0d31aaa

Browse files
committed
Merge pull request #946 from aledbf/nginx-ingress-authentication
[nginx-ingress-controller] Allow authentication in Ingress rules
2 parents 7fdc96f + 4cda656 commit 0d31aaa

39 files changed

+3980
-6
lines changed

ingress/Godeps/Godeps.json

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ingress/controllers/nginx/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nginx-ingress-controller

ingress/controllers/nginx/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,29 @@ This means only one of the rules should define annotations to configure the upst
213213

214214
Please check the [auth](examples/custom-upstream-check/README.md) example
215215

216+
### Authentication
217+
218+
Is possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the the key `auth`
219+
220+
The annotations are:
221+
222+
```
223+
ingress-nginx.kubernetes.io/auth-type:[basic|digest]
224+
```
225+
226+
Indicates the [HTTP Authentication Type: Basic or Digest Access Authentication](https://tools.ietf.org/html/rfc2617).
227+
228+
```
229+
ingress-nginx.kubernetes.io/auth-secret:secretName
230+
```
231+
232+
Name of the secret that contains the usernames and passwords with access to the `path/s` defined in the Ingress Rule.
233+
The secret must be created in the same namespace than the Ingress rule
234+
235+
```
236+
ingress-nginx.kubernetes.io/auth-realm:"realm string"
237+
```
238+
216239

217240
### NGINX status page
218241

ingress/controllers/nginx/controller.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ import (
4040
"k8s.io/kubernetes/pkg/util/intstr"
4141
"k8s.io/kubernetes/pkg/watch"
4242

43-
"k8s.io/contrib/ingress/controllers/nginx/healthcheck"
4443
"k8s.io/contrib/ingress/controllers/nginx/nginx"
44+
"k8s.io/contrib/ingress/controllers/nginx/nginx/auth"
45+
"k8s.io/contrib/ingress/controllers/nginx/nginx/healthcheck"
4546
"k8s.io/contrib/ingress/controllers/nginx/nginx/ratelimit"
4647
"k8s.io/contrib/ingress/controllers/nginx/nginx/rewrite"
4748
)
@@ -584,6 +585,12 @@ func (lbc *loadBalancerController) getUpstreamServers(ngxCfg nginx.NginxConfigur
584585
continue
585586
}
586587

588+
nginxAuth, err := auth.ParseAnnotations(lbc.client, ing, auth.DefAuthDirectory)
589+
glog.V(3).Infof("nginx auth %v", nginxAuth)
590+
if err != nil {
591+
glog.V(3).Infof("error reading authentication in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
592+
}
593+
587594
rl, err := ratelimit.ParseAnnotations(ing)
588595
glog.V(3).Infof("nginx rate limit %v", rl)
589596
if err != nil {
@@ -617,12 +624,14 @@ func (lbc *loadBalancerController) getUpstreamServers(ngxCfg nginx.NginxConfigur
617624
for _, loc := range server.Locations {
618625
if loc.Path == rootLocation && nginxPath == rootLocation && loc.IsDefBackend {
619626
loc.Upstream = *ups
627+
loc.Auth = *nginxAuth
628+
loc.RateLimit = *rl
629+
620630
locRew, err := rewrite.ParseAnnotations(ing)
621631
if err != nil {
622632
glog.V(3).Infof("error parsing rewrite annotations for Ingress rule %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
623633
}
624634
loc.Redirect = *locRew
625-
loc.RateLimit = *rl
626635

627636
addLoc = false
628637
continue
@@ -645,8 +654,9 @@ func (lbc *loadBalancerController) getUpstreamServers(ngxCfg nginx.NginxConfigur
645654
server.Locations = append(server.Locations, &nginx.Location{
646655
Path: nginxPath,
647656
Upstream: *ups,
648-
Redirect: *locRew,
657+
Auth: *nginxAuth,
649658
RateLimit: *rl,
659+
Redirect: *locRew,
650660
})
651661
}
652662
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
2+
This example shows how to add authentication in a Ingress rule using a secret that contains a file generated with `htpasswd`.
3+
4+
5+
```
6+
$ htpasswd -c auth foo
7+
New password: <bar>
8+
New password:
9+
Re-type new password:
10+
Adding password for user foo
11+
```
12+
13+
```
14+
$ kubectl create secret generic basic-auth --from-file=auth
15+
secret "basic-auth" created
16+
```
17+
18+
```
19+
$ kubectl get secret basic-auth -o yaml
20+
apiVersion: v1
21+
data:
22+
auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
23+
kind: Secret
24+
metadata:
25+
name: basic-auth
26+
namespace: default
27+
type: Opaque
28+
```
29+
30+
```
31+
echo "
32+
apiVersion: extensions/v1beta1
33+
kind: Ingress
34+
metadata:
35+
name: ingress-with-auth
36+
annotations:
37+
# type of authentication
38+
ingress-nginx.kubernetes.io/auth-type: basic
39+
# name of the secret that contains the user/password definitions
40+
ingress-nginx.kubernetes.io/auth-secret: basic-auth
41+
# message to display with an appropiate context why the authentication is required
42+
ingress-nginx.kubernetes.io/auth-realm: "Authentication Required - foo"
43+
spec:
44+
rules:
45+
- host: foo.bar.com
46+
http:
47+
paths:
48+
- path: /
49+
backend:
50+
serviceName: echoheaders
51+
servicePort: 80
52+
" | kubectl create -f -
53+
```
54+
55+
```
56+
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'
57+
* Trying 10.2.29.4...
58+
* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
59+
> GET / HTTP/1.1
60+
> Host: foo.bar.com
61+
> User-Agent: curl/7.43.0
62+
> Accept: */*
63+
>
64+
< HTTP/1.1 401 Unauthorized
65+
< Server: nginx/1.10.0
66+
< Date: Wed, 11 May 2016 05:27:23 GMT
67+
< Content-Type: text/html
68+
< Content-Length: 195
69+
< Connection: keep-alive
70+
< WWW-Authenticate: Basic realm="Authentication Required - foo"
71+
<
72+
<html>
73+
<head><title>401 Authorization Required</title></head>
74+
<body bgcolor="white">
75+
<center><h1>401 Authorization Required</h1></center>
76+
<hr><center>nginx/1.10.0</center>
77+
</body>
78+
</html>
79+
* Connection #0 to host 10.2.29.4 left intact
80+
```
81+
82+
```
83+
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -u 'foo:bar'
84+
* Trying 10.2.29.4...
85+
* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
86+
* Server auth using Basic with user 'foo'
87+
> GET / HTTP/1.1
88+
> Host: foo.bar.com
89+
> Authorization: Basic Zm9vOmJhcg==
90+
> User-Agent: curl/7.43.0
91+
> Accept: */*
92+
>
93+
< HTTP/1.1 200 OK
94+
< Server: nginx/1.10.0
95+
< Date: Wed, 11 May 2016 06:05:26 GMT
96+
< Content-Type: text/plain
97+
< Transfer-Encoding: chunked
98+
< Connection: keep-alive
99+
< Vary: Accept-Encoding
100+
<
101+
CLIENT VALUES:
102+
client_address=10.2.29.4
103+
command=GET
104+
real path=/
105+
query=nil
106+
request_version=1.1
107+
request_uri=http://foo.bar.com:8080/
108+
109+
SERVER VALUES:
110+
server_version=nginx: 1.9.11 - lua: 10001
111+
112+
HEADERS RECEIVED:
113+
accept=*/*
114+
authorization=Basic Zm9vOmJhcg==
115+
connection=close
116+
host=foo.bar.com
117+
user-agent=curl/7.43.0
118+
x-forwarded-for=10.2.29.1
119+
x-forwarded-host=foo.bar.com
120+
x-forwarded-port=80
121+
x-forwarded-proto=http
122+
x-real-ip=10.2.29.1
123+
BODY:
124+
* Connection #0 to host 10.2.29.4 left intact
125+
-no body in request-
126+
```

ingress/controllers/nginx/nginx.tmpl

+12
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,18 @@ http {
190190
{{ $limits := buildRateLimit $location }}
191191
{{- range $limit := $limits }}
192192
{{ $limit }}{{ end }}
193+
194+
{{ if $location.Auth.Secured -}}
195+
{{ if eq $location.Auth.Type "basic" }}
196+
auth_basic "{{ $location.Auth.Realm }}";
197+
auth_basic_user_file {{ $location.Auth.File }};
198+
{{ else }}
199+
#TODO: add nginx-http-auth-digest module
200+
auth_digest "{{ $location.Auth.Realm }}";
201+
auth_digest_user_file {{ $location.Auth.File }};
202+
{{ end }}
203+
{{- end }}
204+
193205
proxy_set_header Host $host;
194206

195207
# Pass Real IP

0 commit comments

Comments
 (0)