Skip to content

Commit 5eb5199

Browse files
committed
Add support different Azure Cloud eg. AzureChinaCloud
I have read the CLA Document and I hereby sign the CLA
1 parent 32bfdf9 commit 5eb5199

19 files changed

Lines changed: 150 additions & 51 deletions

AZURE.md

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,24 +77,60 @@ helm version
7777

7878
There are **two authentication methods** available for the credential provider:
7979

80-
- **Option A: Nodepool Managed Identity** (Steps 1 → 2 → 3A4) — Uses the AKS nodepool's user-assigned managed identity to authenticate via Azure IMDS.
80+
- **Option A: Nodepool Managed Identity** (Steps 1 → 2 → 34A → 5) — Uses the AKS nodepool's user-assigned managed identity to authenticate via Azure IMDS.
8181
> **Choose this when:** You want a straightforward setup, all nodes in the pool can share the same identity, and you don't need per-workload credential isolation.
8282
83-
- **Option B: Workload Identity** (Steps 1 → 2 → 3B4) — Uses Kubernetes projected service account tokens. Provides better security isolation as each service account can have its own identity.
83+
- **Option B: Workload Identity** (Steps 1 → 2 → 34B → 5) — Uses Kubernetes projected service account tokens. Provides better security isolation as each service account can have its own identity.
8484
> **Choose this when:** You need fine-grained, per-service-account access control, want to follow the zero-trust principle, or your organization requires workload-level identity isolation.
8585
8686
The setup process consists of the following steps:
8787

88-
1. **Azure AD App Registration** - Create an enterprise application in Azure AD
89-
2. **Federated Identity Credentials** - Configure AKS nodepool access to the Azure App
90-
3. **JFrog Artifactory OIDC Configuration** - Choose one of:
91-
- **Step 3A:** Configure using Nodepool Managed Identity
92-
- **Step 3B:** Configure using Workload Identity (Projected Service Account Tokens)
93-
4. **Deploy Credentials Provider** - Deploy the credential provider using Helm
88+
1. **Identify Azure Cloud Name** - Determine your Azure cloud environment
89+
2. **Azure AD App Registration** - Create an enterprise application in Azure AD
90+
3. **Federated Identity Credentials** - Configure AKS nodepool access to the Azure App
91+
4. **JFrog Artifactory OIDC Configuration** - Choose one of:
92+
- **Step 4A:** Configure using Nodepool Managed Identity
93+
- **Step 4B:** Configure using Workload Identity (Projected Service Account Tokens)
94+
5. **Deploy Credentials Provider** - Deploy the credential provider using Helm
9495

9596
---
9697

97-
## Step 1: 🔐 Azure AD App Registration
98+
## Step 1: 🌍 Identify Azure Cloud Name and Endpoints
99+
100+
Before configuring the credential provider, you need to identify which Azure cloud environment you're using and set the appropriate endpoints. Different Azure clouds have different endpoints for Microsoft Graph and Active Directory authentication.
101+
102+
### 🔍 Determine Your Azure Cloud and Endpoints
103+
104+
Azure operates in multiple sovereign clouds, each with different service endpoints. Identify your cloud environment from the table below and set the corresponding variables:
105+
106+
| Cloud Name | Microsoft Graph (`GRAPH_ENDPOINT`) | Active Directory (`AD_ENDPOINT`) |
107+
|------------|----------------|------------------|
108+
| `AzureCloud` | `https://graph.microsoft.com` | `https://login.microsoftonline.com` |
109+
| `AzureChinaCloud` | `https://microsoftgraph.chinacloudapi.cn` | `https://login.chinacloudapi.cn` |
110+
111+
Set the variables based on your cloud environment:
112+
113+
```bash
114+
# Get your Azure cloud name from the active cloud eg. AzureCloud, AzureChinaCloud
115+
CLOUD_NAME=$(az cloud show --query name -o tsv)
116+
117+
# Set the endpoints from the table above based on your CLOUD_NAME
118+
GRAPH_ENDPOINT="https://graph.microsoft.com"
119+
AD_ENDPOINT="https://login.microsoftonline.com"
120+
121+
echo "Azure Cloud Name: $CLOUD_NAME"
122+
echo "Microsoft Graph Endpoint: $GRAPH_ENDPOINT"
123+
echo "Active Directory Endpoint: $AD_ENDPOINT"
124+
```
125+
126+
> **💾 Important:** Save these values for later use:
127+
> - `CLOUD_NAME` (also called `azure_cloud_name`)
128+
> - `GRAPH_ENDPOINT` (used in subsequent steps for Azure AD API calls)
129+
> - `AD_ENDPOINT` (used as the issuer URL for OIDC configuration)
130+
131+
---
132+
133+
## Step 2: 🔐 Azure AD App Registration
98134

