1
15
16 package software.amazon.awssdk.auth.credentials;
17
18 import java.io.IOException;
19 import java.net.URI;
20 import java.util.HashMap;
21 import java.util.Map;
22 import software.amazon.awssdk.annotations.SdkPublicApi;
23 import software.amazon.awssdk.core.SdkSystemSetting;
24 import software.amazon.awssdk.core.exception.SdkClientException;
25 import software.amazon.awssdk.core.internal.util.UserAgentUtils;
26 import software.amazon.awssdk.regions.internal.util.EC2MetadataUtils;
27 import software.amazon.awssdk.regions.util.HttpResourcesUtils;
28 import software.amazon.awssdk.regions.util.ResourcesEndpointProvider;
29 import software.amazon.awssdk.utils.ToString;
30
31
38 @SdkPublicApi
39 public final class InstanceProfileCredentialsProvider extends HttpCredentialsProvider {
40 private static final String EC2_METADATA_TOKEN_HEADER = "x-aws-ec2-metadata-token";
41
42 private static final String SECURITY_CREDENTIALS_RESOURCE = "/latest/meta-data/iam/security-credentials/";
43
44
47 private InstanceProfileCredentialsProvider(BuilderImpl builder) {
48 super(builder);
49 }
50
51
54 public static Builder builder() {
55 return new BuilderImpl();
56 }
57
58
63 public static InstanceProfileCredentialsProvider create() {
64 return builder().build();
65 }
66
67 @Override
68 protected ResourcesEndpointProvider getCredentialsEndpointProvider() {
69 return new InstanceProviderCredentialsEndpointProvider(getToken());
70 }
71
72 @Override
73 protected boolean isLocalCredentialLoadingDisabled() {
74 return SdkSystemSetting.AWS_EC2_METADATA_DISABLED.getBooleanValueOrThrow();
75 }
76
77 @Override
78 public String toString() {
79 return ToString.create("InstanceProfileCredentialsProvider");
80 }
81
82 private String getToken() {
83 return EC2MetadataUtils.getToken();
84 }
85
86 private static ResourcesEndpointProvider includeTokenHeader(ResourcesEndpointProvider provider, String token) {
87 return new ResourcesEndpointProvider() {
88 @Override
89 public URI endpoint() throws IOException {
90 return provider.endpoint();
91 }
92
93 @Override
94 public Map<String, String> headers() {
95 Map<String, String> headers = new HashMap<>(provider.headers());
96 headers.put(EC2_METADATA_TOKEN_HEADER, token);
97 return headers;
98 }
99 };
100 }
101
102 private static final class InstanceProviderCredentialsEndpointProvider implements ResourcesEndpointProvider {
103 private final String metadataToken;
104
105 private InstanceProviderCredentialsEndpointProvider(String metadataToken) {
106 this.metadataToken = metadataToken;
107 }
108
109 @Override
110 public URI endpoint() throws IOException {
111 String host = SdkSystemSetting.AWS_EC2_METADATA_SERVICE_ENDPOINT.getStringValueOrThrow();
112
113 URI endpoint = URI.create(host + SECURITY_CREDENTIALS_RESOURCE);
114 ResourcesEndpointProvider endpointProvider = () -> endpoint;
115
116 if (metadataToken != null) {
117 endpointProvider = includeTokenHeader(endpointProvider, metadataToken);
118 }
119
120 String securityCredentialsList = HttpResourcesUtils.instance().readResource(endpointProvider);
121 String[] securityCredentials = securityCredentialsList.trim().split("\n");
122
123 if (securityCredentials.length == 0) {
124 throw SdkClientException.builder().message("Unable to load credentials path").build();
125 }
126
127 return URI.create(host + SECURITY_CREDENTIALS_RESOURCE + securityCredentials[0]);
128 }
129
130 @Override
131 public Map<String, String> headers() {
132 Map<String, String> requestHeaders = new HashMap<>();
133 requestHeaders.put("User-Agent", UserAgentUtils.getUserAgent());
134 requestHeaders.put("Accept", "*);
135 requestHeaders.put("Connection", "keep-alive");
136
137 if (metadataToken != null) {
138 requestHeaders.put(EC2_METADATA_TOKEN_HEADER, metadataToken);
139 }
140
141 return requestHeaders;
142 }
143 }
144
145
146 /**
147 * A builder for creating a custom a {@link InstanceProfileCredentialsProvider}.
148 */
149 public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfileCredentialsProvider, Builder> {
150
151
154 @Override
155 InstanceProfileCredentialsProvider build();
156 }
157
158 private static final class BuilderImpl
159 extends HttpCredentialsProvider.BuilderImpl<InstanceProfileCredentialsProvider, Builder>
160 implements Builder {
161
162 private BuilderImpl() {
163 super.asyncThreadName("instance-profile-credentials-provider");
164 }
165
166 @Override
167 public InstanceProfileCredentialsProvider build() {
168 return new InstanceProfileCredentialsProvider(this);
169 }
170 }
171 }
172