Accessing Instance Metadata

Google Cloud Platform provides a metadata server that knows details about your App Engine instance, such as its containing project ID, service accounts, and tokens used by the service accounts. You can access this data using simple HTTP requests: no client libraries are required.

This page shows how to access instance metadata from your deployed Java 8 runtime application by making HTTP calls to the appropriate metadata server endpoints.

One useful way to use this API is to get the service account token and supply it as a bearer token in the Authorization header of one of the Google Cloud APIs, to authenticate your application to that particular API service. See the Google Cloud Translation API documentation for an example of how these bearer tokens are used.

The following table lists the endpoints where you can make HTTP requests for specific metadata. The metadata server is accessible at http://metadata.google.internal .

Metadata endpoint Description
/computeMetadata/v1/project/numeric-project-id The project number assigned to your project.
/computeMetadata/v1/project/project-id The project ID assigned to your project.
/computeMetadata/v1/instance/zone The zone the instance is running in.
/computeMetadata/v1/instance/service-accounts/default/aliases
/computeMetadata/v1/instance/service-accounts/default/email The default service account email assigned to your project.
/computeMetadata/v1/instance/service-accounts/default/ Lists all the default service accounts for your project.
/computeMetadata/v1/instance/service-accounts/default/scopes Lists all the supported scopes for the default service accounts.
/computeMetadata/v1/instance/service-accounts/default/token Returns the auth token that can be used to authenticate your application to other Google Cloud APIs.

For example, to retrieve your project ID, send a request to http://metadata.google.internal/computeMetadata/v1/project/project-id .

