Skip to content

Commit 6459b39

Browse files
committed
rewrite config detection and env override
1 parent 5da2aaa commit 6459b39

File tree

1 file changed

+124
-61
lines changed

1 file changed

+124
-61
lines changed

envbuilder.go

Lines changed: 124 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141
"github.com/distribution/distribution/v3/configuration"
4242
"github.com/distribution/distribution/v3/registry/handlers"
4343
_ "github.com/distribution/distribution/v3/registry/storage/driver/filesystem"
44+
dockerconfig "github.com/docker/cli/cli/config"
4445
"github.com/docker/cli/cli/config/configfile"
4546
"github.com/fatih/color"
4647
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -56,7 +57,7 @@ import (
5657
var ErrNoFallbackImage = errors.New("no fallback image has been specified")
5758

5859
// DockerConfig represents the Docker configuration file.
59-
type DockerConfig configfile.ConfigFile
60+
type DockerConfig = configfile.ConfigFile
6061

6162
type runtimeDataStore struct {
6263
// Runtime data.
@@ -1567,8 +1568,8 @@ func maybeDeleteFilesystem(logger log.Func, force bool) error {
15671568
}
15681569

15691570
func fileExists(fs billy.Filesystem, path string) bool {
1570-
_, err := fs.Stat(path)
1571-
return err == nil
1571+
fi, err := fs.Stat(path)
1572+
return err == nil && !fi.IsDir()
15721573
}
15731574

15741575
func readFile(fs billy.Filesystem, name string) ([]byte, error) {
@@ -1656,88 +1657,150 @@ func parseMagicImageFile(fs billy.Filesystem, path string, v any) error {
16561657
return nil
16571658
}
16581659

1660+
const (
1661+
dockerConfigFile = dockerconfig.ConfigFileName
1662+
dockerConfigEnvKey = dockerconfig.EnvOverrideConfigDir
1663+
)
1664+
1665+
// initDockerConfigOverride sets the DOCKER_CONFIG environment variable
1666+
// to a path within the working directory. If a base64 encoded Docker
1667+
// config is provided, it is written to the path/config.json and the
1668+
// DOCKER_CONFIG environment variable is set to the path. If no base64
1669+
// encoded Docker config is provided, the following paths are checked in
1670+
// order:
1671+
//
1672+
// 1. $DOCKER_CONFIG/config.json
1673+
// 2. $DOCKER_CONFIG
1674+
// 3. /.envbuilder/config.json
1675+
//
1676+
// If a Docker config file is found, its path is set as DOCKER_CONFIG.
16591677
func initDockerConfigOverride(bfs billy.Filesystem, logf log.Func, workingDir workingdir.WorkingDir, dockerConfigBase64 string) (func() error, error) {
1660-
configFile := "config.json"
1661-
oldDockerConfig := os.Getenv("DOCKER_CONFIG")
1662-
newDockerConfig := workingDir.Path()
1678+
// If dockerConfigBase64 is set, it will have priority over file
1679+
// detection.
1680+
var dockerConfigJSON []byte
1681+
var err error
1682+
if dockerConfigBase64 != "" {
1683+
logf(log.LevelInfo, "Using base64 encoded Docker config")
1684+
1685+
dockerConfigJSON, err = base64.StdEncoding.DecodeString(dockerConfigBase64)
1686+
if err != nil {
1687+
return nil, fmt.Errorf("decode docker config: %w", err)
1688+
}
1689+
}
16631690

1664-
err := os.Setenv("DOCKER_CONFIG", newDockerConfig)
1665-
if err != nil {
1666-
logf(log.LevelError, "Failed to set DOCKER_CONFIG: %s", err)
1667-
return nil, fmt.Errorf("set DOCKER_CONFIG: %w", err)
1691+
oldDockerConfig := os.Getenv(dockerConfigEnvKey)
1692+
var oldDockerConfigFile string
1693+
if oldDockerConfig != "" {
1694+
oldDockerConfigFile = filepath.Join(oldDockerConfig, dockerConfigFile)
16681695
}
1669-
logf(log.LevelInfo, "Set DOCKER_CONFIG to %s", newDockerConfig)
1670-
restoreEnv := onceErrFunc(func() error {
1671-
// Restore the old DOCKER_CONFIG value.
1672-
if err := func() error {
1673-
if oldDockerConfig == "" {
1674-
return os.Unsetenv("DOCKER_CONFIG")
1675-
}
1676-
return os.Setenv("DOCKER_CONFIG", oldDockerConfig)
1677-
}(); err != nil {
1678-
return fmt.Errorf("restore DOCKER_CONFIG: %w", err)
1696+
for _, path := range []string{
1697+
oldDockerConfigFile, // $DOCKER_CONFIG/config.json
1698+
oldDockerConfig, // $DOCKER_CONFIG
1699+
workingDir.Join(dockerConfigFile), // /.envbuilder/config.json
1700+
} {
1701+
if path == "" || !fileExists(bfs, path) {
1702+
continue
16791703
}
1680-
logf(log.LevelInfo, "Restored DOCKER_CONFIG to %s", oldDockerConfig)
1681-
return nil
1682-
})
16831704

1684-
// If the user hasn't set the BASE64 encoded Docker config, we
1685-
// should respect the DOCKER_CONFIG environment variable.
1686-
oldDockerConfigFile := filepath.Join(oldDockerConfig, configFile)
1687-
if dockerConfigBase64 == "" && fileExists(bfs, oldDockerConfigFile) {
1688-
// It's possible that the target file is mounted and needs to
1689-
// be remounted later, so we should copy the file instead of
1690-
// hoping that the file is still there when we build.
1691-
logf(log.LevelInfo, "Using DOCKER_CONFIG at %s", oldDockerConfig)
1692-
b, err := readFile(bfs, oldDockerConfigFile)
1693-
if err != nil {
1694-
return nil, fmt.Errorf("read existing DOCKER_CONFIG: %w", err)
1705+
logf(log.LevelWarn, "Found Docker config at %s, this file will remain after the build", path)
1706+
1707+
if dockerConfigJSON == nil {
1708+
logf(log.LevelInfo, "Using Docker config at %s", path)
1709+
1710+
dockerConfigJSON, err = readFile(bfs, path)
1711+
if err != nil {
1712+
return nil, fmt.Errorf("read docker config: %w", err)
1713+
}
1714+
} else {
1715+
logf(log.LevelWarn, "Ignoring Docker config at %s, using base64 encoded Docker config instead", path)
16951716
}
1696-
// Read into dockerConfigBase64 so we can keep the same logic.
1697-
dockerConfigBase64 = base64.StdEncoding.EncodeToString(b)
1717+
break
16981718
}
16991719

1700-
if dockerConfigBase64 == "" {
1701-
return restoreEnv, nil
1720+
if dockerConfigJSON == nil {
1721+
// No user-provided config available.
1722+
return func() error { return nil }, nil
17021723
}
17031724

1704-
decoded, err := base64.StdEncoding.DecodeString(dockerConfigBase64)
1725+
dockerConfigJSON, err = hujson.Standardize(dockerConfigJSON)
17051726
if err != nil {
1706-
return restoreEnv, fmt.Errorf("decode docker config: %w", err)
1727+
return nil, fmt.Errorf("humanize json for docker config: %w", err)
17071728
}
1708-
decoded, err = hujson.Standardize(decoded)
1709-
if err != nil {
1710-
return restoreEnv, fmt.Errorf("humanize json for docker config: %w", err)
1729+
1730+
if err = logDockerAuthConfigs(logf, dockerConfigJSON); err != nil {
1731+
return nil, fmt.Errorf("log docker auth configs: %w", err)
17111732
}
1712-
var dockerConfig DockerConfig
1713-
err = json.Unmarshal(decoded, &dockerConfig)
1733+
1734+
// We're going to set the DOCKER_CONFIG environment variable to a
1735+
// path within the working directory so that Kaniko can pick it up.
1736+
// A user should not mount a file directly to this path as we will
1737+
// write to the file.
1738+
newDockerConfig := workingDir.Join(".docker")
1739+
newDockerConfigFile := filepath.Join(newDockerConfig, dockerConfigFile)
1740+
err = bfs.MkdirAll(newDockerConfig, 0o700)
17141741
if err != nil {
1715-
return restoreEnv, fmt.Errorf("parse docker config: %w", err)
1742+
return nil, fmt.Errorf("create docker config dir: %w", err)
17161743
}
1717-
for k := range dockerConfig.AuthConfigs {
1718-
logf(log.LevelInfo, "Docker config contains auth for registry %q", k)
1744+
1745+
if fileExists(bfs, newDockerConfigFile) {
1746+
return nil, fmt.Errorf("unable to write Docker config file, file already exists: %s", newDockerConfigFile)
17191747
}
17201748

1721-
newDockerConfigFile := filepath.Join(newDockerConfig, configFile)
1722-
err = writeFile(bfs, newDockerConfigFile, decoded, 0o644)
1749+
restoreEnv, err := setAndRestoreEnv(logf, dockerConfigEnvKey, newDockerConfig)
17231750
if err != nil {
1724-
return restoreEnv, fmt.Errorf("write docker config: %w", err)
1751+
return nil, fmt.Errorf("set docker config override: %w", err)
1752+
}
1753+
1754+
err = writeFile(bfs, newDockerConfigFile, dockerConfigJSON, 0o600)
1755+
if err != nil {
1756+
_ = restoreEnv() // Best effort.
1757+
return nil, fmt.Errorf("write docker config: %w", err)
17251758
}
17261759
logf(log.LevelInfo, "Wrote Docker config JSON to %s", newDockerConfigFile)
17271760

1728-
cleanup := onceErrFunc(func() error {
1729-
err := restoreEnv()
1761+
cleanupFile := onceErrFunc(func() error {
17301762
// Remove the Docker config secret file!
1731-
if err2 := os.Remove(newDockerConfigFile); err2 != nil {
1732-
if !errors.Is(err2, fs.ErrNotExist) {
1733-
err2 = fmt.Errorf("remove docker config: %w", err2)
1734-
}
1735-
logf(log.LevelError, "Failed to remove the Docker config secret file: %s", err2)
1736-
err = errors.Join(err, err2)
1763+
if err := bfs.Remove(newDockerConfigFile); err != nil {
1764+
logf(log.LevelError, "Failed to remove the Docker config secret file: %s", err)
1765+
return fmt.Errorf("remove docker config: %w", err)
17371766
}
1738-
return err
1767+
return nil
17391768
})
1740-
return cleanup, nil
1769+
return func() error { return errors.Join(cleanupFile(), restoreEnv()) }, nil
1770+
}
1771+
1772+
func logDockerAuthConfigs(logf log.Func, dockerConfigJSON []byte) error {
1773+
dc := new(DockerConfig)
1774+
err := dc.LoadFromReader(bytes.NewReader(dockerConfigJSON))
1775+
if err != nil {
1776+
return fmt.Errorf("load docker config: %w", err)
1777+
}
1778+
for k := range dc.AuthConfigs {
1779+
logf(log.LevelInfo, "Docker config contains auth for registry %q", k)
1780+
}
1781+
return nil
1782+
}
1783+
1784+
func setAndRestoreEnv(logf log.Func, key, value string) (restore func() error, err error) {
1785+
old := os.Getenv(key)
1786+
err = os.Setenv(key, value)
1787+
if err != nil {
1788+
logf(log.LevelError, "Failed to set %s: %s", key, err)
1789+
return nil, fmt.Errorf("set %s: %w", key, err)
1790+
}
1791+
logf(log.LevelInfo, "Set %s to %s", key, value)
1792+
return onceErrFunc(func() error {
1793+
if err := func() error {
1794+
if old == "" {
1795+
return os.Unsetenv(key)
1796+
}
1797+
return os.Setenv(key, old)
1798+
}(); err != nil {
1799+
return fmt.Errorf("restore %s: %w", key, err)
1800+
}
1801+
logf(log.LevelInfo, "Restored %s to %s", key, old)
1802+
return nil
1803+
}), nil
17411804
}
17421805

17431806
func onceErrFunc(f func() error) func() error {

0 commit comments

Comments
 (0)