Prechádzať zdrojové kódy

Propagate the swarm cluster and node TLS info provided by the swarm
objects into the REST API responses. In the CLI, display only
whether the nodes' TLS info matches the cluster's TLS info, or
whether the node needs cert rotation.

Signed-off-by: Ying Li <ying.li@docker.com>

Ying Li 8 rokov pred
rodič
commit
64cccedbce

+ 63 - 0
api/swagger.yaml

@@ -1716,6 +1716,8 @@ definitions:
                       type: "string"
                       type: "string"
                     Name:
                     Name:
                       type: "string"
                       type: "string"
+          TLSInfo:
+            $ref: "#/definitions/SwarmSpec"
     example:
     example:
       ID: "24ifsmvkjbyhk"
       ID: "24ifsmvkjbyhk"
       Version:
       Version:
@@ -1756,6 +1758,47 @@ definitions:
         Leader: true
         Leader: true
         Reachability: "reachable"
         Reachability: "reachable"
         Addr: "172.17.0.2:2377"
         Addr: "172.17.0.2:2377"
+      TLSInfo:
+        TrustRoot: |
+          -----BEGIN CERTIFICATE-----
+          MIIBajCCARCgAwIBAgIUbYqrLSOSQHoxD8CwG6Bi2PJi9c8wCgYIKoZIzj0EAwIw
+          EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwNDI0MjE0MzAwWhcNMzcwNDE5MjE0
+          MzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
+          A0IABJk/VyMPYdaqDXJb/VXh5n/1Yuv7iNrxV3Qb3l06XD46seovcDWs3IZNV1lf
+          3Skyr0ofcchipoiHkXBODojJydSjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+          Af8EBTADAQH/MB0GA1UdDgQWBBRUXxuRcnFjDfR/RIAUQab8ZV/n4jAKBggqhkjO
+          PQQDAgNIADBFAiAy+JTe6Uc3KyLCMiqGl2GyWGQqQDEcO3/YG36x7om65AIhAJvz
+          pxv6zFeVEkAEEkqIYi0omA9+CjanB/6Bz4n1uw8H
+          -----END CERTIFICATE-----
+        CertIssuerSubject: "MBMxETAPBgNVBAMTCHN3YXJtLWNh"
+        CertIssuerPublicKey: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmT9XIw9h1qoNclv9VeHmf/Vi6/uI2vFXdBveXTpcPjqx6i9wNazchk1XWV/dKTKvSh9xyGKmiIeRcE4OiMnJ1A=="
+  TLSInfo:
+    description: "Information about the issuer of leaf TLS certificates and the trusted root CA certificate"
+    type: "object"
+    properties:
+      TrustRoot:
+        description: "The root CA certificate(s) that are used to validate leaf TLS certificates"
+        type: "string"
+      CertIssuerSubject:
+        description: "The base64-url-safe-encoded raw subject bytes of the issuer"
+        type: "string"
+      CertIssuerPublicKey:
+        description: "The base64-url-safe-encoded raw public key bytes of the issuer"
+        type: "string"
+    example:
+      TrustRoot: |
+        -----BEGIN CERTIFICATE-----
+        MIIBajCCARCgAwIBAgIUbYqrLSOSQHoxD8CwG6Bi2PJi9c8wCgYIKoZIzj0EAwIw
+        EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwNDI0MjE0MzAwWhcNMzcwNDE5MjE0
+        MzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
+        A0IABJk/VyMPYdaqDXJb/VXh5n/1Yuv7iNrxV3Qb3l06XD46seovcDWs3IZNV1lf
+        3Skyr0ofcchipoiHkXBODojJydSjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+        Af8EBTADAQH/MB0GA1UdDgQWBBRUXxuRcnFjDfR/RIAUQab8ZV/n4jAKBggqhkjO
+        PQQDAgNIADBFAiAy+JTe6Uc3KyLCMiqGl2GyWGQqQDEcO3/YG36x7om65AIhAJvz
+        pxv6zFeVEkAEEkqIYi0omA9+CjanB/6Bz4n1uw8H
+        -----END CERTIFICATE-----
+      CertIssuerSubject: "MBMxETAPBgNVBAMTCHN3YXJtLWNh"
+      CertIssuerPublicKey: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmT9XIw9h1qoNclv9VeHmf/Vi6/uI2vFXdBveXTpcPjqx6i9wNazchk1XWV/dKTKvSh9xyGKmiIeRcE4OiMnJ1A=="
   SwarmSpec:
   SwarmSpec:
     description: "User modifiable swarm configuration."
     description: "User modifiable swarm configuration."
     type: "object"
     type: "object"
@@ -1903,6 +1946,11 @@ definitions:
         format: "dateTime"
         format: "dateTime"
       Spec:
       Spec:
         $ref: "#/definitions/SwarmSpec"
         $ref: "#/definitions/SwarmSpec"