The following sample code gets all of the metadata available for the instance and displays it, except for the service account token.

  @SuppressWarnings 
 ( 
 "serial" 
 ) 
 // With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required. 
 @WebServlet 
 ( 
 name 
  
 = 
  
 "Metadata" 
 , 
  
 description 
  
 = 
  
 "Metadata: Write info about GAE Standard" 
 , 
  
 urlPatterns 
  
 = 
  
 "/metadata" 
 ) 
 public 
  
 class 
 MetadataServlet 
  
 extends 
  
 HttpServlet 
  
 { 
  
 private 
  
 final 
  
 String 
 [] 
  
 metaPath 
  
 = 
  
 { 
  
 "/computeMetadata/v1/project/numeric-project-id" 
 , 
  
 //  (pending) 
  
 "/computeMetadata/v1/project/project-id" 
 , 
  
 "/computeMetadata/v1/instance/zone" 
 , 
  
 "/computeMetadata/v1/instance/service-accounts/default/aliases" 
 , 
  
 "/computeMetadata/v1/instance/service-accounts/default/email" 
 , 
  
 "/computeMetadata/v1/instance/service-accounts/default/" 
 , 
  
 "/computeMetadata/v1/instance/service-accounts/default/scopes" 
 , 
  
 // Tokens work - but are a security risk to display 
  
 //      "/computeMetadata/v1/instance/service-accounts/default/token" 
  
 }; 
  
 final 
  
 String 
 [] 
  
 metaServiceAcct 
  
 = 
  
 { 
  
 "/computeMetadata/v1/instance/service-accounts/{account}/aliases" 
 , 
  
 "/computeMetadata/v1/instance/service-accounts/{account}/email" 
 , 
  
 "/computeMetadata/v1/instance/service-accounts/{account}/scopes" 
 , 
  
 // Tokens work - but are a security risk to display 
  
 //     "/computeMetadata/v1/instance/service-accounts/{account}/token" 
  
 }; 
  
 private 
  
 final 
  
 String 
  
 metadata 
  
 = 
  
 "http://metadata.google.internal" 
 ; 
  
 private 
  
 TemplateEngine 
  
 templateEngine 
 ; 
  
 // Use OkHttp from Square as it's quite easy to use for simple fetches. 
  
 private 
  
 final 
  
 OkHttpClient 
  
 ok 
  
 = 
  
 new 
  
 OkHttpClient 
 . 
 Builder 
 () 
  
 . 
 readTimeout 
 ( 
 500 
 , 
  
 TimeUnit 
 . 
 MILLISECONDS 
 ) 
  
 // Don't dawdle 
  
 . 
 writeTimeout 
 ( 
 500 
 , 
  
 TimeUnit 
 . 
 MILLISECONDS 
 ) 
  
 . 
 build 
 (); 
  
 // Setup to pretty print returned json 
  
 private 
  
 final 
  
 Gson 
  
 gson 
  
 = 
  
 new 
  
 GsonBuilder 
 () 
  
 . 
 setPrettyPrinting 
 () 
  
 . 
 create 
 (); 
  
 private 
  
 final 
  
 JsonParser 
  
 jp 
  
 = 
  
 new 
  
 JsonParser 
 (); 
  
 // Fetch Metadata 
  
 String 
  
 fetchMetadata 
 ( 
 String 
  
 key 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 Request 
  
 request 
  
 = 
  
 new 
  
 Request 
 . 
 Builder 
 () 
  
 . 
 url 
 ( 
 metadata 
  
 + 
  
 key 
 ) 
  
 . 
 addHeader 
 ( 
 "Metadata-Flavor" 
 , 
  
 "Google" 
 ) 
  
 . 
 get 
 () 
  
 . 
 build 
 (); 
  
 Response 
  
 response 
  
 = 
  
 ok 
 . 
 newCall 
 ( 
 request 
 ). 
 execute 
 (); 
  
 return 
  
 response 
 . 
 body 
 (). 
 string 
 (); 
  
 } 
  
 String 
  
 fetchJsonMetadata 
 ( 
 String 
  
 prefix 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 Request 
  
 request 
  
 = 
  
 new 
  
 Request 
 . 
 Builder 
 () 
  
 . 
 url 
 ( 
 metadata 
  
 + 
  
 prefix 
 ) 
  
 . 
 addHeader 
 ( 
 "Metadata-Flavor" 
 , 
  
 "Google" 
 ) 
  
 . 
 get 
 () 
  
 . 
 build 
 (); 
  
 Response 
  
 response 
  
 = 
  
 ok 
 . 
 newCall 
 ( 
 request 
 ). 
 execute 
 (); 
  
 // Convert json to prety json 
  
 return 
  
 gson 
 . 
 toJson 
 ( 
 jp 
 . 
 parse 
 ( 
 response 
 . 
 body 
 (). 
 string 
 ())); 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 init 
 () 
  
 { 
  
 // Setup ThymeLeaf 
  
 ServletContextTemplateResolver 
  
 templateResolver 
  
 = 
  
 new 
  
 ServletContextTemplateResolver 
 ( 
 this 
 . 
 getServletContext 
 ()); 
  
 templateResolver 
 . 
 setPrefix 
 ( 
 "/WEB-INF/templates/" 
 ); 
  
 templateResolver 
 . 
 setSuffix 
 ( 
 ".html" 
 ); 
  
 templateResolver 
 . 
 setCacheTTLMs 
 ( 
 Long 
 . 
 valueOf 
 ( 
 1200000L 
 )); 
  
 // TTL=20m 
  
 // Cache is set to true by default. Set to false if you want templates to 
  
 // be automatically updated when modified. 
  
 templateResolver 
 . 
 setCacheable 
 ( 
 true 
 ); 
  
 templateEngine 
  
 = 
  
 new 
  
 TemplateEngine 
 (); 
  
 templateEngine 
 . 
 setTemplateResolver 
 ( 
 templateResolver 
 ); 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 doGet 
 ( 
 HttpServletRequest 
  
 req 
 , 
  
 HttpServletResponse 
  
 resp 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 String 
  
 defaultServiceAccount 
  
 = 
  
 "" 
 ; 
  
 WebContext 
  
 ctx 
  
 = 
  
 new 
  
 WebContext 
 ( 
 req 
 , 
  
 resp 
 , 
  
 getServletContext 
 (), 
  
 req 
 . 
 getLocale 
 ()); 
  
 resp 
 . 
 setContentType 
 ( 
 "text/html" 
 ); 
  
 String 
  
 environment 
  
 = 
  
 ( 
 String 
 ) 
  
 System 
 . 
 getProperties 
 (). 
 get 
 ( 
 "com.google.appengine.runtime.environment" 
 ); 
  
 ctx 
 . 
 setVariable 
 ( 
 "production" 
 , 
  
 environment 
 ); 
  
 // The metadata server is only on a production system 
  
 if 
  
 ( 
 environment 
 . 
 equals 
 ( 
 "Production" 
 )) 
  
 { 
  
 TreeMap<String 
 , 
  
 String 
>  
 m 
  
 = 
  
 new 
  
 TreeMap 
<> (); 
  
 for 
  
 ( 
 String 
  
 key 
  
 : 
  
 metaPath 
 ) 
  
 { 
  
 m 
 . 
 put 
 ( 
 key 
 , 
  
 fetchMetadata 
 ( 
 key 
 )); 
  
 if 
  
 ( 
 key 
 . 
 contains 
 ( 
 "default/email" 
 )) 
  
 { 
  
 defaultServiceAccount 
  
 = 
  
 m 
 . 
 get 
 ( 
 key 
 ); 
  
 } 
  
 } 
  
 ctx 
 . 
 setVariable 
 ( 
 "Metadata" 
 , 
  
 m 
 . 
 descendingMap 
 ()); 
  
 m 
  
 = 
  
 new 
  
 TreeMap 
<> (); 
  
 for 
  
 ( 
 String 
  
 key 
  
 : 
  
 metaServiceAcct 
 ) 
  
 { 
  
 // substitute a service account for {account} 
  
 key 
  
 = 
  
 key 
 . 
 replace 
 ( 
 "{account}" 
 , 
  
 defaultServiceAccount 
 ); 
  
 m 
 . 
 put 
 ( 
 key 
 , 
  
 fetchMetadata 
 ( 
 key 
 )); 
  
 } 
  
 ctx 
 . 
 setVariable 
 ( 
 "sam" 
 , 
  
 m 
 . 
 descendingMap 
 ()); 
  
 // Recursivly get all info about service accounts -- Note tokens are leftout by default. 
  
 ctx 
 . 
 setVariable 
 ( 
 "rsa" 
 , 
  
 fetchJsonMetadata 
 ( 
 "/computeMetadata/v1/instance/service-accounts/?recursive=true" 
 )); 
  
 // Recursivly get all data on Metadata server. 
  
 ctx 
 . 
 setVariable 
 ( 
 "ram" 
 , 
  
 fetchJsonMetadata 
 ( 
 "/?recursive=true" 
 )); 
  
 } 
  
 templateEngine 
 . 
 process 
 ( 
 "index" 
 , 
  
 ctx 
 , 
  
 resp 
 . 
 getWriter 
 ()); 
  
 } 
 } 
 

In the sample code, notice the check to make sure the app is running in production. If the app is running locally, no metadata will be returned from the requests.

Also, notice the use of the Google Gson JSON serializer / deserializer, the OkHttp HTTP and HTTP2 client, and the Thymeleaf templating system. These are not required, but they are useful libraries for your own projects.

Running locally

The metadata server is available for deployed applications: running locally on the development server is not supported. You can add an environment check to your code to expect metadata results only if the app is running in production, as shown in the sample code provided above:

  String 
  
 environment 
  
 = 
  
 ( 
 String 
 ) 
  
 System 
 . 
 getProperties 
 (). 
 get 
 ( 
 "com.google.appengine.runtime.environment" 
 ); 
  
 ctx 
 . 
 setVariable 
 ( 
 "production" 
 , 
  
 environment 
 ); 
  
 // The metadata server is only on a production system 
  
 if 
  
 ( 
 environment 
 . 
 equals 
 ( 
 "Production" 
 )) 
  
 { 
  
 ... 
  
 //show metadata results 
  
 } 
 
Design a Mobile Site
View Site in Mobile | Classic
Share by: