diff --git a/vendor/github.com/google/go-containerregistry/pkg/authn/k8schain/k8schain.go b/vendor/github.com/google/go-containerregistry/pkg/authn/k8schain/k8schain.go
index d90ac4d1..36fb28a9 100644
--- a/vendor/github.com/google/go-containerregistry/pkg/authn/k8schain/k8schain.go
+++ b/vendor/github.com/google/go-containerregistry/pkg/authn/k8schain/k8schain.go
@@ -130,11 +130,14 @@ func NewNoClient() (authn.Keychain, error) {
 	return New(nil, Options{})
 }
 
-type lazyProvider credentialprovider.LazyAuthConfiguration
+type lazyProvider struct {
+	provider credentialprovider.LazyAuthConfiguration
+	repo     string
+}
 
 // Authorization implements Authenticator.
 func (lp lazyProvider) Authorization() (string, error) {
-	authConfig := credentialprovider.LazyProvide(credentialprovider.LazyAuthConfiguration(lp))
+	authConfig := credentialprovider.LazyProvide(credentialprovider.LazyAuthConfiguration(lp.provider), lp.repo)
 	if authConfig.Auth != "" {
 		return "Basic " + authConfig.Auth, nil
 	}
@@ -161,5 +164,8 @@ func (kc *keychain) Resolve(reg name.Registry) (authn.Authenticator, error) {
 		return authn.Anonymous, nil
 	}
 	// TODO(mattmoor): How to support multiple credentials?
-	return lazyProvider(creds[0]), nil
+	return lazyProvider{
+		provider: creds[0],
+		repo:     reg.String(),
+	}, nil
 }