+      TLSInfo:
+        $ref: "#/definitions/TLSInfo"
+      RootRotationInProgress:
+        description: "Whether there is currently a root CA rotation in progress for the swarm"
+        type: "boolean"
   TaskSpec:
   TaskSpec:
     description: "User modifiable task configuration."
     description: "User modifiable task configuration."
     type: "object"
     type: "object"
@@ -7205,6 +7253,21 @@ paths:
               UpdatedAt: "2016-08-15T16:32:09.623207604Z"
               UpdatedAt: "2016-08-15T16:32:09.623207604Z"
               Version:
               Version:
                 Index: 51
                 Index: 51
+              RootRotationInProgress: false
+              TLSInfo:
+                TrustRoot: |
+                  -----BEGIN CERTIFICATE-----
+                  MIIBajCCARCgAwIBAgIUbYqrLSOSQHoxD8CwG6Bi2PJi9c8wCgYIKoZIzj0EAwIw
+                  EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwNDI0MjE0MzAwWhcNMzcwNDE5MjE0
+                  MzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
+                  A0IABJk/VyMPYdaqDXJb/VXh5n/1Yuv7iNrxV3Qb3l06XD46seovcDWs3IZNV1lf
+                  3Skyr0ofcchipoiHkXBODojJydSjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+                  Af8EBTADAQH/MB0GA1UdDgQWBBRUXxuRcnFjDfR/RIAUQab8ZV/n4jAKBggqhkjO
+                  PQQDAgNIADBFAiAy+JTe6Uc3KyLCMiqGl2GyWGQqQDEcO3/YG36x7om65AIhAJvz
+                  pxv6zFeVEkAEEkqIYi0omA9+CjanB/6Bz4n1uw8H
+                  -----END CERTIFICATE-----
+                CertIssuerSubject: "MBMxETAPBgNVBAMTCHN3YXJtLWNh"
+                CertIssuerPublicKey: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmT9XIw9h1qoNclv9VeHmf/Vi6/uI2vFXdBveXTpcPjqx6i9wNazchk1XWV/dKTKvSh9xyGKmiIeRcE4OiMnJ1A=="
         404:
         404:
           description: "no such swarm"
           description: "no such swarm"
           schema:
           schema:

+ 13 - 0
api/types/swarm/common.go

@@ -25,3 +25,16 @@ type Driver struct {
 	Name    string            `json:",omitempty"`
 	Name    string            `json:",omitempty"`
 	Options map[string]string `json:",omitempty"`
 	Options map[string]string `json:",omitempty"`
 }
 }
+
+// TLSInfo represents the TLS information about what CA certificate is trusted,
+// and who the issuer for a TLS certificate is
+type TLSInfo struct {
+	// TrustRoot is the trusted CA root certificate in PEM format
+	TrustRoot string `json:",omitempty"`
+
+	// CertIssuer is the raw subject bytes of the issuer
+	CertIssuerSubject []byte `json:",omitempty"`
+
+	// CertIssuerPublicKey is the raw public key bytes of the issuer
+	CertIssuerPublicKey []byte `json:",omitempty"`
+}

+ 1 - 0
api/types/swarm/node.go

@@ -52,6 +52,7 @@ type NodeDescription struct {
 	Platform  Platform          `json:",omitempty"`
 	Platform  Platform          `json:",omitempty"`
 	Resources Resources         `json:",omitempty"`
 	Resources Resources         `json:",omitempty"`
 	Engine    EngineDescription `json:",omitempty"`
 	Engine    EngineDescription `json:",omitempty"`
+	TLSInfo   TLSInfo           `json:",omitempty"`
 }
 }
 
 
 // Platform represents the platform (Arch/OS).
 // Platform represents the platform (Arch/OS).

+ 3 - 1
api/types/swarm/swarm.go

@@ -7,7 +7,9 @@ import "time"
 type ClusterInfo struct {
 type ClusterInfo struct {
 	ID string
 	ID string
 	Meta
 	Meta
-	Spec Spec
+	Spec                   Spec
+	TLSInfo                TLSInfo
+	RootRotationInProgress bool
 }
 }
 
 
 // Swarm represents a swarm.
 // Swarm represents a swarm.

+ 5 - 0
daemon/cluster/convert/node.go

@@ -50,6 +50,11 @@ func NodeFromGRPC(n swarmapi.Node) types.Node {
 				node.Description.Engine.Plugins = append(node.Description.Engine.Plugins, types.PluginDescription{Type: plugin.Type, Name: plugin.Name})
 				node.Description.Engine.Plugins = append(node.Description.Engine.Plugins, types.PluginDescription{Type: plugin.Type, Name: plugin.Name})
 			}
 			}
 		}
 		}
