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

Commit

Permalink
Merge pull request #946 from aledbf/nginx-ingress-authentication
Browse files Browse the repository at this point in the history
[nginx-ingress-controller] Allow authentication in Ingress rules
  • Loading branch information
bprashanth committed May 31, 2016
2 parents 7fdc96f + 4cda656 commit 0d31aaa
Show file tree
Hide file tree
Showing 39 changed files with 3,980 additions and 6 deletions.
5 changes: 5 additions & 0 deletions ingress/Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ingress/controllers/nginx/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nginx-ingress-controller
23 changes: 23 additions & 0 deletions ingress/controllers/nginx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,29 @@ This means only one of the rules should define annotations to configure the upst

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

### Authentication

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`

The annotations are:

```
ingress-nginx.kubernetes.io/auth-type:[basic|digest]
```

Indicates the [HTTP Authentication Type: Basic or Digest Access Authentication](https://tools.ietf.org/html/rfc2617).

```
ingress-nginx.kubernetes.io/auth-secret:secretName
```

Name of the secret that contains the usernames and passwords with access to the `path/s` defined in the Ingress Rule.
The secret must be created in the same namespace than the Ingress rule

```
ingress-nginx.kubernetes.io/auth-realm:"realm string"
```


### NGINX status page

Expand Down
16 changes: 13 additions & 3 deletions ingress/controllers/nginx/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ import (
"k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/watch"

"k8s.io/contrib/ingress/controllers/nginx/healthcheck"
"k8s.io/contrib/ingress/controllers/nginx/nginx"
"k8s.io/contrib/ingress/controllers/nginx/nginx/auth"
"k8s.io/contrib/ingress/controllers/nginx/nginx/healthcheck"
"k8s.io/contrib/ingress/controllers/nginx/nginx/ratelimit"
"k8s.io/contrib/ingress/controllers/nginx/nginx/rewrite"
)
Expand Down Expand Up @@ -584,6 +585,12 @@ func (lbc *loadBalancerController) getUpstreamServers(ngxCfg nginx.NginxConfigur
continue
}

nginxAuth, err := auth.ParseAnnotations(lbc.client, ing, auth.DefAuthDirectory)
glog.V(3).Infof("nginx auth %v", nginxAuth)
if err != nil {
glog.V(3).Infof("error reading authentication in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
}

rl, err := ratelimit.ParseAnnotations(ing)
glog.V(3).Infof("nginx rate limit %v", rl)
if err != nil {
Expand Down Expand Up @@ -617,12 +624,14 @@ func (lbc *loadBalancerController) getUpstreamServers(ngxCfg nginx.NginxConfigur
for _, loc := range server.Locations {
if loc.Path == rootLocation && nginxPath == rootLocation && loc.IsDefBackend {
loc.Upstream = *ups
loc.Auth = *nginxAuth
loc.RateLimit = *rl

locRew, err := rewrite.ParseAnnotations(ing)
if err != nil {
glog.V(3).Infof("error parsing rewrite annotations for Ingress rule %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
}
loc.Redirect = *locRew
loc.RateLimit = *rl

addLoc = false
continue
Expand All @@ -645,8 +654,9 @@ func (lbc *loadBalancerController) getUpstreamServers(ngxCfg nginx.NginxConfigur
server.Locations = append(server.Locations, &nginx.Location{
Path: nginxPath,
Upstream: *ups,
Redirect: *locRew,
Auth: *nginxAuth,
RateLimit: *rl,
Redirect: *locRew,
})
}
}
Expand Down
126 changes: 126 additions & 0 deletions ingress/controllers/nginx/examples/auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@

This example shows how to add authentication in a Ingress rule using a secret that contains a file generated with `htpasswd`.


```
$ htpasswd -c auth foo
New password: <bar>
New password:
Re-type new password:
Adding password for user foo
```

```
$ kubectl create secret generic basic-auth --from-file=auth
secret "basic-auth" created
```

```
$ kubectl get secret basic-auth -o yaml
apiVersion: v1
data:
auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
kind: Secret
metadata:
name: basic-auth
namespace: default
type: Opaque
```

```
echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-with-auth
annotations:
# type of authentication
ingress-nginx.kubernetes.io/auth-type: basic
# name of the secret that contains the user/password definitions
ingress-nginx.kubernetes.io/auth-secret: basic-auth
# message to display with an appropiate context why the authentication is required
ingress-nginx.kubernetes.io/auth-realm: "Authentication Required - foo"
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /
backend:
serviceName: echoheaders
servicePort: 80
" | kubectl create -f -
```

```
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'
* Trying 10.2.29.4...
* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
> GET / HTTP/1.1
> Host: foo.bar.com
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.10.0
< Date: Wed, 11 May 2016 05:27:23 GMT
< Content-Type: text/html
< Content-Length: 195
< Connection: keep-alive
< WWW-Authenticate: Basic realm="Authentication Required - foo"
<
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.10.0</center>
</body>
</html>
* Connection #0 to host 10.2.29.4 left intact
```

```
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -u 'foo:bar'
* Trying 10.2.29.4...
* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
* Server auth using Basic with user 'foo'
> GET / HTTP/1.1
> Host: foo.bar.com
> Authorization: Basic Zm9vOmJhcg==
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0
< Date: Wed, 11 May 2016 06:05:26 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
<
CLIENT VALUES:
client_address=10.2.29.4
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://foo.bar.com:8080/
SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001
HEADERS RECEIVED:
accept=*/*
authorization=Basic Zm9vOmJhcg==
connection=close
host=foo.bar.com
user-agent=curl/7.43.0
x-forwarded-for=10.2.29.1
x-forwarded-host=foo.bar.com
x-forwarded-port=80
x-forwarded-proto=http
x-real-ip=10.2.29.1
BODY:
* Connection #0 to host 10.2.29.4 left intact
-no body in request-
```
12 changes: 12 additions & 0 deletions ingress/controllers/nginx/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,18 @@ http {
{{ $limits := buildRateLimit $location }}
{{- range $limit := $limits }}
{{ $limit }}{{ end }}

{{ if $location.Auth.Secured -}}
{{ if eq $location.Auth.Type "basic" }}
auth_basic "{{ $location.Auth.Realm }}";
auth_basic_user_file {{ $location.Auth.File }};
{{ else }}
#TODO: add nginx-http-auth-digest module
auth_digest "{{ $location.Auth.Realm }}";
auth_digest_user_file {{ $location.Auth.File }};
{{ end }}
{{- end }}

proxy_set_header Host $host;

# Pass Real IP
Expand Down
Loading

0 comments on commit 0d31aaa

Please sign in to comment.