mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #24349 from aaronlehmann/swarm-secrets-by-default
Generate a swarm joining secret if none is specified
This commit is contained in:
commit
db67db98d8
8 changed files with 84 additions and 13 deletions
|
@ -12,6 +12,13 @@ import (
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
generatedSecretEntropyBytes = 16
|
||||||
|
generatedSecretBase = 36
|
||||||
|
// floor(log(2^128-1, 36)) + 1
|
||||||
|
maxGeneratedSecretLength = 25
|
||||||
|
)
|
||||||
|
|
||||||
type initOptions struct {
|
type initOptions struct {
|
||||||
swarmOptions
|
swarmOptions
|
||||||
listenAddr NodeAddrOption
|
listenAddr NodeAddrOption
|
||||||
|
@ -46,6 +53,12 @@ func runInit(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts initOptions
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// If no secret was specified, we create a random one
|
||||||
|
if !flags.Changed("secret") {
|
||||||
|
opts.secret = generateRandomSecret()
|
||||||
|
fmt.Fprintf(dockerCli.Out(), "No --secret provided. Generated random secret:\n\t%s\n\n", opts.secret)
|
||||||
|
}
|
||||||
|
|
||||||
req := swarm.InitRequest{
|
req := swarm.InitRequest{
|
||||||
ListenAddr: opts.listenAddr.String(),
|
ListenAddr: opts.listenAddr.String(),
|
||||||
ForceNewCluster: opts.forceNewCluster,
|
ForceNewCluster: opts.forceNewCluster,
|
||||||
|
@ -57,7 +70,26 @@ func runInit(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts initOptions
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n", nodeID)
|
fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n\n", nodeID)
|
||||||
|
|
||||||
|
// Fetch CAHash and Address from the API
|
||||||
|
info, err := client.Info(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
node, _, err := client.NodeInspectWithRaw(ctx, nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.ManagerStatus != nil && info.Swarm.CACertHash != "" {
|
||||||
|
var secretArgs string
|
||||||
|
if opts.secret != "" {
|
||||||
|
secretArgs = "--secret " + opts.secret
|
||||||
|
}
|
||||||
|
fmt.Fprintf(dockerCli.Out(), "To add a worker to this swarm, run the following command:\n\tdocker swarm join %s \\\n\t--ca-hash %s \\\n\t%s\n", secretArgs, info.Swarm.CACertHash, node.ManagerStatus.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,7 +237,7 @@ func parseExternalCA(caSpec string) (*swarm.ExternalCA, error) {
|
||||||
|
|
||||||
func addSwarmFlags(flags *pflag.FlagSet, opts *swarmOptions) {
|
func addSwarmFlags(flags *pflag.FlagSet, opts *swarmOptions) {
|
||||||
flags.Var(&opts.autoAccept, flagAutoAccept, "Auto acceptance policy (worker, manager or none)")
|
flags.Var(&opts.autoAccept, flagAutoAccept, "Auto acceptance policy (worker, manager or none)")
|
||||||
flags.StringVar(&opts.secret, flagSecret, "", "Set secret value needed to accept nodes into cluster")
|
flags.StringVar(&opts.secret, flagSecret, "", "Set secret value needed to join a cluster")
|
||||||
flags.Int64Var(&opts.taskHistoryLimit, flagTaskHistoryLimit, 10, "Task history retention limit")
|
flags.Int64Var(&opts.taskHistoryLimit, flagTaskHistoryLimit, 10, "Task history retention limit")
|
||||||
flags.DurationVar(&opts.dispatcherHeartbeat, flagDispatcherHeartbeat, time.Duration(5*time.Second), "Dispatcher heartbeat period")
|
flags.DurationVar(&opts.dispatcherHeartbeat, flagDispatcherHeartbeat, time.Duration(5*time.Second), "Dispatcher heartbeat period")
|
||||||
flags.DurationVar(&opts.nodeCertExpiry, flagCertExpiry, time.Duration(90*24*time.Hour), "Validity period for node certificates")
|
flags.DurationVar(&opts.nodeCertExpiry, flagCertExpiry, time.Duration(90*24*time.Hour), "Validity period for node certificates")
|
||||||
|
|
19
api/client/swarm/secret.go
Normal file
19
api/client/swarm/secret.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package swarm
|
||||||
|
|
||||||
|
import (
|
||||||
|
cryptorand "crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateRandomSecret() string {
|
||||||
|
var secretBytes [generatedSecretEntropyBytes]byte
|
||||||
|
|
||||||
|
if _, err := cryptorand.Read(secretBytes[:]); err != nil {
|
||||||
|
panic(fmt.Errorf("failed to read random bytes: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var nn big.Int
|
||||||
|
nn.SetBytes(secretBytes[:])
|
||||||
|
return fmt.Sprintf("%0[1]*s", maxGeneratedSecretLength, nn.Text(generatedSecretBase))
|
||||||
|
}
|
|
@ -29,12 +29,24 @@ in the newly created one node Swarm cluster.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker swarm init --listen-addr 192.168.99.121:2377
|
$ docker swarm init --listen-addr 192.168.99.121:2377
|
||||||
|
No --secret provided. Generated random secret:
|
||||||
|
4ao565v9jsuogtq5t8s379ulb
|
||||||
|
|
||||||
Swarm initialized: current node (1ujecd0j9n3ro9i6628smdmth) is now a manager.
|
Swarm initialized: current node (1ujecd0j9n3ro9i6628smdmth) is now a manager.
|
||||||
|
|
||||||
|
To add a worker to this swarm, run the following command:
|
||||||
|
docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb \
|
||||||
|
--ca-hash sha256:07ce22bd1a7619f2adc0d63bd110479a170e7c4e69df05b67a1aa2705c88ef09 \
|
||||||
|
192.168.99.121:2377
|
||||||
$ docker node ls
|
$ docker node ls
|
||||||
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER
|
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER
|
||||||
1ujecd0j9n3ro9i6628smdmth * manager1 Accepted Ready Active Reachable Yes
|
1ujecd0j9n3ro9i6628smdmth * manager1 Accepted Ready Active Reachable Yes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If a secret for joining new nodes is not provided with `--secret`, `docker swarm init` will
|
||||||
|
generate a random one and print it to the terminal (as seen in the example above). To initialize
|
||||||
|
a swarm with no secret, use `--secret ""`.
|
||||||
|
|
||||||
### `--auto-accept value`
|
### `--auto-accept value`
|
||||||
|
|
||||||
This flag controls node acceptance into the cluster. By default, `worker` nodes are
|
This flag controls node acceptance into the cluster. By default, `worker` nodes are
|
||||||
|
@ -47,7 +59,6 @@ For example, the following initializes a cluster with auto-acceptance of workers
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker swarm init --listen-addr 192.168.99.121:2377 --auto-accept worker
|
$ docker swarm init --listen-addr 192.168.99.121:2377 --auto-accept worker
|
||||||
Swarm initialized: current node (1m8cdsylxbf3lk8qriqt07hx1) is now a manager.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### `--external-ca value`
|
### `--external-ca value`
|
||||||
|
|
|
@ -27,7 +27,7 @@ targeted by this command becomes a `manager`. If it is not specified, it becomes
|
||||||
### Join a node to swarm as a manager
|
### Join a node to swarm as a manager
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker swarm join --manager --listen-addr 192.168.99.122:2377 192.168.99.121:2377
|
$ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb --manager --listen-addr 192.168.99.122:2377 192.168.99.121:2377
|
||||||
This node joined a Swarm as a manager.
|
This node joined a Swarm as a manager.
|
||||||
$ docker node ls
|
$ docker node ls
|
||||||
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER
|
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER
|
||||||
|
@ -38,7 +38,7 @@ dvfxp4zseq4s0rih1selh0d20 manager1 Accepted Ready Active Reachab
|
||||||
### Join a node to swarm as a worker
|
### Join a node to swarm as a worker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker swarm join --listen-addr 192.168.99.123:2377 192.168.99.121:2377
|
$ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb --listen-addr 192.168.99.123:2377 192.168.99.121:2377
|
||||||
This node joined a Swarm as a worker.
|
This node joined a Swarm as a worker.
|
||||||
$ docker node ls
|
$ docker node ls
|
||||||
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER
|
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER
|
||||||
|
|
|
@ -23,16 +23,17 @@ This tutorial uses the name `worker1`.
|
||||||
the existing swarm:
|
the existing swarm:
|
||||||
|
|
||||||
```
|
```
|
||||||
docker swarm join <MANAGER-IP>:<PORT>
|
docker swarm join --secret <SECRET> <MANAGER-IP>:<PORT>
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `<MANAGER-IP>` with the address of the manager node and `<PORT>`
|
Replace `<SECRET>` with the secret that was printed by `docker swarm init` in the
|
||||||
with the port where the manager listens.
|
previous step. Replace `<MANAGER-IP>` with the address of the manager node
|
||||||
|
and `<PORT>` with the port where the manager listens.
|
||||||
|
|
||||||
In the tutorial, the following command joins `worker1` to the swarm on `manager1`:
|
In the tutorial, the following command joins `worker1` to the swarm on `manager1`:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ docker swarm join 192.168.99.100:2377
|
$ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb 192.168.99.100:2377
|
||||||
|
|
||||||
This node joined a Swarm as a worker.
|
This node joined a Swarm as a worker.
|
||||||
```
|
```
|
||||||
|
@ -40,11 +41,12 @@ the existing swarm:
|
||||||
3. Open a terminal and ssh into the machine where you want to run a second
|
3. Open a terminal and ssh into the machine where you want to run a second
|
||||||
worker node. This tutorial uses the name `worker2`.
|
worker node. This tutorial uses the name `worker2`.
|
||||||
|
|
||||||
4. Run `docker swarm join <MANAGER-IP>:<PORT>` to create a worker node joined to
|
4. Run `docker swarm join --secret <SECRET> <MANAGER-IP>:<PORT>` to create a worker node joined to
|
||||||
the existing Swarm.
|
the existing Swarm.
|
||||||
|
|
||||||
Replace `<MANAGER-IP>` with the address of the manager node and `<PORT>`
|
Replace `<SECRET>` with the secret that was printed by `docker swarm init` in the
|
||||||
with the port where the manager listens.
|
previous step. Replace `<MANAGER-IP>` with the address of the manager node
|
||||||
|
and `<PORT>` with the port where the manager listens.
|
||||||
|
|
||||||
5. Open a terminal and ssh into the machine where the manager node runs and run
|
5. Open a terminal and ssh into the machine where the manager node runs and run
|
||||||
the `docker node ls` command to see the worker nodes:
|
the `docker node ls` command to see the worker nodes:
|
||||||
|
|
|
@ -30,8 +30,15 @@ node. For example, the tutorial uses a machine named `manager1`.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ docker swarm init --listen-addr 192.168.99.100:2377
|
$ docker swarm init --listen-addr 192.168.99.100:2377
|
||||||
|
No --secret provided. Generated random secret:
|
||||||
|
4ao565v9jsuogtq5t8s379ulb
|
||||||
|
|
||||||
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.
|
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.
|
||||||
|
|
||||||
|
To add a worker to this swarm, run the following command:
|
||||||
|
docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb \
|
||||||
|
--ca-hash sha256:07ce22bd1a7619f2adc0d63bd110479a170e7c4e69df05b67a1aa2705c88ef09 \
|
||||||
|
192.168.99.100:2377
|
||||||
```
|
```
|
||||||
|
|
||||||
The `--listen-addr` flag configures the manager node to listen on port
|
The `--listen-addr` flag configures the manager node to listen on port
|
||||||
|
|
|
@ -106,7 +106,7 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
|
||||||
|
|
||||||
c.Assert(d.Leave(true), checker.IsNil)
|
c.Assert(d.Leave(true), checker.IsNil)
|
||||||
|
|
||||||
out, err = d.Cmd("swarm", "init", "--auto-accept", "none")
|
out, err = d.Cmd("swarm", "init", "--auto-accept", "none", "--secret", "")
|
||||||
c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
|
c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
|
||||||
|
|
||||||
spec = getSpec()
|
spec = getSpec()
|
||||||
|
|
Loading…
Reference in a new issue