Merge pull request #6190 from liggitt/client_cert_auth

Add client cert authentication
This commit is contained in:
Robert Bailey
2015-04-01 14:11:29 -07:00
4 changed files with 137 additions and 13 deletions

View File

@@ -19,18 +19,61 @@ package apiserver
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator/bearertoken"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/auth/authenticator/request/union"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/auth/authenticator/request/x509"
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/auth/authenticator/token/tokenfile"
)
// NewAuthenticatorFromTokenFile returns an authenticator.Request or an error
func NewAuthenticatorFromTokenFile(tokenAuthFile string) (authenticator.Request, error) {
var authenticator authenticator.Request
if len(tokenAuthFile) != 0 {
tokenAuthenticator, err := tokenfile.NewCSV(tokenAuthFile)
// NewAuthenticator returns an authenticator.Request or an error
func NewAuthenticator(clientCAFile string, tokenFile string) (authenticator.Request, error) {
authenticators := []authenticator.Request{}
if len(clientCAFile) > 0 {
certAuth, err := newAuthenticatorFromClientCAFile(clientCAFile)
if err != nil {
return nil, err
}
authenticator = bearertoken.New(tokenAuthenticator)
authenticators = append(authenticators, certAuth)
}
return authenticator, nil
if len(tokenFile) > 0 {
tokenAuth, err := newAuthenticatorFromTokenFile(tokenFile)
if err != nil {
return nil, err
}
authenticators = append(authenticators, tokenAuth)
}
if len(authenticators) == 0 {
return nil, nil
}
if len(authenticators) == 1 {
return authenticators[1], nil
}
return union.New(authenticators...), nil
}
// newAuthenticatorFromTokenFile returns an authenticator.Request or an error
func newAuthenticatorFromTokenFile(tokenAuthFile string) (authenticator.Request, error) {
tokenAuthenticator, err := tokenfile.NewCSV(tokenAuthFile)
if err != nil {
return nil, err
}
return bearertoken.New(tokenAuthenticator), nil
}
// newAuthenticatorFromClientCAFile returns an authenticator.Request or an error
func newAuthenticatorFromClientCAFile(clientCAFile string) (authenticator.Request, error) {
roots, err := util.CertPoolFromFile(clientCAFile)
if err != nil {
return nil, err
}
opts := x509.DefaultVerifyOptions()
opts.Roots = roots
return x509.New(opts, x509.CommonNameUserConversion), nil
}

View File

@@ -23,6 +23,7 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"math/big"
@@ -97,3 +98,65 @@ func GenerateSelfSignedCert(host, certPath, keyPath string) error {
return nil
}
// CertPoolFromFile returns an x509.CertPool containing the certificates in the given PEM-encoded file.
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
func CertPoolFromFile(filename string) (*x509.CertPool, error) {
certs, err := certificatesFromFile(filename)
if err != nil {
return nil, err
}
pool := x509.NewCertPool()
for _, cert := range certs {
pool.AddCert(cert)
}
return pool, nil
}
// certificatesFromFile returns the x509.Certificates contained in the given PEM-encoded file.
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
func certificatesFromFile(file string) ([]*x509.Certificate, error) {
if len(file) == 0 {
return nil, errors.New("error reading certificates from an empty filename")
}
pemBlock, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
certs, err := certsFromPEM(pemBlock)
if err != nil {
return nil, fmt.Errorf("error reading %s: %s", file, err)
}
return certs, nil
}
// certsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array
// Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
func certsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
ok := false
certs := []*x509.Certificate{}
for len(pemCerts) > 0 {
var block *pem.Block
block, pemCerts = pem.Decode(pemCerts)
if block == nil {
break
}
// Only use PEM "CERTIFICATE" blocks without extra headers
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return certs, err
}
certs = append(certs, cert)
ok = true
}
if !ok {
return certs, errors.New("could not read any certificates")
}
return certs, nil
}