簡體   English   中英

Google Cloud Storage API無法在App Engine上獲取應用程序默認憑據,以查找Compute Engine錯誤

[英]Google Cloud Storage API cannot get Application Default Credentials on App Engine looking for Compute Engine error

我在Google App Engine而非Compute Engine上運行的Play(v2.5.12)應用程序中使用Google Cloud Storage API庫獲得了自定義代碼。 啟用了Cloud Storage API。 我正在嘗試將文件(作為文件流)發送到Google Cloud Platform中的存儲桶。

這是代碼:

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();

}

我編寫的代碼使用此示例:

https://cloud.google.com/appengine/docs/flexible/java/using-cloud-storage#application_code

嘗試設置Storage對象時遇到錯誤:

Storage storage = StorageOptions.getDefaultInstance().getService();

這是完整的錯誤:

 [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

由於我在Google App Engine而不是Compute Engine上運行應用程序,因此該錯誤使我感到困惑。 我檢查了服務帳戶,但只有默認的App Engine帳戶和為Google Drive訪問創建的服務帳戶。

我正在使用此處所述的應用程序默認憑據:

https://cloud.google.com/docs/authentication/production

默認的App Engine服務帳戶沒有密鑰,但是會創建一個密鑰,然后嘗試以下代碼示例:

Storage storage = StorageOptions.newBuilder()
    .setCredentials(ServiceAccountCredentials.fromStream(new FileInputStream("/path/to/my/key.json")))
    .build()
    .getService();

從此頁面:

https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/README.md#authentication

解決我的問題?

我發現了一些關於此的文章,但是我無法解釋如何在我的代碼中實現,因此它們沒有幫助我:

應用引擎項目訪問Google雲存儲的默認憑據?

向Google Cloud Storage API提供憑據

感謝您的幫助。

-------------------------編輯3/23/2018 ------------------- -------------

收到錯誤后:

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.

然后點擊鏈接,在該頁面上顯示:

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.

但是我正在使用App Engine flex環境,這使我感到困惑。

因此,我去了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();

}

我沒有收到原始錯誤,它確實建立了Storage對象。 但是,當它嘗試構建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
...

我看到的是:

com.google.cloud.storage.StorageException: Error getting access token for service account

因此,我猜想它仍然帶有服務帳戶憑據。

嘗試直接獲取應用程序默認憑據怎么辦?

您能否嘗試以下方法:

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();

另外,您使用的是AppEngine標准版還是彈性版?

我在Compute Engine上也遇到過類似的問題。 然后,我在環境上使用了靜態路徑來存儲所需的所有屬性。 這是我的變量類:

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");
    }
}

然后在我的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();
        }
    }
}

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM