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)
|
## 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)
|
## 1.0.1 (August 06, 2018)
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
|
@ -21,20 +28,80 @@ type Config struct {
|
||||||
CertPath string
|
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.
|
// NewClient returns a new Docker client.
|
||||||
func (c *Config) NewClient() (*client.Client, error) {
|
func (c *Config) NewClient() (*client.Client, error) {
|
||||||
if c.Ca != "" || c.Cert != "" || c.Key != "" {
|
if c.Cert != "" || c.Key != "" {
|
||||||
if c.Ca == "" || c.Cert == "" || c.Key == "" {
|
if c.Cert == "" || c.Key == "" {
|
||||||
return nil, fmt.Errorf("ca_material, cert_material, and key_material must be specified")
|
return nil, fmt.Errorf("cert_material, and key_material must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.CertPath != "" {
|
if c.CertPath != "" {
|
||||||
return nil, fmt.Errorf("cert_path must not be specified")
|
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(
|
return client.NewClientWithOpts(
|
||||||
|
client.WithHTTPClient(httpClient),
|
||||||
client.WithHost(c.Host),
|
client.WithHost(c.Host),
|
||||||
client.WithTLSClientConfig(c.Ca, c.Cert, c.Key),
|
|
||||||
client.WithVersion(apiVersion),
|
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
|
## Argument Reference
|
||||||
|
|
||||||
The following arguments are supported:
|
The following arguments are supported:
|
||||||
|
|
@ -99,11 +118,12 @@ The following arguments are supported:
|
||||||
blank, the `DOCKER_HOST` environment variable will also be read.
|
blank, the `DOCKER_HOST` environment variable will also be read.
|
||||||
|
|
||||||
* `cert_path` - (Optional) Path to a directory with certificate information
|
* `cert_path` - (Optional) Path to a directory with certificate information
|
||||||
for connecting to the Docker host via TLS. If this is blank, the
|
for connecting to the Docker host via TLS. It is expected that the 3 files `{ca, cert, key}.pem`
|
||||||
`DOCKER_CERT_PATH` will also be checked.
|
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
|
* `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
|
* `registry_auth` - (Optional) A block specifying the credentials for a target
|
||||||
v2 Docker registry.
|
v2 Docker registry.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue