mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-20 22:59:42 -05:00
Fix/cert material (#91)
* Fixes connection via TLS to docker host with file contents. Closes #86 * Fixes skip of TLS verification if ca_material is not present. Closes #14
This commit is contained in:
parent
79c198a3b4
commit
f8a9755fcd
3 changed files with 99 additions and 7 deletions
|
|
@ -1,4 +1,9 @@
|
|||
## 1.0.2 (Unreleased)
|
||||
|
||||
BUG FIXES
|
||||
* Fixes connection via TLS to docker host with file contents [GH-86]
|
||||
* Skips TLS verification if `ca_material` is not set [GH-14]
|
||||
|
||||
## 1.0.1 (August 06, 2018)
|
||||
|
||||
BUG FIXES
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
|
|
@ -21,20 +28,80 @@ type Config struct {
|
|||
CertPath string
|
||||
}
|
||||
|
||||
// buildHTTPClientFromBytes builds the http client from bytes (content of the files)
|
||||
func buildHTTPClientFromBytes(caPEMCert, certPEMBlock, keyPEMBlock []byte) (*http.Client, error) {
|
||||
tlsConfig := &tls.Config{}
|
||||
if certPEMBlock != nil && keyPEMBlock != nil {
|
||||
tlsCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{tlsCert}
|
||||
}
|
||||
|
||||
if caPEMCert == nil || len(caPEMCert) == 0 {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
} else {
|
||||
caPool := x509.NewCertPool()
|
||||
if !caPool.AppendCertsFromPEM(caPEMCert) {
|
||||
return nil, errors.New("Could not add RootCA pem")
|
||||
}
|
||||
tlsConfig.RootCAs = caPool
|
||||
}
|
||||
|
||||
tr := defaultTransport()
|
||||
tr.TLSClientConfig = tlsConfig
|
||||
return &http.Client{Transport: tr}, nil
|
||||
}
|
||||
|
||||
// defaultTransport returns a new http.Transport with similar default values to
|
||||
// http.DefaultTransport, but with idle connections and keepalives disabled.
|
||||
func defaultTransport() *http.Transport {
|
||||
transport := defaultPooledTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport.MaxIdleConnsPerHost = -1
|
||||
return transport
|
||||
}
|
||||
|
||||
// defaultPooledTransport returns a new http.Transport with similar default
|
||||
// values to http.DefaultTransport.
|
||||
func defaultPooledTransport() *http.Transport {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
return transport
|
||||
}
|
||||
|
||||
// NewClient returns a new Docker client.
|
||||
func (c *Config) NewClient() (*client.Client, error) {
|
||||
if c.Ca != "" || c.Cert != "" || c.Key != "" {
|
||||
if c.Ca == "" || c.Cert == "" || c.Key == "" {
|
||||
return nil, fmt.Errorf("ca_material, cert_material, and key_material must be specified")
|
||||
if c.Cert != "" || c.Key != "" {
|
||||
if c.Cert == "" || c.Key == "" {
|
||||
return nil, fmt.Errorf("cert_material, and key_material must be specified")
|
||||
}
|
||||
|
||||
if c.CertPath != "" {
|
||||
return nil, fmt.Errorf("cert_path must not be specified")
|
||||
}
|
||||
|
||||
httpClient, err := buildHTTPClientFromBytes([]byte(c.Ca), []byte(c.Cert), []byte(c.Key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Note: don't change the order here, because the custom client
|
||||
// needs to be set first them we overwrite the other options: host, version
|
||||
return client.NewClientWithOpts(
|
||||
client.WithHTTPClient(httpClient),
|
||||
client.WithHost(c.Host),
|
||||
client.WithTLSClientConfig(c.Ca, c.Cert, c.Key),
|
||||
client.WithVersion(apiVersion),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,25 @@ and paste it into `~/.docker/config.json`:
|
|||
}
|
||||
```
|
||||
|
||||
## Certificate information
|
||||
|
||||
Specify certificate information either with a directory or
|
||||
directly with the content of the files for connecting to the Docker host via TLS.
|
||||
|
||||
```hcl
|
||||
provider "docker" {
|
||||
host = "tcp://your-host-ip:2376/"
|
||||
|
||||
# -> specify either
|
||||
cert_path = "${pathexpand("~/.docker")}"
|
||||
|
||||
# -> or the following
|
||||
ca_material = "${file(pathexpand("~/.docker/ca.pem"))}" # this can be omitted
|
||||
cert_material = "${file(pathexpand("~/.docker/cert.pem"))}"
|
||||
key_material = "${file(pathexpand("~/.docker/key.pem"))}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
|
@ -99,11 +118,12 @@ The following arguments are supported:
|
|||
blank, the `DOCKER_HOST` environment variable will also be read.
|
||||
|
||||
* `cert_path` - (Optional) Path to a directory with certificate information
|
||||
for connecting to the Docker host via TLS. If this is blank, the
|
||||
`DOCKER_CERT_PATH` will also be checked.
|
||||
for connecting to the Docker host via TLS. It is expected that the 3 files `{ca, cert, key}.pem`
|
||||
are present in the path. If the path is blank, the `DOCKER_CERT_PATH` will also be checked.
|
||||
|
||||
* `ca_material`, `cert_material`, `key_material`, - (Optional) Content of `ca.pem`, `cert.pem`, and `key.pem` files
|
||||
for TLS authentication. Cannot be used together with `cert_path`.
|
||||
for TLS authentication. Cannot be used together with `cert_path`. If `ca_material` is omitted
|
||||
the client does not check the servers certificate chain and host name.
|
||||
|
||||
* `registry_auth` - (Optional) A block specifying the credentials for a target
|
||||
v2 Docker registry.
|
||||
|
|
|
|||
Loading…
Reference in a new issue