Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth problem with private Docker registry when building from Dockerfile #389

Closed
rzajac opened this issue Dec 2, 2021 · 12 comments
Closed

Comments

@rzajac
Copy link
Contributor

rzajac commented Dec 2, 2021

Describe the bug
When building image from Dockerfile using private Docker repo I get en error:

req := tc.ContainerRequest{
        FromDockerfile: tc.FromDockerfile{
            Context:       "/my/path",
            Dockerfile:    "Dockerfile",
            PrintBuildLog: true,
        },

dp, _ := tc.NewDockerProvider()
tag, err := dp.BuildImage(ctx, &req) // This returns an error.
Head "http://my.domain.dev:5000/v2/ifp-docker/dki-proftpd/manifests/v0.2.1": no basic auth credentials

Docker info
output of the command:

$ docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Build with BuildKit (Docker Inc., v0.6.3-docker)
  scan: Docker Scan (Docker Inc., v0.9.0)

Server:
 Containers: 251
  Running: 0
  Paused: 0
  Stopped: 251
 Images: 1216
 Server Version: 20.10.10
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc io.containerd.runc.v2 io.containerd.runtime.v1.linux
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 5b46e404f6b9f661a205e28d59c982d3634148f8
 runc version: v1.0.2-0-g52b36a2
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.11.0-41-generic
 Operating System: Ubuntu 21.04
 OSType: linux
 Architecture: x86_64
 CPUs: 12
 Total Memory: 31.26GiB
 Name: thor
 ID: S4XQ:6LAR:AMRS:JRG5:FPSO:NXHA:AD7P:TEZF:Y6FQ:RQ6R:NB46:CUQ7
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  my.domain.dev:5000
  127.0.0.0/8
 Live Restore Enabled: false

Additional context

  • I can pull the image from command line witout problems docker pull my.domain.dev:5000/ifp-docker/dki-proftpd:v0.2.1 and then i do not have this problem anymore.
  • The image I'm trying to build is based on the dki-proftpd:v0.2.1 image (FROM dki-proftpd:v0.2.1 as source).
@rzajac
Copy link
Contributor Author

rzajac commented Dec 2, 2021

After some research I found that

buildOptions := types.ImageBuildOptions{
lacks the AuthConfig key.

I cloned the repository ands when I added below code it stared working as expected.

buildOptions := types.ImageBuildOptions{
    BuildArgs:  img.GetBuildArgs(),
    Dockerfile: img.GetDockerfile(),
    Context:    buildContext,
    Tags:       []string{repoTag},
    AuthConfigs: map[string]types.AuthConfig{
        "my.domain.dev:5000": {
            Username: "user",
            Password: "pass",
        },
    },
}

Unfortunately currently there is noway to pass it from my tests. The ImageBuildInfo intrerface would have to be extended.

@mdelapenya
Copy link
Collaborator

Hey @rzajac thanks for opening this issue, it seems we are missing those credentials when pulling the building the image. I wonder if we are missing AuthConfig elsewhere 🤔

Unfortunately currently there is noway to pass it from my tests. The ImageBuildInfo intrerface would have to be extended.

Sorry but I do not get this. Do you mean that you cannot test it because you'll be forced to expose your credentials in the code? If that's the case, have you tried to force a docker login in your build pipeline first?

@rzajac
Copy link
Contributor Author

rzajac commented Dec 3, 2021

@mdelapenya I meant that with current way BuildImage method is implemented there is no way to set AuthConfigs.

Since yesterday I found a workaround for this problem by pulling the image using Docker API before I use testcontainers.

My function looks like below in case someone wants to know how i did the workaround:

// PullImage uses Docker client to pull the image reference.
func PullImage(ctx context.Context, ref string) error {
	cli, err := client.NewClientWithOpts(
		client.FromEnv,
		client.WithAPIVersionNegotiation(),
	)
	if err != nil {
		return err
	}

	cred, err := RegistryCred(ref, "")
	if err != nil {
		return err
	}

	options := types.ImagePullOptions{
		All:          true,
		RegistryAuth: cred,
	}

	rc, err := cli.ImagePull(ctx, ref, options)
	if err != nil {
		return err
	}
	defer func() { _ = rc.Close() }()

	if _, err = io.ReadAll(rc); err != nil {
		return err
	}

	return nil
}

// RegistryCred returns private registry credentials string for image. The dir
// should be path to the directory with Docker configuration file or empty
// string. The default config (~/.docker/config.json) will be used if the dir
// is set to empty string.
func RegistryCred(image, dir string) (string, error) {
	cf, err := config.Load(dir)
	if err != nil {
		return "", err
	}

	named, err := reference.ParseNormalizedNamed(image)
	if err != nil {
		return "", err
	}

	domain := reference.Domain(named)
	if domain == "docker.io" {
		return "", nil
	}

	ac, err := cf.GetAuthConfig(domain)
	if err != nil {
		return "", err
	}

	encodedJSON, err := json.Marshal(ac)
	if err != nil {
		return "", fmt.Errorf("error when encoding auth: %w", err)
	}
	return base64.URLEncoding.EncodeToString(encodedJSON), nil
}

@ruchidhore12
Copy link

I am getting the same error in pipeline "no basic auth credentials". We have uploaded images to AWS ECR and trying to pull images from there.

The thing is we are doing docker login in pipeline before running these tests and still getting this error.

@mehulgohil
Copy link

I was facing the same problem. But when I looked into docker go pkg. I found how we can give the registry credential for auth docker pull. https://docs.docker.com/engine/api/sdk/examples/#pull-an-image-with-authentication

image

So I gave the above auth str with my encoded registry credentials to RegistryCred as below in ContainerRequest. This worked from in my local as well CI pipeline.

req := testcontainers.ContainerRequest{
		Image:        "<Image Path>",
		ExposedPorts: []string{"1433/tcp"},
		RegistryCred: authStr,
		SkipReaper:   true, // skips ryuk container cleanup
		WaitingFor:   wait.ForLog("database setup completed"),
	}

@mdelapenya
Copy link
Collaborator

So I gave the above auth str with my encoded registry credentials to RegistryCred as below in ContainerRequest. This worked from in my local as well CI pipeline.

@rzajac could you please check with @mehulgohil's approach? If this is working for you too, I think we could close this issue

@matdehaast
Copy link

@mdelapenya the above may work for static creds, but the docker build fails for me where I am using a credential helper to inject the credentials as ENV variables. This is far safer and the recommended approach

@rvichery
Copy link

rvichery commented Sep 8, 2022

@mdelapenya running into a similar issue on simple pull images from ECR (despite being logged in already). Looks like the go implementation for testcontainer does not handle loading the docker config.json when no RegistryCred are passed. The java implementation for testcontainer seems to handle this by default (https://github.com/testcontainers/testcontainers-java/blob/de1324ed2800eff4da326d0c23d281399d006bc0/core/src/main/java/org/testcontainers/utility/RegistryAuthLocator.java).

Are you open for a contribution to implement a similar behavior in the go implementation?

@mdelapenya
Copy link
Collaborator

@rvichery thanks for pinging us about this issue, your contributions are super welcomed!! So feel free to elaborate a PR describing the use case it solves. Having Java code as a reference is a good thing to follow, so please reference it whenever you need it.

@mdelapenya
Copy link
Collaborator

@mdelapenya the above may work for static creds, but the docker build fails for me where I am using a credential helper to inject the credentials as ENV variables. This is far safer and the recommended approach

@matdehaast sorry for the radio silence, for some reason this message felt out of my radar, my bad 😞

I know @rvichery is willing to contribute a fix, but if you want to participate too, I wonder if you both would be interested in opening a discussion to collaborate in the fix. wdyt?

@szaher
Copy link

szaher commented Sep 16, 2022

@mehulgohil nice work around, however, I am using multi-stage docker file with multiple private repositories so another problem is which credential to use at build time...

I added this issue #532 to hopefully support multiple registry creds (@rzajac Can you please check if it make sense?)

@mdelapenya
Copy link
Collaborator

I think this issue can be closed, as #602 was already merged.

Thank you all for creating such a healthy discussion 👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants