Description
When building an image, symbolic links to directories are copied as clones of the directories instead of as symbolic links.
This is problematic for the following reasons:
- Security issues and incorrectness. A symlink to
/some/unintended/absolute/path/with/sensitive/data/
can end up resolving to a directory outside of the build directory, and so a clone of a directory with sensitive data can end up in the resulting Docker image. A less dangerous version of this issue may be that the container contents will be incorrect. - Duplication of data. This can mean bloated Docker images. Additionally, this can cause issues where some code assumes that modifying data in a symlinked directory will result in changes in all places where that data is being used.
Replicating The Issue
Source directory structure (note a single large file and two symlinks pointing to the directory that contains it):
.
├── [ 33] Dockerfile
└── [ 96] fileSystem
└── [ 160] stuff
├── [ 96] subdir
│ └── [ 95M] equals.txt
├── [ 7] symlink_to_subdir -> subdir/
└── [ 7] symlink_to_subdir2 -> subdir/
Dockerfile contents:
FROM scratch
COPY fileSystem/* .
If I run docker build .
from CLI the resulting image is ~100MB in size.
However, when I run the following code, the resulting image is triple the size:
package test_client;
import java.io.File;
import java.io.IOException;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DockerClientImpl;
import com.github.dockerjava.api.command.BuildImageCmd;
import com.github.dockerjava.api.command.BuildImageResultCallback;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
class DockerClientTest {
public static void main(String[] args) throws IOException {
String buildDir = args[0];
System.out.println("Build directory: " + buildDir);
DockerClientConfig clientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build();
DockerClient client = DockerClientImpl.getInstance(
clientConfig,
new ApacheDockerHttpClient.Builder()
.dockerHost(clientConfig.getDockerHost())
.sslConfig(clientConfig.getSSLConfig())
.build()
);
String imageId;
try (BuildImageCmd buildImageCmd = client.buildImageCmd(new File(buildDir));
BuildImageResultCallback callback = new BuildImageResultCallback()) {
try (BuildImageResultCallback resultCallback = buildImageCmd.exec(callback)) {
imageId = resultCallback.awaitImageId();
}
}
System.out.println(String.format("Built image: %s", imageId));
}
}
Potential Fix
I believe the fix for this would be simple; however, I haven't gotten around to it as I had some issues building the library locally.
The check in this line can be changed from f.isDirectory()
to something similar to f.isDirectory() && !Files.isSymbolicLink(Paths.get(f.getAbsolutePath()))
and this should resolve the issue.
There is a chance I will create a PR for this issue; however, if someone gets to this first it would be appreciated.