Whitelisting *.pkg.dev for the GCP credential provider

This commit is contained in:
Yuriy Gridasov 2020-01-21 16:00:32 -08:00 committed by Yury Gridasov
parent c9b4cf3d25
commit f641ecd6f8
2 changed files with 76 additions and 72 deletions

View File

@ -50,7 +50,7 @@ var gceProductNameFile = "/sys/class/dmi/id/product_name"
// For these urls, the parts of the host name can be glob, for example '*.gcr.io" will match // For these urls, the parts of the host name can be glob, for example '*.gcr.io" will match
// "foo.gcr.io" and "bar.gcr.io". // "foo.gcr.io" and "bar.gcr.io".
var containerRegistryUrls = []string{"container.cloud.google.com", "gcr.io", "*.gcr.io"} var containerRegistryUrls = []string{"container.cloud.google.com", "gcr.io", "*.gcr.io", "*.pkg.dev"}
var metadataHeader = &http.Header{ var metadataHeader = &http.Header{
"Metadata-Flavor": []string{"Google"}, "Metadata-Flavor": []string{"Google"},

View File

@ -193,86 +193,90 @@ func TestDockerKeyringFromGoogleDockerConfigMetadataUrl(t *testing.T) {
} }
func TestContainerRegistryBasics(t *testing.T) { func TestContainerRegistryBasics(t *testing.T) {
registryURL := "container.cloud.google.com" registryURLs := []string{"container.cloud.google.com", "eu.gcr.io", "us-west2-docker.pkg.dev"}
email := "1234@project.gserviceaccount.com" for _, registryURL := range registryURLs {
token := &tokenBlob{AccessToken: "ya26.lots-of-indiscernible-garbage"} t.Run(registryURL, func(t *testing.T) {
email := "1234@project.gserviceaccount.com"
token := &tokenBlob{AccessToken: "ya26.lots-of-indiscernible-garbage"}
const ( const (
serviceAccountsEndpoint = "/computeMetadata/v1/instance/service-accounts/" serviceAccountsEndpoint = "/computeMetadata/v1/instance/service-accounts/"
defaultEndpoint = "/computeMetadata/v1/instance/service-accounts/default/" defaultEndpoint = "/computeMetadata/v1/instance/service-accounts/default/"
scopeEndpoint = defaultEndpoint + "scopes" scopeEndpoint = defaultEndpoint + "scopes"
emailEndpoint = defaultEndpoint + "email" emailEndpoint = defaultEndpoint + "email"
tokenEndpoint = defaultEndpoint + "token" tokenEndpoint = defaultEndpoint + "token"
) )
var err error var err error
gceProductNameFile, err = createProductNameFile() gceProductNameFile, err = createProductNameFile()
if err != nil {
t.Errorf("failed to create gce product name file: %v", err)
}
defer os.Remove(gceProductNameFile)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Only serve the URL key and the value endpoint
if scopeEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `["%s.read_write"]`, storageScopePrefix)
} else if emailEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, email)
} else if tokenEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
bytes, err := json.Marshal(token)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Errorf("failed to create gce product name file: %v", err)
} }
fmt.Fprintln(w, string(bytes)) defer os.Remove(gceProductNameFile)
} else if serviceAccountsEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "default/\ncustom")
} else {
http.Error(w, "", http.StatusNotFound)
}
}))
defer server.Close()
// Make a transport that reroutes all traffic to the example server server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
transport := utilnet.SetTransportDefaults(&http.Transport{ // Only serve the URL key and the value endpoint
Proxy: func(req *http.Request) (*url.URL, error) { if scopeEndpoint == r.URL.Path {
return url.Parse(server.URL + req.URL.Path) w.WriteHeader(http.StatusOK)
}, w.Header().Set("Content-Type", "application/json")
}) fmt.Fprintf(w, `["%s.read_write"]`, storageScopePrefix)
} else if emailEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, email)
} else if tokenEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
bytes, err := json.Marshal(token)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
fmt.Fprintln(w, string(bytes))
} else if serviceAccountsEndpoint == r.URL.Path {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "default/\ncustom")
} else {
http.Error(w, "", http.StatusNotFound)
}
}))
defer server.Close()
keyring := &credentialprovider.BasicDockerKeyring{} // Make a transport that reroutes all traffic to the example server
provider := &containerRegistryProvider{ transport := utilnet.SetTransportDefaults(&http.Transport{
metadataProvider{Client: &http.Client{Transport: transport}}, Proxy: func(req *http.Request) (*url.URL, error) {
} return url.Parse(server.URL + req.URL.Path)
},
})
if !provider.Enabled() { keyring := &credentialprovider.BasicDockerKeyring{}
t.Errorf("Provider is unexpectedly disabled") provider := &containerRegistryProvider{
} metadataProvider{Client: &http.Client{Transport: transport}},
}
keyring.Add(provider.Provide("")) if !provider.Enabled() {
t.Errorf("Provider is unexpectedly disabled")
}
creds, ok := keyring.Lookup(registryURL) keyring.Add(provider.Provide(""))
if !ok {
t.Errorf("Didn't find expected URL: %s", registryURL)
return
}
if len(creds) > 1 {
t.Errorf("Got more hits than expected: %s", creds)
}
val := creds[0]
if val.Username != "_token" { creds, ok := keyring.Lookup(registryURL)
t.Errorf("Unexpected username value, want: %s, got: %s", "_token", val.Username) if !ok {
} t.Errorf("Didn't find expected URL: %s", registryURL)
if token.AccessToken != val.Password { return
t.Errorf("Unexpected password value, want: %s, got: %s", token.AccessToken, val.Password) }
} if len(creds) > 1 {
if email != val.Email { t.Errorf("Got more hits than expected: %s", creds)
t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email) }
val := creds[0]
if val.Username != "_token" {
t.Errorf("Unexpected username value, want: %s, got: %s", "_token", val.Username)
}
if token.AccessToken != val.Password {
t.Errorf("Unexpected password value, want: %s, got: %s", token.AccessToken, val.Password)
}
if email != val.Email {
t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
}
})
} }
} }