-
-
Notifications
You must be signed in to change notification settings - Fork 512
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support for reading auth credentials from docker credential hel…
…pers (#869) * feat: expose a way to retrieve credentials from the credentials helpers * chore: support for retrieving the config file from the DOCKER_CONFIG env var * docs: document how to retrieve Docker credentials * chore: support reading from DOCKER_AUTH_CONFIG * feat: populate the auth struct from the Docker credentials helper if user and password are empty in the configuration file * chore: simplify * chore: load from credentials helper properly * docs: typo * chore: move to constants * chor: do not expose helper method * chore: support getting auth for default registry * chore: friendlier func names * chore: extract registry from a Docker image * chore: move constant to internal package * chore: return default Docker registry if no registry is found * chore: define a fallback * chore: include protocol of the registry * chore: refactor func to get the auth from a Docker image * chore: do not hardcode ports in tests * fix: apply credentials to the right struct * feart: pull image using the registry credentials of the image * feat: support extracting all images from a Dockerfile * chore: deprecated AuthConfigs from BuildFormDockerfile They will automatically discovered extracting all the FROM images in the Dockerfiles * Revert "chore: do not hardcode ports in tests" This reverts commit 24ac700. * chore: do not recalculate base64 if it exists * chore: set custom Auth config for the registry tests * chore: remove deprecated AuthConfigs usage * chore: set proper docker config for tests involving a private registry * chore: avoid double call to extract registry * chore: extract expected registries to constants * fix: use the right format for the registry auth * chore: improve test names * chore: better test names * chore: move docker auth tests to another test file * docs: update docs * chore: interpolate build args when extracting images from dockerfile * chore: remove logs from tests * chore: extract message to constant * fix: remove whitespaces from each line * chore: verify that Docker's default config file exist
- Loading branch information
1 parent
e67432e
commit b56e66a
Showing
20 changed files
with
865 additions
and
218 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package testcontainers | ||
|
||
import ( | ||
"context" | ||
"encoding/base64" | ||
"encoding/json" | ||
"os" | ||
|
||
"github.com/cpuguy83/dockercfg" | ||
"github.com/docker/docker/api/types" | ||
"github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" | ||
) | ||
|
||
// DockerImageAuth returns the auth config for the given Docker image, extracting first its Docker registry. | ||
// Finally, it will use the credential helpers to extract the information from the docker config file | ||
// for that registry, if it exists. | ||
func DockerImageAuth(ctx context.Context, image string) (string, types.AuthConfig, error) { | ||
defaultRegistry := defaultRegistry(ctx) | ||
registry := testcontainersdocker.ExtractRegistry(image, defaultRegistry) | ||
|
||
cfgs, err := getDockerAuthConfigs() | ||
if err != nil { | ||
return registry, types.AuthConfig{}, err | ||
} | ||
|
||
if cfg, ok := cfgs[registry]; ok { | ||
return registry, cfg, nil | ||
} | ||
|
||
return registry, types.AuthConfig{}, dockercfg.ErrCredentialsNotFound | ||
} | ||
|
||
// defaultRegistry returns the default registry to use when pulling images | ||
// It will use the docker daemon to get the default registry, returning "https://index.docker.io/v1/" if | ||
// it fails to get the information from the daemon | ||
func defaultRegistry(ctx context.Context) string { | ||
p, err := NewDockerProvider() | ||
if err != nil { | ||
return testcontainersdocker.IndexDockerIO | ||
} | ||
|
||
info, err := p.client.Info(ctx) | ||
if err != nil { | ||
return testcontainersdocker.IndexDockerIO | ||
} | ||
|
||
return info.IndexServerAddress | ||
} | ||
|
||
// getDockerAuthConfigs returns a map with the auth configs from the docker config file | ||
// using the registry as the key | ||
func getDockerAuthConfigs() (map[string]types.AuthConfig, error) { | ||
cfg, err := getDockerConfig() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
cfgs := map[string]types.AuthConfig{} | ||
for k, v := range cfg.AuthConfigs { | ||
ac := types.AuthConfig{ | ||
Auth: v.Auth, | ||
Email: v.Email, | ||
IdentityToken: v.IdentityToken, | ||
Password: v.Password, | ||
RegistryToken: v.RegistryToken, | ||
ServerAddress: v.ServerAddress, | ||
Username: v.Username, | ||
} | ||
|
||
if v.Username == "" && v.Password == "" { | ||
u, p, _ := dockercfg.GetRegistryCredentials(k) | ||
ac.Username = u | ||
ac.Password = p | ||
} | ||
|
||
if v.Auth == "" { | ||
ac.Auth = base64.StdEncoding.EncodeToString([]byte(ac.Username + ":" + ac.Password)) | ||
} | ||
|
||
cfgs[k] = ac | ||
} | ||
|
||
return cfgs, nil | ||
} | ||
|
||
// getDockerConfig returns the docker config file. It will internally check, in this particular order: | ||
// 1. the DOCKER_AUTH_CONFIG environment variable, unmarshalling it into a dockercfg.Config | ||
// 2. the DOCKER_CONFIG environment variable, as the path to the config file | ||
// 3. else it will load the default config file, which is ~/.docker/config.json | ||
func getDockerConfig() (dockercfg.Config, error) { | ||
dockerAuthConfig := os.Getenv("DOCKER_AUTH_CONFIG") | ||
if dockerAuthConfig != "" { | ||
cfg := dockercfg.Config{} | ||
err := json.Unmarshal([]byte(dockerAuthConfig), &cfg) | ||
if err == nil { | ||
return cfg, nil | ||
} | ||
|
||
} | ||
|
||
cfg, err := dockercfg.LoadDefaultConfig() | ||
if err != nil { | ||
return cfg, err | ||
} | ||
|
||
return cfg, nil | ||
} |
Oops, something went wrong.