Skip to content

Commit e05cbee

Browse files
committed
Copy CA and user TLS registries certs to the container
Signed-off-by: CrazyMax <[email protected]>
1 parent c05a6eb commit e05cbee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+11598
-27
lines changed

driver/docker-container/driver.go

+178-27
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
package docker
22

33
import (
4-
"archive/tar"
54
"bytes"
65
"context"
76
"io"
87
"io/ioutil"
98
"net"
109
"os"
10+
"path"
11+
"path/filepath"
1112
"time"
1213

1314
"github.com/docker/buildx/driver"
1415
"github.com/docker/buildx/driver/bkimage"
1516
"github.com/docker/buildx/util/imagetools"
1617
"github.com/docker/buildx/util/progress"
18+
"github.com/docker/cli/cli/command"
1719
"github.com/docker/docker/api/types"
1820
dockertypes "github.com/docker/docker/api/types"
1921
"github.com/docker/docker/api/types/container"
2022
"github.com/docker/docker/api/types/mount"
2123
"github.com/docker/docker/api/types/network"
2224
dockerclient "github.com/docker/docker/client"
25+
dockerarchive "github.com/docker/docker/pkg/archive"
2326
"github.com/docker/docker/pkg/stdcopy"
27+
"github.com/docker/docker/pkg/system"
2428
"github.com/moby/buildkit/client"
29+
buildkitconfig "github.com/moby/buildkit/cmd/buildkitd/config"
2530
"github.com/moby/buildkit/util/tracing/detect"
2631
"github.com/pkg/errors"
2732
)
@@ -130,11 +135,10 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
130135
return err
131136
}
132137
if f := d.InitConfig.ConfigFile; f != "" {
133-
buf, err := readFileToTar(f)
134-
if err != nil {
138+
if err := d.copyToContainer(ctx, f, "/"); err != nil {
135139
return err
136140
}
137-
if err := d.DockerAPI.CopyToContainer(ctx, d.Name, "/", buf, dockertypes.CopyToContainerOptions{}); err != nil {
141+
if err := d.copyRegCertsToContainer(ctx, f); err != nil {
138142
return err
139143
}
140144
}
@@ -196,6 +200,126 @@ func (d *Driver) copyLogs(ctx context.Context, l progress.SubLogger) error {
196200
return rc.Close()
197201
}
198202

203+
// copyToContainer is based on the implementation from docker/cli
204+
// https://github.com/docker/cli/blob/master/cli/command/container/cp.go
205+
func (d *Driver) copyToContainer(ctx context.Context, srcPath string, dstPath string) error {
206+
var err error
207+
208+
// Get an absolute source path.
209+
srcPath, err = resolveLocalPath(srcPath)
210+
if err != nil {
211+
return err
212+
}
213+
214+
// Prepare the destination.
215+
dstInfo := dockerarchive.CopyInfo{Path: dstPath}
216+
dstStat, err := d.DockerAPI.ContainerStatPath(ctx, d.Name, dstPath)
217+
218+
// If the destination is a symbolic link, we should evaluate it.
219+
if err == nil && dstStat.Mode&os.ModeSymlink != 0 {
220+
linkTarget := dstStat.LinkTarget
221+
if !system.IsAbs(linkTarget) {
222+
dstParent, _ := dockerarchive.SplitPathDirEntry(dstPath)
223+
linkTarget = filepath.Join(dstParent, linkTarget)
224+
}
225+
dstInfo.Path = linkTarget
226+
dstStat, err = d.DockerAPI.ContainerStatPath(ctx, d.Name, linkTarget)
227+
}
228+
229+
// Validate the destination path.
230+
if err := command.ValidateOutputPathFileMode(dstStat.Mode); err != nil {
231+
return errors.Wrapf(err, `destination "%s:%s" must be a directory or a regular file`, d.Name, dstPath)
232+
}
233+
234+
// Ignore any error and assume that the parent directory of the destination
235+
// path exists, in which case the copy may still succeed. If there is any
236+
// type of conflict (e.g., non-directory overwriting an existing directory
237+
// or vice versa) the extraction will fail. If the destination simply did
238+
// not exist, but the parent directory does, the extraction will still
239+
// succeed.
240+
dstInfo.Exists, dstInfo.IsDir = true, dstStat.Mode.IsDir()
241+
242+
// Prepare source copy info.
243+
srcInfo, err := dockerarchive.CopyInfoSourcePath(srcPath, true)
244+
if err != nil {
245+
return err
246+
}
247+
248+
srcArchive, err := dockerarchive.TarResource(srcInfo)
249+
if err != nil {
250+
return err
251+
}
252+
defer srcArchive.Close()
253+
254+
// With the stat info about the local source as well as the
255+
// destination, we have enough information to know whether we need to
256+
// alter the archive that we upload so that when the server extracts
257+
// it to the specified directory in the container we get the desired
258+
// copy behavior.
259+
260+
// See comments in the implementation of `dockerarchive.PrepareArchiveCopy`
261+
// for exactly what goes into deciding how and whether the source
262+
// archive needs to be altered for the correct copy behavior when it is
263+
// extracted. This function also infers from the source and destination
264+
// info which directory to extract to, which may be the parent of the
265+
// destination that the user specified.
266+
dstDir, preparedArchive, err := dockerarchive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo)
267+
if err != nil {
268+
return err
269+
}
270+
defer preparedArchive.Close()
271+
272+
return d.DockerAPI.CopyToContainer(ctx, d.Name, dstDir, preparedArchive, dockertypes.CopyToContainerOptions{
273+
AllowOverwriteDirWithFile: false,
274+
})
275+
}
276+
277+
func resolveLocalPath(localPath string) (absPath string, err error) {
278+
if absPath, err = filepath.Abs(localPath); err != nil {
279+
return
280+
}
281+
return dockerarchive.PreserveTrailingDotOrSeparator(absPath, localPath, filepath.Separator), nil
282+
}
283+
284+
func (d *Driver) copyRegCertsToContainer(ctx context.Context, bkconfig string) error {
285+
// Load BuildKit config.
286+
bcfg, err := buildkitconfig.LoadFile(bkconfig)
287+
if err != nil {
288+
return err
289+
}
290+
291+
// Create a temp folder and copy all certs to it with copyFileParents
292+
// to keep the exact same folder structure as defined in BuildKit config.
293+
// It's required to do that here because we cannot copy a file in a folder
294+
// that does not exist in the container with the CopyToContainer API.
295+
tmpRegCerts, err := os.MkdirTemp("", "basedir-certs")
296+
if err != nil {
297+
return err
298+
}
299+
defer os.RemoveAll(tmpRegCerts)
300+
for _, reg := range bcfg.Registries {
301+
for _, rootCA := range reg.RootCAs {
302+
if err := copyFileParents(rootCA, tmpRegCerts); err != nil {
303+
return err
304+
}
305+
}
306+
for _, keyPair := range reg.KeyPairs {
307+
if len(keyPair.Key) > 0 {
308+
if err := copyFileParents(keyPair.Key, tmpRegCerts); err != nil {
309+
return err
310+
}
311+
}
312+
if len(keyPair.Certificate) > 0 {
313+
if err := copyFileParents(keyPair.Certificate, tmpRegCerts); err != nil {
314+
return err
315+
}
316+
}
317+
}
318+
}
319+
320+
return d.copyToContainer(ctx, tmpRegCerts+"/.", "/")
321+
}
322+
199323
func (d *Driver) exec(ctx context.Context, cmd []string) (string, net.Conn, error) {
200324
execConfig := types.ExecConfig{
201325
Cmd: cmd,
@@ -357,29 +481,6 @@ func (d *demux) Read(dt []byte) (int, error) {
357481
return d.Reader.Read(dt)
358482
}
359483

360-
func readFileToTar(fn string) (*bytes.Buffer, error) {
361-
buf := bytes.NewBuffer(nil)
362-
tw := tar.NewWriter(buf)
363-
dt, err := ioutil.ReadFile(fn)
364-
if err != nil {
365-
return nil, err
366-
}
367-
if err := tw.WriteHeader(&tar.Header{
368-
Name: "/etc/buildkit/buildkitd.toml",
369-
Size: int64(len(dt)),
370-
Mode: 0644,
371-
}); err != nil {
372-
return nil, err
373-
}
374-
if _, err := tw.Write(dt); err != nil {
375-
return nil, err
376-
}
377-
if err := tw.Close(); err != nil {
378-
return nil, err
379-
}
380-
return buf, nil
381-
}
382-
383484
type logWriter struct {
384485
logger progress.SubLogger
385486
stream int
@@ -389,3 +490,53 @@ func (l *logWriter) Write(dt []byte) (int, error) {
389490
l.logger.Log(l.stream, dt)
390491
return len(dt), nil
391492
}
493+
494+
// copyFileParents copies a file using the full source file name under a
495+
// folder. For example, copying /bar/foo.txt to /tmp will result in
496+
// the file being placed in /tmp/bar/foo.txt.
497+
func copyFileParents(srcFile string, destFolder string) error {
498+
si, err := os.Stat(srcFile)
499+
if err != nil {
500+
return err
501+
}
502+
503+
pi, err := os.Stat(path.Dir(srcFile))
504+
if err != nil {
505+
return err
506+
}
507+
508+
tdd := path.Join(destFolder, path.Dir(srcFile))
509+
if err := os.MkdirAll(tdd, pi.Mode()); err != nil {
510+
return err
511+
}
512+
513+
if si.Mode()&os.ModeSymlink != 0 {
514+
if srcFile, err = os.Readlink(srcFile); err != nil {
515+
return err
516+
}
517+
si, err = os.Stat(srcFile)
518+
if err != nil {
519+
return err
520+
}
521+
}
522+
523+
sf, err := os.Open(srcFile)
524+
if err != nil {
525+
return err
526+
}
527+
defer sf.Close()
528+
529+
tdf := path.Join(tdd, path.Base(srcFile))
530+
df, err := os.Create(tdf)
531+
if err != nil {
532+
return err
533+
}
534+
defer df.Close()
535+
536+
_, err = io.Copy(df, sf)
537+
if err != nil {
538+
return err
539+
}
540+
541+
return os.Chmod(tdf, si.Mode())
542+
}

vendor/github.com/containerd/containerd/pkg/userns/userns_linux.go

+62
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/containerd/containerd/pkg/userns/userns_unsupported.go

+25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/docker/docker/pkg/archive/README.md

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)