99135
The Azure AD App Registration serves as the identity that authenticates with JFrog Artifactory via OIDC.
100136

@@ -158,7 +194,7 @@ Setting **Assignment Required** to **Yes** ensures that only explicitly assigned
158194
SPN_OBJECT_ID=$(az ad sp list --filter "appId eq '$APP_CLIENT_ID'" --query "[0].id" -o tsv)
159195

160196
az rest --method PATCH \
161-
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SPN_OBJECT_ID" \
197+
--uri "$GRAPH_ENDPOINT/v1.0/servicePrincipals/$SPN_OBJECT_ID" \
162198
--headers "Content-Type=application/json" \
163199
--body '{"appRoleAssignmentRequired": true}'
164200
```
@@ -179,7 +215,7 @@ Or via CLI:
179215
OBJECT_ID=$(az ad app show --id "$APP_CLIENT_ID" --query "id" -o tsv)
180216

181217
az rest --method PATCH \
182-
--uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" \
218+
--uri "$GRAPH_ENDPOINT/v1.0/applications/$OBJECT_ID" \
183219
--headers "Content-Type=application/json" \
184220
--body '{
185221
"appRoles": [{
@@ -204,7 +240,7 @@ ROLE_ID=$(az ad sp show --id "$SPN_OBJECT_ID" --query "appRoles[?value=='Task.Re
204240

205241
```bash
206242
az rest --method POST \
207-
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SPN_OBJECT_ID/appRoleAssignments" \
243+
--uri "$GRAPH_ENDPOINT/v1.0/servicePrincipals/$SPN_OBJECT_ID/appRoleAssignments" \
208244
--headers "Content-Type=application/json" \
209245
--body "{
210246
\"principalId\": \"$SPN_OBJECT_ID\",
@@ -217,7 +253,7 @@ After this, the credential provider will continue to work via the federated cred
217253

218254
### ⚙️ Configure Access Token Version
219255

220-
The credential provider uses `https://login.microsoftonline.com` as the issuer URL (instead of the older `https://sts.windows.net/`). Azure requires you to set `requestedAccessTokenVersion` to `2` for this to work.
256+
The credential provider uses the Active Directory endpoint (e.g., `$AD_ENDPOINT`) as the issuer URL. Azure requires you to set `requestedAccessTokenVersion` to `2` for this to work.
221257

222258
```bash
223259
# Get the object ID of the app created above
@@ -226,7 +262,7 @@ OBJECT_ID=$(az ad app show --id "$APP_CLIENT_ID" --query "id" -o tsv)
226262
# Update the access token version
227263
az rest --method PATCH \
228264
--headers "Content-Type=application/json" \
229-
--uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" \
265+
--uri "$GRAPH_ENDPOINT/v1.0/applications/$OBJECT_ID" \
230266
--body '{"api":{"requestedAccessTokenVersion": 2}}'
231267
```
232268

@@ -238,9 +274,12 @@ az rest --method PATCH \
238274
4. Set `"requestedAccessTokenVersion": 2` in the JSON
239275
5. Click **Save**
240276

277+
> **💾 Important:** For AzureChinaCloud, the key will be:
278+
> `"accessTokenAcceptedVersion": 2`
279+
241280
---
242281

243-
## Step 2: 🔗 Federated Identity Credentials
282+
## Step 3: 🔗 Federated Identity Credentials
244283

245284
Federated credentials allow the AKS nodepool's managed identity to exchange tokens with the Azure AD App Registration. This establishes trust between your AKS cluster and Azure AD.
246285

@@ -311,7 +350,7 @@ echo "Nodepool Client ID: $NODEPOOL_CLIENT_ID"
311350
# Use the kubelet identity object ID (or nodepool if different)
312351
FEDERATED_CREDENTIAL_NAME="aks-nodepool-federated-credential"
313352
AUDIENCE="api://AzureADTokenExchange"
314-
ISSUER="https://login.microsoftonline.com/$TENANT_ID/v2.0"
353+
ISSUER="$AD_ENDPOINT/$TENANT_ID/v2.0"
315354