diff --git a/vendor/k8s.io/client-go/tools/cache/expiration_cache.go b/vendor/k8s.io/client-go/tools/cache/expiration_cache.go
index fa88fc40..823a15a8 100644
--- a/vendor/k8s.io/client-go/tools/cache/expiration_cache.go
+++ b/vendor/k8s.io/client-go/tools/cache/expiration_cache.go
@@ -48,7 +48,7 @@ type ExpirationCache struct {
 // ExpirationPolicy dictates when an object expires. Currently only abstracted out
 // so unittests don't rely on the system clock.
 type ExpirationPolicy interface {
-	IsExpired(obj *timestampedEntry) bool
+	IsExpired(obj *TimestampedEntry) bool
 }
 
 // TTLPolicy implements a ttl based ExpirationPolicy.
@@ -63,20 +63,23 @@ type TTLPolicy struct {
 
 // IsExpired returns true if the given object is older than the ttl, or it can't
 // determine its age.
-func (p *TTLPolicy) IsExpired(obj *timestampedEntry) bool {
-	return p.Ttl > 0 && p.Clock.Since(obj.timestamp) > p.Ttl
+func (p *TTLPolicy) IsExpired(obj *TimestampedEntry) bool {
+	return p.Ttl > 0 && p.Clock.Since(obj.Timestamp) > p.Ttl
 }
 
-// timestampedEntry is the only type allowed in a ExpirationCache.
-type timestampedEntry struct {
-	obj       interface{}
-	timestamp time.Time
+// TimestampedEntry is the only type allowed in a ExpirationCache.
+// // Keep in mind that it is not safe to share timestamps between computers.
+// // Behavior may be inconsistent if you get a timestamp from the API Server and
+// // use it on the client machine as part of your ExpirationCache.
+type TimestampedEntry struct {
+	Obj       interface{}
+	Timestamp time.Time
 }
 
 // getTimestampedEntry returns the timestampedEntry stored under the given key.
-func (c *ExpirationCache) getTimestampedEntry(key string) (*timestampedEntry, bool) {
+func (c *ExpirationCache) getTimestampedEntry(key string) (*TimestampedEntry, bool) {
 	item, _ := c.cacheStorage.Get(key)
-	if tsEntry, ok := item.(*timestampedEntry); ok {
+	if tsEntry, ok := item.(*TimestampedEntry); ok {
 		return tsEntry, true
 	}
 	return nil, false
@@ -95,11 +98,11 @@ func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
 		return nil, false
 	}
 	if c.expirationPolicy.IsExpired(timestampedItem) {
-		glog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
+		glog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.Obj)
 		c.cacheStorage.Delete(key)
 		return nil, false
 	}
-	return timestampedItem.obj, true
+	return timestampedItem.Obj, true
 }
 
 // GetByKey returns the item stored under the key, or sets exists=false.
@@ -126,7 +129,7 @@ func (c *ExpirationCache) List() []interface{} {
 
 	list := make([]interface{}, 0, len(items))
 	for _, item := range items {
-		obj := item.(*timestampedEntry).obj
+		obj := item.(*TimestampedEntry).Obj
 		if key, err := c.keyFunc(obj); err != nil {
 			list = append(list, obj)
 		} else if obj, exists := c.getOrExpire(key); exists {
@@ -151,7 +154,7 @@ func (c *ExpirationCache) Add(obj interface{}) error {
 	if err != nil {
 		return KeyError{obj, err}
 	}
-	c.cacheStorage.Add(key, &timestampedEntry{obj, c.clock.Now()})
+	c.cacheStorage.Add(key, &TimestampedEntry{obj, c.clock.Now()})
 	return nil
 }
 
@@ -186,7 +189,7 @@ func (c *ExpirationCache) Replace(list []interface{}, resourceVersion string) er
 		if err != nil {
 			return KeyError{item, err}
 		}
-		items[key] = &timestampedEntry{item, ts}
+		items[key] = &TimestampedEntry{item, ts}
 	}
 	c.cacheStorage.Replace(items, resourceVersion)
 	return nil
@@ -199,10 +202,15 @@ func (c *ExpirationCache) Resync() error {
 
 // NewTTLStore creates and returns a ExpirationCache with a TTLPolicy
 func NewTTLStore(keyFunc KeyFunc, ttl time.Duration) Store {
+	return NewExpirationStore(keyFunc, &TTLPolicy{ttl, clock.RealClock{}})
+}
+
+// NewExpirationStore creates and returns a ExpirationCache for a given policy
+func NewExpirationStore(keyFunc KeyFunc, expirationPolicy ExpirationPolicy) Store {
 	return &ExpirationCache{
 		cacheStorage:     NewThreadSafeStore(Indexers{}, Indices{}),
 		keyFunc:          keyFunc,
 		clock:            clock.RealClock{},
-		expirationPolicy: &TTLPolicy{ttl, clock.RealClock{}},
+		expirationPolicy: expirationPolicy,
 	}
 }
diff --git a/vendor/k8s.io/client-go/tools/cache/expiration_cache_fakes.go b/vendor/k8s.io/client-go/tools/cache/expiration_cache_fakes.go
index a096765f..d61db3d5 100644
--- a/vendor/k8s.io/client-go/tools/cache/expiration_cache_fakes.go
+++ b/vendor/k8s.io/client-go/tools/cache/expiration_cache_fakes.go
@@ -38,7 +38,7 @@ type FakeExpirationPolicy struct {
 	RetrieveKeyFunc KeyFunc
 }
 
-func (p *FakeExpirationPolicy) IsExpired(obj *timestampedEntry) bool {
+func (p *FakeExpirationPolicy) IsExpired(obj *TimestampedEntry) bool {
 	key, _ := p.RetrieveKeyFunc(obj)
 	return !p.NeverExpire.Has(key)
 }
diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/aws/aws_credentials.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/aws/aws_credentials.go
index d889cbf1..dead2ed0 100644
--- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/aws/aws_credentials.go
+++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/aws/aws_credentials.go
@@ -18,8 +18,12 @@ package credentials
 
 import (
 	"encoding/base64"
+	"errors"
 	"fmt"
+	"net/url"
+	"regexp"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/aws/aws-sdk-go/aws"
@@ -27,200 +31,280 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/ecr"
 	"github.com/golang/glog"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/client-go/tools/cache"
 	"k8s.io/kubernetes/pkg/credentialprovider"
+	"k8s.io/kubernetes/pkg/version"
 )
 
-const awsChinaRegionPrefix = "cn-"
-const awsStandardDNSSuffix = "amazonaws.com"
-const awsChinaDNSSuffix = "amazonaws.com.cn"
-const registryURLTemplate = "*.dkr.ecr.%s.%s"
+var ecrPattern = regexp.MustCompile(`^(\d{12})\.dkr\.ecr(\-fips)?\.([a-zA-Z0-9][a-zA-Z0-9-_]*)\.amazonaws\.com(\.cn)?$`)
 
-// awsHandlerLogger is a handler that logs all AWS SDK requests
-// Copied from pkg/cloudprovider/providers/aws/log_handler.go
-func awsHandlerLogger(req *request.Request) {
-	service := req.ClientInfo.ServiceName
-	region := req.Config.Region
-
-	name := "?"
-	if req.Operation != nil {
-		name = req.Operation.Name
-	}
-
-	glog.V(3).Infof("AWS request: %s:%s in %s", service, name, *region)
+// init registers a credential provider for each registryURLTemplate and creates
+// an ECR token getter factory with a new cache to store token getters
+func init() {
+	credentialprovider.RegisterCredentialProvider("amazon-ecr",
+		newECRProvider(&ecrTokenGetterFactory{cache: make(map[string]tokenGetter)}))
 }
 
-// An interface for testing purposes.
-type tokenGetter interface {
-	GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error)
+// ecrProvider is a DockerConfigProvider that gets and refreshes tokens
+// from AWS to access ECR.
+type ecrProvider struct {
+	cache         cache.Store
+	getterFactory tokenGetterFactory
 }
 
-// The canonical implementation
-type ecrTokenGetter struct {
-	svc *ecr.ECR
+var _ credentialprovider.DockerConfigProvider = &ecrProvider{}
+
+func newECRProvider(getterFactory tokenGetterFactory) *ecrProvider {
+	return &ecrProvider{
+		cache:         cache.NewExpirationStore(stringKeyFunc, &ecrExpirationPolicy{}),
+		getterFactory: getterFactory,
+	}
 }
 
-func (p *ecrTokenGetter) GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) {
-	return p.svc.GetAuthorizationToken(input)
+// Enabled implements DockerConfigProvider.Enabled. Enabled is true if AWS
+// credentials are found.
+func (p *ecrProvider) Enabled() bool {
+	sess, err := session.NewSessionWithOptions(session.Options{
+		SharedConfigState: session.SharedConfigEnable,
+	})
+	if err != nil {
+		glog.Errorf("while validating AWS credentials %v", err)
+		return false
+	}
+	if _, err := sess.Config.Credentials.Get(); err != nil {
+		glog.Errorf("while getting AWS credentials %v", err)
+		return false
+	}
+	return true
 }
 
-// lazyEcrProvider is a DockerConfigProvider that creates on demand an
-// ecrProvider for a given region and then proxies requests to it.
-type lazyEcrProvider struct {
-	region         string
-	regionURL      string
-	actualProvider *credentialprovider.CachingDockerConfigProvider
+// LazyProvide is lazy
+// TODO: the LazyProvide methods will be removed in a future PR
+func (p *ecrProvider) LazyProvide(image string) *credentialprovider.DockerConfigEntry {
+	return nil
 }
 
-var _ credentialprovider.DockerConfigProvider = &lazyEcrProvider{}
+// Provide returns a DockerConfig with credentials from the cache if they are
+// found, or from ECR
+func (p *ecrProvider) Provide(image string) credentialprovider.DockerConfig {
+	parsed, err := parseRepoURL(image)
+	if err != nil {
+		glog.V(3).Info(err)
+		return credentialprovider.DockerConfig{}
+	}
 
-// ecrProvider is a DockerConfigProvider that gets and refreshes 12-hour tokens
-// from AWS to access ECR.
-type ecrProvider struct {
-	region    string
-	regionURL string
-	getter    tokenGetter
+	if cfg, exists := p.getFromCache(parsed); exists {
+		glog.V(6).Infof("Got ECR credentials from cache for %s", parsed.registry)
+		return cfg
+	}
+	glog.V(3).Info("unable to get ECR credentials from cache, checking ECR API")
+
+	cfg, err := p.getFromECR(parsed)
+	if err != nil {
+		glog.Errorf("error getting credentials from ECR for %s %v", parsed.registry, err)
+		return credentialprovider.DockerConfig{}
+	}
+	glog.V(3).Infof("Got ECR credentials from ECR API for %s", parsed.registry)
+	return cfg
 }
 
-var _ credentialprovider.DockerConfigProvider = &ecrProvider{}
+// getFromCache attempts to get credentials from the cache
+func (p *ecrProvider) getFromCache(parsed *parsedURL) (credentialprovider.DockerConfig, bool) {
+	cfg := credentialprovider.DockerConfig{}
 
-// registryURL has different suffix in AWS China region
-func registryURL(region string) string {
-	dnsSuffix := awsStandardDNSSuffix
-	// deal with aws none standard regions
-	if strings.HasPrefix(region, awsChinaRegionPrefix) {
-		dnsSuffix = awsChinaDNSSuffix
+	obj, exists, err := p.cache.GetByKey(parsed.registry)
+	if err != nil {
+		glog.Errorf("error getting ECR credentials from cache: %v", err)
+		return cfg, false
 	}
-	return fmt.Sprintf(registryURLTemplate, region, dnsSuffix)
-}
 
-// RegisterCredentialsProvider registers a credential provider for the specified region.
-// It creates a lazy provider for each AWS region, in order to support
-// cross-region ECR access. They have to be lazy because it's unlikely, but not
-// impossible, that we'll use more than one.
-// This should be called only if using the AWS cloud provider.
-// This way, we avoid timeouts waiting for a non-existent provider.
-func RegisterCredentialsProvider(region string) {
-	glog.V(4).Infof("registering credentials provider for AWS region %q", region)
+	if !exists {
+		return cfg, false
+	}
 
-	credentialprovider.RegisterCredentialProvider("aws-ecr-"+region,
-		&lazyEcrProvider{
-			region:    region,
-			regionURL: registryURL(region),
-		})
+	entry := obj.(*cacheEntry)
+	cfg[entry.registry] = entry.credentials
+	return cfg, true
 }
 
-// Enabled implements DockerConfigProvider.Enabled for the lazy provider.
-// Since we perform no checks/work of our own and actualProvider is only created
-// later at image pulling time (if ever), always return true.
-func (p *lazyEcrProvider) Enabled() bool {
-	return true
+// getFromECR gets credentials from ECR since they are not in the cache
+func (p *ecrProvider) getFromECR(parsed *parsedURL) (credentialprovider.DockerConfig, error) {
+	cfg := credentialprovider.DockerConfig{}
+	getter, err := p.getterFactory.GetTokenGetterForRegion(parsed.region)
+	if err != nil {
+		return cfg, err
+	}
+	params := &ecr.GetAuthorizationTokenInput{RegistryIds: []*string{aws.String(parsed.registryID)}}
+	output, err := getter.GetAuthorizationToken(params)
+	if err != nil {
+		return cfg, err
+	}
+	if output == nil {
+		return cfg, errors.New("authorization token is nil")
+	}
+	if len(output.AuthorizationData) == 0 {
+		return cfg, errors.New("authorization data from response is empty")
+	}
+	data := output.AuthorizationData[0]
+	if data.AuthorizationToken == nil {
+		return cfg, errors.New("authorization token in response is nil")
+	}
+	entry, err := makeCacheEntry(data, parsed.registry)
+	if err != nil {
+		return cfg, err
+	}
+	if err := p.cache.Add(entry); err != nil {
+		return cfg, err
+	}
+	cfg[entry.registry] = entry.credentials
+	return cfg, nil
 }
 
-// LazyProvide implements DockerConfigProvider.LazyProvide. It will be called
-// by the client when attempting to pull an image and it will create the actual
-// provider only when we actually need it the first time.
-func (p *lazyEcrProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
-	if p.actualProvider == nil {
-		glog.V(2).Infof("Creating ecrProvider for %s", p.region)
-		p.actualProvider = &credentialprovider.CachingDockerConfigProvider{
-			Provider: newEcrProvider(p.region, nil),
-			// Refresh credentials a little earlier than expiration time
-			Lifetime: 11*time.Hour + 55*time.Minute,
-		}
-		if !p.actualProvider.Enabled() {
-			return nil
-		}
-	}
-	entry := p.actualProvider.Provide()[p.regionURL]
-	return &entry
+type parsedURL struct {
+	registryID string
+	region     string
+	registry   string
 }
 
-// Provide implements DockerConfigProvider.Provide, creating dummy credentials.
-// Client code will call Provider.LazyProvide() at image pulling time.
-func (p *lazyEcrProvider) Provide() credentialprovider.DockerConfig {
-	entry := credentialprovider.DockerConfigEntry{
-		Provider: p,
+// parseRepoURL parses and splits the registry URL into the registry ID,
+// region, and registry.
+// <registryID>.dkr.ecr(-fips).<region>.amazonaws.com(.cn)
+func parseRepoURL(image string) (*parsedURL, error) {
+	parsed, err := url.Parse("https://" + image)
+	if err != nil {
+		return nil, fmt.Errorf("error parsing image %s %v", image, err)
 	}
-	cfg := credentialprovider.DockerConfig{}
-	cfg[p.regionURL] = entry
-	return cfg
+	splitURL := ecrPattern.FindStringSubmatch(parsed.Hostname())
+	if len(splitURL) == 0 {
+		return nil, fmt.Errorf("%s is not a valid ECR repository URL", parsed.Hostname())
+	}
+	return &parsedURL{
+		registryID: splitURL[1],
+		region:     splitURL[3],
+		registry:   parsed.Hostname(),
+	}, nil
 }
 
-func newEcrProvider(region string, getter tokenGetter) *ecrProvider {
-	return &ecrProvider{
-		region:    region,
-		regionURL: registryURL(region),
-		getter:    getter,
-	}
+// tokenGetter is for testing purposes
+type tokenGetter interface {
+	GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error)
 }
 
-// Enabled implements DockerConfigProvider.Enabled for the AWS token-based implementation.
-// For now, it gets activated only if AWS was chosen as the cloud provider.
-// TODO: figure how to enable it manually for deployments that are not on AWS but still
-// use ECR somehow?
-func (p *ecrProvider) Enabled() bool {
-	if p.region == "" {
-		glog.Errorf("Called ecrProvider.Enabled() with no region set")
-		return false
+// tokenGetterFactory is for testing purposes
+type tokenGetterFactory interface {
+	GetTokenGetterForRegion(string) (tokenGetter, error)
+}
+
+// ecrTokenGetterFactory stores a token getter per region
+type ecrTokenGetterFactory struct {
+	cache map[string]tokenGetter
+	mutex sync.Mutex
+}
+
+// awsHandlerLogger is a handler that logs all AWS SDK requests
+// Copied from pkg/cloudprovider/providers/aws/log_handler.go
+func awsHandlerLogger(req *request.Request) {
+	service := req.ClientInfo.ServiceName
+	region := req.Config.Region
+
+	name := "?"
+	if req.Operation != nil {
+		name = req.Operation.Name
 	}
 
-	getter := &ecrTokenGetter{svc: ecr.New(session.New(&aws.Config{
-		Credentials: nil,
-		Region:      &p.region,
-	}))}
+	glog.V(3).Infof("AWS request: %s:%s in %s", service, name, *region)
+}
+
+func newECRTokenGetter(region string) (tokenGetter, error) {
+	sess, err := session.NewSessionWithOptions(session.Options{
+		Config:            aws.Config{Region: aws.String(region)},
+		SharedConfigState: session.SharedConfigEnable,
+	})
+	if err != nil {
+		return nil, err
+	}
+	getter := &ecrTokenGetter{svc: ecr.New(sess)}
+	getter.svc.Handlers.Build.PushFrontNamed(request.NamedHandler{
+		Name: "k8s/user-agent",
+		Fn:   request.MakeAddToUserAgentHandler("kubernetes", version.Get().String()),
+	})
 	getter.svc.Handlers.Sign.PushFrontNamed(request.NamedHandler{
 		Name: "k8s/logger",
 		Fn:   awsHandlerLogger,
 	})
-	p.getter = getter
+	return getter, nil
+}
 
-	return true
+// GetTokenGetterForRegion gets the token getter for the requested region. If it
+// doesn't exist, it creates a new ECR token getter
+func (f *ecrTokenGetterFactory) GetTokenGetterForRegion(region string) (tokenGetter, error) {
+	f.mutex.Lock()
+	defer f.mutex.Unlock()
+
+	if getter, ok := f.cache[region]; ok {
+		return getter, nil
+	}
+	getter, err := newECRTokenGetter(region)
+	if err != nil {
+		return nil, fmt.Errorf("unable to create token getter for region %v %v", region, err)
+	}
+	f.cache[region] = getter
+	return getter, nil
 }
 
-// LazyProvide implements DockerConfigProvider.LazyProvide. Should never be called.
-func (p *ecrProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
-	return nil
+// The canonical implementation
+type ecrTokenGetter struct {
+	svc *ecr.ECR
 }
 
-// Provide implements DockerConfigProvider.Provide, refreshing ECR tokens on demand
-func (p *ecrProvider) Provide() credentialprovider.DockerConfig {
-	cfg := credentialprovider.DockerConfig{}
+// GetAuthorizationToken gets the ECR authorization token using the ECR API
+func (p *ecrTokenGetter) GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) {
+	return p.svc.GetAuthorizationToken(input)
+}
+
+type cacheEntry struct {
+	expiresAt   time.Time
+	credentials credentialprovider.DockerConfigEntry
+	registry    string
+}
 
-	// TODO: fill in RegistryIds?
-	params := &ecr.GetAuthorizationTokenInput{}
-	output, err := p.getter.GetAuthorizationToken(params)
+// makeCacheEntry decodes the ECR authorization entry and re-packages it into a
+// cacheEntry.
+func makeCacheEntry(data *ecr.AuthorizationData, registry string) (*cacheEntry, error) {
+	decodedToken, err := base64.StdEncoding.DecodeString(aws.StringValue(data.AuthorizationToken))
 	if err != nil {
-		glog.Errorf("while requesting ECR authorization token %v", err)
-		return cfg
+		return nil, fmt.Errorf("error decoding ECR authorization token: %v", err)
 	}
-	if output == nil {
-		glog.Errorf("Got back no ECR token")
-		return cfg
+	parts := strings.SplitN(string(decodedToken), ":", 2)
+	if len(parts) < 2 {
+		return nil, errors.New("error getting username and password from authorization token")
 	}
-
-	for _, data := range output.AuthorizationData {
-		if data.ProxyEndpoint != nil &&
-			data.AuthorizationToken != nil {
-			decodedToken, err := base64.StdEncoding.DecodeString(aws.StringValue(data.AuthorizationToken))
-			if err != nil {
-				glog.Errorf("while decoding token for endpoint %v %v", data.ProxyEndpoint, err)
-				return cfg
-			}
-			parts := strings.SplitN(string(decodedToken), ":", 2)
-			user := parts[0]
-			password := parts[1]
-			entry := credentialprovider.DockerConfigEntry{
-				Username: user,
-				Password: password,
-				// ECR doesn't care and Docker is about to obsolete it
-				Email: "not@val.id",
-			}
-
-			glog.V(3).Infof("Adding credentials for user %s in %s", user, p.region)
-			// Add our config entry for this region's registry URLs
-			cfg[p.regionURL] = entry
-
-		}
+	creds := credentialprovider.DockerConfigEntry{
+		Username: parts[0],
+		Password: parts[1],
+		Email:    "not@val.id", // ECR doesn't care and Docker is about to obsolete it
 	}
-	return cfg
+	if data.ExpiresAt == nil {
+		return nil, errors.New("authorization data expiresAt is nil")
+	}
+	return &cacheEntry{
+		expiresAt:   data.ExpiresAt.Add(-1 * wait.Jitter(30*time.Minute, 0.2)),
+		credentials: creds,
+		registry:    registry,
+	}, nil
+}
+
+// ecrExpirationPolicy implements ExpirationPolicy from client-go.
+type ecrExpirationPolicy struct{}
+
+// stringKeyFunc returns the cache key as a string
+func stringKeyFunc(obj interface{}) (string, error) {
+	key := obj.(*cacheEntry).registry
+	return key, nil
+}
+
+// IsExpired checks if the ECR credentials are expired.
+func (p *ecrExpirationPolicy) IsExpired(entry *cache.TimestampedEntry) bool {
+	return time.Now().After(entry.Obj.(*cacheEntry).expiresAt)
 }
diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go
index 486128dc..5f6c4224 100644
--- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go
+++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go
@@ -136,7 +136,7 @@ func (a *acrProvider) Enabled() bool {
 	return true
 }
 
-func (a *acrProvider) Provide() credentialprovider.DockerConfig {
+func (a *acrProvider) Provide(image string) credentialprovider.DockerConfig {
 	cfg := credentialprovider.DockerConfig{}
 
 	glog.V(4).Infof("listing registries")
@@ -198,6 +198,6 @@ func getACRDockerEntryFromARMToken(a *acrProvider, loginServer string) (*credent
 	}, nil
 }
 
-func (a *acrProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
+func (a *acrProvider) LazyProvide(image string) *credentialprovider.DockerConfigEntry {
 	return nil
 }
diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/jwt.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/jwt.go
index d187560a..3616675e 100644
--- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/jwt.go
+++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/jwt.go
@@ -21,12 +21,11 @@ import (
 	"time"
 
 	"github.com/golang/glog"
+	"github.com/spf13/pflag"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
 	"golang.org/x/oauth2/jwt"
 	"k8s.io/kubernetes/pkg/credentialprovider"
-
-	"github.com/spf13/pflag"
 )
 
 const (
@@ -87,12 +86,12 @@ func (j *jwtProvider) Enabled() bool {
 }
 
 // LazyProvide implements DockerConfigProvider. Should never be called.
-func (j *jwtProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
+func (j *jwtProvider) LazyProvide(image string) *credentialprovider.DockerConfigEntry {
 	return nil
 }
 
 // Provide implements DockerConfigProvider
-func (j *jwtProvider) Provide() credentialprovider.DockerConfig {
+func (j *jwtProvider) Provide(image string) credentialprovider.DockerConfig {
 	cfg := credentialprovider.DockerConfig{}
 
 	ts := j.config.TokenSource(oauth2.NoContext)
diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/metadata.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/metadata.go
index 4c668d0b..de3bf2f8 100644
--- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/metadata.go
+++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/metadata.go
@@ -130,12 +130,12 @@ func (g *metadataProvider) Enabled() bool {
 }
 
 // LazyProvide implements DockerConfigProvider. Should never be called.
-func (g *dockerConfigKeyProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
+func (g *dockerConfigKeyProvider) LazyProvide(image string) *credentialprovider.DockerConfigEntry {
 	return nil
 }
 
 // Provide implements DockerConfigProvider
-func (g *dockerConfigKeyProvider) Provide() credentialprovider.DockerConfig {
+func (g *dockerConfigKeyProvider) Provide(image string) credentialprovider.DockerConfig {
 	// Read the contents of the google-dockercfg metadata key and
 	// parse them as an alternate .dockercfg
 	if cfg, err := credentialprovider.ReadDockerConfigFileFromUrl(dockerConfigKey, g.Client, metadataHeader); err != nil {
@@ -148,12 +148,12 @@ func (g *dockerConfigKeyProvider) Provide() credentialprovider.DockerConfig {
 }
 
 // LazyProvide implements DockerConfigProvider. Should never be called.
-func (g *dockerConfigUrlKeyProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
+func (g *dockerConfigUrlKeyProvider) LazyProvide(image string) *credentialprovider.DockerConfigEntry {
 	return nil
 }
 
 // Provide implements DockerConfigProvider
-func (g *dockerConfigUrlKeyProvider) Provide() credentialprovider.DockerConfig {
+func (g *dockerConfigUrlKeyProvider) Provide(image string) credentialprovider.DockerConfig {
 	// Read the contents of the google-dockercfg-url key and load a .dockercfg from there
 	if url, err := credentialprovider.ReadUrl(dockerConfigUrlKey, g.Client, metadataHeader); err != nil {
 		glog.Errorf("while reading 'google-dockercfg-url' metadata: %v", err)
@@ -258,12 +258,12 @@ type tokenBlob struct {
 }
 
 // LazyProvide implements DockerConfigProvider. Should never be called.
-func (g *containerRegistryProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
+func (g *containerRegistryProvider) LazyProvide(image string) *credentialprovider.DockerConfigEntry {
 	return nil
 }
 
 // Provide implements DockerConfigProvider
-func (g *containerRegistryProvider) Provide() credentialprovider.DockerConfig {
+func (g *containerRegistryProvider) Provide(image string) credentialprovider.DockerConfig {
 	cfg := credentialprovider.DockerConfig{}
 
 	tokenJsonBlob, err := credentialprovider.ReadUrl(metadataToken, g.Client, metadataHeader)
diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/keyring.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/keyring.go
index b269f474..31b3e289 100644
--- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/keyring.go
+++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/keyring.go
@@ -23,9 +23,8 @@ import (
 	"sort"
 	"strings"
 
-	"github.com/golang/glog"
-
 	dockertypes "github.com/docker/docker/api/types"
+	"github.com/golang/glog"
 	"k8s.io/apimachinery/pkg/util/sets"
 )
 
@@ -267,7 +266,7 @@ func (dk *lazyDockerKeyring) Lookup(image string) ([]LazyAuthConfiguration, bool
 	keyring := &BasicDockerKeyring{}
 
 	for _, p := range dk.Providers {
-		keyring.Add(p.Provide())
+		keyring.Add(p.Provide(image))
 	}
 
 	return keyring.Lookup(image)
diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/provider.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/provider.go
index 419dc43e..9621ccf2 100644
--- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/provider.go
+++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/provider.go
@@ -34,15 +34,15 @@ type DockerConfigProvider interface {
 	Enabled() bool
 	// Provide returns docker configuration.
 	// Implementations can be blocking - e.g. metadata server unavailable.
-	Provide() DockerConfig
+	Provide(image string) DockerConfig
 	// LazyProvide() gets called after URL matches have been performed, so the
 	// location used as the key in DockerConfig would be redundant.
-	LazyProvide() *DockerConfigEntry
+	LazyProvide(image string) *DockerConfigEntry
 }
 
-func LazyProvide(creds LazyAuthConfiguration) dockertypes.AuthConfig {
+func LazyProvide(creds LazyAuthConfiguration, image string) dockertypes.AuthConfig {
 	if creds.Provider != nil {
-		entry := *creds.Provider.LazyProvide()
+		entry := *creds.Provider.LazyProvide(image)
 		return DockerConfigEntryToLazyAuthConfiguration(entry).AuthConfig
 	} else {
 		return creds.AuthConfig
@@ -81,7 +81,7 @@ func (d *defaultDockerConfigProvider) Enabled() bool {
 }
 
 // Provide implements dockerConfigProvider
-func (d *defaultDockerConfigProvider) Provide() DockerConfig {
+func (d *defaultDockerConfigProvider) Provide(image string) DockerConfig {
 	// Read the standard Docker credentials from .dockercfg
 	if cfg, err := ReadDockerConfigFile(); err == nil {
 		return cfg
@@ -92,7 +92,7 @@ func (d *defaultDockerConfigProvider) Provide() DockerConfig {
 }
 
 // LazyProvide implements dockerConfigProvider. Should never be called.
-func (d *defaultDockerConfigProvider) LazyProvide() *DockerConfigEntry {
+func (d *defaultDockerConfigProvider) LazyProvide(image string) *DockerConfigEntry {
 	return nil
 }
 
@@ -102,12 +102,12 @@ func (d *CachingDockerConfigProvider) Enabled() bool {
 }
 
 // LazyProvide implements dockerConfigProvider. Should never be called.
-func (d *CachingDockerConfigProvider) LazyProvide() *DockerConfigEntry {
+func (d *CachingDockerConfigProvider) LazyProvide(image string) *DockerConfigEntry {
 	return nil
 }
 
 // Provide implements dockerConfigProvider
-func (d *CachingDockerConfigProvider) Provide() DockerConfig {
+func (d *CachingDockerConfigProvider) Provide(image string) DockerConfig {
 	d.mu.Lock()
 	defer d.mu.Unlock()
 
@@ -117,7 +117,7 @@ func (d *CachingDockerConfigProvider) Provide() DockerConfig {
 	}
 
 	glog.V(2).Infof("Refreshing cache for provider: %v", reflect.TypeOf(d.Provider).String())
-	d.cacheDockerConfig = d.Provider.Provide()
+	d.cacheDockerConfig = d.Provider.Provide(image)
 	d.expiration = time.Now().Add(d.Lifetime)
 	return d.cacheDockerConfig
 }
