mirror of https://github.com/docker/docs.git
TLS support.
TLS authentication support between the CLI and Swarm but also between Swarm and the Docker nodes. Closes #148. Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
parent
c6815ee1fe
commit
39fe73a231
13
README.md
13
README.md
|
@ -51,6 +51,19 @@ $ swarm list --token=6856663cdefdec325839a4b7e1de38e8
|
|||
http://<node_ip:2375>
|
||||
```
|
||||
|
||||
### TLS
|
||||
|
||||
Swarm supports TLS authentication between the CLI and Swarm but also between Swarm and the Docker nodes.
|
||||
|
||||
In order to enable TLS, the same command line options as Docker can be specified:
|
||||
|
||||
`swarm manage --tlsverify --tlscacert=<CACERT> --tlscert=<CERT> --tlskey=<KEY> [...]`
|
||||
|
||||
Please refer to the [Docker documentation](https://docs.docker.com/articles/https/) for more information on how
|
||||
to set up TLS authentication on Docker and generating the certificates.
|
||||
|
||||
Note that Swarm certificates must be generated with`extendedKeyUsage = clientAuth,serverAuth`.
|
||||
|
||||
## Participating
|
||||
|
||||
We welcome pull requests and patches; come say hi on IRC, #docker-swarm on freenode.
|
||||
|
|
16
api/api.go
16
api/api.go
|
@ -2,9 +2,11 @@ package api
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
@ -362,7 +364,7 @@ func createRouter(c *context, enableCors bool) (*mux.Router, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
func ListenAndServe(c *cluster.Cluster, s *scheduler.Scheduler, addr, version string, enableCors bool) error {
|
||||
func ListenAndServe(c *cluster.Cluster, s *scheduler.Scheduler, addr, version string, enableCors bool, tlsConfig *tls.Config) error {
|
||||
context := &context{
|
||||
cluster: c,
|
||||
scheduler: s,
|
||||
|
@ -374,9 +376,19 @@ func ListenAndServe(c *cluster.Cluster, s *scheduler.Scheduler, addr, version st
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: r,
|
||||
}
|
||||
return server.ListenAndServe()
|
||||
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tlsConfig != nil {
|
||||
tlsConfig.NextProtos = []string{"http/1.1"}
|
||||
l = tls.NewListener(l, tlsConfig)
|
||||
}
|
||||
return server.Serve(l)
|
||||
}
|
||||
|
|
27
main.go
27
main.go
|
@ -54,6 +54,26 @@ func main() {
|
|||
Name: "api-enable-cors, cors",
|
||||
Usage: "enable CORS headers in the remote API",
|
||||
}
|
||||
flTls := cli.BoolFlag{
|
||||
Name: "tls",
|
||||
Usage: "Use TLS; implied by --tlsverify=true",
|
||||
}
|
||||
flTlsCaCert := cli.StringFlag{
|
||||
Name: "tlscacert",
|
||||
Usage: "Trust only remotes providing a certificate signed by the CA given here",
|
||||
}
|
||||
flTlsCert := cli.StringFlag{
|
||||
Name: "tlscert",
|
||||
Usage: "Path to TLS certificate file",
|
||||
}
|
||||
flTlsKey := cli.StringFlag{
|
||||
Name: "tlskey",
|
||||
Usage: "Path to TLS key file",
|
||||
}
|
||||
flTlsVerify := cli.BoolFlag{
|
||||
Name: "tlsverify",
|
||||
Usage: "Use TLS and verify the remote",
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
|
@ -91,8 +111,11 @@ func main() {
|
|||
Name: "manage",
|
||||
ShortName: "m",
|
||||
Usage: "manage a docker cluster",
|
||||
Flags: []cli.Flag{flToken, flAddr, flHeartBeat, flEnableCors},
|
||||
Action: manage,
|
||||
Flags: []cli.Flag{
|
||||
flToken, flAddr, flHeartBeat,
|
||||
flTls, flTlsCaCert, flTlsCert, flTlsKey, flTlsVerify,
|
||||
flEnableCors},
|
||||
Action: manage,
|
||||
},
|
||||
{
|
||||
Name: "join",
|
||||
|
|
53
manage.go
53
manage.go
|
@ -1,6 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -22,7 +26,52 @@ func (h *logHandler) Handle(e *cluster.Event) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Load the TLS certificates/keys and, if verify is true, the CA.
|
||||
func loadTlsConfig(ca, cert, key string, verify bool) (*tls.Config, error) {
|
||||
c, err := tls.LoadX509KeyPair(cert, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?",
|
||||
cert, key, err)
|
||||
}
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{c},
|
||||
MinVersion: tls.VersionTLS10,
|
||||
}
|
||||
|
||||
if verify {
|
||||
certPool := x509.NewCertPool()
|
||||
file, err := ioutil.ReadFile(ca)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't read CA certificate: %s", err)
|
||||
}
|
||||
certPool.AppendCertsFromPEM(file)
|
||||
config.RootCAs = certPool
|
||||
} else {
|
||||
// If --tlsverify is not supplied, disable CA validation.
|
||||
config.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func manage(c *cli.Context) {
|
||||
var (
|
||||
tlsConfig *tls.Config = nil
|
||||
err error
|
||||
)
|
||||
|
||||
// If either --tls or --tlsverify are specified, load the certificates.
|
||||
if c.Bool("tls") || c.Bool("tlsverify") {
|
||||
tlsConfig, err = loadTlsConfig(
|
||||
c.String("tlscacert"),
|
||||
c.String("tlscert"),
|
||||
c.String("tlskey"),
|
||||
c.Bool("tlsverify"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
refresh := func(c *cluster.Cluster, nodes []string) {
|
||||
for _, addr := range nodes {
|
||||
|
@ -32,7 +81,7 @@ func manage(c *cli.Context) {
|
|||
}
|
||||
if c.Node(addr) == nil {
|
||||
n := cluster.NewNode(addr)
|
||||
if err := n.Connect(nil); err != nil {
|
||||
if err := n.Connect(tlsConfig); err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
@ -82,5 +131,5 @@ func manage(c *cli.Context) {
|
|||
},
|
||||
)
|
||||
|
||||
log.Fatal(api.ListenAndServe(cluster, s, c.String("addr"), c.App.Version, c.Bool("cors")))
|
||||
log.Fatal(api.ListenAndServe(cluster, s, c.String("addr"), c.App.Version, c.Bool("cors"), tlsConfig))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue