package main import ( "crypto/tls" "crypto/x509" "encoding/json" "encoding/pem" "io/ioutil" "os" "path/filepath" "github.com/coreos/etcd/log" "github.com/coreos/etcd/server" ) //-------------------------------------- // Config //-------------------------------------- // Get the server info from previous conf file // or from the user func getInfo(path string) *Info { infoPath := filepath.Join(path, "info") if force { // Delete the old configuration if exist logPath := filepath.Join(path, "log") confPath := filepath.Join(path, "conf") snapshotPath := filepath.Join(path, "snapshot") os.Remove(infoPath) os.Remove(logPath) os.Remove(confPath) os.RemoveAll(snapshotPath) } else if info := readInfo(infoPath); info != nil { log.Infof("Found node configuration in '%s'. Ignoring flags", infoPath) return info } // Read info from command line info := &argInfo // Write to file. content, _ := json.MarshalIndent(info, "", " ") content = []byte(string(content) + "\n") if err := ioutil.WriteFile(infoPath, content, 0644); err != nil { log.Fatalf("Unable to write info to file: %v", err) } log.Infof("Wrote node configuration to '%s'", infoPath) return info } // readInfo reads from info file and decode to Info struct func readInfo(path string) *Info { file, err := os.Open(path) if err != nil { if os.IsNotExist(err) { return nil } log.Fatal(err) } defer file.Close() info := &Info{} content, err := ioutil.ReadAll(file) if err != nil { log.Fatalf("Unable to read info: %v", err) return nil } if err = json.Unmarshal(content, &info); err != nil { log.Fatalf("Unable to parse info: %v", err) return nil } return info } func tlsConfigFromInfo(info server.TLSInfo) (t server.TLSConfig, ok bool) { var keyFile, certFile, CAFile string var tlsCert tls.Certificate var err error t.Scheme = "http" keyFile = info.KeyFile certFile = info.CertFile CAFile = info.CAFile // If the user do not specify key file, cert file and // CA file, the type will be HTTP if keyFile == "" && certFile == "" && CAFile == "" { return t, true } // both the key and cert must be present if keyFile == "" || certFile == "" { return t, false } tlsCert, err = tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatal(err) } t.Scheme = "https" t.Server.ClientAuth, t.Server.ClientCAs = newCertPool(CAFile) // The client should trust the RootCA that the Server uses since // everyone is a peer in the network. t.Client.Certificates = []tls.Certificate{tlsCert} t.Client.RootCAs = t.Server.ClientCAs return t, true } // newCertPool creates x509 certPool and corresponding Auth Type. // If the given CAfile is valid, add the cert into the pool and verify the clients' // certs against the cert in the pool. // If the given CAfile is empty, do not verify the clients' cert. // If the given CAfile is not valid, fatal. func newCertPool(CAFile string) (tls.ClientAuthType, *x509.CertPool) { if CAFile == "" { return tls.NoClientCert, nil } pemByte, err := ioutil.ReadFile(CAFile) check(err) block, pemByte := pem.Decode(pemByte) cert, err := x509.ParseCertificate(block.Bytes) check(err) certPool := x509.NewCertPool() certPool.AddCert(cert) return tls.RequireAndVerifyClientCert, certPool }