4141import com .google .api .client .json .GenericJson ;
4242import com .google .api .client .json .JsonParser ;
4343import com .google .common .annotations .VisibleForTesting ;
44+ import com .google .common .collect .ImmutableList ;
4445import java .io .IOException ;
4546import java .io .UnsupportedEncodingException ;
4647import java .net .MalformedURLException ;
6263 */
6364public class AwsCredentials extends ExternalAccountCredentials {
6465
66+ // Supported environment variables.
67+ static final String AWS_REGION = "AWS_REGION" ;
68+ static final String AWS_DEFAULT_REGION = "AWS_DEFAULT_REGION" ;
69+ static final String AWS_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID" ;
70+ static final String AWS_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY" ;
71+ static final String AWS_SESSION_TOKEN = "AWS_SESSION_TOKEN" ;
72+
6573 static final String AWS_IMDSV2_SESSION_TOKEN_HEADER = "x-aws-ec2-metadata-token" ;
6674 static final String AWS_IMDSV2_SESSION_TOKEN_TTL_HEADER = "x-aws-ec2-metadata-token-ttl-seconds" ;
6775 static final String AWS_IMDSV2_SESSION_TOKEN_TTL = "300" ;
@@ -181,7 +189,10 @@ public AccessToken refreshAccessToken() throws IOException {
181189
182190 @ Override
183191 public String retrieveSubjectToken () throws IOException {
184- Map <String , Object > metadataRequestHeaders = createMetadataRequestHeaders (awsCredentialSource );
192+ Map <String , Object > metadataRequestHeaders = new HashMap <>();
193+ if (shouldUseMetadataServer ()) {
194+ metadataRequestHeaders = createMetadataRequestHeaders (awsCredentialSource );
195+ }
185196
186197 // The targeted region is required to generate the signed request. The regional
187198 // endpoint must also be used.
@@ -266,6 +277,39 @@ private String buildSubjectToken(AwsRequestSignature signature)
266277 return URLEncoder .encode (token .toString (), "UTF-8" );
267278 }
268279
280+ private boolean canRetrieveRegionFromEnvironment () {
281+ // The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. Only one is
282+ // required.
283+ List <String > keys = ImmutableList .of (AWS_REGION , AWS_DEFAULT_REGION );
284+ for (String env : keys ) {
285+ String value = getEnvironmentProvider ().getEnv (env );
286+ if (value != null && value .trim ().length () > 0 ) {
287+ // Region available.
288+ return true ;
289+ }
290+ }
291+ return false ;
292+ }
293+
294+ private boolean canRetrieveSecurityCredentialsFromEnvironment () {
295+ // Check if both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are available.
296+ List <String > keys = ImmutableList .of (AWS_ACCESS_KEY_ID , AWS_SECRET_ACCESS_KEY );
297+ for (String env : keys ) {
298+ String value = getEnvironmentProvider ().getEnv (env );
299+ if (value == null || value .trim ().length () == 0 ) {
300+ // Return false if one of them are missing.
301+ return false ;
302+ }
303+ }
304+ return true ;
305+ }
306+
307+ @ VisibleForTesting
308+ boolean shouldUseMetadataServer () {
309+ return !canRetrieveRegionFromEnvironment () || !canRetrieveSecurityCredentialsFromEnvironment ();
310+ }
311+
312+ @ VisibleForTesting
269313 Map <String , Object > createMetadataRequestHeaders (AwsCredentialSource awsCredentialSource )
270314 throws IOException {
271315 Map <String , Object > metadataRequestHeaders = new HashMap <>();
@@ -302,15 +346,14 @@ Map<String, Object> createMetadataRequestHeaders(AwsCredentialSource awsCredenti
302346
303347 @ VisibleForTesting
304348 String getAwsRegion (Map <String , Object > metadataRequestHeaders ) throws IOException {
305- // For AWS Lambda, the region is retrieved through the AWS_REGION environment variable.
306- String region = getEnvironmentProvider ().getEnv ("AWS_REGION" );
307- if (region != null ) {
308- return region ;
309- }
310-
311- String defaultRegion = getEnvironmentProvider ().getEnv ("AWS_DEFAULT_REGION" );
312- if (defaultRegion != null ) {
313- return defaultRegion ;
349+ String region ;
350+ if (canRetrieveRegionFromEnvironment ()) {
351+ // For AWS Lambda, the region is retrieved through the AWS_REGION environment variable.
352+ region = getEnvironmentProvider ().getEnv (AWS_REGION );
353+ if (region != null && region .trim ().length () > 0 ) {
354+ return region ;
355+ }
356+ return getEnvironmentProvider ().getEnv (AWS_DEFAULT_REGION );
314357 }
315358
316359 if (awsCredentialSource .regionUrl == null || awsCredentialSource .regionUrl .isEmpty ()) {
@@ -329,10 +372,10 @@ String getAwsRegion(Map<String, Object> metadataRequestHeaders) throws IOExcepti
329372 AwsSecurityCredentials getAwsSecurityCredentials (Map <String , Object > metadataRequestHeaders )
330373 throws IOException {
331374 // Check environment variables for credentials first.
332- String accessKeyId = getEnvironmentProvider (). getEnv ( "AWS_ACCESS_KEY_ID" );
333- String secretAccessKey = getEnvironmentProvider ().getEnv ("AWS_SECRET_ACCESS_KEY" );
334- String token = getEnvironmentProvider ().getEnv ("AWS_SESSION_TOKEN" );
335- if ( accessKeyId != null && secretAccessKey != null ) {
375+ if ( canRetrieveSecurityCredentialsFromEnvironment ()) {
376+ String accessKeyId = getEnvironmentProvider ().getEnv (AWS_ACCESS_KEY_ID );
377+ String secretAccessKey = getEnvironmentProvider ().getEnv (AWS_SECRET_ACCESS_KEY );
378+ String token = getEnvironmentProvider (). getEnv ( AWS_SESSION_TOKEN );
336379 return new AwsSecurityCredentials (accessKeyId , secretAccessKey , token );
337380 }
338381
@@ -355,9 +398,9 @@ AwsSecurityCredentials getAwsSecurityCredentials(Map<String, Object> metadataReq
355398 JsonParser parser = OAuth2Utils .JSON_FACTORY .createJsonParser (awsCredentials );
356399 GenericJson genericJson = parser .parseAndClose (GenericJson .class );
357400
358- accessKeyId = (String ) genericJson .get ("AccessKeyId" );
359- secretAccessKey = (String ) genericJson .get ("SecretAccessKey" );
360- token = (String ) genericJson .get ("Token" );
401+ String accessKeyId = (String ) genericJson .get ("AccessKeyId" );
402+ String secretAccessKey = (String ) genericJson .get ("SecretAccessKey" );
403+ String token = (String ) genericJson .get ("Token" );
361404
362405 // These credentials last for a few hours - we may consider caching these in the
363406 // future.
0 commit comments