Merge pull request #504 from jcmoraisjr/jm-haproxy-client-cert-auth
HAProxy Ingress - client cert auth docs
This commit is contained in:
commit
a7af8409c8
1 changed files with 182 additions and 0 deletions
182
examples/auth/client-certs/haproxy/README.md
Normal file
182
examples/auth/client-certs/haproxy/README.md
Normal file
|
@ -0,0 +1,182 @@
|
|||
# HAProxy Ingress Client Certificate Authentication
|
||||
|
||||
This example demonstrates how to configure client certificate
|
||||
authentication on HAProxy Ingress controller.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This document has the following prerequisites:
|
||||
|
||||
* Deploy [HAProxy Ingress](/examples/deployment/haproxy) controller, you should
|
||||
end up with controller, a sample web app and an ingress resource named `app` to
|
||||
the `foo.bar` domain
|
||||
* Configure [TLS termination](/examples/tls-termination/haproxy)
|
||||
* Create a [CA, certificate and private key](/examples/PREREQUISITES.md#ca-authentication),
|
||||
following these steps you should have a secret named `caingress`, a certificate file
|
||||
`client.crt` and it's private key `client.key`
|
||||
* Use these same steps and create another CA and generate another certificate and private
|
||||
key `fake.crt` and `fake.key` just for testing
|
||||
* Feature not on stable version yet; use `canary` tag
|
||||
|
||||
As mentioned in the deployment instructions, you MUST turn down any existing
|
||||
ingress controllers before running HAProxy Ingress.
|
||||
|
||||
Secret, certificates and keys can be created using these shortcuts:
|
||||
|
||||
CA and it's secret:
|
||||
|
||||
```console
|
||||
$ openssl req -x509 -newkey rsa:2048 -nodes -subj '/CN=example-ca' -keyout ca.key -out ca.crt
|
||||
$ kubectl create secret generic caingress --from-file=ca.crt
|
||||
```
|
||||
|
||||
Valid certificate and private key:
|
||||
|
||||
```console
|
||||
$ openssl req -new -newkey rsa:2048 -nodes -subj '/CN=client' -keyout client.key | \
|
||||
openssl x509 -req -CA ca.crt -CAkey ca.key -set_serial 1 -out client.crt
|
||||
```
|
||||
|
||||
Another CA, certificate and private key that should be refused by ingress:
|
||||
|
||||
```console
|
||||
$ openssl req -x509 -newkey rsa:2048 -nodes -subj '/CN=example-ca' -keyout ca-fake.key -out ca-fake.crt
|
||||
$ openssl req -new -newkey rsa:2048 -nodes -subj '/CN=client' -keyout fake.key | \
|
||||
openssl x509 -req -CA ca-fake.crt -CAkey ca-fake.key -set_serial 1 -out fake.crt
|
||||
```
|
||||
|
||||
## Using Client Certificate Authentication
|
||||
|
||||
HAProxy Ingress read one or a bundle of certificate authorities from a secret.
|
||||
Only client certificates signed by one of these certificate authorities should be
|
||||
allowed to make requests.
|
||||
|
||||
Annotate the ingress resource to use our valid certificate authority. The ingress resource and the
|
||||
secret `caingress` were created on the prerequisites.
|
||||
|
||||
```console
|
||||
$ kubectl annotate ingress/app ingress.kubernetes.io/auth-tls-secret=default/caingress
|
||||
```
|
||||
|
||||
Make some SSL requests against domain `foo.bar`. Change `31692:172.17.4.99` below to the IP and
|
||||
port of HAProxy Ingress controller.
|
||||
|
||||
Note: `curl`'s `--cert` and `-k` options on macOS (since 10.9 Mavericks) doesn't work as
|
||||
expected, see troubleshooting below if using macOS.
|
||||
|
||||
Connect without a certificate:
|
||||
|
||||
```console
|
||||
$ curl -ik https://foo.bar:31692 --resolve 'foo.bar:31692:172.17.4.99'
|
||||
curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
|
||||
```
|
||||
|
||||
Connect using the correct certificate and private key:
|
||||
|
||||
```console
|
||||
$ curl -ik https://foo.bar:31692 --resolve 'foo.bar:31692:172.17.4.99' --cert client.crt --key client.key
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx/1.9.11
|
||||
Date: Fri, 26 Mar 2017 13:41:26 GMT
|
||||
Content-Type: text/plain
|
||||
Transfer-Encoding: chunked
|
||||
Strict-Transport-Security: max-age=15768000
|
||||
|
||||
CLIENT VALUES:
|
||||
...
|
||||
```
|
||||
|
||||
Now connect using a private key and certificate signed by another CA:
|
||||
|
||||
```console
|
||||
$ curl -ik https://foo.bar:31692 --resolve 'foo.bar:31692:172.17.4.99' --cert fake.crt --key fake.key
|
||||
curl: (35) error:1409441B:SSL routines:ssl3_read_bytes:tlsv1 alert decrypt error
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
`curl` on macOS since 10.9 Mavericks has some issues regarding certificate on command line
|
||||
parameters:
|
||||
|
||||
* [sni](https://en.wikipedia.org/wiki/Server_Name_Indication) TLS extension isn't used
|
||||
if `-k` (unsecure connection) is provided. The sni extension is used by HAProxy to identify
|
||||
the host of the request. Without sni, the default backend will be used. The TLS
|
||||
certificate should be added to Keychain instead and `-k` should be avoided.
|
||||
|
||||
* `--cert` option is broken.
|
||||
|
||||
These issues and it's workarounds are described on
|
||||
[this message](https://curl.haxx.se/mail/archive-2013-10/0036.html) from curl mailing list.
|
||||
In short, in order to test client auth use a Linux VM or the options below on macOS.
|
||||
|
||||
### Using wget
|
||||
|
||||
Add `foo.bar` to `/etc/hosts` and change `31692` below to the
|
||||
port of HAProxy Ingress controller:
|
||||
|
||||
```console
|
||||
$ wget https://foo.bar:31692 -S -nv -O- --no-check-certificate
|
||||
OpenSSL: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
|
||||
Unable to establish SSL connection.
|
||||
```
|
||||
|
||||
Now with certificate and private key:
|
||||
|
||||
```console
|
||||
$ wget https://foo.bar:31692 -S -nv -O- --no-check-certificate --certificate client.crt --private-key client.key
|
||||
WARNING: cannot verify foo.bar's certificate, issued by ‘/CN=foo.bar’:
|
||||
Self-signed certificate encountered.
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx/1.9.11
|
||||
Date: Sun, 26 Mar 2017 13:57:53 GMT
|
||||
Content-Type: text/plain
|
||||
Transfer-Encoding: chunked
|
||||
Strict-Transport-Security: max-age=15768000
|
||||
CLIENT VALUES:
|
||||
```
|
||||
|
||||
### Using openssl
|
||||
|
||||
Change `31692` below to the port of HAProxy Ingress controller:
|
||||
|
||||
```console
|
||||
$ openssl s_client -connect 172.17.4.99:31692 -servername foo.bar
|
||||
CONNECTED(00000003)
|
||||
depth=0 /CN=foo.bar
|
||||
verify error:num=18:self signed certificate
|
||||
verify return:1
|
||||
depth=0 /CN=foo.bar
|
||||
verify return:1
|
||||
91929:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/OpenSSL098/OpenSSL098-59.60.1/src/ssl/s3_pkt.c:1145:SSL alert number 40
|
||||
91929:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/OpenSSL098/OpenSSL098-59.60.1/src/ssl/s23_lib.c:185:
|
||||
```
|
||||
|
||||
Now with certificate and private key - copy these two lines to the clipboard
|
||||
(HAProxy will timeout after 5 seconds waiting a http request):
|
||||
|
||||
```
|
||||
GET / HTTP/1.0
|
||||
Host: foo.bar
|
||||
```
|
||||
|
||||
Type the command below, paste the http request (two lines above) and send a blank line
|
||||
pressing enter twice:
|
||||
|
||||
```console
|
||||
$ openssl s_client -connect 172.17.4.99:31692 -servername foo.bar -cert client.crt -key client.key
|
||||
...
|
||||
---
|
||||
GET / HTTP/1.0
|
||||
Host: foo.bar
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx/1.9.11
|
||||
Date: Sun, 26 Mar 2017 14:06:30 GMT
|
||||
Content-Type: text/plain
|
||||
Content-Length: 268
|
||||
Connection: close
|
||||
Strict-Transport-Security: max-age=15768000
|
||||
|
||||
CLIENT VALUES:
|
||||
...
|
||||
```
|
Loading…
Reference in a new issue