1 /*
2  * Copyright 2011-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *    http://aws.amazon.com/apache2.0
9  *
10  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
11  * OR CONDITIONS OF ANY KIND, either express or implied. See the
12  * License for the specific language governing permissions and
13  * limitations under the License.
14  */

15 package com.amazonaws.auth;
16
17 import com.amazonaws.SdkClientException;
18 import com.amazonaws.internal.CredentialsEndpointProvider;
19 import com.amazonaws.retry.internal.CredentialsEndpointRetryPolicy;
20 import com.amazonaws.util.CollectionUtils;
21
22 import java.net.URI;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Map;
28 import java.util.Set;
29
30 /**
31  * <p>
32  * {@link AWSCredentialsProvider} implementation that loads credentials
33  * from an Amazon Elastic Container.
34  * </p>
35  * <p>
36  * By default, the URI path is retrieved from the environment variable
37  * "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" in the container's environment.
38  * </p>
39  */

40 public class ContainerCredentialsProvider implements AWSCredentialsProvider {
41
42     /** Environment variable to get the Amazon ECS credentials resource path. */
43     static final String ECS_CONTAINER_CREDENTIALS_PATH = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
44
45     /** Environment variable to get the full URI for a credentials path */
46     static final String CONTAINER_CREDENTIALS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
47
48     static final String CONTAINER_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
49
50     private static final Set<String> ALLOWED_FULL_URI_HOSTS = allowedHosts();
51
52     /** Default endpoint to retreive the Amazon ECS Credentials. */
53     private static final String ECS_CREDENTIALS_ENDPOINT = "http://169.254.170.2";
54
55     private final ContainerCredentialsFetcher credentialsFetcher;
56
57     /**
58      * @deprecated use {@link #ContainerCredentialsProvider(CredentialsEndpointProvider)}
59      */

60     @Deprecated
61     public ContainerCredentialsProvider() {
62         this(new ECSCredentialsEndpointProvider());
63     }
64
65     public ContainerCredentialsProvider(CredentialsEndpointProvider credentialsEndpointProvider) {
66         this.credentialsFetcher = new ContainerCredentialsFetcher(credentialsEndpointProvider);
67     }
68
69     @Override
70     public AWSCredentials getCredentials() {
71         return credentialsFetcher.getCredentials();
72     }
73
74     @Override
75     public void refresh() {
76         credentialsFetcher.refresh();
77     }
78
79     public Date getCredentialsExpiration() {
80         return credentialsFetcher.getCredentialsExpiration();
81     }
82
83
84     static class ECSCredentialsEndpointProvider extends CredentialsEndpointProvider {
85         @Override
86         public URI getCredentialsEndpoint() {
87             String path = System.getenv(ECS_CONTAINER_CREDENTIALS_PATH);
88             if (path == null) {
89                 throw new SdkClientException(
90                         "The environment variable " + ECS_CONTAINER_CREDENTIALS_PATH + " is empty");
91             }
92
93             return URI.create(ECS_CREDENTIALS_ENDPOINT + path);
94         }
95         @Override
96         public CredentialsEndpointRetryPolicy getRetryPolicy() {
97             return ContainerCredentialsRetryPolicy.getInstance();
98         }
99
100     }
101
102     /**
103      * A URI resolver that uses environment variable {@value CONTAINER_CREDENTIALS_FULL_URI} as the URI
104      * for the metadata service.
105      * Optionally an authorization token can be provided using the {@value CONTAINER_AUTHORIZATION_TOKEN} environment variable.
106      */

107     static class FullUriCredentialsEndpointProvider extends CredentialsEndpointProvider {
108
109         @Override
110         public URI getCredentialsEndpoint() {
111             String fullUri = System.getenv(CONTAINER_CREDENTIALS_FULL_URI);
112             if (fullUri == null || fullUri.length() == 0) {
113                 throw new SdkClientException("The environment variable " + CONTAINER_CREDENTIALS_FULL_URI + " is empty");
114             }
115
116             URI uri = URI.create(fullUri);
117
118             if (!ALLOWED_FULL_URI_HOSTS.contains(uri.getHost())) {
119                 throw new SdkClientException("The full URI (" + uri + ") contained withing environment variable " +
120                     CONTAINER_CREDENTIALS_FULL_URI + " has an invalid host. Host can only be one of [" +
121                     CollectionUtils.join(ALLOWED_FULL_URI_HOSTS, ", ") + "]");
122             }
123
124             return uri;
125         }
126
127         @Override
128         public Map<String, String> getHeaders() {
129             if (System.getenv(CONTAINER_AUTHORIZATION_TOKEN) != null) {
130                 return Collections.singletonMap("Authorization", System.getenv(CONTAINER_AUTHORIZATION_TOKEN));
131             }
132             return new HashMap<String, String>();
133         }
134     }
135
136     private static Set<String> allowedHosts() {
137         HashSet<String> hosts = new HashSet<String>();
138         hosts.add("127.0.0.1");
139         hosts.add("localhost");
140         return Collections.unmodifiableSet(hosts);
141     }
142
143 }
144