Adds correct support for TLS Muthual autentication

This commit is contained in:
Ricardo Pchevuzinske Katz 2017-02-06 16:16:36 -02:00
parent bf8e2e91b2
commit 39643bc4f6
5 changed files with 151 additions and 10 deletions

View file

@ -221,10 +221,13 @@ http {
{{ $path := buildLocation $location }}
{{ $authPath := buildAuthLocation $location }}
{{ if not (empty $location.CertificateAuth.CertFileName) }}
{{ if not (empty $location.CertificateAuth.CAFileName) }}
# PEM sha: {{ $location.CertificateAuth.PemSHA }}
ssl_client_certificate {{ $location.CertificateAuth.CAFileName }};
ssl_verify_client on;
ssl_verify_depth 10;
proxy_set_header SSL_CLIENT_CERT $ssl_client_cert;
{{ end }}
{{ if not (empty $authPath) }}

View file

@ -98,6 +98,8 @@ func (ic *GenericController) syncSecret(k interface{}) error {
return nil
}
// getPemCertificate receives a secret, and creates a ingress.SSLCert as return.
// It parses the secret and verifies if it's a keypair, or a 'ca.crt' secret only.
func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLCert, error) {
secretInterface, exists, err := ic.secrLister.Store.GetByKey(secretName)
if err != nil {
@ -108,19 +110,24 @@ func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLC
}
secret := secretInterface.(*api.Secret)
cert, ok := secret.Data[api.TLSCertKey]
if !ok {
return nil, fmt.Errorf("secret named %v has no private key", secretName)
}
key, ok := secret.Data[api.TLSPrivateKeyKey]
if !ok {
return nil, fmt.Errorf("secret named %v has no cert", secretName)
}
cert, okcert := secret.Data[api.TLSCertKey]
key, okkey := secret.Data[api.TLSPrivateKeyKey]
ca := secret.Data["ca.crt"]
nsSecName := strings.Replace(secretName, "/", "-", -1)
s, err := ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca)
var s *ingress.SSLCert
if okcert && okkey {
glog.V(3).Infof("Found certificate and private key, configuring %v as a TLS Secret", secretName)
s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca)
} else if ca != nil {
glog.V(3).Infof("Found only ca.crt, configuring %v as an AuthCert secret", secretName)
s, err = ssl.AddOrUpdateCertAuth(nsSecName, ca)
} else {
return nil, fmt.Errorf("No keypair or CA cert could be found in %v", secretName)
}
if err != nil {
return nil, err
}

View file

@ -37,6 +37,8 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
pemFileName := fmt.Sprintf("%v/%v", ingress.DefaultSSLDirectory, pemName)
tempPemFile, err := ioutil.TempFile(ingress.DefaultSSLDirectory, pemName)
glog.V(3).Infof("AddOrUpdateCertAndKey: Creating temp file %v for Keypair: %v", tempPemFile.Name(), pemName)
if err != nil {
return nil, fmt.Errorf("could not create temp pem file %v: %v", pemFileName, err)
}
@ -125,6 +127,56 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
}, nil
}
// AddOrUpdateCertAuth creates a .pem file with the specified CAs to be used in Cert Authentication
func AddOrUpdateCertAuth(name string, ca []byte) (*ingress.SSLCert, error) {
caName := fmt.Sprintf("ca-%v.pem", name)
caFileName := fmt.Sprintf("%v/%v", ingress.DefaultSSLDirectory, caName)
tempCAPemFile, err := ioutil.TempFile(ingress.DefaultSSLDirectory, caName)
glog.V(3).Infof("AddOrUpdateCertAuth: Creating temp file %v for CA: %v", tempCAPemFile.Name(), caName)
if err != nil {
return nil, fmt.Errorf("could not create temp CA pem file %v: %v", tempCAPemFile.Name(), err)
}
_, err = tempCAPemFile.Write(ca)
if err != nil {
return nil, fmt.Errorf("could not write to CA pem file %v: %v", tempCAPemFile.Name(), err)
}
err = tempCAPemFile.Close()
if err != nil {
return nil, fmt.Errorf("could not close CA temp pem file %v: %v", tempCAPemFile.Name(), err)
}
pemCACerts, err := ioutil.ReadFile(tempCAPemFile.Name())
if err != nil {
return nil, err
}
pemCABlock, _ := pem.Decode(pemCACerts)
if pemCABlock == nil {
return nil, fmt.Errorf("No valid PEM formatted block found")
}
_, err = x509.ParseCertificate(pemCABlock.Bytes)
if err != nil {
return nil, err
}
err = os.Rename(tempCAPemFile.Name(), caFileName)
if err != nil {
return nil, fmt.Errorf("could not move temp pem file %v to destination %v: %v", tempCAPemFile.Name(), caFileName, err)
}
return &ingress.SSLCert{
CAFileName: caFileName,
PemFileName: caFileName,
PemSHA: pemSHA1(caFileName),
}, nil
}
// SearchDHParamFile iterates all the secrets mounted inside the /etc/nginx-ssl directory
// in order to find a file with the name dhparam.pem. If such file exists it will
// returns the path. If not it just returns an empty string

View file

@ -0,0 +1,56 @@
# TLS termination
This example demonstrates how to enable the TLS Authentication through the nginx Ingress controller.
## Prerequisites
You need a valid CA File, composed of a group of valid enabled CAs. This MUST be in PEM Format.
Also the Ingress must terminate TLS, otherwise this makes no sense ;)
## Deployment
The following command instructs the controller to enable the TLS Authentication using
the secret containing the valid CA chains.
```console
$ kubectl create -f nginx-tls-auth.yaml
```
## Validation
You can confirm that the Ingress works.
```console
$ kubectl describe ing nginx-test
Name: nginx-test
Namespace: default
Address: 104.198.183.6
Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
TLS:
tls-secret terminates ingress.test.com
Rules:
Host Path Backends
---- ---- --------
*
http-svc:80 (<none>)
Annotations:
auth-tls-secret: default/caingress
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test
7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test
7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6
7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /
$ curl -k https://ingress.test.com
HTTP/1.1 400 Bad Request
Server: nginx/1.11.9
$ curl -I -k --key ~/user.key --cert ~/user.cer https://ingress.test.com
HTTP/1.1 200 OK
Server: nginx/1.11.9
```

View file

@ -0,0 +1,23 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
# Create this with kubectl create secret generic caingress --from-file=ca.crt --namespace=default
ingress.kubernetes.io/auth-tls-secret: default/caingress
name: nginx-test
namespace: default
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: http-svc:80
servicePort: 80
path: /
tls:
- hosts:
- ingress.test.com
# Create this cert as described in 'multi-tls' example
secretName: cert