diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index 18971c4b07..9e33a6c6fd 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -1886,6 +1886,14 @@ definitions: CACert: description: "The root CA certificate (in PEM format) this external CA uses to issue TLS certificates (assumed to be to the current swarm root CA certificate if not provided)." type: "string" + SigningCACert: + description: "The desired signing CA certificate for all swarm node TLS leaf certificates, in PEM format." + type: "string" + SigningCAKey: + description: "The desired signing CA key for all swarm node TLS leaf certificates, in PEM format." + type: "string" + ForceRotate: + description: "An integer whose purpose is to force swarm to generate a new signing CA certificate and key, if none have been specified in `SigningCACert` and `SigningCAKey`" EncryptionConfig: description: "Parameters related to encryption-at-rest." type: "object" diff --git a/components/engine/api/types/swarm/swarm.go b/components/engine/api/types/swarm/swarm.go index bdb3042337..5b74f14b11 100644 --- a/components/engine/api/types/swarm/swarm.go +++ b/components/engine/api/types/swarm/swarm.go @@ -109,6 +109,16 @@ type CAConfig struct { // ExternalCAs is a list of CAs to which a manager node will make // certificate signing requests for node certificates. ExternalCAs []*ExternalCA `json:",omitempty"` + + // SigningCACert and SigningCAKey specify the desired signing root CA and + // root CA key for the swarm. When inspecting the cluster, the key will + // be redacted. + SigningCACert string `json:",omitempty"` + SigningCAKey string `json:",omitempty"` + + // If this value changes, and there is no specified signing cert and key, + // then the swarm is forced to generate a new root certificate ane key. + ForceRotate uint64 `json:",omitempty"` } // ExternalCAProtocol represents type of external CA. diff --git a/components/engine/daemon/cluster/convert/swarm.go b/components/engine/daemon/cluster/convert/swarm.go index 64fc7f72d9..c6e1f3652b 100644 --- a/components/engine/daemon/cluster/convert/swarm.go +++ b/components/engine/daemon/cluster/convert/swarm.go @@ -30,6 +30,11 @@ func SwarmFromGRPC(c swarmapi.Cluster) types.Swarm { EncryptionConfig: types.EncryptionConfig{ AutoLockManagers: c.Spec.EncryptionConfig.AutoLockManagers, }, + CAConfig: types.CAConfig{ + // do not include the signing CA key (it should already be redacted via the swarm APIs) + SigningCACert: string(c.Spec.CAConfig.SigningCACert), + ForceRotate: c.Spec.CAConfig.ForceRotate, + }, }, TLSInfo: types.TLSInfo{ TrustRoot: string(c.RootCA.CACert), @@ -114,6 +119,14 @@ func MergeSwarmSpecToGRPC(s types.Spec, spec swarmapi.ClusterSpec) (swarmapi.Clu if s.CAConfig.NodeCertExpiry != 0 { spec.CAConfig.NodeCertExpiry = gogotypes.DurationProto(s.CAConfig.NodeCertExpiry) } + if s.CAConfig.SigningCACert != "" { + spec.CAConfig.SigningCACert = []byte(s.CAConfig.SigningCACert) + } + if s.CAConfig.SigningCAKey != "" { + // do prpagate the signing CA key here because we want to provide it TO the swarm APIs + spec.CAConfig.SigningCAKey = []byte(s.CAConfig.SigningCAKey) + } + spec.CAConfig.ForceRotate = s.CAConfig.ForceRotate for _, ca := range s.CAConfig.ExternalCAs { protocol, ok := swarmapi.ExternalCA_CAProtocol_value[strings.ToUpper(string(ca.Protocol))] diff --git a/components/engine/docs/api/version-history.md b/components/engine/docs/api/version-history.md index 359813d87e..4e02e7193a 100644 --- a/components/engine/docs/api/version-history.md +++ b/components/engine/docs/api/version-history.md @@ -19,11 +19,14 @@ keywords: "API, Docker, rcli, REST, documentation" * `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. + leaf certificate issuer's subject and public key. It also displays the desired CA signing certificate, if any was provided as part of the spec. * `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. * `GET /distribution/(name)/json` is a new endpoint that returns a JSON output stream with payload `types.DistributionInspect` for an image name. It includes a descriptor with the digest, and supported platforms retrieved from directly contacting the registry. +* `POST /swarm/update` now accepts 3 additional parameters as part of the swarm spec's CA configuration; the desired CA certificate for + the swarm, the desired CA key for the swarm (if not using an external certificate), and an optional parameter to force swarm to + generate and rotate to a new CA certificate/key pair. ## v1.29 API changes