Skip to content

Commit bb94d10

Browse files
authored
[Identity] Add support for Bridge to Kubernetes to ManagedIdentityCredential (Azure#22584)
* Add IMDS override for Bridge to K8s * Add to change log
1 parent 1daae94 commit bb94d10

File tree

5 files changed

+49
-8
lines changed

5 files changed

+49
-8
lines changed

sdk/core/azure-core/src/main/java/com/azure/core/util/Configuration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ public class Configuration implements Cloneable {
8989
public static final String PROPERTY_AZURE_IDENTITY_DISABLE_CP1 = "AZURE_IDENTITY_DISABLE_CP1";
9090

9191
/**
92+
* URL used by Bridge To Kubernetes to redirect IMDS calls in the development environment.
93+
*/
94+
public static final String PROPERTY_AZURE_POD_IDENTITY_TOKEN_URL = "AZURE_POD_IDENTITY_TOKEN_URL";
95+
96+
/*
9297
* Name of Azure AAD regional authority.
9398
*/
9499
public static final String PROPERTY_AZURE_REGIONAL_AUTHORITY_NAME = "AZURE_REGIONAL_AUTHORITY_NAME";

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 1.4.0-beta.1 (Unreleased)
44
### Features Added
55

6+
- Added support to `ManagedIdentityCredential` for Bridge to Kubernetes local development authentication.
67
- Added regional STS support to client credential types.
78
- Added the `RegionalAuthority` type, that allows specifying Azure regions.
89
- Added `regionalAuthority()` setter to `ClientSecretCredentialBuilder` and `ClientCertificateCredentialBuilder`.

sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/IdentityClient.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.azure.core.http.policy.HttpPipelinePolicy;
1616
import com.azure.core.http.policy.HttpPolicyProviders;
1717
import com.azure.core.http.policy.RetryPolicy;
18+
import com.azure.core.util.Configuration;
1819
import com.azure.core.util.CoreUtils;
1920
import com.azure.core.util.logging.ClientLogger;
2021
import com.azure.core.util.serializer.JacksonAdapter;
@@ -25,6 +26,7 @@
2526
import com.azure.identity.RegionalAuthority;
2627
import com.azure.identity.TokenCachePersistenceOptions;
2728
import com.azure.identity.implementation.util.CertificateUtil;
29+
import com.azure.identity.implementation.util.IdentityConstants;
2830
import com.azure.identity.implementation.util.IdentitySslUtil;
2931
import com.azure.identity.implementation.util.ScopeUtil;
3032
import com.fasterxml.jackson.databind.JsonNode;
@@ -1114,15 +1116,18 @@ public Mono<AccessToken> authenticateToIMDSEndpoint(TokenRequestContext request)
11141116
return Mono.error(exception);
11151117
}
11161118

1117-
return checkIMDSAvailable().flatMap(available -> Mono.fromCallable(() -> {
1119+
String endpoint = Configuration.getGlobalConfiguration().get(
1120+
Configuration.PROPERTY_AZURE_POD_IDENTITY_TOKEN_URL,
1121+
IdentityConstants.DEFAULT_IMDS_ENDPOINT);
1122+
1123+
return checkIMDSAvailable(endpoint).flatMap(available -> Mono.fromCallable(() -> {
11181124
int retry = 1;
11191125
while (retry <= options.getMaxRetry()) {
11201126
URL url = null;
11211127
HttpURLConnection connection = null;
11221128
try {
11231129
url =
1124-
new URL(String.format("http://169.254.169.254/metadata/identity/oauth2/token?%s",
1125-
payload.toString()));
1130+
new URL(String.format("%s?%s", endpoint, payload.toString()));
11261131

11271132
connection = (HttpURLConnection) url.openConnection();
11281133
connection.setRequestMethod("GET");
@@ -1189,7 +1194,7 @@ public Mono<AccessToken> authenticateToIMDSEndpoint(TokenRequestContext request)
11891194
}));
11901195
}
11911196

1192-
private Mono<Boolean> checkIMDSAvailable() {
1197+
private Mono<Boolean> checkIMDSAvailable(String endpoint) {
11931198
StringBuilder payload = new StringBuilder();
11941199

11951200
try {
@@ -1200,8 +1205,7 @@ private Mono<Boolean> checkIMDSAvailable() {
12001205
}
12011206
return Mono.fromCallable(() -> {
12021207
HttpURLConnection connection = null;
1203-
URL url = new URL(String.format("http://169.254.169.254/metadata/identity/oauth2/token?%s",
1204-
payload.toString()));
1208+
URL url = new URL(String.format("%s?%s", endpoint, payload.toString()));
12051209

12061210
try {
12071211
connection = (HttpURLConnection) url.openConnection();

sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/IdentityConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@ public class IdentityConstants {
88
* The Single Sign On ID.
99
*/
1010
public static final String DEVELOPER_SINGLE_SIGN_ON_ID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46";
11+
12+
/**
13+
* The default IMDS authentication endpoint.
14+
*/
15+
public static final String DEFAULT_IMDS_ENDPOINT = "http://169.254.169.254/metadata/identity/oauth2/token";
1116
}

sdk/identity/azure-identity/src/test/java/com/azure/identity/implementation/IdentityClientTests.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.azure.core.util.Configuration;
1010
import com.azure.core.util.logging.ClientLogger;
1111
import com.azure.identity.implementation.util.CertificateUtil;
12+
import com.azure.identity.implementation.util.IdentityConstants;
1213
import com.azure.identity.util.TestUtils;
1314
import com.microsoft.aad.msal4j.AuthorizationCodeParameters;
1415
import com.microsoft.aad.msal4j.ClientCredentialFactory;
@@ -306,7 +307,31 @@ public void testValidIMDSCodeFlow() throws Exception {
306307

307308

308309
// mock
309-
mockForIMDSCodeFlow(tokenJson);
310+
mockForIMDSCodeFlow(IdentityConstants.DEFAULT_IMDS_ENDPOINT, tokenJson);
311+
312+
// mockForDeviceCodeFlow(request, accessToken, expiresOn);
313+
314+
// test
315+
IdentityClient client = new IdentityClientBuilder().build();
316+
AccessToken token = client.authenticateToIMDSEndpoint(request).block();
317+
Assert.assertEquals("token1", token.getToken());
318+
Assert.assertEquals(expiresOn.getSecond(), token.getExpiresAt().getSecond());
319+
}
320+
321+
@Test
322+
public void testCustomIMDSCodeFlow() throws Exception {
323+
// setup
324+
Configuration configuration = Configuration.getGlobalConfiguration();
325+
String endpoint = "http://awesome.pod.url";
326+
TokenRequestContext request = new TokenRequestContext().addScopes("https://management.azure.com");
327+
OffsetDateTime expiresOn = OffsetDateTime.now(ZoneOffset.UTC).plusHours(1);
328+
configuration.put(Configuration.PROPERTY_AZURE_POD_IDENTITY_TOKEN_URL, endpoint);
329+
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/yyyy H:mm:ss XXX");
330+
String tokenJson = "{ \"access_token\" : \"token1\", \"expires_on\" : \"" + expiresOn.format(dtf) + "\" }";
331+
332+
333+
// mock
334+
mockForIMDSCodeFlow(endpoint, tokenJson);
310335

311336
// mockForDeviceCodeFlow(request, accessToken, expiresOn);
312337

@@ -570,8 +595,9 @@ private void mockForArcCodeFlow(int responseCode) throws Exception {
570595
when(initConnection.getResponseCode()).thenReturn(responseCode);
571596
}
572597

573-
private void mockForIMDSCodeFlow(String tokenJson) throws Exception {
598+
private void mockForIMDSCodeFlow(String endpoint, String tokenJson) throws Exception {
574599
URL u = PowerMockito.mock(URL.class);
600+
whenNew(URL.class).withArguments(ArgumentMatchers.startsWith(endpoint)).thenReturn(u);
575601
whenNew(URL.class).withAnyArguments().thenReturn(u);
576602
HttpURLConnection huc = PowerMockito.mock(HttpURLConnection.class);
577603
when(u.openConnection()).thenReturn(huc);

0 commit comments

Comments
 (0)