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

Fails to pull image from registry - registry.redhat.io #2106

Closed
cmoulliard opened this issue Oct 28, 2019 · 23 comments · Fixed by #2201
Closed

Fails to pull image from registry - registry.redhat.io #2106

cmoulliard opened this issue Oct 28, 2019 · 23 comments · Fixed by #2201
Milestone

Comments

@cmoulliard
Copy link

cmoulliard commented Oct 28, 2019

Issue

We cannot pull an image from the registry.redhat.io as jib is returning an error 403
even if we pass the parameters -Djib.from.auth.username and -Djib.from.auth.password

Error

Caused by: org.apache.maven.plugin.MojoExecutionException: Build image failed, perhaps you should make sure you have permissions for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift and set correct credentials. See https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the-registry-responds-with-forbidden-or-denied for help
    at com.google.cloud.tools.jib.maven.BuildImageMojo.execute (BuildImageMojo.java:162)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:954)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
Caused by: com.google.cloud.tools.jib.api.RegistryUnauthorizedException: Unauthorized for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift
    at com.google.cloud.tools.jib.registry.RegistryEndpointCaller.call (RegistryEndpointCaller.java:279)
    at com.google.cloud.tools.jib.registry.RegistryEndpointCaller.callWithAllowInsecureRegistryHandling (RegistryEndpointCaller.java:175)
    at com.google.cloud.tools.jib.registry.RegistryEndpointCaller.call (RegistryEndpointCaller.java:152)
    at com.google.cloud.tools.jib.registry.RegistryClient.callRegistryEndpoint (RegistryClient.java:470)
    at com.google.cloud.tools.jib.registry.RegistryClient.pullManifest (RegistryClient.java:299)
    at com.google.cloud.tools.jib.registry.RegistryClient.pullManifest (RegistryClient.java:304)
    at com.google.cloud.tools.jib.builder.steps.PullBaseImageStep.pullBaseImage (PullBaseImageStep.java:212)
    at com.google.cloud.tools.jib.builder.steps.PullBaseImageStep.call (PullBaseImageStep.java:169)
    at com.google.cloud.tools.jib.builder.steps.PullBaseImageStep.call (PullBaseImageStep.java:60)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly (TrustedListenableFutureTask.java:125)
    at com.google.common.util.concurrent.InterruptibleTask.run (InterruptibleTask.java:69)
    at com.google.common.util.concurrent.TrustedListenableFutureTask.run (TrustedListenableFutureTask.java:78)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:624)
    at java.lang.Thread.run (Thread.java:748)
Caused by: com.google.api.client.http.HttpResponseException: 403 Forbidden
<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY>
An error occurred while processing your request.<p>
Reference&#32;&#35;199&#46;c5f7ef50&#46;1572258213&#46;23b79840
</BODY></HTML>

Steps to reproduce

mvn compile com.google.cloud.tools:jib-maven-plugin:build -Djib.from.image=registry.redhat.io/redhat-openjdk-18/openjdk18-openshift -Dimage=dabou/spring-boot-jib -Djib.from.auth.username=xxxxx -Djib.from.auth.password=yyyyy

Docker login

The command docker login -u xxxxx -p yyyyy registry.redhat.io works without issues as I can pull the image

docker login registry.redhat.io -u xxxxx -p yyyyy
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
docker pull registry.redhat.io/redhat-openjdk-18/openjdk18-openshift
Using default tag: latest
latest: Pulling from redhat-openjdk-18/openjdk18-openshift
Digest: sha256:873f79531ffa5b0783c0ffe6cdbdb05f1bcc0485d27b1aace16a9b062fc5bd77
Status: Image is up to date for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift:latest
registry.redhat.io/redhat-openjdk-18/openjdk18-openshift:latest
@chanseokoh
Copy link
Member

403 usually means you successfully authenticated with the server using your username and password but your account does not have sufficient permissions to do the operation. 401 is usually for failing to authenticate. And the log shows that the endpoint returns an HTML page, so another possibility is a typo in your image reference making Jib try a wrong endpoint on the server. A registry endpoint should return a proper registry error JSON for all kinds of errors including unauthorized or forbidden.

That said, this seems weird. Jib can use Docker credentials (.docker/config.json), so if Docker can push or pull, Jib should just work. To rule out the target registry, can you try jib: buildTar instead of jib:build?

@chanseokoh
Copy link
Member

Another thing to try is to pass a totally wrong password and see whether it returns 401 or 403.

@cmoulliard
Copy link
Author

Another thing to try is to pass a totally wrong password and see whether it returns

If the Password is wrong, then I get an error 401

@cmoulliard
Copy link
Author

cmoulliard commented Oct 28, 2019

I'm also getting an error 403 using buildTar

mvn compile com.google.cloud.tools:jib-maven-plugin:buildTar \
  -Djib.from.image=registry.redhat.io/redhat-openjdk-18/openjdk18-openshift \
  -Dimage=dabou/spring-boot-jib \
  -Djib.from.auth.username=$USERNAME \
  -Djib.from.auth.password=$PASSWORD

