Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions pkg/auth/authenticator/request/x509request/x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package x509request

import (
"crypto/x509"
"crypto/x509/pkix"
"net/http"

"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
Expand Down Expand Up @@ -70,6 +71,16 @@ func DefaultVerifyOptions() x509.VerifyOptions {
}
}

// SubjectToUserConversion calls SubjectToUser on the subject of the first certificate in the chain.
// If the resulting user has no name, it returns nil, false, nil
var SubjectToUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
user := SubjectToUser(chain[0].Subject)
if len(user.GetName()) == 0 {
return nil, false, nil
}
return user, true, nil
})

// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
if len(chain[0].Subject.CommonName) == 0 {
Expand All @@ -93,3 +104,18 @@ var EmailAddressUserConversion = UserConversionFunc(func(chain []*x509.Certifica
}
return &user.DefaultInfo{Name: chain[0].EmailAddresses[0]}, true, nil
})

func UserToSubject(u user.Info) pkix.Name {
return pkix.Name{
CommonName: u.GetName(),
SerialNumber: u.GetUID(),
Organization: u.GetGroups(),
}
}
func SubjectToUser(subject pkix.Name) user.Info {
return &user.DefaultInfo{
Name: subject.CommonName,
UID: subject.SerialNumber,
Groups: subject.Organization,
}
}
29 changes: 17 additions & 12 deletions pkg/cmd/server/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import (
"strconv"
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
clientcmd "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api"
"github.com/golang/glog"
"github.com/openshift/origin/pkg/auth/authenticator/request/x509request"
)

func filenamesFromDir(dir string) (string, string, string) {
Expand Down Expand Up @@ -342,22 +344,25 @@ func (ca *CA) MakeServerCert(name string, hostnames []string) (*TLSCertificateCo
}

// MakeClientConfig creates a folder containing certificates for the given client:
// <CA.dir>/
// <username>/
// root.crt - Root certificate bundle.
// cert.crt - Client certificate
// key.key - Private key
// <CA.dir>/
// <id>/
// root.crt - Root certificate bundle.
// cert.crt - Client certificate
// key.key - Private key
// The generated certificate has the following attributes:
// CommonName: username
// ExtKeyUsage: ExtKeyUsageClientAuth
func (ca *CA) MakeClientConfig(provider, username string, groups []string, defaults kclient.Config) (kclient.Config, error) {
clientDir := filepath.Join(ca.Dir, username)
// Subject:
// SerialNumber: user.GetUID()
// CommonName: user.GetName()
// Organization: user.GetGroups()
// ExtKeyUsage: ExtKeyUsageClientAuth
func (ca *CA) MakeClientConfig(clientId string, u user.Info, defaults kclient.Config) (kclient.Config, error) {
clientDir := filepath.Join(ca.Dir, clientId)
kubeConfig := filepath.Join(clientDir, ".kubeconfig")

client, err := readClientConfigFromDir(clientDir, defaults)
if err == nil {
// Always write .kubeconfig to pick up hostname changes
if err := writeKubeConfigToDir(&client, username, clientDir); err != nil {
if err := writeKubeConfigToDir(&client, clientId, clientDir); err != nil {
return client, err
}
glog.Infof("Using existing client config in %s", kubeConfig)
Expand All @@ -371,7 +376,7 @@ func (ca *CA) MakeClientConfig(provider, username string, groups []string, defau

// Create cert for system components to use to talk to the API
clientPublicKey, clientPrivateKey, _ := NewKeyPair()
clientTemplate, _ := newClientCertificateTemplate(pkix.Name{CommonName: provider + ":" + username})
clientTemplate, _ := newClientCertificateTemplate(x509request.UserToSubject(u))
clientCrt, _ := ca.signCertificate(clientTemplate, clientPublicKey)

caData, err := encodeCertificates(ca.Config.Roots...)
Expand All @@ -394,7 +399,7 @@ func (ca *CA) MakeClientConfig(provider, username string, groups []string, defau
if err := writeClientCertsToDir(&client, clientDir); err != nil {
return client, err
}
if err := writeKubeConfigToDir(&client, username, clientDir); err != nil {
if err := writeKubeConfigToDir(&client, clientId, clientDir); err != nil {
return client, err
}

Expand Down
25 changes: 19 additions & 6 deletions pkg/cmd/server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,21 +430,35 @@ func start(cfg *config, args []string) error {
osClientConfigTemplate := kclient.Config{Host: cfg.MasterAddr.URL.String(), Version: latest.Version}

// Openshift client
if osmaster.OSClientConfig, err = ca.MakeClientConfig("system", "openshift-client", nil, osClientConfigTemplate); err != nil {
openshiftClientUser := &user.DefaultInfo{Name: "system:openshift-client"}
if osmaster.OSClientConfig, err = ca.MakeClientConfig("openshift-client", openshiftClientUser, osClientConfigTemplate); err != nil {
return err
}
// Openshift deployer client
if osmaster.DeployerOSClientConfig, err = ca.MakeClientConfig("system", "openshift-deployer", nil, osClientConfigTemplate); err != nil {
openshiftDeployerUser := &user.DefaultInfo{Name: "system:openshift-deployer", Groups: []string{"system:deployers"}}
if osmaster.DeployerOSClientConfig, err = ca.MakeClientConfig("openshift-deployer", openshiftDeployerUser, osClientConfigTemplate); err != nil {
return err
}
// Admin config (creates files on disk for osc)
if _, err = ca.MakeClientConfig("system", "admin", nil, osClientConfigTemplate); err != nil {
adminUser := &user.DefaultInfo{Name: "system:admin", Groups: []string{"system:cluster-admins"}}
if _, err = ca.MakeClientConfig("admin", adminUser, osClientConfigTemplate); err != nil {
return err
}

// One client config per node
for _, node := range cfg.NodeList {
nodeIdentityName := fmt.Sprintf("node-%s", node)
nodeUserName := fmt.Sprintf("system:%s", nodeIdentityName)
nodeUser := &user.DefaultInfo{Name: nodeUserName, Groups: []string{"system:nodes"}}
if _, err = ca.MakeClientConfig(nodeIdentityName, nodeUser, osClientConfigTemplate); err != nil {
return err
}
}

// If we're running our own Kubernetes, build client credentials
if startKube {
if osmaster.KubeClientConfig, err = ca.MakeClientConfig("system", "kube-client", nil, osmaster.KubeClientConfig); err != nil {
kubeClientUser := &user.DefaultInfo{Name: "system:kube-client"}
if osmaster.KubeClientConfig, err = ca.MakeClientConfig("kube-client", kubeClientUser, osmaster.KubeClientConfig); err != nil {
return err
}
}
Expand All @@ -458,10 +472,9 @@ func start(cfg *config, args []string) error {

// build cert authenticator
// TODO: add cert users to etcd?
// TODO: provider-qualify cert users?
opts := x509request.DefaultVerifyOptions()
opts.Roots = roots
certauth := x509request.New(opts, x509request.CommonNameUserConversion)
certauth := x509request.New(opts, x509request.SubjectToUserConversion)
authenticators = append(authenticators, certauth)
} else {
// No security, use the same client config for all OpenShift clients
Expand Down