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 }