Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1526 from Timer/insecure-host-behavior
Browse files Browse the repository at this point in the history
Skip TLS check when using insecure host
  • Loading branch information
squaremo authored Feb 4, 2019
2 parents 8bcf060 + fe5963d commit 737815d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 32 deletions.
10 changes: 6 additions & 4 deletions cmd/fluxd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,17 @@ func main() {
gitTimeout = fs.Duration("git-timeout", 20*time.Second, "duration after which git operations time out")
// syncing
syncInterval = fs.Duration("sync-interval", 5*time.Minute, "apply config in git to cluster at least this often, even if there are no new commits")

// registry
memcachedHostname = fs.String("memcached-hostname", "memcached", "hostname for memcached service.")
memcachedTimeout = fs.Duration("memcached-timeout", time.Second, "maximum time to wait before giving up on memcached requests.")
memcachedService = fs.String("memcached-service", "memcached", "SRV service used to discover memcache servers.")
memcachedHostname = fs.String("memcached-hostname", "memcached", "hostname for memcached service.")
memcachedTimeout = fs.Duration("memcached-timeout", time.Second, "maximum time to wait before giving up on memcached requests.")
memcachedService = fs.String("memcached-service", "memcached", "SRV service used to discover memcache servers.")

registryPollInterval = fs.Duration("registry-poll-interval", 5*time.Minute, "period at which to check for updated images")
registryRPS = fs.Float64("registry-rps", 50, "maximum registry requests per second per host")
registryBurst = fs.Int("registry-burst", defaultRemoteConnections, "maximum number of warmer connections to remote and memcache")
registryTrace = fs.Bool("registry-trace", false, "output trace of image registry requests to log")
registryInsecure = fs.StringSlice("registry-insecure-host", []string{}, "use HTTP for this image registry domain (e.g., registry.cluster.local), instead of HTTPS")
registryInsecure = fs.StringSlice("registry-insecure-host", []string{}, "let these registry hosts skip TLS host verification and fall back to using HTTP instead of HTTPS; this allows man-in-the-middle attacks, so use with extreme caution")
registryExcludeImage = fs.StringSlice("registry-exclude-image", []string{"k8s.gcr.io/*"}, "do not scan images that match these glob expressions; the default is to exclude the 'k8s.gcr.io/*' images")

// AWS authentication
Expand Down
88 changes: 60 additions & 28 deletions registry/client_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package registry

import (
"context"
"crypto/tls"
"net/http"
"net/url"
"sync"
Expand All @@ -17,9 +18,12 @@ import (
)

type RemoteClientFactory struct {
Logger log.Logger
Limiters *middleware.RateLimiters
Trace bool
Logger log.Logger
Limiters *middleware.RateLimiters
Trace bool

// hosts with which to tolerate insecure connections (e.g., with
// TLS_INSECURE_SKIP_VERIFY, or as a fallback, using HTTP).
InsecureHosts []string

mu sync.Mutex
Expand All @@ -41,35 +45,17 @@ func (t *logging) RoundTrip(req *http.Request) (*http.Response, error) {
return res, err
}

func (f *RemoteClientFactory) ClientFor(repo image.CanonicalName, creds Credentials) (Client, error) {
tx := f.Limiters.RoundTripper(http.DefaultTransport, repo.Domain)
if f.Trace {
tx = &logging{f.Logger, tx}
}

f.mu.Lock()
if f.challengeManager == nil {
f.challengeManager = challenge.NewSimpleManager()
}
manager := f.challengeManager
f.mu.Unlock()

scheme := "https"
for _, h := range f.InsecureHosts {
if repo.Domain == h {
scheme = "http"
}
}

func (f *RemoteClientFactory) doChallenge(manager challenge.Manager, tx http.RoundTripper, domain string, insecureOK bool) (*url.URL, error) {
registryURL := url.URL{
Scheme: scheme,
Host: repo.Domain,
Scheme: "https",
Host: domain,
Path: "/v2/",
}

// Before we know how to authorise, need to establish which
// authorisation challenges the host will send. See if we've been
// here before.
attemptChallenge:
cs, err := manager.GetChallenges(registryURL)
if err != nil {
return nil, err
Expand All @@ -89,6 +75,11 @@ func (f *RemoteClientFactory) ClientFor(repo image.CanonicalName, creds Credenti
Transport: tx,
}).Do(req.WithContext(ctx))
if err != nil {
if insecureOK {
registryURL.Scheme = "http"
insecureOK = false
goto attemptChallenge
}
return nil, err
}
defer res.Body.Close()
Expand All @@ -97,15 +88,56 @@ func (f *RemoteClientFactory) ClientFor(repo image.CanonicalName, creds Credenti
}
registryURL = *res.Request.URL // <- the URL after any redirection
}
return &registryURL, nil
}

func (f *RemoteClientFactory) ClientFor(repo image.CanonicalName, creds Credentials) (Client, error) {
insecure := false
for _, h := range f.InsecureHosts {
if repo.Domain == h {
insecure = true
break
}
}

tlsConfig := &tls.Config{
InsecureSkipVerify: insecure,
}
// Since we construct one of these per scan, be fairly ruthless
// about throttling the number, and closing of, idle connections.
baseTx := &http.Transport{
TLSClientConfig: tlsConfig,
MaxIdleConns: 10,
IdleConnTimeout: 10 * time.Second,
Proxy: http.ProxyFromEnvironment,
}
tx := f.Limiters.RoundTripper(baseTx, repo.Domain)
if f.Trace {
tx = &logging{f.Logger, tx}
}

f.mu.Lock()
if f.challengeManager == nil {
f.challengeManager = challenge.NewSimpleManager()
}
manager := f.challengeManager
f.mu.Unlock()

registryURL, err := f.doChallenge(manager, tx, repo.Domain, insecure)
if err != nil {
return nil, err
}

cred := creds.credsFor(repo.Domain)
if f.Trace {
f.Logger.Log("repo", repo.String(), "auth", cred.String(), "api", registryURL.String())
}

tokenHandler := auth.NewTokenHandler(tx, &store{cred}, repo.Image, "pull")
basicauthHandler := auth.NewBasicHandler(&store{cred})
tx = transport.NewTransport(tx, auth.NewAuthorizer(manager, tokenHandler, basicauthHandler))
authHandlers := []auth.AuthenticationHandler{
auth.NewTokenHandler(tx, &store{cred}, repo.Image, "pull"),
auth.NewBasicHandler(&store{cred}),
}
tx = transport.NewTransport(tx, auth.NewAuthorizer(manager, authHandlers...))

// For the API base we want only the scheme and host.
registryURL.Path = ""
Expand Down

0 comments on commit 737815d

Please sign in to comment.