316355
# Create the federated credential
317356
az ad app federated-credential create \
@@ -333,13 +372,13 @@ az ad app federated-credential list --id "$APP_CLIENT_ID"
333372
```
334373

335374
You should see your federated credential with:
336-
- `issuer`: `https://login.microsoftonline.com/<TENANT_ID>/v2.0`
375+
- `issuer`: `<AD_ENDPOINT>/<TENANT_ID>/v2.0` (e.g., `https://login.microsoftonline.com/<TENANT_ID>/v2.0` for AzureCloud)
337376
- `subject`: Your kubelet/nodepool identity object ID
338377
- `audiences`: `["api://AzureADTokenExchange"]`
339378

340379
---
341380

342-
## Step 3A: 🐸 JFrog Artifactory OIDC Configuration
381+
## Step 4A: 🐸 JFrog Artifactory OIDC Configuration
343382

344383
Configure JFrog Artifactory to accept OIDC tokens from Azure. This involves creating an OIDC provider and an identity mapping in Artifactory.
345384

@@ -365,10 +404,10 @@ curl -X POST "https://$ARTIFACTORY_URL/access/api/v1/oidc" \
365404
-H "Authorization: Bearer $ARTIFACTORY_ADMIN_TOKEN" \
366405
-d "{
367406
\"name\": \"$OIDC_PROVIDER_NAME\",
368-
\"issuer_url\": \"https://login.microsoftonline.com/$TENANT_ID/v2.0\",
407+
\"issuer_url\": \"$AD_ENDPOINT/$TENANT_ID/v2.0\",
369408
\"description\": \"OIDC provider for Azure AKS\",
370409
\"provider_type\": \"Azure\",
371-
\"token_issuer\": \"https://login.microsoftonline.com/$TENANT_ID/v2.0\",
410+
\"token_issuer\": \"$AD_ENDPOINT/$TENANT_ID/v2.0\",
372411
\"azure_app_id\": \"$APP_CLIENT_ID\",
373412
\"audience\": \"$APP_CLIENT_ID\",
374413
\"use_default_proxy\": false
@@ -392,7 +431,7 @@ curl -X POST "https://$ARTIFACTORY_URL/access/api/v1/oidc/$OIDC_PROVIDER_NAME/id
392431
\"description\": \"Azure OIDC identity mapping\",
393432
\"claims\": {
394433
\"aud\": \"$APP_CLIENT_ID\",
395-
\"iss\": \"https://login.microsoftonline.com/$TENANT_ID/v2.0\"
434+
\"iss\": \"$AD_ENDPOINT/$TENANT_ID/v2.0\"
396435
},
397436
\"token_spec\": {
398437
\"username\": \"$ARTIFACTORY_USER\",
@@ -408,7 +447,7 @@ curl -X POST "https://$ARTIFACTORY_URL/access/api/v1/oidc/$OIDC_PROVIDER_NAME/id
408447
<summary><strong>📝 Configuration Notes</strong></summary>
409448

410449
- The `claims.aud` must match your `azure_app_client_id`
411-
- The `claims.iss` must match the Azure AD issuer URL: `https://login.microsoftonline.com/$TENANT_ID/v2.0`
450+
- The `claims.iss` must match the Azure AD issuer URL: `$AD_ENDPOINT/$TENANT_ID/v2.0` (e.g., `https://login.microsoftonline.com/$TENANT_ID/v2.0` for AzureCloud)
412451
- The `token_spec.username` must be an existing Artifactory user
413452
- Ensure the user has permissions to pull images from your repositories
414453

@@ -430,7 +469,7 @@ curl -X GET "https://$ARTIFACTORY_URL/access/api/v1/oidc/$OIDC_PROVIDER_NAME" \
430469

431470
---
432471

433-
## Step 3B: Using Projected Service Account Tokens (Workload Identity)
472+
## Step 4B: Using Projected Service Account Tokens (Workload Identity)
434473

435474
Instead of using the Nodepool's Managed Identity, you can use **Kubernetes Workload Identity**. This allows the Credential Provider to use a specific Kubernetes Service Account to authenticate with Artifactory. This method provides better security isolation as each service account can have its own Azure AD app registration.
436475

@@ -444,7 +483,7 @@ Instead of using the Nodepool's Managed Identity, you can use **Kubernetes Workl
444483

445484
4. The kubelet uses the registry token to authenticate and pull the container image
446485

447-
### Step 3B.1: ✅ Enable OIDC Issuer on AKS
486+
### Step 4B.1: ✅ Enable OIDC Issuer on AKS
448487

449488
First, ensure your cluster has the OIDC issuer enabled to support Workload Identity:
450489

@@ -471,7 +510,7 @@ echo "Service Account Issuer: $SERVICE_ACCOUNT_ISSUER"
471510

472511
> **💾 Important:** Save the `SERVICE_ACCOUNT_ISSUER` URL - you'll need it for Artifactory OIDC configuration.
473512
474-
### Step 3B.2: 👤 Configure the Kubernetes Service Account
513+
### Step 4B.2: 👤 Configure the Kubernetes Service Account
475514

476515
Create a Service Account that the Credential Provider will use to project the tokens:
477516

@@ -496,7 +535,7 @@ kubectl annotate serviceaccount "$SERVICE_ACCOUNT_NAME" \
496535

497536
> **ℹ️ Note:** The `JFrogExchange="true"` annotation tells the credential provider to use the projected service account token instead of the nodepool's managed identity.
498537
499-
### Step 3B.3: 🐸 Update JFrog Artifactory OIDC Configuration
538+
### Step 4B.3: 🐸 Update JFrog Artifactory OIDC Configuration
500539

501540
You must point Artifactory to your AKS Cluster's OIDC Issuer instead of the global Azure Login URL for this flow:
502541

@@ -547,7 +586,7 @@ curl -X POST "https://$ARTIFACTORY_URL/access/api/v1/oidc/aks-workload-identity/
547586
548587
---
549588

550-
## Step 4: 🚀 Deploy Credentials Provider
589+
## Step 5: 🚀 Deploy Credentials Provider
551590

