// OptionKVOpts function returns an option setter for kvstore options func OptionKVOpts(opts map[string]string) Option { return func(c *Config) { if opts["kv.cacertfile"] != "" && opts["kv.certfile"] != "" && opts["kv.keyfile"] != "" { log.Info("Option Initializing KV with TLS") tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ CAFile: opts["kv.cacertfile"], CertFile: opts["kv.certfile"], KeyFile: opts["kv.keyfile"], }) if err != nil { log.Errorf("Unable to set up TLS: %s", err) return } if _, ok := c.Scopes[datastore.GlobalScope]; !ok { c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{} } if c.Scopes[datastore.GlobalScope].Client.Config == nil { c.Scopes[datastore.GlobalScope].Client.Config = &store.Config{TLS: tlsConfig} } else { c.Scopes[datastore.GlobalScope].Client.Config.TLS = tlsConfig } // Workaround libkv/etcd bug for https c.Scopes[datastore.GlobalScope].Client.Config.ClientTLS = &store.ClientTLSConfig{ CACertFile: opts["kv.cacertfile"], CertFile: opts["kv.certfile"], KeyFile: opts["kv.keyfile"], } } else { log.Info("Option Initializing KV without TLS") } } }
// CreateClient creates a docker client based on the specified options. func CreateClient(c ClientOpts) (dockerclient.Client, error) { if c.TLSOptions.CAFile == "" { c.TLSOptions.CAFile = filepath.Join(dockerCertPath, defaultCaFile) } if c.TLSOptions.CertFile == "" { c.TLSOptions.CertFile = filepath.Join(dockerCertPath, defaultCertFile) } if c.TLSOptions.KeyFile == "" { c.TLSOptions.KeyFile = filepath.Join(dockerCertPath, defaultKeyFile) } if c.Host == "" { defaultHost := os.Getenv("DOCKER_HOST") if defaultHost == "" { if runtime.GOOS != "windows" { // If we do not have a host, default to unix socket defaultHost = fmt.Sprintf("unix://%s", opts.DefaultUnixSocket) } else { // If we do not have a host, default to TCP socket on Windows defaultHost = fmt.Sprintf("tcp://%s:%d", opts.DefaultHTTPHost, opts.DefaultHTTPPort) } } defaultHost, err := opts.ValidateHost(defaultHost) if err != nil { return nil, err } c.Host = defaultHost } if c.TrustKey == "" { c.TrustKey = filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile) } if c.TLSVerify { c.TLS = true } if c.TLS { c.TLSOptions.InsecureSkipVerify = !c.TLSVerify } var tlsConfig *tls.Config if c.TLS { var err error tlsConfig, err = tlsconfig.Client(c.TLSOptions) if err != nil { return nil, err } } return dockerclient.NewDockerClient(c.Host, tlsConfig) }
// Initialize is exported func (s *Discovery) Initialize(uris string, heartbeat time.Duration, ttl time.Duration, discoveryOpt map[string]string) error { var ( parts = strings.SplitN(uris, "/", 2) addrs = strings.Split(parts[0], ",") err error ) // A custom prefix to the path can be optionally used. if len(parts) == 2 { s.prefix = parts[1] } s.heartbeat = heartbeat s.ttl = ttl // Use a custom path if specified in discovery options dpath := defaultDiscoveryPath if discoveryOpt["kv.path"] != "" { dpath = discoveryOpt["kv.path"] } s.path = path.Join(s.prefix, dpath) var config *store.Config if discoveryOpt["kv.cacertfile"] != "" && discoveryOpt["kv.certfile"] != "" && discoveryOpt["kv.keyfile"] != "" { log.Debug("Initializing discovery with TLS") tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ CAFile: discoveryOpt["kv.cacertfile"], CertFile: discoveryOpt["kv.certfile"], KeyFile: discoveryOpt["kv.keyfile"], }) if err != nil { return err } config = &store.Config{ // Set ClientTLS to trigger https (bug in libkv/etcd) ClientTLS: &store.ClientTLSConfig{ CACertFile: discoveryOpt["kv.cacertfile"], CertFile: discoveryOpt["kv.certfile"], KeyFile: discoveryOpt["kv.keyfile"], }, // The actual TLS config that will be used TLS: tlsConfig, } } else { log.Debug("Initializing discovery without TLS") } // Creates a new store, will ignore options given // if not supported by the chosen store s.store, err = libkv.NewStore(s.backend, addrs, config) return err }
func setupTlsConfig() (*tls.Config, error) { if os.Getenv("DOCKER_TLS_VERIFY") == "" { return &tls.Config{}, nil } dockerCertPath := os.Getenv("DOCKER_CERT_PATH") var tlsOptions tlsconfig.Options tlsOptions.CAFile = filepath.Join(dockerCertPath, defaultCaFile) tlsOptions.CertFile = filepath.Join(dockerCertPath, defaultCertFile) tlsOptions.KeyFile = filepath.Join(dockerCertPath, defaultKeyFile) return tlsconfig.Client(tlsOptions) }
// NewClient creates a new plugin client (http). func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) { tr := &http.Transport{} c, err := tlsconfig.Client(tlsConfig) if err != nil { return nil, err } tr.TLSClientConfig = c protoAndAddr := strings.Split(addr, "://") ConfigureTCPTransport(tr, protoAndAddr[0], protoAndAddr[1]) return &Client{&http.Client{Transport: tr}, protoAndAddr[1]}, nil }
func newClientTransport(tlsOptions *tlsconfig.Options) (*http.Transport, error) { if tlsOptions == nil { return &http.Transport{}, nil } config, err := tlsconfig.Client(*tlsOptions) if err != nil { return nil, err } return &http.Transport{ TLSClientConfig: config, }, nil }
// NewClient creates a new plugin client (http). func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) { tr := &http.Transport{} c, err := tlsconfig.Client(tlsConfig) if err != nil { return nil, err } tr.TLSClientConfig = c protoAndAddr := strings.Split(addr, "://") sockets.ConfigureTCPTransport(tr, protoAndAddr[0], protoAndAddr[1]) scheme := protoAndAddr[0] if scheme != "https" { scheme = "http" } return &Client{&http.Client{Transport: tr}, scheme, protoAndAddr[1]}, nil }
// NewClient initializes a new API client for the given host and API version. // It won't send any version information if the version number is empty. // It uses the tlsOptions to decide whether to use a secure connection or not. // It also initializes the custom http headers to add to each request. func NewClient(host string, version string, tlsOptions *tlsconfig.Options, httpHeaders map[string]string) (*Client, error) { var ( basePath string tlsConfig *tls.Config scheme = "http" protoAddrParts = strings.SplitN(host, "://", 2) proto, addr = protoAddrParts[0], protoAddrParts[1] ) if proto == "tcp" { parsed, err := url.Parse("tcp://" + addr) if err != nil { return nil, err } addr = parsed.Host basePath = parsed.Path } if tlsOptions != nil { scheme = "https" var err error tlsConfig, err = tlsconfig.Client(*tlsOptions) if err != nil { return nil, err } } // The transport is created here for reuse during the client session. transport := &http.Transport{ TLSClientConfig: tlsConfig, } sockets.ConfigureTCPTransport(transport, proto, addr) return &Client{ proto: proto, addr: addr, basePath: basePath, scheme: scheme, tlsConfig: tlsConfig, httpClient: &http.Client{Transport: transport}, version: version, customHTTPHeaders: httpHeaders, }, nil }
func (d *Daemon) getClientConfig() (*clientConfig, error) { var ( transport *http.Transport scheme string addr string proto string ) if d.useDefaultTLSHost { option := &tlsconfig.Options{ CAFile: "fixtures/https/ca.pem", CertFile: "fixtures/https/client-cert.pem", KeyFile: "fixtures/https/client-key.pem", } tlsConfig, err := tlsconfig.Client(*option) if err != nil { return nil, err } transport = &http.Transport{ TLSClientConfig: tlsConfig, } addr = fmt.Sprintf("%s:%d", opts.DefaultHTTPHost, opts.DefaultTLSHTTPPort) scheme = "https" proto = "tcp" } else if d.useDefaultHost { addr = opts.DefaultUnixSocket proto = "unix" scheme = "http" transport = &http.Transport{} } else { addr = filepath.Join(d.folder, "docker.sock") proto = "unix" scheme = "http" transport = &http.Transport{} } sockets.ConfigureTCPTransport(transport, proto, addr) return &clientConfig{ transport: transport, scheme: scheme, addr: addr, }, nil }
func getTLSConfig() (*tls.Config, error) { dockerCertPath := os.Getenv("DOCKER_CERT_PATH") if dockerCertPath == "" { return nil, fmt.Errorf("DOCKER_TLS_VERIFY specified, but no DOCKER_CERT_PATH environment variable") } option := &tlsconfig.Options{ CAFile: filepath.Join(dockerCertPath, "ca.pem"), CertFile: filepath.Join(dockerCertPath, "cert.pem"), KeyFile: filepath.Join(dockerCertPath, "key.pem"), } tlsConfig, err := tlsconfig.Client(*option) if err != nil { return nil, err } return tlsConfig, nil }
func main() { if reexec.Init() { return } // Set terminal emulation based on platform as required. stdin, stdout, stderr := term.StdStreams() initLogging(stderr) flag.Parse() // FIXME: validate daemon flags here if *flVersion { showVersion() return } if *flConfigDir != "" { cliconfig.SetConfigDir(*flConfigDir) } if *flLogLevel != "" { lvl, err := logrus.ParseLevel(*flLogLevel) if err != nil { fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", *flLogLevel) os.Exit(1) } setLogLevel(lvl) } else { setLogLevel(logrus.InfoLevel) } if *flDebug { os.Setenv("DEBUG", "1") setLogLevel(logrus.DebugLevel) } if len(flHosts) == 0 { defaultHost := os.Getenv("DOCKER_HOST") if defaultHost == "" || *flDaemon { if runtime.GOOS != "windows" { // If we do not have a host, default to unix socket defaultHost = fmt.Sprintf("unix://%s", opts.DefaultUnixSocket) } else { // If we do not have a host, default to TCP socket on Windows defaultHost = fmt.Sprintf("tcp://%s:%d", opts.DefaultHTTPHost, opts.DefaultHTTPPort) } } defaultHost, err := opts.ValidateHost(defaultHost) if err != nil { if *flDaemon { logrus.Fatal(err) } else { fmt.Fprint(os.Stderr, err) } os.Exit(1) } flHosts = append(flHosts, defaultHost) } setDefaultConfFlag(flTrustKey, defaultTrustKeyFile) // Regardless of whether the user sets it to true or false, if they // specify --tlsverify at all then we need to turn on tls // *flTlsVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well if flag.IsSet("-tlsverify") || *flTlsVerify { *flTls = true } if *flDaemon { if *flHelp { flag.Usage() return } mainDaemon() return } // From here on, we assume we're a client, not a server. if len(flHosts) > 1 { fmt.Fprintf(os.Stderr, "Please specify only one -H") os.Exit(0) } protoAddrParts := strings.SplitN(flHosts[0], "://", 2) var tlsConfig *tls.Config if *flTls { tlsOptions.InsecureSkipVerify = !*flTlsVerify if !flag.IsSet("-tlscert") { if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) { tlsOptions.CertFile = "" } } if !flag.IsSet("-tlskey") { if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) { tlsOptions.KeyFile = "" } } var err error tlsConfig, err = tlsconfig.Client(tlsOptions) if err != nil { fmt.Fprintln(stderr, err) os.Exit(1) } } cli := client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], tlsConfig) if err := cli.Cmd(flag.Args()...); err != nil { if sterr, ok := err.(client.StatusError); ok { if sterr.Status != "" { fmt.Fprintln(cli.Err(), sterr.Status) os.Exit(1) } os.Exit(sterr.StatusCode) } fmt.Fprintln(cli.Err(), err) os.Exit(1) } }
//docker client 创建函数 // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } cli.init = func() error { clientFlags.PostParse() hosts := clientFlags.Common.Hosts switch len(hosts) { case 0: hosts = []string{os.Getenv("DOCKER_HOST")} case 1: // only accept one host to talk to default: return errors.New("Please specify only one -H") } defaultHost := opts.DefaultTCPHost if clientFlags.Common.TLSOptions != nil { defaultHost = opts.DefaultTLSHost } var e error if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil { return e } protoAddrParts := strings.SplitN(hosts[0], "://", 2) cli.proto, cli.addr = protoAddrParts[0], protoAddrParts[1] if cli.proto == "tcp" { // error is checked in pkg/parsers already parsed, _ := url.Parse("tcp://" + cli.addr) cli.addr = parsed.Host cli.basePath = parsed.Path } if clientFlags.Common.TLSOptions != nil { cli.scheme = "https" //启用HTTPS var e error cli.tlsConfig, e = tlsconfig.Client(*clientFlags.Common.TLSOptions) if e != nil { return e } } else { cli.scheme = "http" } if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } // The transport is created here for reuse during the client session. cli.transport = &http.Transport{ TLSClientConfig: cli.tlsConfig, } sockets.ConfigureTCPTransport(cli.transport, cli.proto, cli.addr) configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } cli.configFile = configFile return nil } return cli }
func runAction(c *cli.Context) { log.Infof("interlock %s", version.FullVersion()) // init kv kvOpts := &kvstore.Config{ ConnectionTimeout: time.Second * 10, } dURL := c.String("discovery") dTLSCACert := c.String("discovery-tls-ca-cert") dTLSCert := c.String("discovery-tls-cert") dTLSKey := c.String("discovery-tls-key") var data string if dURL != "" { log.Debugf("using kv: addr=%s", dURL) if dTLSCACert != "" && dTLSCert != "" && dTLSKey != "" { tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ CAFile: dTLSCACert, CertFile: dTLSCert, KeyFile: dTLSKey, }) if err != nil { log.Fatal(err) } log.Debug("configuring TLS for KV") kvOpts.TLS = tlsConfig } kv, err := getKVStore(dURL, kvOpts) if err != nil { log.Fatal(err) } // get config from kv exists, err := kv.Exists(kvConfigKey) if err != nil { log.Fatal(err) } if !exists { log.Warnf("unable to find config in key %s; using default config", kvConfigKey) data = defaultConfig } else { kvPair, err := kv.Get(kvConfigKey) if err != nil { log.Fatalf("error getting configuration from kv: %s", err) } data = string(kvPair.Value) if data == "" { data = defaultConfig } } } else { configPath := c.String("config") d, err := ioutil.ReadFile(configPath) switch { case os.IsNotExist(err): log.Debug("no config detected; using default config") data = defaultConfig case err == nil: data = string(d) default: log.Fatal(err) } } config, err := config.ParseConfig(data) if err != nil { log.Fatal(err) } srv, err := server.NewServer(config) if err != nil { log.Fatal(err) } if err := srv.Run(); err != nil { log.Fatal(err) } }