Skip to content

Commit 0ad6db6

Browse files
mgmt, support MSI for access ACR, when create ACI (#45274)
1 parent 830a0be commit 0ad6db6

File tree

6 files changed

+155
-0
lines changed

6 files changed

+155
-0
lines changed

sdk/resourcemanager/azure-resourcemanager-authorization/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Features Added
66

7+
- Added `ACR_PULL` to `BuiltInRole`.
8+
79
### Breaking Changes
810

911
### Bugs Fixed

sdk/resourcemanager/azure-resourcemanager-authorization/src/main/java/com/azure/resourcemanager/authorization/models/BuiltInRole.java

+3
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ public final class BuiltInRole extends ExpandableStringEnum<BuiltInRole> {
234234
/** Read and create quota requests, get quota request status, and create support tickets. */
235235
public static final BuiltInRole QUOTA_REQUEST_OPERATOR = BuiltInRole.fromString("Quota Request Operator");
236236

237+
/** Read-only access to pull images. */
238+
public static final BuiltInRole ACR_PULL = BuiltInRole.fromString("AcrPull");
239+
237240
/**
238241
* Creates a new instance of BuiltInRole value.
239242
*

sdk/resourcemanager/azure-resourcemanager-containerinstance/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Features Added
66

7+
- Added `withPrivateImageRegistry` overload for managed identity in `ContainerGroup`.
8+
79
### Breaking Changes
810

911
### Bugs Fixed

sdk/resourcemanager/azure-resourcemanager-containerinstance/src/main/java/com/azure/resourcemanager/containerinstance/implementation/ContainerGroupImpl.java

+16
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,22 @@ public ContainerGroupImpl withPrivateImageRegistry(String server, String usernam
361361
return this;
362362
}
363363

364+
@Override
365+
public ContainerGroupImpl withPrivateImageRegistry(String server, Identity identity) {
366+
return withPrivateImageRegistry(server, Objects.requireNonNull(identity).id());
367+
}
368+
369+
private ContainerGroupImpl withPrivateImageRegistry(String server, String managedIdentityResourceId) {
370+
if (this.innerModel().imageRegistryCredentials() == null) {
371+
this.innerModel().withImageRegistryCredentials(new ArrayList<ImageRegistryCredential>());
372+
}
373+
this.innerModel()
374+
.imageRegistryCredentials()
375+
.add(new ImageRegistryCredential().withServer(server).withIdentity(managedIdentityResourceId));
376+
377+
return this;
378+
}
379+
364380
@Override
365381
public ContainerGroupImpl withNewAzureFileShareVolume(String volumeName, String shareName) {
366382
if (this.newFileShares == null || this.creatableStorageAccountKey == null) {

sdk/resourcemanager/azure-resourcemanager-containerinstance/src/main/java/com/azure/resourcemanager/containerinstance/models/ContainerGroup.java

+9
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,15 @@ interface WithPrivateImageRegistry {
395395
* @return the next stage of the definition
396396
*/
397397
WithPrivateImageRegistryOrVolume withPrivateImageRegistry(String server, String username, String password);
398+
399+
/**
400+
* Specifies the private container image registry server login for the container group.
401+
*
402+
* @param server Docker image registry server, without protocol such as "http" and "https"
403+
* @param identity the managed identity (with "acrpull" role)
404+
* @return the next stage of the definition
405+
*/
406+
WithPrivateImageRegistryOrVolume withPrivateImageRegistry(String server, Identity identity);
398407
}
399408

400409
/** The stage of the container group definition allowing to specify a private image registry or a volume. */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.resourcemanager;
5+
6+
import com.azure.core.credential.TokenCredential;
7+
import com.azure.core.http.HttpClient;
8+
import com.azure.core.http.HttpPipeline;
9+
import com.azure.core.http.policy.HttpLogOptions;
10+
import com.azure.core.http.policy.HttpPipelinePolicy;
11+
import com.azure.core.http.policy.RetryPolicy;
12+
import com.azure.core.management.Region;
13+
import com.azure.core.management.profile.AzureProfile;
14+
import com.azure.resourcemanager.authorization.models.BuiltInRole;
15+
import com.azure.resourcemanager.authorization.models.RoleAssignment;
16+
import com.azure.resourcemanager.containerinstance.models.ContainerGroup;
17+
import com.azure.resourcemanager.containerregistry.models.ImportImageParameters;
18+
import com.azure.resourcemanager.containerregistry.models.ImportMode;
19+
import com.azure.resourcemanager.containerregistry.models.ImportSource;
20+
import com.azure.resourcemanager.containerregistry.models.Registry;
21+
import com.azure.resourcemanager.msi.models.Identity;
22+
import com.azure.resourcemanager.resources.fluentcore.utils.HttpPipelineProvider;
23+
import com.azure.resourcemanager.resources.fluentcore.utils.ResourceManagerUtils;
24+
import com.azure.resourcemanager.test.ResourceManagerTestProxyTestBase;
25+
import com.azure.resourcemanager.test.utils.TestDelayProvider;
26+
import com.azure.resourcemanager.test.utils.TestIdentifierProvider;
27+
import org.junit.jupiter.api.Disabled;
28+
import org.junit.jupiter.api.Test;
29+
30+
import java.time.temporal.ChronoUnit;
31+
import java.util.Arrays;
32+
import java.util.List;
33+
import java.util.UUID;
34+
35+
public class ContainerGroupTests extends ResourceManagerTestProxyTestBase {
36+
37+
private AzureResourceManager azureResourceManager;
38+
39+
protected String rgName = "";
40+
protected final Region region = Region.US_WEST3;
41+
42+
@Override
43+
protected HttpPipeline buildHttpPipeline(TokenCredential credential, AzureProfile profile,
44+
HttpLogOptions httpLogOptions, List<HttpPipelinePolicy> policies, HttpClient httpClient) {
45+
return HttpPipelineProvider.buildHttpPipeline(credential, profile, null, httpLogOptions, null,
46+
new RetryPolicy("Retry-After", ChronoUnit.SECONDS), policies, httpClient);
47+
}
48+
49+
@Override
50+
protected void initializeClients(HttpPipeline httpPipeline, AzureProfile profile) {
51+
ResourceManagerUtils.InternalRuntimeContext.setDelayProvider(new TestDelayProvider(!isPlaybackMode()));
52+
ResourceManagerUtils.InternalRuntimeContext internalContext = new ResourceManagerUtils.InternalRuntimeContext();
53+
internalContext.setIdentifierFunction(name -> new TestIdentifierProvider(testResourceNamer));
54+
azureResourceManager = buildManager(AzureResourceManager.class, httpPipeline, profile);
55+
setInternalContext(internalContext, azureResourceManager);
56+
57+
rgName = generateRandomResourceName("javacsmrg", 15);
58+
}
59+
60+
@Override
61+
protected void cleanUpResources() {
62+
try {
63+
azureResourceManager.resourceGroups().beginDeleteByName(rgName);
64+
} catch (Exception e) {
65+
}
66+
}
67+
68+
@Disabled("Admin in ACR is disallowed by policy, but it is required to deploy the image to ACI.")
69+
// https://learn.microsoft.com/azure/container-registry/container-registry-authentication?tabs=azure-cli#admin-account
70+
@Test
71+
public void testContainerGroupWithPrivateImageRegistryAndMsi() {
72+
// acr
73+
final String acrName = generateRandomResourceName("acr", 10);
74+
Registry registry = azureResourceManager.containerRegistries()
75+
.define(acrName)
76+
.withRegion(region)
77+
.withNewResourceGroup(rgName)
78+
.withBasicSku()
79+
.withRegistryNameAsAdminUser()
80+
.create();
81+
82+
azureResourceManager.containerRegistries()
83+
.manager()
84+
.serviceClient()
85+
.getRegistries()
86+
.importImage(rgName, registry.name(),
87+
new ImportImageParameters()
88+
.withSource(new ImportSource().withRegistryUri("docker.io").withSourceImage("library/nginx:latest"))
89+
.withTargetTags(Arrays.asList("nginx:latest"))
90+
.withMode(ImportMode.NO_FORCE));
91+
92+
// msi
93+
final String msiName = generateRandomResourceName("msi", 10);
94+
Identity identity = azureResourceManager.identities()
95+
.define(msiName)
96+
.withRegion(region)
97+
.withExistingResourceGroup(rgName)
98+
.create();
99+
100+
// rbac
101+
RoleAssignment roleAssignment = azureResourceManager.accessManagement()
102+
.roleAssignments()
103+
.define(UUID.randomUUID().toString())
104+
.forObjectId(identity.principalId())
105+
.withBuiltInRole(BuiltInRole.ACR_PULL)
106+
.withScope(registry.id())
107+
.create();
108+
109+
// aci
110+
final String containerGroupName = generateRandomResourceName("acg", 10);
111+
ContainerGroup containerGroup = azureResourceManager.containerGroups()
112+
.define(containerGroupName)
113+
.withRegion(region)
114+
.withNewResourceGroup(rgName)
115+
.withLinux()
116+
.withPrivateImageRegistry(registry.loginServerUrl(), identity)
117+
.withoutVolume()
118+
.withContainerInstance("nginx", 80)
119+
.withNewVirtualNetwork("10.0.0.0/24")
120+
.withExistingUserAssignedManagedServiceIdentity(identity)
121+
.create();
122+
}
123+
}

0 commit comments

Comments
 (0)