|
@@ -14,6 +14,7 @@ import (
|
|
"strings"
|
|
"strings"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
|
|
+ log "github.com/Sirupsen/logrus"
|
|
"github.com/docker/docker/utils"
|
|
"github.com/docker/docker/utils"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -35,7 +36,7 @@ const (
|
|
ConnectTimeout
|
|
ConnectTimeout
|
|
)
|
|
)
|
|
|
|
|
|
-func newClient(jar http.CookieJar, roots *x509.CertPool, cert *tls.Certificate, timeout TimeoutType) *http.Client {
|
|
|
|
|
|
+func newClient(jar http.CookieJar, roots *x509.CertPool, cert *tls.Certificate, timeout TimeoutType, secure bool) *http.Client {
|
|
tlsConfig := tls.Config{
|
|
tlsConfig := tls.Config{
|
|
RootCAs: roots,
|
|
RootCAs: roots,
|
|
// Avoid fallback to SSL protocols < TLS1.0
|
|
// Avoid fallback to SSL protocols < TLS1.0
|
|
@@ -46,6 +47,10 @@ func newClient(jar http.CookieJar, roots *x509.CertPool, cert *tls.Certificate,
|
|
tlsConfig.Certificates = append(tlsConfig.Certificates, *cert)
|
|
tlsConfig.Certificates = append(tlsConfig.Certificates, *cert)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if !secure {
|
|
|
|
+ tlsConfig.InsecureSkipVerify = true
|
|
|
|
+ }
|
|
|
|
+
|
|
httpTransport := &http.Transport{
|
|
httpTransport := &http.Transport{
|
|
DisableKeepAlives: true,
|
|
DisableKeepAlives: true,
|
|
Proxy: http.ProxyFromEnvironment,
|
|
Proxy: http.ProxyFromEnvironment,
|
|
@@ -86,69 +91,76 @@ func newClient(jar http.CookieJar, roots *x509.CertPool, cert *tls.Certificate,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func doRequest(req *http.Request, jar http.CookieJar, timeout TimeoutType) (*http.Response, *http.Client, error) {
|
|
|
|
- hasFile := func(files []os.FileInfo, name string) bool {
|
|
|
|
- for _, f := range files {
|
|
|
|
- if f.Name() == name {
|
|
|
|
- return true
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- hostDir := path.Join("/etc/docker/certs.d", req.URL.Host)
|
|
|
|
- fs, err := ioutil.ReadDir(hostDir)
|
|
|
|
- if err != nil && !os.IsNotExist(err) {
|
|
|
|
- return nil, nil, err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+func doRequest(req *http.Request, jar http.CookieJar, timeout TimeoutType, secure bool) (*http.Response, *http.Client, error) {
|
|
var (
|
|
var (
|
|
pool *x509.CertPool
|
|
pool *x509.CertPool
|
|
certs []*tls.Certificate
|
|
certs []*tls.Certificate
|
|
)
|
|
)
|
|
|
|
|
|
- for _, f := range fs {
|
|
|
|
- if strings.HasSuffix(f.Name(), ".crt") {
|
|
|
|
- if pool == nil {
|
|
|
|
- pool = x509.NewCertPool()
|
|
|
|
- }
|
|
|
|
- data, err := ioutil.ReadFile(path.Join(hostDir, f.Name()))
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, nil, err
|
|
|
|
|
|
+ if secure && req.URL.Scheme == "https" {
|
|
|
|
+ hasFile := func(files []os.FileInfo, name string) bool {
|
|
|
|
+ for _, f := range files {
|
|
|
|
+ if f.Name() == name {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- pool.AppendCertsFromPEM(data)
|
|
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ hostDir := path.Join("/etc/docker/certs.d", req.URL.Host)
|
|
|
|
+ log.Debugf("hostDir: %s", hostDir)
|
|
|
|
+ fs, err := ioutil.ReadDir(hostDir)
|
|
|
|
+ if err != nil && !os.IsNotExist(err) {
|
|
|
|
+ return nil, nil, err
|
|
}
|
|
}
|
|
- if strings.HasSuffix(f.Name(), ".cert") {
|
|
|
|
- certName := f.Name()
|
|
|
|
- keyName := certName[:len(certName)-5] + ".key"
|
|
|
|
- if !hasFile(fs, keyName) {
|
|
|
|
- return nil, nil, fmt.Errorf("Missing key %s for certificate %s", keyName, certName)
|
|
|
|
|
|
+
|
|
|
|
+ for _, f := range fs {
|
|
|
|
+ if strings.HasSuffix(f.Name(), ".crt") {
|
|
|
|
+ if pool == nil {
|
|
|
|
+ pool = x509.NewCertPool()
|
|
|
|
+ }
|
|
|
|
+ log.Debugf("crt: %s", hostDir+"/"+f.Name())
|
|
|
|
+ data, err := ioutil.ReadFile(path.Join(hostDir, f.Name()))
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, nil, err
|
|
|
|
+ }
|
|
|
|
+ pool.AppendCertsFromPEM(data)
|
|
}
|
|
}
|
|
- cert, err := tls.LoadX509KeyPair(path.Join(hostDir, certName), path.Join(hostDir, keyName))
|
|
|
|
- if err != nil {
|
|
|
|
- return nil, nil, err
|
|
|
|
|
|
+ if strings.HasSuffix(f.Name(), ".cert") {
|
|
|
|
+ certName := f.Name()
|
|
|
|
+ keyName := certName[:len(certName)-5] + ".key"
|
|
|
|
+ log.Debugf("cert: %s", hostDir+"/"+f.Name())
|
|
|
|
+ if !hasFile(fs, keyName) {
|
|
|
|
+ return nil, nil, fmt.Errorf("Missing key %s for certificate %s", keyName, certName)
|
|
|
|
+ }
|
|
|
|
+ cert, err := tls.LoadX509KeyPair(path.Join(hostDir, certName), path.Join(hostDir, keyName))
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, nil, err
|
|
|
|
+ }
|
|
|
|
+ certs = append(certs, &cert)
|
|
}
|
|
}
|
|
- certs = append(certs, &cert)
|
|
|
|
- }
|
|
|
|
- if strings.HasSuffix(f.Name(), ".key") {
|
|
|
|
- keyName := f.Name()
|
|
|
|
- certName := keyName[:len(keyName)-4] + ".cert"
|
|
|
|
- if !hasFile(fs, certName) {
|
|
|
|
- return nil, nil, fmt.Errorf("Missing certificate %s for key %s", certName, keyName)
|
|
|
|
|
|
+ if strings.HasSuffix(f.Name(), ".key") {
|
|
|
|
+ keyName := f.Name()
|
|
|
|
+ certName := keyName[:len(keyName)-4] + ".cert"
|
|
|
|
+ log.Debugf("key: %s", hostDir+"/"+f.Name())
|
|
|
|
+ if !hasFile(fs, certName) {
|
|
|
|
+ return nil, nil, fmt.Errorf("Missing certificate %s for key %s", certName, keyName)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if len(certs) == 0 {
|
|
if len(certs) == 0 {
|
|
- client := newClient(jar, pool, nil, timeout)
|
|
|
|
|
|
+ client := newClient(jar, pool, nil, timeout, secure)
|
|
res, err := client.Do(req)
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, nil, err
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
return res, client, nil
|
|
return res, client, nil
|
|
}
|
|
}
|
|
|
|
+
|
|
for i, cert := range certs {
|
|
for i, cert := range certs {
|
|
- client := newClient(jar, pool, cert, timeout)
|
|
|
|
|
|
+ client := newClient(jar, pool, cert, timeout, secure)
|
|
res, err := client.Do(req)
|
|
res, err := client.Do(req)
|
|
// If this is the last cert, otherwise, continue to next cert if 403 or 5xx
|
|
// If this is the last cert, otherwise, continue to next cert if 403 or 5xx
|
|
if i == len(certs)-1 || err == nil &&
|
|
if i == len(certs)-1 || err == nil &&
|
|
@@ -213,49 +225,6 @@ func ResolveRepositoryName(reposName string) (string, string, error) {
|
|
return hostname, reposName, nil
|
|
return hostname, reposName, nil
|
|
}
|
|
}
|
|
|
|
|
|
-// this method expands the registry name as used in the prefix of a repo
|
|
|
|
-// to a full url. if it already is a url, there will be no change.
|
|
|
|
-func ExpandAndVerifyRegistryUrl(hostname string, secure bool) (string, error) {
|
|
|
|
- if hostname == IndexServerAddress() {
|
|
|
|
- return hostname, nil
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- endpoint := fmt.Sprintf("http://%s/v1/", hostname)
|
|
|
|
-
|
|
|
|
- if secure {
|
|
|
|
- endpoint = fmt.Sprintf("https://%s/v1/", hostname)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if _, oerr := pingRegistryEndpoint(endpoint); oerr != nil {
|
|
|
|
- //TODO: triggering highland build can be done there without "failing"
|
|
|
|
- err := fmt.Errorf("Invalid registry endpoint '%s': %s ", endpoint, oerr)
|
|
|
|
-
|
|
|
|
- if secure {
|
|
|
|
- err = fmt.Errorf("%s. If this private registry supports only HTTP, please add `--insecure-registry %s` to the daemon's arguments.", oerr, hostname)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return "", err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return endpoint, nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// this method verifies if the provided hostname is part of the list of
|
|
|
|
-// insecure registries and returns false if HTTP should be used
|
|
|
|
-func IsSecure(hostname string, insecureRegistries []string) bool {
|
|
|
|
- if hostname == IndexServerAddress() {
|
|
|
|
- return true
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for _, h := range insecureRegistries {
|
|
|
|
- if hostname == h {
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return true
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
func trustedLocation(req *http.Request) bool {
|
|
func trustedLocation(req *http.Request) bool {
|
|
var (
|
|
var (
|
|
trusteds = []string{"docker.com", "docker.io"}
|
|
trusteds = []string{"docker.com", "docker.io"}
|