mirror of https://github.com/docker/docs.git
Disable extended key usage as a client for non-Swarm-master server certs
Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
This commit is contained in:
parent
bca4af7130
commit
c0b721b5f9
|
@ -66,7 +66,19 @@ func BootstrapCertificates(authOptions *auth.Options) error {
|
|||
return errors.New("The client key already exists. Please remove it or specify a different key/cert.")
|
||||
}
|
||||
|
||||
if err := GenerateCert([]string{""}, clientCertPath, clientKeyPath, caCertPath, caPrivateKeyPath, org, bits); err != nil {
|
||||
// Used to generate the client certificate.
|
||||
certOptions := &Options{
|
||||
Hosts: []string{""},
|
||||
CertFile: clientCertPath,
|
||||
KeyFile: clientKeyPath,
|
||||
CAFile: caCertPath,
|
||||
CAKeyFile: caPrivateKeyPath,
|
||||
Org: org,
|
||||
Bits: bits,
|
||||
SwarmMaster: false,
|
||||
}
|
||||
|
||||
if err := GenerateCert(certOptions); err != nil {
|
||||
return fmt.Errorf("Generating client certificate failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,16 @@ import (
|
|||
|
||||
var defaultGenerator = NewX509CertGenerator()
|
||||
|
||||
type Options struct {
|
||||
Hosts []string
|
||||
CertFile, KeyFile, CAFile, CAKeyFile, Org string
|
||||
Bits int
|
||||
SwarmMaster bool
|
||||
}
|
||||
|
||||
type Generator interface {
|
||||
GenerateCACertificate(certFile, keyFile, org string, bits int) error
|
||||
GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error
|
||||
GenerateCert(opts *Options) error
|
||||
ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error)
|
||||
ValidateCertificate(addr string, authOptions *auth.Options) (bool, error)
|
||||
}
|
||||
|
@ -38,8 +45,8 @@ func GenerateCACertificate(certFile, keyFile, org string, bits int) error {
|
|||
return defaultGenerator.GenerateCACertificate(certFile, keyFile, org, bits)
|
||||
}
|
||||
|
||||
func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
|
||||
return defaultGenerator.GenerateCert(hosts, certFile, keyFile, caFile, caKeyFile, org, bits)
|
||||
func GenerateCert(opts *Options) error {
|
||||
return defaultGenerator.GenerateCert(opts)
|
||||
}
|
||||
|
||||
func ValidateCertificate(addr string, authOptions *auth.Options) (bool, error) {
|
||||
|
@ -150,18 +157,24 @@ func (xcg *X509CertGenerator) GenerateCACertificate(certFile, keyFile, org strin
|
|||
// certificate authority files and stores the result in the certificate
|
||||
// file and key provided. The provided host names are set to the
|
||||
// appropriate certificate fields.
|
||||
func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
|
||||
template, err := xcg.newCertificate(org)
|
||||
func (xcg *X509CertGenerator) GenerateCert(opts *Options) error {
|
||||
template, err := xcg.newCertificate(opts.Org)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// client
|
||||
if len(hosts) == 1 && hosts[0] == "" {
|
||||
if len(opts.Hosts) == 1 && opts.Hosts[0] == "" {
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
|
||||
template.KeyUsage = x509.KeyUsageDigitalSignature
|
||||
} else { // server
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
|
||||
for _, h := range hosts {
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
if opts.SwarmMaster {
|
||||
// Extend the Swarm master's server certificate
|
||||
// permissions to also be able to connect to downstream
|
||||
// nodes as a client.
|
||||
template.ExtKeyUsage = append(template.ExtKeyUsage, x509.ExtKeyUsageClientAuth)
|
||||
}
|
||||
for _, h := range opts.Hosts {
|
||||
if ip := net.ParseIP(h); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
|
@ -170,12 +183,12 @@ func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, ca
|
|||
}
|
||||
}
|
||||
|
||||
tlsCert, err := tls.LoadX509KeyPair(caFile, caKeyFile)
|
||||
tlsCert, err := tls.LoadX509KeyPair(opts.CAFile, opts.CAKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
priv, err := rsa.GenerateKey(rand.Reader, opts.Bits)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -190,7 +203,7 @@ func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, ca
|
|||
return err
|
||||
}
|
||||
|
||||
certOut, err := os.Create(certFile)
|
||||
certOut, err := os.Create(opts.CertFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -198,7 +211,7 @@ func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, ca
|
|||
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
certOut.Close()
|
||||
|
||||
keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
keyOut, err := os.OpenFile(opts.KeyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -212,8 +225,8 @@ func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, ca
|
|||
// ReadTLSConfig reads the tls config for a machine.
|
||||
func (xcg *X509CertGenerator) ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error) {
|
||||
caCertPath := authOptions.CaCertPath
|
||||
serverCertPath := authOptions.ServerCertPath
|
||||
serverKeyPath := authOptions.ServerKeyPath
|
||||
clientCertPath := authOptions.ClientCertPath
|
||||
clientKeyPath := authOptions.ClientKeyPath
|
||||
|
||||
log.Debugf("Reading CA certificate from %s", caCertPath)
|
||||
caCert, err := ioutil.ReadFile(caCertPath)
|
||||
|
@ -221,19 +234,19 @@ func (xcg *X509CertGenerator) ReadTLSConfig(addr string, authOptions *auth.Optio
|
|||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Reading server certificate from %s", serverCertPath)
|
||||
serverCert, err := ioutil.ReadFile(serverCertPath)
|
||||
log.Debugf("Reading client certificate from %s", clientCertPath)
|
||||
clientCert, err := ioutil.ReadFile(clientCertPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Reading server key from %s", serverKeyPath)
|
||||
serverKey, err := ioutil.ReadFile(serverKeyPath)
|
||||
log.Debugf("Reading client key from %s", clientKeyPath)
|
||||
clientKey, err := ioutil.ReadFile(clientKeyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return xcg.getTLSConfig(caCert, serverCert, serverKey, false)
|
||||
return xcg.getTLSConfig(caCert, clientCert, clientKey, false)
|
||||
}
|
||||
|
||||
// ValidateCertificate validate the certificate installed on the vm.
|
||||
|
|
|
@ -56,7 +56,18 @@ func TestGenerateCert(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := GenerateCert([]string{}, certPath, keyPath, caCertPath, caKeyPath, testOrg, bits); err != nil {
|
||||
opts := &Options{
|
||||
Hosts: []string{},
|
||||
CertFile: certPath,
|
||||
CAKeyFile: caKeyPath,
|
||||
CAFile: caCertPath,
|
||||
KeyFile: keyPath,
|
||||
Org: testOrg,
|
||||
Bits: bits,
|
||||
SwarmMaster: false,
|
||||
}
|
||||
|
||||
if err := GenerateCert(opts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ func (fcg FakeCertGenerator) GenerateCACertificate(certFile, keyFile, org string
|
|||
return nil
|
||||
}
|
||||
|
||||
func (fcg FakeCertGenerator) GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
|
||||
func (fcg FakeCertGenerator) GenerateCert(opts *cert.Options) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,10 @@ func (provisioner *Boot2DockerProvisioner) GetAuthOptions() auth.Options {
|
|||
return provisioner.AuthOptions
|
||||
}
|
||||
|
||||
func (provisioner *Boot2DockerProvisioner) GetSwarmOptions() swarm.Options {
|
||||
return provisioner.SwarmOptions
|
||||
}
|
||||
|
||||
func (provisioner *Boot2DockerProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
|
||||
var (
|
||||
engineCfg bytes.Buffer
|
||||
|
|
|
@ -43,6 +43,10 @@ func (fp *FakeProvisioner) GetAuthOptions() auth.Options {
|
|||
return auth.Options{}
|
||||
}
|
||||
|
||||
func (fp *FakeProvisioner) GetSwarmOptions() swarm.Options {
|
||||
return swarm.Options{}
|
||||
}
|
||||
|
||||
func (fp *FakeProvisioner) Package(name string, action pkgaction.PackageAction) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -76,6 +76,10 @@ func (provisioner *GenericProvisioner) GetAuthOptions() auth.Options {
|
|||
return provisioner.AuthOptions
|
||||
}
|
||||
|
||||
func (provisioner *GenericProvisioner) GetSwarmOptions() swarm.Options {
|
||||
return provisioner.SwarmOptions
|
||||
}
|
||||
|
||||
func (provisioner *GenericProvisioner) SetOsReleaseInfo(info *OsRelease) {
|
||||
provisioner.OsReleaseInfo = info
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ type Provisioner interface {
|
|||
// Return the auth options used to configure remote connection for the daemon.
|
||||
GetAuthOptions() auth.Options
|
||||
|
||||
// Get the swarm options associated with this host.
|
||||
GetSwarmOptions() swarm.Options
|
||||
|
||||
// Run a package action e.g. install
|
||||
Package(name string, action pkgaction.PackageAction) error
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ func ConfigureAuth(p Provisioner) error {
|
|||
driver := p.GetDriver()
|
||||
machineName := driver.GetMachineName()
|
||||
authOptions := p.GetAuthOptions()
|
||||
swarmOptions := p.GetSwarmOptions()
|
||||
org := mcnutils.GetUsername() + "." + machineName
|
||||
bits := 2048
|
||||
|
||||
|
@ -98,15 +99,16 @@ func ConfigureAuth(p Provisioner) error {
|
|||
|
||||
// TODO: Switch to passing just authOptions to this func
|
||||
// instead of all these individual fields
|
||||
err = cert.GenerateCert(
|
||||
hosts,
|
||||
authOptions.ServerCertPath,
|
||||
authOptions.ServerKeyPath,
|
||||
authOptions.CaCertPath,
|
||||
authOptions.CaPrivateKeyPath,
|
||||
org,
|
||||
bits,
|
||||
)
|
||||
err = cert.GenerateCert(&cert.Options{
|
||||
Hosts: hosts,
|
||||
CertFile: authOptions.ServerCertPath,
|
||||
KeyFile: authOptions.ServerKeyPath,
|
||||
CAFile: authOptions.CaCertPath,
|
||||
CAKeyFile: authOptions.CaPrivateKeyPath,
|
||||
Org: org,
|
||||
Bits: bits,
|
||||
SwarmMaster: swarmOptions.Master,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating server cert: %s", err)
|
||||
|
|
Loading…
Reference in New Issue