func()

in pkg/cmd/podidentity/detect.go [130:233]


func (dc *detectCmd) run() error {
	mlog.Debug("detecting aad-pod-identity configuration", "namespace", dc.namespace)

	// Implementing force namespaced mode
	// 1. Get AzureIdentityBinding in the namespace
	// 2. Get AzureIdentity referenced by AzureIdentityBinding and store in map with aadpodidbinding label value as key and AzureIdentity as value
	// 3. Get all pods in the namespace that have aadpodidbinding label
	// 4. For each pod, check if there is an owner reference (deployment, statefulset, cronjob, job, daemonset, replicaset, replicationcontroller)
	// 5. If there is an owner reference, get the owner reference object and add to map with aadpodidbinding label value as key and owner reference as value
	// 6. If no owner reference, then assume it's a static pod and add to map with aadpodidbinding label value as key and pod as value
	// 7. Loop through the first map and generate new config file for each owner reference and service account
	//    1. If owner is using a service account, get the service account and generate a config file with it
	//    2. If owner doesn't use service account, generate a new service account yaml file with owner name as service account name

	azureIdentityBindings, err := kuberneteshelper.ListAzureIdentityBinding(context.TODO(), dc.kubeClient, dc.namespace)
	if err != nil {
		return err
	}
	azureIdentities, err := kuberneteshelper.ListAzureIdentity(context.TODO(), dc.kubeClient, dc.namespace)
	if err != nil {
		return err
	}
	azureIdentityMap := make(map[string]aadpodv1.AzureIdentity)
	for _, azureIdentity := range azureIdentities {
		if azureIdentity.Spec.Type == aadpodv1.UserAssignedMSI {
			azureIdentityMap[azureIdentity.Name] = azureIdentity
		}
	}

	labelsToAzureIdentityMap := filterAzureIdentities(azureIdentityBindings, azureIdentityMap)
	if count := len(labelsToAzureIdentityMap); count > 0 {
		mlog.Debug("found valid aad-pod-identity bindings", "count", count)
	} else {
		mlog.Debug("did not find any valid aad-pod-identity bindings")
	}

	ownerReferences := make(map[metav1.OwnerReference]string)
	results := make(map[client.Object]string)

	for selector, azureIdentity := range labelsToAzureIdentityMap {
		mlog.Debug("getting pods", "selector", selector)
		pods, err := kuberneteshelper.ListPods(context.TODO(), dc.kubeClient, dc.namespace, map[string]string{aadpodv1.CRDLabelKey: selector})
		if err != nil {
			return err
		}
		for i := range pods {
			// for pods created by higher level constructors like deployment, statefulset, cronjob, job, daemonset, replicaset, replicationcontroller
			// we can get the owner reference with pod.OwnerReferences
			ownerFound := false
			if len(pods[i].OwnerReferences) > 0 {
				for _, ownerReference := range pods[i].OwnerReferences {
					// only get the owner reference that was set by the parent controller
					if ownerReference.Controller != nil && *ownerReference.Controller {
						ownerReferences[ownerReference] = azureIdentity.Spec.ClientID
						ownerFound = true
						break
					}
				}
			}
			// this is a standalone pod, so add it to the results
			if !ownerFound {
				p := pods[i]
				results[&p] = azureIdentity.Spec.ClientID
			}
		}
	}

	for ownerReference, clientID := range ownerReferences {
		owner, err := dc.getOwner(ownerReference)
		if err != nil {
			return err
		}
		results[owner] = clientID
	}

	// results contains all the resources that we need to generate a config file.
	// for each entry in the results map, we will generate a service account yaml file
	// and a resource file
	for o, clientID := range results {
		localObject := k8s.NewLocalObject(o)

		sa, err := dc.createServiceAccountFile(localObject.GetServiceAccountName(), localObject.GetName(), clientID)
		if err != nil {
			return err
		}
		if err = dc.createResourceFile(localObject, sa); err != nil {
			return err
		}
		mlog.Debug("generated config",
			"kind", strings.ToLower(localObject.GetObjectKind().GroupVersionKind().Kind),
			"name", localObject.GetName(),
			"clientID", clientID,
		)
	}

	if len(results) == 0 {
		mlog.Debug("no aad-pod-identity configuration found", "namespace", dc.namespace)
		return nil
	}

	mlog.Info("generated resource and service account files", "directory", dc.outputDir)
	mlog.Info(nextStepsLogMessage)
	return nil
}