Adds correct support for TLS Muthual autentication
This commit is contained in:
parent
bf8e2e91b2
commit
39643bc4f6
5 changed files with 151 additions and 10 deletions
|
@ -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) }}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
56
examples/tls-authentication/nginx/README.md
Normal file
56
examples/tls-authentication/nginx/README.md
Normal 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
|
||||
|
||||
```
|
23
examples/tls-authentication/nginx/nginx-tls-auth.yaml
Normal file
23
examples/tls-authentication/nginx/nginx-tls-auth.yaml
Normal 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
|
||||
|
Loading…
Reference in a new issue