Browse Source

fix: handle managed identity ClientID or ResourceID in acr generator (#4150)

* fix: use ClientID instead of ResourceID in acr generator

Signed-off-by: Dmytro Bondar <git@bonddim.com>

* Handle both cases: with ClientID and ResourceID

Signed-off-by: Dmytro Bondar <git@bonddim.com>

* Update ACR docs

Signed-off-by: Dmytro Bondar <git@bonddim.com>

---------

Signed-off-by: Dmytro Bondar <git@bonddim.com>
Dmytro Bondar 1 year ago
parent
commit
08566af7c1

+ 9 - 1
docs/api/generator/acr.md

@@ -9,7 +9,6 @@ The token is generated for a particular ACR registry defined in `spec.registry`.
 | username | username for the `docker login` command |
 | password | password for the `docker login` command |
 
-
 ## Authentication
 
 You must choose one out of three authentication mechanisms:
@@ -21,6 +20,8 @@ You must choose one out of three authentication mechanisms:
 The generated token will inherit the permissions from the assigned policy. I.e. when you assign a read-only policy all generated tokens will be read-only.
 You **must** [assign a Azure RBAC role](https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-steps), such as `AcrPush` or `AcrPull` to the service principal or managed identity in order to be able to authenticate with the Azure container registry API.
 
+You can also use a kubelet managed identity with the default `AcrPull` role to authenticate to the integrated Azure Container Registry.
+
 You can scope tokens to a particular repository using `spec.scope`.
 
 ## Scope
@@ -49,6 +50,13 @@ repository:my-repository:pull
 ```
 
 Example `ExternalSecret` that references the ACR generator:
+
 ```yaml
 {% include 'generator-acr-example.yaml' %}
 ```
+
+Example using AKS kubelet managed identity to create [Argo CD helm chart repository](https://argo-cd.readthedocs.io/en/latest/operator-manual/declarative-setup/#helm-chart-repositories) secret:
+
+```yaml
+{% include 'generator-acr-argocd-helm-repo.yaml' %}
+```

+ 38 - 0
docs/snippets/generator-acr-argocd-helm-repo.yaml

@@ -0,0 +1,38 @@
+{% raw %}
+apiVersion: generators.external-secrets.io/v1alpha1
+kind: ACRAccessToken
+metadata:
+  name: azurecr
+spec:
+  tenantId: 11111111-2222-3333-4444-111111111111
+  registry: example.azurecr.io
+  auth:
+    managedIdentity:
+      identityId: 11111111-2222-3333-4444-111111111111
+---
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: azurecr-credentials
+spec:
+  dataFrom:
+    - sourceRef:
+        generatorRef:
+          apiVersion: generators.external-secrets.io/v1alpha1
+          kind: ACRAccessToken
+          name: azurecr
+  refreshInterval: 3h
+  target:
+    name: azurecr-credentials
+    template:
+      metadata:
+        labels:
+          argocd.argoproj.io/secret-type: repository
+      data:
+        name: "example.azurecr.io"
+        url: "example.azurecr.io"
+        username: "{{ .username }}"
+        password: "{{ .password }}"
+        enableOCI: "true"
+        type: "helm"
+{% endraw %}

+ 3 - 3
docs/snippets/generator-acr.yaml

@@ -28,13 +28,13 @@ spec:
           name: az-secret
           key: clientid
 
-    # option 2:
+    # option 2: use a managed identity Client ID
     managedIdentity:
-      identityId: "xxxxx"
+      identityId: 11111111-2222-3333-4444-111111111111
 
     # option 3:
     workloadIdentity:
       # note: you can reference service accounts across namespaces.
       serviceAccountRef:
         name: "my-service-account"
-        audiences: []
+        audiences: []

+ 11 - 5
pkg/generator/acr/acr.go

@@ -282,12 +282,18 @@ func accessTokenForWorkloadIdentity(ctx context.Context, crClient client.Client,
 }
 
 func accessTokenForManagedIdentity(ctx context.Context, envType v1beta1.AzureEnvironmentType, identityID string) (string, error) {
-	// handle workload identity
-	creds, err := azidentity.NewManagedIdentityCredential(
-		&azidentity.ManagedIdentityCredentialOptions{
+	// handle managed identity
+	var opts *azidentity.ManagedIdentityCredentialOptions
+	if strings.Contains(identityID, "/") {
+		opts = &azidentity.ManagedIdentityCredentialOptions{
 			ID: azidentity.ResourceID(identityID),
-		},
-	)
+		}
+	} else {
+		opts = &azidentity.ManagedIdentityCredentialOptions{
+			ID: azidentity.ClientID(identityID),
+		}
+	}
+	creds, err := azidentity.NewManagedIdentityCredential(opts)
 	if err != nil {
 		return "", err
 	}