+		if n.Description.TLSInfo != nil {
+			node.Description.TLSInfo.TrustRoot = string(n.Description.TLSInfo.TrustRoot)
+			node.Description.TLSInfo.CertIssuerPublicKey = n.Description.TLSInfo.CertIssuerPublicKey
+			node.Description.TLSInfo.CertIssuerSubject = n.Description.TLSInfo.CertIssuerSubject
+		}
 	}
 	}
 
 
 	//Manager
 	//Manager

+ 11 - 0
daemon/cluster/convert/swarm.go

@@ -7,6 +7,7 @@ import (
 
 
 	types "github.com/docker/docker/api/types/swarm"
 	types "github.com/docker/docker/api/types/swarm"
 	swarmapi "github.com/docker/swarmkit/api"
 	swarmapi "github.com/docker/swarmkit/api"
+	"github.com/docker/swarmkit/ca"
 	gogotypes "github.com/gogo/protobuf/types"
 	gogotypes "github.com/gogo/protobuf/types"
 )
 )
 
 
@@ -30,6 +31,10 @@ func SwarmFromGRPC(c swarmapi.Cluster) types.Swarm {
 					AutoLockManagers: c.Spec.EncryptionConfig.AutoLockManagers,
 					AutoLockManagers: c.Spec.EncryptionConfig.AutoLockManagers,
 				},
 				},
 			},
 			},
+			TLSInfo: types.TLSInfo{
+				TrustRoot: string(c.RootCA.CACert),
+			},
+			RootRotationInProgress: c.RootCA.RootRotation != nil,
 		},
 		},
 		JoinTokens: types.JoinTokens{
 		JoinTokens: types.JoinTokens{
 			Worker:  c.RootCA.JoinTokens.Worker,
 			Worker:  c.RootCA.JoinTokens.Worker,
@@ -37,6 +42,12 @@ func SwarmFromGRPC(c swarmapi.Cluster) types.Swarm {
 		},
 		},
 	}
 	}
 
 
+	issuerInfo, err := ca.IssuerFromAPIRootCA(&c.RootCA)
+	if err == nil && issuerInfo != nil {
+		swarm.TLSInfo.CertIssuerSubject = issuerInfo.Subject
+		swarm.TLSInfo.CertIssuerPublicKey = issuerInfo.PublicKey
+	}
+
 	heartbeatPeriod, _ := gogotypes.DurationFromProto(c.Spec.Dispatcher.HeartbeatPeriod)
 	heartbeatPeriod, _ := gogotypes.DurationFromProto(c.Spec.Dispatcher.HeartbeatPeriod)
 	swarm.Spec.Dispatcher.HeartbeatPeriod = heartbeatPeriod
 	swarm.Spec.Dispatcher.HeartbeatPeriod = heartbeatPeriod
 
 

+ 4 - 0
docs/api/version-history.md

@@ -18,7 +18,11 @@ keywords: "API, Docker, rcli, REST, documentation"
 [Docker Engine API v1.30](https://docs.docker.com/engine/api/v1.30/) documentation
 [Docker Engine API v1.30](https://docs.docker.com/engine/api/v1.30/) documentation
 
 
 * `GET /info` now returns the list of supported logging drivers, including plugins.
 * `GET /info` now returns the list of supported logging drivers, including plugins.
+* `GET /info` and `GET /swarm` now returns the cluster-wide swarm CA info if the node is in a swarm: the cluster root CA certificate, and the cluster TLS
+ leaf certificate issuer's subject and public key.
 * `POST /build/` now (when not silent) produces an `Aux` message in the JSON output stream with payload `types.BuildResult` for each image produced. The final such message will reference the image resulting from the build.
 * `POST /build/` now (when not silent) produces an `Aux` message in the JSON output stream with payload `types.BuildResult` for each image produced. The final such message will reference the image resulting from the build.
+* `GET /nodes` and `GET /nodes/{id}` now returns additional information about swarm TLS info if the node is part of a swarm: the trusted root CA, and the
+ issuer's subject and public key.
 
 
 ## v1.29 API changes
 ## v1.29 API changes
 
 

+ 1 - 0
integration-cli/docker_api_swarm_test.go

@@ -32,6 +32,7 @@ func (s *DockerSwarmSuite) TestAPISwarmInit(c *check.C) {
 	c.Assert(err, checker.IsNil)
 	c.Assert(err, checker.IsNil)
 	c.Assert(info.ControlAvailable, checker.True)
 	c.Assert(info.ControlAvailable, checker.True)
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
+	c.Assert(info.Cluster.RootRotationInProgress, checker.False)
 
 
 	d2 := s.AddDaemon(c, true, false)
 	d2 := s.AddDaemon(c, true, false)
 	info, err = d2.SwarmInfo()
 	info, err = d2.SwarmInfo()