Skip to content

Commit c32f09c

Browse files
authored
End to End TLS SSL step #7 - Add support for user-assigned managed identity (Azure#17015)
1 parent 81db0c2 commit c32f09c

File tree

16 files changed

+148
-35
lines changed

16 files changed

+148
-35
lines changed

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/AuthClient.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33

44
package com.azure.security.keyvault.jca;
55

6-
import com.azure.security.keyvault.jca.rest.OAuthToken;
6+
import com.azure.security.keyvault.jca.model.OAuthToken;
77

88
import java.util.HashMap;
99
import java.util.logging.Logger;
1010

1111
import static java.util.logging.Level.FINER;
12+
import static java.util.logging.Level.INFO;
1213

1314
/**
1415
* The REST client specific to getting an access token for Azure REST APIs.
@@ -71,16 +72,17 @@ class AuthClient extends DelegateRestClient {
7172
* Get an access token for a managed identity.
7273
*
7374
* @param resource the resource.
75+
* @param identity the user-assigned identity (null if system-assigned)
7476
* @return the authorization token.
7577
*/
76-
public String getAccessToken(String resource) {
78+
public String getAccessToken(String resource, String identity) {
7779
String result;
7880

7981
if (System.getenv("WEBSITE_SITE_NAME") != null
8082
&& !System.getenv("WEBSITE_SITE_NAME").isEmpty()) {
81-
result = getAccessTokenOnAppService(resource);
83+
result = getAccessTokenOnAppService(resource, identity);
8284
} else {
83-
result = getAccessTokenOnOthers(resource);
85+
result = getAccessTokenOnOthers(resource, identity);
8486
}
8587
return result;
8688
}
@@ -126,17 +128,25 @@ public String getAccessToken(String resource, String tenantId,
126128
* Get the access token on Azure App Service.
127129
*
128130
* @param resource the resource.
131+
* @param identity the user-assigned identity (null if system-assigned).
129132
* @return the authorization token.
130133
*/
131-
private String getAccessTokenOnAppService(String resource) {
134+
private String getAccessTokenOnAppService(String resource, String identity) {
132135
LOGGER.entering("AuthClient", "getAccessTokenOnAppService", resource);
133136
LOGGER.info("Getting access token using managed identity based on MSI_SECRET");
137+
if (identity != null) {
138+
LOGGER.log(INFO, "Using managed identity with object ID: {0}", identity);
139+
}
134140
String result = null;
135141

136142
StringBuilder url = new StringBuilder();
137143
url.append(System.getenv("MSI_ENDPOINT"))
138144
.append("?api-version=2017-09-01")
139145
.append(RESOURCE_FRAGMENT).append(resource);
146+
147+
if (identity != null) {
148+
url.append("&objectid=").append(identity);
149+
}
140150

141151
HashMap<String, String> headers = new HashMap<>();
142152
headers.put("Metadata", "true");
@@ -156,16 +166,25 @@ private String getAccessTokenOnAppService(String resource) {
156166
* Get the authorization token on everything else but Azure App Service.
157167
*
158168
* @param resource the resource.
169+
* @param identity the user-assigned identity (null if system-assigned).
159170
* @return the authorization token.
160171
*/
161-
private String getAccessTokenOnOthers(String resource) {
172+
private String getAccessTokenOnOthers(String resource, String identity) {
162173
LOGGER.entering("AuthClient", "getAccessTokenOnOthers", resource);
163174
LOGGER.info("Getting access token using managed identity");
175+
if (identity != null) {
176+
LOGGER.log(INFO, "Using managed identity with object ID: {0}", identity);
177+
}
178+
164179
String result = null;
165180

166181
StringBuilder url = new StringBuilder();
167182
url.append(OAUTH2_MANAGED_IDENTITY_TOKEN_URL)
168183
.append(RESOURCE_FRAGMENT).append(resource);
184+
185+
if (identity != null) {
186+
url.append("&object_id=").append(identity);
187+
}
169188

170189
HashMap<String, String> headers = new HashMap<>();
171190
headers.put("Metadata", "true");

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultClient.java

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
// Licensed under the MIT License.
33
package com.azure.security.keyvault.jca;
44

5-
import com.azure.security.keyvault.jca.rest.CertificateBundle;
6-
import com.azure.security.keyvault.jca.rest.CertificateItem;
7-
import com.azure.security.keyvault.jca.rest.CertificateListResult;
8-
import com.azure.security.keyvault.jca.rest.CertificatePolicy;
9-
import com.azure.security.keyvault.jca.rest.KeyProperties;
10-
import com.azure.security.keyvault.jca.rest.SecretBundle;
5+
import com.azure.security.keyvault.jca.model.CertificateBundle;
6+
import com.azure.security.keyvault.jca.model.CertificateItem;
7+
import com.azure.security.keyvault.jca.model.CertificateListResult;
8+
import com.azure.security.keyvault.jca.model.CertificatePolicy;
9+
import com.azure.security.keyvault.jca.model.KeyProperties;
10+
import com.azure.security.keyvault.jca.model.SecretBundle;
1111

1212
import java.io.ByteArrayInputStream;
1313
import java.io.IOException;
@@ -67,6 +67,12 @@ class KeyVaultClient extends DelegateRestClient {
6767
*/
6868
private String clientSecret;
6969

70+
/**
71+
* Stores the managed identity (either the user-assigned managed identity
72+
* object ID or null if system-assigned)
73+
*/
74+
private String managedIdentity;
75+
7076
/**
7177
* Constructor.
7278
*
@@ -81,6 +87,22 @@ class KeyVaultClient extends DelegateRestClient {
8187
this.keyVaultUrl = keyVaultUri;
8288
}
8389

90+
/**
91+
* Constructor.
92+
*
93+
* @param keyVaultUri the Azure Key Vault URI.
94+
* @param managedIdentity the managed identity object ID.
95+
*/
96+
KeyVaultClient(String keyVaultUri, String managedIdentity) {
97+
super(RestClientFactory.createClient());
98+
LOGGER.log(INFO, "Using Azure Key Vault: {0}", keyVaultUri);
99+
if (!keyVaultUri.endsWith("/")) {
100+
keyVaultUri = keyVaultUri + "/";
101+
}
102+
this.keyVaultUrl = keyVaultUri;
103+
this.managedIdentity = managedIdentity;
104+
}
105+
84106
/**
85107
* Constructor.
86108
*
@@ -106,11 +128,16 @@ private String getAccessToken() {
106128
String accessToken = null;
107129
try {
108130
AuthClient authClient = new AuthClient();
131+
109132
String resource = URLEncoder.encode("https://vault.azure.net", "UTF-8");
133+
if (managedIdentity != null) {
134+
managedIdentity = URLEncoder.encode(managedIdentity, "UTF-8");
135+
}
136+
110137
if (tenantId != null && clientId != null && clientSecret != null) {
111138
accessToken = authClient.getAccessToken(resource, tenantId, clientId, clientSecret);
112139
} else {
113-
accessToken = authClient.getAccessToken(resource);
140+
accessToken = authClient.getAccessToken(resource, managedIdentity);
114141
}
115142
} catch (UnsupportedEncodingException uee) {
116143
LOGGER.log(WARNING, "Unsupported encoding", uee);
@@ -235,13 +262,12 @@ Key getKey(String alias, char[] password) {
235262
}
236263
}
237264
}
238-
265+
239266
//
240267
// If the private key is not available the certificate cannot be
241268
// used for server side certificates or mTLS. Then we do not know
242269
// the intent of the usage at this stage we skip this key.
243270
//
244-
245271
LOGGER.exiting("KeyVaultClient", "getKey", key);
246272
return key;
247273
}

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ public final class KeyVaultKeyStore extends KeyStoreSpi {
7373
* The constructor uses System.getProperty for
7474
* <code>azure.keyvault.uri</code>, <code>azure.keyvault.tenantId</code>,
7575
* <code>azure.keyvault.clientId</code>,
76-
* <code>azure.keyvault.clientSecret</code> to initialize the keyvault
77-
* client.
76+
* <code>azure.keyvault.clientSecret</code> and
77+
* <code>azure.keyvault.userAssignedIdentity</code> to initialize the
78+
* keyvault client.
7879
* </p>
7980
*/
8081
public KeyVaultKeyStore() {
@@ -83,7 +84,12 @@ public KeyVaultKeyStore() {
8384
String tenantId = System.getProperty("azure.keyvault.tenantId");
8485
String clientId = System.getProperty("azure.keyvault.clientId");
8586
String clientSecret = System.getProperty("azure.keyvault.clientSecret");
86-
keyVaultClient = new KeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret);
87+
String managedIdentity = System.getProperty("azure.keyvault.managedIdentity");
88+
if (clientId != null) {
89+
keyVaultClient = new KeyVaultClient(keyVaultUri, tenantId, clientId, clientSecret);
90+
} else {
91+
keyVaultClient = new KeyVaultClient(keyVaultUri, managedIdentity);
92+
}
8793
}
8894

8995
@Override
@@ -198,11 +204,20 @@ public boolean engineIsKeyEntry(String alias) {
198204
public void engineLoad(KeyStore.LoadStoreParameter param) {
199205
if (param instanceof KeyVaultLoadStoreParameter) {
200206
KeyVaultLoadStoreParameter parameter = (KeyVaultLoadStoreParameter) param;
201-
keyVaultClient = new KeyVaultClient(
202-
parameter.getUri(),
203-
parameter.getTenantId(),
204-
parameter.getClientId(),
205-
parameter.getClientSecret());
207+
if (parameter.getClientId() != null) {
208+
keyVaultClient = new KeyVaultClient(
209+
parameter.getUri(),
210+
parameter.getTenantId(),
211+
parameter.getClientId(),
212+
parameter.getClientSecret());
213+
} else if (parameter.getUserAssignedIdentity() != null) {
214+
keyVaultClient = new KeyVaultClient(
215+
parameter.getUri(),
216+
parameter.getUserAssignedIdentity()
217+
);
218+
} else {
219+
keyVaultClient = new KeyVaultClient(parameter.getUri());
220+
}
206221
}
207222
sideLoad();
208223
}

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultLoadStoreParameter.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public class KeyVaultLoadStoreParameter implements KeyStore.LoadStoreParameter {
2929
* Stores the client secret.
3030
*/
3131
private final String clientSecret;
32+
33+
/**
34+
* Stores the user-assigned identity.
35+
*/
36+
private final String userAssignedIdentity;
3237

3338
/**
3439
* Constructor.
@@ -43,8 +48,36 @@ public KeyVaultLoadStoreParameter(String uri, String tenantId, String clientId,
4348
this.tenantId = tenantId;
4449
this.clientId = clientId;
4550
this.clientSecret = clientSecret;
51+
this.userAssignedIdentity = null;
4652
}
4753

54+
/**
55+
* Constructor.
56+
*
57+
* @param uri the Azure Key Vault URI.
58+
* @param userAssignedIdentity the user-assigned identity.
59+
*/
60+
public KeyVaultLoadStoreParameter(String uri, String userAssignedIdentity) {
61+
this.uri = uri;
62+
this.tenantId = null;
63+
this.clientId = null;
64+
this.clientSecret = null;
65+
this.userAssignedIdentity = userAssignedIdentity;
66+
}
67+
68+
/**
69+
* Constructor.
70+
*
71+
* @param uri the Azure Key Vault URI.
72+
*/
73+
public KeyVaultLoadStoreParameter(String uri) {
74+
this.uri = uri;
75+
this.tenantId = null;
76+
this.clientId = null;
77+
this.clientSecret = null;
78+
this.userAssignedIdentity = null;
79+
}
80+
4881
/**
4982
* Get the protection parameter.
5083
*
@@ -90,4 +123,13 @@ public String getTenantId() {
90123
public String getUri() {
91124
return uri;
92125
}
126+
127+
/**
128+
* Get the user-assigned identity.
129+
*
130+
* @return the user-assign identity.
131+
*/
132+
public String getUserAssignedIdentity() {
133+
return userAssignedIdentity;
134+
}
93135
}

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/rest/CertificateBundle.java renamed to sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/CertificateBundle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
package com.azure.security.keyvault.jca.rest;
4+
package com.azure.security.keyvault.jca.model;
55

66
import java.io.Serializable;
77

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/rest/CertificateItem.java renamed to sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/CertificateItem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
package com.azure.security.keyvault.jca.rest;
4+
package com.azure.security.keyvault.jca.model;
55

66
import java.io.Serializable;
77

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/rest/CertificateListResult.java renamed to sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/CertificateListResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
package com.azure.security.keyvault.jca.rest;
4+
package com.azure.security.keyvault.jca.model;
55

66
import java.io.Serializable;
77
import java.util.List;

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/rest/CertificatePolicy.java renamed to sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/CertificatePolicy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
package com.azure.security.keyvault.jca.rest;
4+
package com.azure.security.keyvault.jca.model;
55

66
import com.fasterxml.jackson.annotation.JsonProperty;
77
import java.io.Serializable;

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/rest/KeyProperties.java renamed to sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/KeyProperties.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
package com.azure.security.keyvault.jca.rest;
4+
package com.azure.security.keyvault.jca.model;
55

66
import java.io.Serializable;
77

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/rest/OAuthToken.java renamed to sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/OAuthToken.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
3-
package com.azure.security.keyvault.jca.rest;
3+
package com.azure.security.keyvault.jca.model;
44

55
import com.fasterxml.jackson.annotation.JsonProperty;
66
import java.io.Serializable;

0 commit comments

Comments
 (0)