[ERROR] Failed to execute goal com.google.cloud.tools:jib-maven-plugin:1.7.0:buildTar (default-cli) 
on project hello: Building image tarball failed, perhaps you should make sure you have permissions 
for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift and set correct credentials. See 
https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-
the-registry-responds-with-forbidden-or-denied for help: Unauthorized for 
registry.redhat.io/redhat-openjdk-18/openjdk18-openshift: 403 Forbidden
[ERROR] <HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY>
[ERROR] An error occurred while processing your request.<p>
[ERROR] Reference&#32;&#35;199&#46;c5f7ef50&#46;1572278784&#46;2657f518
[ERROR] </BODY></HTML>
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

@cmoulliard
Copy link
Author

so another possibility is a typo in your image reference

Reference of the image is correct: https://access.redhat.com/containers/?tab=images#/registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift

$ docker login registry.redhat.io
Username: ${REGISTRY-SERVICE-ACCOUNT-USERNAME}
Password: ${REGISTRY-SERVICE-ACCOUNT-PASSWORD}
Login Succeeded!

$ docker pull registry.redhat.io/redhat-openjdk-18/openjdk18-openshift

@chanseokoh
Copy link
Member

chanseokoh commented Oct 28, 2019

That makes sense. Since it returns 401 when the password is incorrect, I think it is that the server does not think your account has sufficient permissions. Make sure your account has correct roles and permissions.

@cmoulliard
Copy link
Author

Here is another test which is working using same credentials with docker

1) Wrong user
docker login registry.redhat.io -u cmoulliaaa
Password:
Error response from daemon: Get https://registry.redhat.io/v2/: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/articles/3399531
2) Good user
docker login registry.redhat.io -u cmoullia
Password:
Login Succeeded
docker pull registry.redhat.io/redhat-openjdk-18/openjdk18-openshift:latest
latest: Pulling from redhat-openjdk-18/openjdk18-openshift
Digest: sha256:873f79531ffa5b0783c0ffe6cdbdb05f1bcc0485d27b1aace16a9b062fc5bd77
Status: Image is up to date for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift:latest
registry.redhat.io/redhat-openjdk-18/openjdk18-openshift:latest

@cmoulliard
Copy link
Author

Question: How jib knows that it must auth the user against this registry in my case -> registry.redhat.io ?

@chanseokoh
Copy link
Member

chanseokoh commented Oct 28, 2019

Hmm... I actually suspect the server is malfunctioning. It returns 403 instead of 401, so if it were working correctly, it means you have successfully authenticated with the server but the server intentionally denies your request because you are not allowed to do the operation. If it were returning 401, then it would be certain that Jib failed to auth. But the response is not 401, so the auth must have been succeeded. But since you are using the same username and password, this doesn't make sense. Another reason I suspect server malfunction is the error message:

<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY>
An error occurred while processing your request.<p>
Reference&#32;&#35;199&#46;c5f7ef50&#46;1572258213&#46;23b79840
</BODY></HTML>

Although this isn't hard evidence, the message "an error occurred while processing your request" and the title "Error" don't really match with 403 (or even 401), and it almost seems like the server had an internal error and it just fell back to returning 403 in such a case. And the fact that it returns a human-readable HTML page is another reason I suspect it's the server malfunctioning.

So let's do this. We can actually check in more details how the communication between Jib and registry.redhat.io does. See #1986 (comment) and follow the instructions to capture low-level HTTP request/response traffic. It will also explain how Jib figures out if it should auth. While capturing the network traffic, don't forget to add -X as well to enable DEBUG output.

@cmoulliard
Copy link
Author

@chanseokoh
Copy link
Member

chanseokoh commented Oct 28, 2019

Yeah, actually, this is what I suspected. We've seen a very similar case with Red Hat Quay. It's basically that the server is not conforming to the HTTP standard. What's happening is that basically, your server returns OK with https://registry.redhat.io?foo=bar but it rejects (or malfunctions) with https://registry.redhat.io?foo=%62%61%72 even though the two URLs are equivalent and the server should handle them equally and correctly.

FYI, the auth had been successful well before Jib requested a manifest for pulling: the registry token auth workflow was already completed, and Jib got the auth token from the server. And there was a successful interaction with the server using the returned auth token. There is no problem with auth. It is just that, the registry fails to see that (so to speak) https://registry.redhat.io?foo=%62%61%72 is an acceptable URL equivalent to https://registry.redhat.io?foo=bar, hence returning 403.

For the similar Quay issue I mentioned earlier, the Red Hat devs told us that they would file a ticket to fix their non-conformant registry server. Likewise, I urge you to file a bug against Red Hat for your registry so that it conforms to the HTTP standard.

BTW, what is the actual registry implementation behind registry.redhat.io you are using? I'd like to know so that I can respond to other users coming to us with the same issue in the future.

@cmoulliard
Copy link
Author

Many thanks for your help and quick reply/return :-)

@cmoulliard
Copy link
Author

cmoulliard commented Oct 29, 2019

@chanseokoh. We are in a deadlock See response hereafter from Red Hat

