[英]Google Cloud Storage API cannot get Application Default Credentials on App Engine looking for Compute Engine error
I have custom code using the Google Cloud Storage API library in a Play (v2.5.12) application running on the Google App Engine, not the Compute Engine. 我在Google App Engine而非Compute Engine上运行的Play(v2.5.12)应用程序中使用Google Cloud Storage API库获得了自定义代码。 The Cloud Storage API is enabled.
启用了Cloud Storage API。 I am trying to send a file (as a file stream) to a storage bucket in the Google Cloud Platform.
我正在尝试将文件(作为文件流)发送到Google Cloud Platform中的存储桶。
Here is the code: 这是代码:
public static String sendFileToBucket(InputStream fileStream, String fileName) throws IOException {
Logger.info("GoogleStorage: sendFileToBucket: Starting...");
Storage storage = StorageOptions.getDefaultInstance().getService();
// Modify access list to allow all users with link to read file
List<Acl> acls = new ArrayList<>();
acls.add(Acl.of(Acl.User.ofAllUsers(), Acl.Role.READER));
// the inputstream is closed by default, so we don't need to close it
// here
Blob blob = null;
blob = storage.create(BlobInfo.newBuilder(BUCKET_NAME, fileName).setAcl(acls).build(),
fileStream);
return blob.getMediaLink();
}
The code I wrote is using this example: 我编写的代码使用此示例:
https://cloud.google.com/appengine/docs/flexible/java/using-cloud-storage#application_code https://cloud.google.com/appengine/docs/flexible/java/using-cloud-storage#application_code
I am running into an error when I attempt to set the Storage
object: 尝试设置
Storage
对象时遇到错误:
Storage storage = StorageOptions.getDefaultInstance().getService();
Here is the full error: 这是完整的错误:
[warn] c.g.a.o.ComputeEngineCredentials - Failed to detect whether we are running on Google Compute Engine.
java.net.SocketException: Network is unreachable: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
[warn] c.g.a.o.ComputeEngineCredentials - Failed to detect whether we are running on Google Compute Engine.
java.net.SocketException: Network is unreachable: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
[warn] c.g.a.o.ComputeEngineCredentials - Failed to detect whether we are running on Google Compute Engine.
java.net.SocketException: Network is unreachable: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
com.google.cloud.storage.StorageException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.google.cloud.storage.spi.v1.HttpStorageRpc.translate(HttpStorageRpc.java:220)
at com.google.cloud.storage.spi.v1.HttpStorageRpc.create(HttpStorageRpc.java:291)
at com.google.cloud.storage.StorageImpl.create(StorageImpl.java:148)
at google.GoogleStorage.sendFileToBucket(GoogleStorage.java:80)
at controllers.AdultPTPController.adultPTPUpdateFields(AdultPTPController.java:3878)
at controllers.AdultPTPController.adultPTPUpdate(AdultPTPController.java:3544)
at router.Routes$$anonfun$routes$1$$anonfun$applyOrElse$10$$anonfun$apply$10.apply(Routes.scala:2083)
at router.Routes$$anonfun$routes$1$$anonfun$applyOrElse$10$$anonfun$apply$10.apply(Routes.scala:2083)
at play.core.routing.HandlerInvokerFactory$$anon$4.resultCall(HandlerInvoker.scala:157)
at play.core.routing.HandlerInvokerFactory$$anon$4.resultCall(HandlerInvoker.scala:156)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$14$$anon$3$$anon$1.invocation(HandlerInvoker.scala:136)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:73)
at play.http.HttpRequestHandler$1.call(HttpRequestHandler.java:54)
at play.core.j.JavaAction$$anonfun$7.apply(JavaAction.scala:108)
at play.core.j.JavaAction$$anonfun$7.apply(JavaAction.scala:108)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:48)
at scala.concurrent.impl.Future$.apply(Future.scala:31)
at scala.concurrent.Future$.apply(Future.scala:492)
at play.core.j.JavaAction.apply(JavaAction.scala:108)
at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5$$anonfun$apply$6.apply(Action.scala:112)
at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5$$anonfun$apply$6.apply(Action.scala:112)
at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5.apply(Action.scala:111)
at play.api.mvc.Action$$anonfun$apply$2$$anonfun$apply$5.apply(Action.scala:110)
at scala.Option.map(Option.scala:146)
at play.api.mvc.Action$$anonfun$apply$2.apply(Action.scala:110)
at play.api.mvc.Action$$anonfun$apply$2.apply(Action.scala:103)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
at akka.dispatch.BatchingExecutor$BlockableBatch$$anonfun$run$1.apply$mcV$sp(BatchingExecutor.scala:91)
at akka.dispatch.BatchingExecutor$BlockableBatch$$anonfun$run$1.apply(BatchingExecutor.scala:91)
at akka.dispatch.BatchingExecutor$BlockableBatch$$anonfun$run$1.apply(BatchingExecutor.scala:91)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:72)
at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:90)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:415)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283)
at sun.net.www.protocol.http.HttpURLConnection.access$100(HttpURLConnection.java:90)
at sun.net.www.protocol.http.HttpURLConnection$8.run(HttpURLConnection.java:1250)
at sun.net.www.protocol.http.HttpURLConnection$8.run(HttpURLConnection.java:1248)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessController.doPrivilegedWithCombiner(AccessController.java:782)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1247)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:77)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:981)
at com.google.api.client.googleapis.media.MediaHttpUploader.executeCurrentRequestWithoutGZip(MediaHttpUploader.java:545)
at com.google.api.client.googleapis.media.MediaHttpUploader.executeCurrentRequest(MediaHttpUploader.java:562)
at com.google.api.client.googleapis.media.MediaHttpUploader.directUpload(MediaHttpUploader.java:360)
at com.google.api.client.googleapis.media.MediaHttpUploader.upload(MediaHttpUploader.java:334)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:428)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.google.cloud.storage.spi.v1.HttpStorageRpc.create(HttpStorageRpc.java:288)
... 44 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
... 71 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 77 more
That error confuses me since I am running the application on the Google App Engine, not the Compute Engine. 由于我在Google App Engine而不是Compute Engine上运行应用程序,因此该错误使我感到困惑。 I checked the Service Accounts, I only have the default App Engine account and a Service Account that I created for Google Drive Access.
我检查了服务帐户,但只有默认的App Engine帐户和为Google Drive访问创建的服务帐户。
I am using the Application Default Credentials as stated here: 我正在使用此处所述的应用程序默认凭据:
https://cloud.google.com/docs/authentication/production https://cloud.google.com/docs/authentication/production
The default App Engine Service Account does not have a key, but would creating a key and then try this code example: 默认的App Engine服务帐户没有密钥,但是会创建一个密钥,然后尝试以下代码示例:
Storage storage = StorageOptions.newBuilder()
.setCredentials(ServiceAccountCredentials.fromStream(new FileInputStream("/path/to/my/key.json")))
.build()
.getService();
from this page: 从此页面:
https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/README.md#authentication https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/README.md#authentication
fix my issue? 解决我的问题?
I found a few posts on this, but I cannot decipher how to implement in my code, so they aren't helping me: 我发现了一些关于此的文章,但是我无法解释如何在我的代码中实现,因此它们没有帮助我:
Default credential for app engine project accessing google cloud storage? 应用引擎项目访问Google云存储的默认凭据?
Providing Credentials to Google Cloud Storage API 向Google Cloud Storage API提供凭据
I appreciate the help. 感谢您的帮助。
------------------------- EDIT 3/23/2018 -------------------------------- -------------------------编辑3/23/2018 ------------------- -------------
After receiving the error: 收到错误后:
java.io.IOException: The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.
and following the link, it states on that page: 然后点击链接,在该页面上显示:
If your application runs on Compute Engine, Kubernetes Engine, the App Engine flexible environment, or Cloud Functions, you don't need to create your own service account.
but I am using the App Engine flex environment, which confuses me. 但是我正在使用App Engine flex环境,这使我感到困惑。
So, I went to the Google Cloud Project, selected IAM & Admin > Service Accounts and for the default App Engine service account, I created a key, downloaded, and changed my code to: 因此,我去了Google Cloud Project,选择了IAM&Admin>服务帐户,并为默认的App Engine服务帐户创建了一个密钥,下载并将代码更改为:
public static String sendFileToBucket(InputStream fileStream, String fileName) throws IOException {
Logger.info("GoogleStorage: sendFileToBucket: Starting...");
GoogleCredential credential = null;
String credentialsFileName = "";
Storage storage = null;
Logger.info("GoogleStorage: authorize: Getting credentialsFileName path...");
credentialsFileName = Configuration.root().getString("google.storage.credentials.file");
Logger.info("GoogleStorage: authorize: credentialsFileName = " + credentialsFileName);
Logger.info("GoogleStorage: authorize: Setting InputStream...");
InputStream in = GoogleStorage.class.getClassLoader().getResourceAsStream(credentialsFileName);
if (in == null) {
Logger.info("GoogleStorage: authorize: InputStream is null");
}
Logger.info("GoogleStorage: authorize: InputStream set...");
storage = StorageOptions.newBuilder()
.setCredentials(ServiceAccountCredentials.fromStream(in))
.build()
.getService();
// Modify access list to allow all users with link to read file
List<Acl> acls = new ArrayList<>();
acls.add(Acl.of(Acl.User.ofAllUsers(), Acl.Role.READER));
// the inputstream is closed by default, so we don't need to close it
// here
Blob blob = null;
blob = storage.create(BlobInfo.newBuilder(BUCKET_NAME, fileName).setAcl(acls).build(),
fileStream);
return blob.getMediaLink();
}
I do not receive the original error and it does build the Storage
object. 我没有收到原始错误,它确实建立了
Storage
对象。 However, when it attempts to build the Blob
object, I receive this error: 但是,当它尝试构建
Blob
对象时,我收到此错误:
[warn] c.g.a.c.h.HttpTransport - exception thrown while executing request
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
com.google.cloud.storage.StorageException: Error getting access token for service account:
...
Caused by: java.io.IOException: Error getting access token for service account:
...
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
which I see: 我看到的是:
com.google.cloud.storage.StorageException: Error getting access token for service account
So, I am guessing it is still something with the Service Account credentials. 因此,我猜想它仍然带有服务帐户凭据。
What about trying to get application default credentials directly? 尝试直接获取应用程序默认凭据怎么办?
Could you please try the following approach: 您能否尝试以下方法:
GoogleCredentials applicationDefault = GoogleCredentials.getApplicationDefault();
if (applicationDefault.createScopedRequired()){
applicationDefault = applicationDefault.createScoped(Collections.singleton("https://www.googleapis.com/auth/devstorage.full_control"));
}
final Storage storage = StorageOptions.newBuilder()
.setCredentials(applicationDefault)
.build()
.getService();
Also, are you using AppEngine standard or flexible? 另外,您使用的是AppEngine标准版还是弹性版?
I had faced similar issues with Compute Engine. 我在Compute Engine上也遇到过类似的问题。 Then, I used a static path on the environment to store all the properties required.
然后,我在环境上使用了静态路径来存储所需的所有属性。 This is my variables class:
这是我的变量类:
public class Variables(){
public Variables(){
if(!loaded)init();
}
final static Logger logger = Logger.getLogger(Variables.class);
static Properties prop = new Properties();
static InputStream input = null;
static boolean loaded = false;
private static void init(){
try{
logger.info("Loading properties for server . . . ");
//Do not change this path
input = new FileInputStream("/path-on-server/app-config.properties");
prop.load(input);
loaded = true;
}catch(Exception ex){
logger.error("Error while loading configuration file for server. . . ");
logger.error(ex.getMessage());
}
finally{
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static final String gcsClientId = getGCSClientId();
public static final String gcsClientEmail = getGCSClientEmail();
public static final String gcsPrivateKey = getGCSPrivateKey();
public static final String gcsPrivateKeyId = getGCSPrivateKeyId();
public static final String gcsProjectId = getGCSProjectId();
public static final String gcsBucketName = getGCSBucketName();
private static String getGCSClientId(){
if(!loaded)init();
return prop.getProperty("storageClientId");
}
private static String getGCSClientEmail(){
if(!loaded)init();
return prop.getProperty("storageClientEmail");
}
private static String getGCSPrivateKeyId(){
if(!loaded)init();
return prop.getProperty("storagePrivateKeyId");
}
private static String getGCSPrivateKey(){
if(!loaded)init();
return prop.getProperty("storagePrivateKey");
}
private static String getGCSProjectId(){
if(!loaded)init();
return prop.getProperty("storageProjectId");
}
private static String getGCSBucketName(){
if(!loaded)init();
return prop.getProperty("storageBucketName");
}
}
And then use the variables class in my Google Storage: 然后在我的Google Storage中使用变量类:
public class GoogleCloudStorage {
Variables variables = new Variables();
public GoogleCloudStorage() {
setDefaultStorageCredentials();
}
private static Storage storage = null;
private static String bucketName = null;
private static Credentials credentials = null;
private void setDefaultStorageCredentials() {
try {
this.bucketName = variables.gcsBucketName;
credentials = ServiceAccountCredentials.fromPkcs8(variables.gcsClientId, variables.gcsClientEmail,
variables.gcsPrivateKey, variables.gcsPrivateKeyId, null);
storage = StorageOptions.newBuilder()
.setCredentials(credentials)
.setProjectId(variables.gcsProjectId).build().getService();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hope this helps. 希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.