github.com/Azure/aad-pod-identity@v1.8.17/pkg/nmi/managed.go (about)

     1  package nmi
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	aadpodid "github.com/Azure/aad-pod-identity/pkg/apis/aadpodidentity"
     9  	auth "github.com/Azure/aad-pod-identity/pkg/auth"
    10  	k8s "github.com/Azure/aad-pod-identity/pkg/k8s"
    11  	utils "github.com/Azure/aad-pod-identity/pkg/utils"
    12  
    13  	"github.com/Azure/go-autorest/autorest/adal"
    14  	"k8s.io/klog/v2"
    15  )
    16  
    17  // ManagedClient implements the TokenClient interface
    18  type ManagedClient struct {
    19  	TokenClient
    20  	KubeClient   k8s.Client
    21  	IsNamespaced bool
    22  }
    23  
    24  // NewManagedTokenClient creates new managed token client
    25  func NewManagedTokenClient(client k8s.Client, config Config) (*ManagedClient, error) {
    26  	// managed mode supported only in force namespaced mode
    27  	if !config.Namespaced {
    28  		return nil, fmt.Errorf("managed mode not intialized in force namespaced mode")
    29  	}
    30  	return &ManagedClient{
    31  		KubeClient:   client,
    32  		IsNamespaced: config.Namespaced,
    33  	}, nil
    34  }
    35  
    36  // GetIdentities gets the azure identity that matches the podns/podname and client id
    37  func (mc *ManagedClient) GetIdentities(ctx context.Context, podns, podname, clientID, resourceID string) (*aadpodid.AzureIdentity, error) {
    38  	// get pod object to retrieve labels
    39  	pod, err := mc.KubeClient.GetPod(podns, podname)
    40  	if err != nil {
    41  		return nil, fmt.Errorf("failed to get pod %s/%s, error: %+v", podns, podname, err)
    42  	}
    43  	// get all the azure identities based on azure identity bindings
    44  	azureIdentities, err := mc.KubeClient.ListPodIdsWithBinding(podns, pod.Labels)
    45  	if err != nil {
    46  		return nil, fmt.Errorf("failed to get AzureIdentities for pod %s/%s, error: %+v", podns, podname, err)
    47  	}
    48  	identityUnspecified := len(clientID) == 0 && len(resourceID) == 0
    49  	for _, id := range azureIdentities {
    50  		// if client id exists in the request, then send the first identity that matched the client id
    51  		if len(clientID) != 0 && id.Spec.ClientID == clientID {
    52  			klog.Infof("clientID in request: %s, %s/%s has been matched with azure identity %s/%s", utils.RedactClientID(clientID), podns, podname, id.Namespace, id.Name)
    53  			return &id, nil
    54  		}
    55  
    56  		// if resource id exists in the request, then send the first identity that matched the resource id
    57  		if len(resourceID) != 0 && id.Spec.ResourceID == resourceID {
    58  			return &id, nil
    59  		}
    60  
    61  		// if client doesn't exist in the request, then return the first identity in the same namespace as the pod
    62  		if identityUnspecified && strings.EqualFold(id.Namespace, podns) {
    63  			klog.Infof("no clientID or resourceID in request. %s/%s has been matched with azure identity %s/%s", podns, podname, id.Namespace, id.Name)
    64  			return &id, nil
    65  		}
    66  	}
    67  	return nil, fmt.Errorf("no azure identity found for request clientID %s", utils.RedactClientID(clientID))
    68  }
    69  
    70  // GetTokens returns ADAL tokens based on the request and its pod identity.
    71  func (mc *ManagedClient) GetTokens(ctx context.Context, rqClientID, rqResource string, azureID aadpodid.AzureIdentity) ([]*adal.Token, error) {
    72  	rqHasClientID := len(rqClientID) != 0
    73  	clientID := azureID.Spec.ClientID
    74  
    75  	idType := azureID.Spec.Type
    76  	switch idType {
    77  	case aadpodid.UserAssignedMSI:
    78  		if rqHasClientID && !strings.EqualFold(rqClientID, clientID) {
    79  			klog.Warningf("client ID mismatch, requested:%s available:%s", rqClientID, clientID)
    80  		}
    81  		klog.Infof("matched identityType:%v clientid:%s resource:%s", idType, utils.RedactClientID(clientID), rqResource)
    82  		token, err := auth.GetServicePrincipalTokenFromMSIWithUserAssignedID(clientID, rqResource)
    83  		return []*adal.Token{token}, err
    84  	case aadpodid.ServicePrincipal:
    85  		tenantID := azureID.Spec.TenantID
    86  		auxiliaryTenantIDs := azureID.Spec.AuxiliaryTenantIDs
    87  		adEndpoint := azureID.Spec.ADEndpoint
    88  		secretRef := &azureID.Spec.ClientPassword
    89  		klog.Infof("matched identityType:%v adendpoint:%s tenantid:%s auxiliaryTenantIDs:%v clientid:%s resource:%s",
    90  			idType, adEndpoint, tenantID, auxiliaryTenantIDs, utils.RedactClientID(clientID), rqResource)
    91  		secret, err := mc.KubeClient.GetSecret(secretRef)
    92  		if err != nil {
    93  			return nil, fmt.Errorf("failed to get Kubernetes secret %s/%s, err: %v", secretRef.Namespace, secretRef.Name, err)
    94  		}
    95  		clientSecret := ""
    96  		for _, v := range secret.Data {
    97  			clientSecret = string(v)
    98  			break
    99  		}
   100  		tokens, err := auth.GetServicePrincipalToken(adEndpoint, tenantID, clientID, clientSecret, rqResource, auxiliaryTenantIDs)
   101  		return tokens, err
   102  	case aadpodid.ServicePrincipalCertificate:
   103  		tenantID := azureID.Spec.TenantID
   104  		adEndpoint := azureID.Spec.ADEndpoint
   105  		secretRef := &azureID.Spec.ClientPassword
   106  		klog.Infof("matched identityType:%v adendpoint:%s tenantid:%s clientid:%s resource:%s",
   107  			idType, adEndpoint, tenantID, utils.RedactClientID(clientID), rqResource)
   108  		secret, err := mc.KubeClient.GetSecret(secretRef)
   109  		if err != nil {
   110  			return nil, fmt.Errorf("failed to get Kubernetes secret %s/%s, err: %v", secretRef.Namespace, secretRef.Name, err)
   111  		}
   112  		certificate, password := secret.Data["certificate"], secret.Data["password"]
   113  		token, err := auth.GetServicePrincipalTokenWithCertificate(adEndpoint, tenantID, clientID,
   114  			certificate, string(password), rqResource)
   115  		return []*adal.Token{token}, err
   116  	default:
   117  		return nil, fmt.Errorf("unsupported identity type %+v", idType)
   118  	}
   119  }