552591
Deploy the credential provider using Helm. For manual deployment with Kubernetes manifests, refer to the [Kubernetes Kubelet Credential Provider documentation](https://kubernetes.io/docs/tasks/administer-cluster/kubelet-credential-provider/).
553592

@@ -564,6 +603,7 @@ You can use the following commands to print the values you need:
564603

565604
```bash
566605
echo "artifactory_url: $ARTIFACTORY_URL"
606+
echo "azure_cloud_name: $CLOUD_NAME"
567607
echo "azure_tenant_id: $TENANT_ID"
568608
echo "azure_app_client_id: $APP_CLIENT_ID"
569609
echo "azure_nodepool_client_id: $NODEPOOL_CLIENT_ID"
@@ -573,6 +613,7 @@ echo "jfrog_oidc_provider_name: $OIDC_PROVIDER_NAME"
573613

574614
| Configuration Value | Description | Example |
575615
|---------------------|-------------|---------|
616+
| `azure_cloud_name` | Your Azure Cloud Name | `AzureCloud` `AzureChinaCloud` |
576617
| `azure_tenant_id` | Your Azure AD tenant ID | `12345678-1234-1234-1234-123456789012` |
577618
| `azure_app_client_id` | The Azure AD application client ID | `87654321-4321-4321-4321-210987654321` |
578619
| `azure_nodepool_client_id` | Client ID of the user-assigned managed identity attached to the AKS nodepool (also added to the app registration's federated credential) | `11111111-2222-3333-4444-555555555555` |
@@ -582,7 +623,7 @@ echo "jfrog_oidc_provider_name: $OIDC_PROVIDER_NAME"
582623

583624
#### Configuration for Traditional Nodepool Identity
584625

585-
Use this configuration if you're using the **nodepool's managed identity** (Steps 1-3A):
626+
Use this configuration if you're using the **nodepool's managed identity** (Steps 2-4A):
586627

587628
```yaml
588629
providerConfig:
@@ -595,6 +636,7 @@ providerConfig:
595636
enabled: false # Set to false for nodepool identity
596637
azure:
597638
enabled: true
639+
azure_cloud_name: "<cloud-name>"
598640
azure_tenant_id: "<tenant-id>"
599641
azure_app_client_id: "<app-client-id>"
600642
azure_nodepool_client_id: "<nodepool-client-id>"
@@ -607,7 +649,7 @@ rbac:
607649
608650
#### Configuration for Workload Identity (Projected Service Account Tokens)
609651
610-
Use this configuration if you're using **Kubernetes Workload Identity** (Steps 3B):
652+
Use this configuration if you're using **Kubernetes Workload Identity** (Steps 4B):
611653
612654
```yaml
613655
providerConfig:
@@ -621,6 +663,7 @@ providerConfig:
621663
serviceAccountTokenAudience: "<app-audience>"
622664
azure:
623665
enabled: true
666+
azure_cloud_name: "<cloud-name>"
624667
azure_app_client_id: "<app-client-id>"
625668
azure_app_audience: "<app-audience>"
626669
jfrog_oidc_provider_name: "<oidc-provider-name>"
@@ -631,7 +674,7 @@ rbac:
631674
# Note: You must also create the service account and annotate it as described in Step 3B.2
632675
```
633676

634-
> **ℹ️ Note:** When using Workload Identity, ensure the service account `jfrog-provider-sa` is annotated with `JFrogExchange="true"` and the Azure App Client ID as shown in Step 3B.2.
677+
> **ℹ️ Note:** When using Workload Identity, ensure the service account `jfrog-provider-sa` is annotated with `JFrogExchange="true"` and the Azure App Client ID as shown in Step 4B.2.
635678
636679

637680
### 📦 Install with Helm
@@ -714,3 +757,4 @@ For troubleshooting help, see the [debug documentation](./debug.md).
714757
- [JFrog Artifactory OIDC Documentation](https://www.jfrog.com/confluence/display/JFROG/Access+Tokens#AccessTokens-OIDCIntegration)
715758
- [Kubernetes Kubelet Credential Provider](https://kubernetes.io/docs/tasks/administer-cluster/kubelet-credential-provider/)
716759
- [Main README](./README.md)
760+

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,3 @@ For detailed debugging instructions, troubleshooting steps, and common issues, s
159159
- [🔷 Azure Setup Guide](./AZURE.md) - Complete Azure AKS setup instructions
160160
- [🔵 GCP Setup Guide](./GCP.md) - Complete GCP GKE setup instructions
161161
- [🐛 Debug Documentation](./debug.md) - Troubleshooting and debugging guide
162-

debug.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Example for Azure:
7070

7171
```bash
7272
export artifactory_url=YOUR_ARTIFACTORY_URL
73+
export azure_cloud_name=YOUR_AZURE_CLOUD_NAME
7374
export azure_app_client_id=YOUR_AZURE_APP_CLIENT_ID
7475
export azure_tenant_id=YOUR_AZURE_TENANT_ID
7576
export azure_nodepool_client_id=YOUR_AZURE_NODEPOOL_CLIENT_ID

examples/azure-values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ providerConfig:
77
azure:
88
enabled: true
99
azure_app_client_id: "<azure-app-client-id>"
10+
azure_cloud_name: "<azure-cloud-name>"
1011
azure_tenant_id: "<azure-tenant-id>"
1112
azure_app_audience: "api://AzureADTokenExchange"
1213
jfrog_oidc_provider_name: "<jfrog-oidc-provider-name>"

helm/templates/configmap-provider.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ data:
138138
value: "{{ .artifactoryUrl }}"
139139
- name: azure_app_client_id
140140
value: "{{ .azure.azure_app_client_id }}"
141+
- name: azure_cloud_name
142+
value: "{{ .azure.azure_cloud_name }}"
141143
- name: azure_tenant_id
142144
value: "{{ .azure.azure_tenant_id }}"
143145
- name: azure_nodepool_client_id

helm/templates/configmap-setup.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ data:
5151
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
5252
ARCH_SUFFIX="arm64"
5353
fi
54-
export JFROG_CREDENTIAL_PROVIDER_BINARY_URL="${JFROG_CREDENTIAL_PROVIDER_BINARY_URL}-${ARCH_SUFFIX}"
54+
if [[ "${JFROG_CREDENTIAL_PROVIDER_BINARY_URL}" == *"?"* ]]; then
55+
QUERY_STRING="${JFROG_CREDENTIAL_PROVIDER_BINARY_URL#*\?}"
56+
BASE_URL="${JFROG_CREDENTIAL_PROVIDER_BINARY_URL%%\?*}"
57+
export JFROG_CREDENTIAL_PROVIDER_BINARY_URL="${BASE_URL}-${ARCH_SUFFIX}?${QUERY_STRING}"
58+
else
59+
export JFROG_CREDENTIAL_PROVIDER_BINARY_URL="${JFROG_CREDENTIAL_PROVIDER_BINARY_URL}-${ARCH_SUFFIX}"
60+
fi
5561
5662
# Pull the jfrog-credential-provider binary
5763
echo "Downloading the jfrog-credential-provider binary (${JFROG_CREDENTIAL_PROVIDER_BINARY_URL})"

helm/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ providerConfig:
104104
azure:
105105
enabled: false
106106
azure_app_client_id: ""
107+
azure_cloud_name: ""
107108
azure_tenant_id: ""
108109
azure_app_audience: ""
109110
jfrog_oidc_provider_name: ""

0 commit comments

Comments
 (0)