"The ticket is opened, but no solution has been found and, to be honest, won't likely be solved for a very long time. The reality is: the only good solution either requires Jib to fix their bad implementation (which they say they will not do) OR a new custom compilation of nginx on our end to add additional modules (which is a hard sell at this time), so I don't see any resolution coming for a while."

@chanseokoh
Copy link
Member

Yeah, I agree we are kind of in a deadlock. This doesn't look good.

(FTR, the thread is at https://groups.google.com/forum/#!topic/quay-sig/2y7tMP0h0g0)

I'll try to see if there is a way to turn off query string normalization in Google HTTP Client or Apache HttpClient.

@chanseokoh
Copy link
Member

chanseokoh commented Oct 29, 2019

I figured that it is Google HTTP Client (more specifically GenericUrl) on top of Apache HttpClient that escapes the unsafe query string values in URL. Google's HttpRequest.execute() builds a String URL and passes it to LowLevelHttpRequest.

      // build low-level HTTP request
      String urlString = url.build();
      LowLevelHttpRequest lowLevelHttpRequest = transport.buildRequest(requestMethod, urlString);

(I don't know if LowLevelHttpRequest might further transform query strings, but since it's passing a String, I hope it won't, but who knows if Apache will do something similar too?)

So, it is the GenericUrl.build() that produces a String value for the URL. It goes down the route build() --> buildRelativeUrl() --> addQueryParams() --> appendParam(), where it calls CharEscapers.escapeUriQuery().

    String stringValue = CharEscapers.escapeUriQuery(value.toString());
    if (stringValue.length() != 0) {
      buf.append('=').append(stringValue);
    }

So, for example, if we test the actual query string value causing this issue, we can see that it escapes the value and returns the exact same escaped value we can see in the actual Jib log.

    // Note this is the *value* itself. The entire query string including the key is "_auth_=exp=1572..."
    String originalQueryStringValue = "exp=1572285389~hmac=f0a387f...";
    System.out.println(originalQueryStringValue);
    System.out.println(CharEscapers.escapeUriQuery(originalQueryStringValue));

Output:

exp=1572285389~hmac=f0a387f...     --> OpenShift says OK
exp%3D1572285389~hmac%3Df0a387f... --> confuses OpenShift

So, OpenShift says OK to the first value but denies the second one even though they are just equivalent and an HTTP standard-conforming server should work fine on both.

Unfortunately, there is no option to turn this off in GenericUrl.

@chanseokoh
Copy link
Member

chanseokoh commented Oct 29, 2019

I don't know if LowLevelHttpRequest might further transform query strings, but since it's passing a String, I hope it won't, but who knows if Apache will do something similar too?

We could ask Google HTTP Client if they can add an option to disable query string escaping, but I think we should first verify Apache doesn't do escaping either. I feel like it is quite possible that they may escape query strings anyways.

@chanseokoh
Copy link
Member

chanseokoh commented Oct 29, 2019

So this is very much a duplicate of the 401 errors in #1986 (but the #1986 issue is wider in that it includes random 500 internal server errors).

However, I've noticed one difference between this 403 issue and 401 in #1986. For the 401 issue, it is the unescaping of the query string that confuses Quay, whereas here it is the query string escaping. And worse, I realized unescaping is being done at a different place where GenericUrl first parses the given URL instance. So, if there were to be an option to disable escaping in GenericUrl, it should also disable unescaping during initial parsing. (And not sure if such an option makes sense at all or is safe to include in the API.)

But even so, it is still possible that Apache may do something similar.

@iocanel
Copy link

iocanel commented Nov 20, 2019

This pull request: googleapis/google-http-java-client#871 solves the issue. I tested it and it works fine.

Currently, the PR has been approved and is waiting for a merge!

@cmoulliard
Copy link
Author

Can you help @iocanel to approve/merge the PR please @chanseokoh ?

@cmoulliard
Copy link
Author

When is it scheduled to release v1.9.0 including those fixes ? @chanseokoh

@chanseokoh
Copy link
Member

@cmoulliard it's likely next year. But it won't get too late.

@chanseokoh chanseokoh added this to the v2.0.0 milestone Jan 29, 2020
@chanseokoh
Copy link
Member

@cmoulliard 2.0.0 is released, and I expect Jib will work fine with registry.redhat.io (as well as Quay).

@cmoulliard
Copy link
Author

I did a test and that works

[INFO] Containerizing application to quay.io/cmoulliard/hello-sb...
[WARNING] Base image 'registry.redhat.io/redhat-openjdk-18/openjdk18-openshift' does not use a specific image digest - build may not be reproducible
[INFO] Using credentials from Docker config (/Users/dabou/.docker/config.json) for quay.io/cmoulliard/hello-sb
[INFO] The base image requires auth. Trying again for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift...
[INFO] Using credentials from <from><auth> for registry.redhat.io/redhat-openjdk-18/openjdk18-openshift
[INFO] Using base image with digest: sha256:9dab23924157b0c588f738c97b2a1f434315175b0be4156e1877028fa44360a8
[INFO] Executing tasks:
[INFO] [================              ] 53,6% complete
[INFO] > launching layer pushers
[INFO] > pulling base image layer sha256:00f17e0b37b05...

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