Skip to content

Commit c7b1275

Browse files
committed
Remote build: nTar secrets with relative paths and ignore bypass
When `podman-remote` tars the context, extra `podman-build-secret*` paths were either dropped by `.dockerignore` (#25314) or archived as absolute paths so `COPY . .` pulled host-shaped trees into the image (#28334). Use relative names under the primary context for extra sources and do not apply `.dockerignore` to those forced entries. Fixes: #25314 Fixes: #28334 Signed-off-by: Jan Rodák <hony.com@seznam.cz>
1 parent 03ee20c commit c7b1275

8 files changed

Lines changed: 47 additions & 2 deletions

File tree

pkg/bindings/images/build.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,10 @@ func build(ctx context.Context, containerFiles []string, options types.BuildOpti
10951095
return processBuildResponse(response, stdout, saveFormat)
10961096
}
10971097

1098+
// nTar builds a gzip-compressed tar of sources and returns it as a ReadCloser.
1099+
// sources[0] is the build context directory (walked recursively). Remaining entries
1100+
// are extra regular files (e.g. secrets) that are always archived; exclude patterns
1101+
// apply only to the first source.
10981102
func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
10991103
pm, err := fileutils.NewPatternMatcher(excludes)
11001104
if err != nil {
@@ -1115,13 +1119,17 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
11151119
defer gw.Close()
11161120
defer tw.Close()
11171121
seen := make(map[devino]string)
1122+
firstSourceAbs := ""
11181123
for i, src := range sources {
11191124
source, err := filepath.Abs(src)
11201125
if err != nil {
11211126
logrus.Errorf("Cannot stat one of source context: %v", err)
11221127
merr = multierror.Append(merr, err)
11231128
return
11241129
}
1130+
if i == 0 {
1131+
firstSourceAbs = source
1132+
}
11251133
err = filepath.WalkDir(source, func(path string, dentry fs.DirEntry, err error) error {
11261134
if err != nil {
11271135
return err
@@ -1149,17 +1157,24 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
11491157
}
11501158
}
11511159
var name string
1160+
skipExclude := false
11521161
if i == 0 {
11531162
name = filepath.ToSlash(strings.TrimPrefix(path, source+separator))
11541163
} else {
11551164
if !dentry.Type().IsRegular() {
11561165
return fmt.Errorf("path %s must be a regular file", path)
11571166
}
1158-
name = filepath.ToSlash(path)
1167+
fsSep := string(filepath.Separator)
1168+
if strings.HasPrefix(path, firstSourceAbs+fsSep) {
1169+
name = filepath.ToSlash(strings.TrimPrefix(path, firstSourceAbs+fsSep))
1170+
} else {
1171+
name = filepath.ToSlash(path)
1172+
}
1173+
skipExclude = true
11591174
}
11601175
// If name is absolute path, then it has to be containerfile outside of build context.
11611176
// If not, we should check it for being excluded via pattern matcher.
1162-
if !filepath.IsAbs(name) {
1177+
if !filepath.IsAbs(name) && !skipExclude {
11631178
excluded, err := pm.Matches(name) //nolint:staticcheck
11641179
if err != nil {
11651180
return fmt.Errorf("checking if %q is excluded: %w", name, err)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM alpine
2+
COPY . .
3+
RUN test -e hello
4+
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
5+
RUN sh -c 'test -z "$(find / -name '\''podman-build-secret*'\'' 2>/dev/null | head -n1)"'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hi
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM alpine
2+
COPY . .
3+
RUN test ! -e ignored-by-dockerignore.txt
4+
RUN --mount=type=secret,id=MY_SECRET cat /run/secrets/MY_SECRET
5+
RUN sh -c 'test -z "$(find / -name '\''podman-build-secret*'\'' 2>/dev/null | head -n1)"'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Super Secret
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
this file must not appear in the image

test/e2e/build_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,22 @@ var _ = Describe("Podman build", func() {
136136
Expect(session).Should(ExitCleanly())
137137
})
138138

139+
It("podman remote build file secret with dockerignore that ignores all files", func() {
140+
// Test for: https://github.com/containers/podman/issues/25314
141+
session := podmanTest.PodmanExitCleanly("build", "-f", "build/remote-secret-dockerignore-star/Dockerfile", "--secret", "id=MY_SECRET,type=file,src=build/remote-secret-dockerignore-star/host-secret.txt", "build/remote-secret-dockerignore-star")
142+
Expect(session.OutputToString()).To(ContainSubstring("Super Secret"))
143+
})
144+
145+
It("podman remote build env secret with COPY does not leak podman-build-secret temp files", func() {
146+
// Test for: https://github.com/containers/podman/issues/28334
147+
secret := "somesecretvalue"
148+
os.Setenv("MYSECRET", secret)
149+
defer os.Unsetenv("MYSECRET")
150+
151+
session := podmanTest.PodmanExitCleanly("build", "-f", "build/remote-secret-copy/Dockerfile", "--secret", "id=mysecret,env=MYSECRET", "build/remote-secret-copy")
152+
Expect(session.OutputToString()).To(ContainSubstring(secret))
153+
})
154+
139155
It("podman build with not found Containerfile or Dockerfile", func() {
140156
targetPath := filepath.Join(podmanTest.TempDir, "notfound")
141157
err = os.Mkdir(targetPath, 0o755)

0 commit comments

Comments
 (0)