Generate a swarm joining secret if none is specified
| ... | ... |
@@ -12,6 +12,13 @@ import ( |
| 12 | 12 |
"github.com/spf13/pflag" |
| 13 | 13 |
) |
| 14 | 14 |
|
| 15 |
+const ( |
|
| 16 |
+ generatedSecretEntropyBytes = 16 |
|
| 17 |
+ generatedSecretBase = 36 |
|
| 18 |
+ // floor(log(2^128-1, 36)) + 1 |
|
| 19 |
+ maxGeneratedSecretLength = 25 |
|
| 20 |
+) |
|
| 21 |
+ |
|
| 15 | 22 |
type initOptions struct {
|
| 16 | 23 |
swarmOptions |
| 17 | 24 |
listenAddr NodeAddrOption |
| ... | ... |
@@ -46,6 +53,12 @@ func runInit(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts initOptions |
| 46 | 46 |
client := dockerCli.Client() |
| 47 | 47 |
ctx := context.Background() |
| 48 | 48 |
|
| 49 |
+ // If no secret was specified, we create a random one |
|
| 50 |
+ if !flags.Changed("secret") {
|
|
| 51 |
+ opts.secret = generateRandomSecret() |
|
| 52 |
+ fmt.Fprintf(dockerCli.Out(), "No --secret provided. Generated random secret:\n\t%s\n\n", opts.secret) |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 49 | 55 |
req := swarm.InitRequest{
|
| 50 | 56 |
ListenAddr: opts.listenAddr.String(), |
| 51 | 57 |
ForceNewCluster: opts.forceNewCluster, |
| ... | ... |
@@ -57,7 +70,26 @@ func runInit(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts initOptions |
| 57 | 57 |
return err |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 |
- fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n", nodeID) |
|
| 60 |
+ fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n\n", nodeID) |
|
| 61 |
+ |
|
| 62 |
+ // Fetch CAHash and Address from the API |
|
| 63 |
+ info, err := client.Info(ctx) |
|
| 64 |
+ if err != nil {
|
|
| 65 |
+ return err |
|
| 66 |
+ } |
|
| 67 |
+ |
|
| 68 |
+ node, _, err := client.NodeInspectWithRaw(ctx, nodeID) |
|
| 69 |
+ if err != nil {
|
|
| 70 |
+ return err |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ if node.ManagerStatus != nil && info.Swarm.CACertHash != "" {
|
|
| 74 |
+ var secretArgs string |
|
| 75 |
+ if opts.secret != "" {
|
|
| 76 |
+ secretArgs = "--secret " + opts.secret |
|
| 77 |
+ } |
|
| 78 |
+ 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) |
|
| 79 |
+ } |
|
| 61 | 80 |
|
| 62 | 81 |
return nil |
| 63 | 82 |
} |
| ... | ... |
@@ -237,7 +237,7 @@ func parseExternalCA(caSpec string) (*swarm.ExternalCA, error) {
|
| 237 | 237 |
|
| 238 | 238 |
func addSwarmFlags(flags *pflag.FlagSet, opts *swarmOptions) {
|
| 239 | 239 |
flags.Var(&opts.autoAccept, flagAutoAccept, "Auto acceptance policy (worker, manager or none)") |
| 240 |
- flags.StringVar(&opts.secret, flagSecret, "", "Set secret value needed to accept nodes into cluster") |
|
| 240 |
+ flags.StringVar(&opts.secret, flagSecret, "", "Set secret value needed to join a cluster") |
|
| 241 | 241 |
flags.Int64Var(&opts.taskHistoryLimit, flagTaskHistoryLimit, 10, "Task history retention limit") |
| 242 | 242 |
flags.DurationVar(&opts.dispatcherHeartbeat, flagDispatcherHeartbeat, time.Duration(5*time.Second), "Dispatcher heartbeat period") |
| 243 | 243 |
flags.DurationVar(&opts.nodeCertExpiry, flagCertExpiry, time.Duration(90*24*time.Hour), "Validity period for node certificates") |
| 244 | 244 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,19 @@ |
| 0 |
+package swarm |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ cryptorand "crypto/rand" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "math/big" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func generateRandomSecret() string {
|
|
| 9 |
+ var secretBytes [generatedSecretEntropyBytes]byte |
|
| 10 |
+ |
|
| 11 |
+ if _, err := cryptorand.Read(secretBytes[:]); err != nil {
|
|
| 12 |
+ panic(fmt.Errorf("failed to read random bytes: %v", err))
|
|
| 13 |
+ } |
|
| 14 |
+ |
|
| 15 |
+ var nn big.Int |
|
| 16 |
+ nn.SetBytes(secretBytes[:]) |
|
| 17 |
+ return fmt.Sprintf("%0[1]*s", maxGeneratedSecretLength, nn.Text(generatedSecretBase))
|
|
| 18 |
+} |
| ... | ... |
@@ -29,12 +29,24 @@ in the newly created one node Swarm cluster. |
| 29 | 29 |
|
| 30 | 30 |
```bash |
| 31 | 31 |
$ docker swarm init --listen-addr 192.168.99.121:2377 |
| 32 |
+No --secret provided. Generated random secret: |
|
| 33 |
+ 4ao565v9jsuogtq5t8s379ulb |
|
| 34 |
+ |
|
| 32 | 35 |
Swarm initialized: current node (1ujecd0j9n3ro9i6628smdmth) is now a manager. |
| 36 |
+ |
|
| 37 |
+To add a worker to this swarm, run the following command: |
|
| 38 |
+ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb \ |
|
| 39 |
+ --ca-hash sha256:07ce22bd1a7619f2adc0d63bd110479a170e7c4e69df05b67a1aa2705c88ef09 \ |
|
| 40 |
+ 192.168.99.121:2377 |
|
| 33 | 41 |
$ docker node ls |
| 34 | 42 |
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER |
| 35 | 43 |
1ujecd0j9n3ro9i6628smdmth * manager1 Accepted Ready Active Reachable Yes |
| 36 | 44 |
``` |
| 37 | 45 |
|
| 46 |
+If a secret for joining new nodes is not provided with `--secret`, `docker swarm init` will |
|
| 47 |
+generate a random one and print it to the terminal (as seen in the example above). To initialize |
|
| 48 |
+a swarm with no secret, use `--secret ""`. |
|
| 49 |
+ |
|
| 38 | 50 |
### `--auto-accept value` |
| 39 | 51 |
|
| 40 | 52 |
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 |
| 47 | 47 |
|
| 48 | 48 |
```bash |
| 49 | 49 |
$ docker swarm init --listen-addr 192.168.99.121:2377 --auto-accept worker |
| 50 |
-Swarm initialized: current node (1m8cdsylxbf3lk8qriqt07hx1) is now a manager. |
|
| 51 | 50 |
``` |
| 52 | 51 |
|
| 53 | 52 |
### `--external-ca value` |
| ... | ... |
@@ -27,7 +27,7 @@ targeted by this command becomes a `manager`. If it is not specified, it becomes |
| 27 | 27 |
### Join a node to swarm as a manager |
| 28 | 28 |
|
| 29 | 29 |
```bash |
| 30 |
-$ docker swarm join --manager --listen-addr 192.168.99.122:2377 192.168.99.121:2377 |
|
| 30 |
+$ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb --manager --listen-addr 192.168.99.122:2377 192.168.99.121:2377 |
|
| 31 | 31 |
This node joined a Swarm as a manager. |
| 32 | 32 |
$ docker node ls |
| 33 | 33 |
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER |
| ... | ... |
@@ -38,7 +38,7 @@ dvfxp4zseq4s0rih1selh0d20 manager1 Accepted Ready Active Reachab |
| 38 | 38 |
### Join a node to swarm as a worker |
| 39 | 39 |
|
| 40 | 40 |
```bash |
| 41 |
-$ docker swarm join --listen-addr 192.168.99.123:2377 192.168.99.121:2377 |
|
| 41 |
+$ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb --listen-addr 192.168.99.123:2377 192.168.99.121:2377 |
|
| 42 | 42 |
This node joined a Swarm as a worker. |
| 43 | 43 |
$ docker node ls |
| 44 | 44 |
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS LEADER |
| ... | ... |
@@ -23,16 +23,17 @@ This tutorial uses the name `worker1`. |
| 23 | 23 |
the existing swarm: |
| 24 | 24 |
|
| 25 | 25 |
``` |
| 26 |
- docker swarm join <MANAGER-IP>:<PORT> |
|
| 26 |
+ docker swarm join --secret <SECRET> <MANAGER-IP>:<PORT> |
|
| 27 | 27 |
``` |
| 28 | 28 |
|
| 29 |
- Replace `<MANAGER-IP>` with the address of the manager node and `<PORT>` |
|
| 30 |
- with the port where the manager listens. |
|
| 29 |
+ Replace `<SECRET>` with the secret that was printed by `docker swarm init` in the |
|
| 30 |
+ previous step. Replace `<MANAGER-IP>` with the address of the manager node |
|
| 31 |
+ and `<PORT>` with the port where the manager listens. |
|
| 31 | 32 |
|
| 32 | 33 |
In the tutorial, the following command joins `worker1` to the swarm on `manager1`: |
| 33 | 34 |
|
| 34 | 35 |
``` |
| 35 |
- $ docker swarm join 192.168.99.100:2377 |
|
| 36 |
+ $ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb 192.168.99.100:2377 |
|
| 36 | 37 |
|
| 37 | 38 |
This node joined a Swarm as a worker. |
| 38 | 39 |
``` |
| ... | ... |
@@ -40,11 +41,12 @@ the existing swarm: |
| 40 | 40 |
3. Open a terminal and ssh into the machine where you want to run a second |
| 41 | 41 |
worker node. This tutorial uses the name `worker2`. |
| 42 | 42 |
|
| 43 |
-4. Run `docker swarm join <MANAGER-IP>:<PORT>` to create a worker node joined to |
|
| 43 |
+4. Run `docker swarm join --secret <SECRET> <MANAGER-IP>:<PORT>` to create a worker node joined to |
|
| 44 | 44 |
the existing Swarm. |
| 45 | 45 |
|
| 46 |
- Replace `<MANAGER-IP>` with the address of the manager node and `<PORT>` |
|
| 47 |
- with the port where the manager listens. |
|
| 46 |
+ Replace `<SECRET>` with the secret that was printed by `docker swarm init` in the |
|
| 47 |
+ previous step. Replace `<MANAGER-IP>` with the address of the manager node |
|
| 48 |
+ and `<PORT>` with the port where the manager listens. |
|
| 48 | 49 |
|
| 49 | 50 |
5. Open a terminal and ssh into the machine where the manager node runs and run |
| 50 | 51 |
the `docker node ls` command to see the worker nodes: |
| ... | ... |
@@ -30,8 +30,15 @@ node. For example, the tutorial uses a machine named `manager1`. |
| 30 | 30 |
|
| 31 | 31 |
``` |
| 32 | 32 |
$ docker swarm init --listen-addr 192.168.99.100:2377 |
| 33 |
+ No --secret provided. Generated random secret: |
|
| 34 |
+ 4ao565v9jsuogtq5t8s379ulb |
|
| 33 | 35 |
|
| 34 | 36 |
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager. |
| 37 |
+ |
|
| 38 |
+ To add a worker to this swarm, run the following command: |
|
| 39 |
+ docker swarm join --secret 4ao565v9jsuogtq5t8s379ulb \ |
|
| 40 |
+ --ca-hash sha256:07ce22bd1a7619f2adc0d63bd110479a170e7c4e69df05b67a1aa2705c88ef09 \ |
|
| 41 |
+ 192.168.99.100:2377 |
|
| 35 | 42 |
``` |
| 36 | 43 |
|
| 37 | 44 |
The `--listen-addr` flag configures the manager node to listen on port |
| ... | ... |
@@ -106,7 +106,7 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
|
| 106 | 106 |
|
| 107 | 107 |
c.Assert(d.Leave(true), checker.IsNil) |
| 108 | 108 |
|
| 109 |
- out, err = d.Cmd("swarm", "init", "--auto-accept", "none")
|
|
| 109 |
+ out, err = d.Cmd("swarm", "init", "--auto-accept", "none", "--secret", "")
|
|
| 110 | 110 |
c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
|
| 111 | 111 |
|
| 112 | 112 |
spec = getSpec() |