Skip to content

Commit

Permalink
Merge pull request #1426 from diazjf/ma-logging
Browse files Browse the repository at this point in the history
Enhance Certificate Logging and Clearup Mutual Auth Docs
  • Loading branch information
aledbf authored Sep 27, 2017
2 parents 6e24dc6 + 1ffeb2c commit 9164c38
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 29 deletions.
4 changes: 2 additions & 2 deletions controllers/nginx/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,14 @@ Please check the [auth](/examples/auth/basic/nginx/README.md) example.

### Certificate Authentication

It's possible to enable Certificate based authentication using additional annotations in Ingress Rule.
It's possible to enable Certificate-Based Authentication (Mutual Authentication) using additional annotations in Ingress Rule.

The annotations are:
```
ingress.kubernetes.io/auth-tls-secret: secretName
```

The name of the secret that contains the full Certificate Authority chain that is enabled to authenticate against this ingress. It's composed of namespace/secretName
The name of the secret that contains the full Certificate Authority chain `ca.crt` that is enabled to authenticate against this ingress. It's composed of namespace/secretName.

```
ingress.kubernetes.io/auth-tls-verify-depth
Expand Down
34 changes: 23 additions & 11 deletions core/pkg/ingress/controller/backend_ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,35 +74,47 @@ func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLC

cert, okcert := secret.Data[apiv1.TLSCertKey]
key, okkey := secret.Data[apiv1.TLSPrivateKeyKey]

ca := secret.Data["ca.crt"]

// namespace/secretName -> namespace-secretName
nsSecName := strings.Replace(secretName, "/", "-", -1)

var s *ingress.SSLCert
if okcert && okkey {
if cert == nil || key == nil {
return nil, fmt.Errorf("error retrieving cert or key from secret %v: %v", secretName, err)
if cert == nil {
return nil, fmt.Errorf("secret %v has no 'tls.crt'", secretName)
}
if key == nil {
return nil, fmt.Errorf("secret %v has no 'tls.key'", secretName)
}

// If 'ca.crt' is also present, it will allow this secret to be used in the
// 'ingress.kubernetes.io/auth-tls-secret' annotation
s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca)
if err != nil {
return nil, fmt.Errorf("unexpected error creating pem file %v", err)
return nil, fmt.Errorf("unexpected error creating pem file: %v", err)
}
glog.V(3).Infof("found certificate and private key, configuring %v as a TLS Secret (CN: %v)", secretName, s.CN)

glog.V(3).Infof("found 'tls.crt' and 'tls.key', configuring %v as a TLS Secret (CN: %v)", secretName, s.CN)
if ca != nil {
glog.V(3).Infof("found 'ca.crt', secret %v can also be used for Certificate Authentication", secretName)
}

} else if ca != nil {
glog.V(3).Infof("found only ca.crt, configuring %v as an Certificate Authentication secret", secretName)
s, err = ssl.AddCertAuth(nsSecName, ca)

if err != nil {
return nil, fmt.Errorf("unexpected error creating pem file %v", err)
return nil, fmt.Errorf("unexpected error creating pem file: %v", err)
}

// makes this secret in 'syncSecret' to be used for Certificate Authentication
// this does not enable Certificate Authentication
glog.V(3).Infof("found only 'ca.crt', configuring %v as an Certificate Authentication Secret", secretName)

} else {
return nil, fmt.Errorf("no keypair or CA cert could be found in %v", secretName)
}

if err != nil {
return nil, err
}

s.Name = secret.Name
s.Namespace = secret.Namespace
return s, nil
Expand Down
13 changes: 10 additions & 3 deletions core/pkg/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,13 @@ func (ic *GenericController) getBackendServers(ingresses []*extensions.Ingress)
ca := ic.annotations.CertificateAuth(ing)
if ca != nil {
server.CertificateAuth = *ca
// It is possible that no CAFileName is found in the secret
if server.CertificateAuth.CAFileName == "" {
glog.V(3).Infof("secret %v does not contain 'ca.crt', mutual authentication not enabled - ingress rule %v/%v.", server.CertificateAuth.Secret, ing.Namespace, ing.Name)
}
}
} else {
glog.V(3).Infof("server %v already contains a muthual autentication configuration - ingress rule %v/%v", server.Hostname, ing.Namespace, ing.Name)
glog.V(3).Infof("server %v already contains a mutual authentication configuration - ingress rule %v/%v", server.Hostname, ing.Namespace, ing.Name)
}

for _, path := range rule.HTTP.Paths {
Expand Down Expand Up @@ -671,7 +675,8 @@ func (ic *GenericController) getBackendServers(ingresses []*extensions.Ingress)
return aUpstreams, aServers
}

// GetAuthCertificate ...

// GetAuthCertificate is used by the auth-tls annotations to get a cert from a secret
func (ic GenericController) GetAuthCertificate(secretName string) (*resolver.AuthSSLCert, error) {
if _, exists := ic.sslCertTracker.Get(secretName); !exists {
ic.syncSecret(secretName)
Expand Down Expand Up @@ -894,10 +899,12 @@ func (ic *GenericController) createServers(data []*extensions.Ingress,
RequestBuffering: bdef.ProxyRequestBuffering,
}

// generated on Start() with createDefaultSSLCertificate()
defaultPemFileName := fakeCertificatePath
defaultPemSHA := fakeCertificateSHA

// Tries to fetch the default Certificate. If it does not exists, generate a new self signed one.
// Tries to fetch the default Certificate from nginx configuration.
// If it does not exists, use the ones generated on Start()
defaultCertificate, err := ic.getPemCertificate(ic.cfg.DefaultSSLCertificate)
if err == nil {
defaultPemFileName = defaultCertificate.PemFileName
Expand Down
2 changes: 1 addition & 1 deletion core/pkg/ingress/resolver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type AuthSSLCert struct {
Secret string `json:"secret"`
// CAFileName contains the path to the secrets 'ca.crt'
CAFileName string `json:"caFilename"`
// PemSHA contains the SHA1 hash of the 'tls.crt' value
// PemSHA contains the SHA1 hash of the 'ca.crt' or combinations of (tls.crt, tls.key, tls.crt) depending on certs in secret
PemSHA string `json:"pemSha"`
}

Expand Down
2 changes: 1 addition & 1 deletion core/pkg/net/ssl/ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func AddCertAuth(name string, ca []byte) (*ingress.SSLCert, error) {
return nil, fmt.Errorf("could not write CA file %v: %v", caFileName, err)
}

glog.V(3).Infof("Created CA Certificate for authentication: %v", caFileName)
glog.V(3).Infof("Created CA Certificate for Authentication: %v", caFileName)
return &ingress.SSLCert{
CAFileName: caFileName,
PemFileName: caFileName,
Expand Down
7 changes: 6 additions & 1 deletion examples/PREREQUISITES.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,12 @@ The final step is to create a secret with the content of this file. This secret
the TLS Auth directive:

```console
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt=<ca.crt>
```

Note: You can also generate the CA Authentication Secret along with the TLS Secret by using:
```console
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt=<ca.crt> --from-file=tls.crt=<tls.crt> --from-file=tls.key=<tls.key>
```

## Test HTTP Service
Expand Down
13 changes: 5 additions & 8 deletions examples/auth/client-certs/nginx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ the child, except for the root, which has Issuer == Subject.

* Client Cert: Certificate used by the clients to authenticate themselves with the loadbalancer/backends.


## Prerequisites

You need a valid CA File, composed of a group of valid enabled CAs. This MUST be in PEM Format.
The instructions are described [here](../../../PREREQUISITES.md#ca-authentication)
The instructions are described [here](../../../PREREQUISITES.md)

Also your ingress must be configured as a HTTPs/TLS Ingress.
Also your ingress must be configured as a HTTPS/TLS Ingress.

## Deployment

Expand Down Expand Up @@ -51,8 +50,7 @@ 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
TLS: tls-secret terminates ingress.test.com
Rules:
Host Path Backends
---- ---- --------
Expand All @@ -79,13 +77,12 @@ 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

```

You must use the full DNS name while testing, as NGINX relies on the Server Name (SNI) to select the correct Ingress to be used.

The curl version used here was ``curl 7.47.0``

## Which certificate was used for authentication?

In your backend application you might want to know which certificate was used for authentication. For this purpose, we pass the full certificate in PEM format to the backend in the `ssl-client-cert` header.
In your backend application you might want to know which certificate was used for authentication.
For this purpose, we pass the full certificate in PEM format to the backend in the `ssl-client-cert` header.
3 changes: 1 addition & 2 deletions examples/auth/client-certs/nginx/nginx-tls-auth.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ spec:
tls:
- hosts:
- ingress.test.com
# Create this cert as described in 'multi-tls' example
secretName: cert
secretName: tls-secret

0 comments on commit 9164c38

Please sign in to comment.