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

     1  package nmi
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"reflect"
     7  	"testing"
     8  
     9  	aadpodid "github.com/Azure/aad-pod-identity/pkg/apis/aadpodidentity"
    10  	auth "github.com/Azure/aad-pod-identity/pkg/auth"
    11  	"github.com/Azure/aad-pod-identity/pkg/k8s"
    12  	"github.com/Azure/aad-pod-identity/pkg/metrics"
    13  
    14  	v1 "k8s.io/api/core/v1"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/client-go/kubernetes/fake"
    17  )
    18  
    19  type TestKubeClient struct {
    20  	k8s.Client
    21  	azureIdentities interface{}
    22  	err             error
    23  }
    24  
    25  func NewTestKubeClient(azids interface{}) *TestKubeClient {
    26  	return &TestKubeClient{
    27  		azureIdentities: azids,
    28  	}
    29  }
    30  
    31  func (c *TestKubeClient) ListPodIds(podns, podname string) (map[string][]aadpodid.AzureIdentity, error) {
    32  	identities, _ := c.azureIdentities.(map[string][]aadpodid.AzureIdentity)
    33  	return identities, c.err
    34  }
    35  
    36  func TestGetTokenForMatchingIDBySP(t *testing.T) {
    37  	fakeClient := fake.NewSimpleClientset()
    38  	reporter, err := metrics.NewReporter()
    39  	if err != nil {
    40  		t.Fatalf("expected nil error, got: %+v", err)
    41  	}
    42  	auth.InitReporter(reporter)
    43  
    44  	secret := &v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "clientSecret"}, Data: make(map[string][]byte)}
    45  	val, _ := base64.StdEncoding.DecodeString("YWJjZA==")
    46  	secret.Data["key1"] = val
    47  	_, err = fakeClient.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{})
    48  	if err != nil {
    49  		t.Fatalf("Error creating secret: %v", err)
    50  	}
    51  
    52  	kubeClient := &k8s.KubeClient{ClientSet: fakeClient}
    53  	tokenClient, err := NewStandardTokenClient(kubeClient, Config{})
    54  	if err != nil {
    55  		t.Fatalf("expected err to be nil, got: %v", err)
    56  	}
    57  
    58  	secretRef := v1.SecretReference{
    59  		Name:      "clientSecret",
    60  		Namespace: "default",
    61  	}
    62  
    63  	podID := aadpodid.AzureIdentity{
    64  		Spec: aadpodid.AzureIdentitySpec{
    65  			Type:           aadpodid.ServicePrincipal,
    66  			TenantID:       "11111111-1111-1111-1111-111111111111",
    67  			ClientID:       "aabc0000-a83v-9h4m-000j-2c0a66b0c1f9",
    68  			ClientPassword: secretRef,
    69  		},
    70  	}
    71  	_, _ = tokenClient.GetTokens(context.Background(), podID.Spec.ClientID, "https://management.azure.com/", podID)
    72  }
    73  
    74  func TestGetTokenForMatchingIDBySPCertificate(t *testing.T) {
    75  	fakeClient := fake.NewSimpleClientset()
    76  	reporter, err := metrics.NewReporter()
    77  	if err != nil {
    78  		t.Fatalf("expected nil error, got: %+v", err)
    79  	}
    80  	auth.InitReporter(reporter)
    81  
    82  	secret := &v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "certificate"}, Data: make(map[string][]byte)}
    83  	val, _ := base64.StdEncoding.DecodeString("YWJjZA==")
    84  	secret.Data["certificate"] = val
    85  	secret.Data["password"] = val
    86  	_, err = fakeClient.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{})
    87  	if err != nil {
    88  		t.Fatalf("Error creating secret: %v", err)
    89  	}
    90  
    91  	kubeClient := &k8s.KubeClient{ClientSet: fakeClient}
    92  	tokenClient, err := NewStandardTokenClient(kubeClient, Config{})
    93  	if err != nil {
    94  		t.Fatalf("expected err to be nil, got: %v", err)
    95  	}
    96  
    97  	secretRef := v1.SecretReference{
    98  		Name:      "certificate",
    99  		Namespace: "default",
   100  	}
   101  
   102  	podID := aadpodid.AzureIdentity{
   103  		Spec: aadpodid.AzureIdentitySpec{
   104  			Type:           aadpodid.ServicePrincipalCertificate,
   105  			TenantID:       "tid",
   106  			ClientID:       "aabc0000-a83v-9h4m-000j-2c0a66b0c1f9",
   107  			ClientPassword: secretRef,
   108  		},
   109  	}
   110  	_, _ = tokenClient.GetTokens(context.Background(), podID.Spec.ClientID, "https://management.azure.com/", podID)
   111  }
   112  
   113  func TestGetIdentitiesStandardClient(t *testing.T) {
   114  	cases := []struct {
   115  		name                  string
   116  		azureIdentities       map[string][]aadpodid.AzureIdentity
   117  		clientID              string
   118  		resourceID            string
   119  		expectedErr           bool
   120  		expectedAzureIdentity *aadpodid.AzureIdentity
   121  		isNamespaced          bool
   122  		podName               string
   123  		podNamespace          string
   124  	}{
   125  		{
   126  			name:                  "no azure identities",
   127  			azureIdentities:       make(map[string][]aadpodid.AzureIdentity),
   128  			expectedErr:           true,
   129  			expectedAzureIdentity: nil,
   130  			podName:               "pod1",
   131  			podNamespace:          "default",
   132  		},
   133  		{
   134  			name: "azure identities with old 1.3/1.4, no request client id",
   135  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   136  				"": {
   137  					{
   138  						ObjectMeta: metav1.ObjectMeta{
   139  							Name:      "azid1",
   140  							Namespace: "default",
   141  						},
   142  						Spec: aadpodid.AzureIdentitySpec{
   143  							ClientID: "clientid1",
   144  						},
   145  					},
   146  					{
   147  						ObjectMeta: metav1.ObjectMeta{
   148  							Name:      "azid2",
   149  							Namespace: "default",
   150  						},
   151  						Spec: aadpodid.AzureIdentitySpec{
   152  							ClientID: "clientid2",
   153  						},
   154  					},
   155  				},
   156  			},
   157  			expectedErr: false,
   158  			expectedAzureIdentity: &aadpodid.AzureIdentity{
   159  				ObjectMeta: metav1.ObjectMeta{
   160  					Name:      "azid1",
   161  					Namespace: "default",
   162  				},
   163  				Spec: aadpodid.AzureIdentitySpec{
   164  					ClientID: "clientid1",
   165  				},
   166  			},
   167  			podName:      "pod2",
   168  			podNamespace: "default",
   169  		},
   170  		{
   171  			name: "no identity requested, found in created state only",
   172  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   173  				aadpodid.AssignedIDCreated: {
   174  					{
   175  						ObjectMeta: metav1.ObjectMeta{
   176  							Name:      "azid3",
   177  							Namespace: "default",
   178  						},
   179  						Spec: aadpodid.AzureIdentitySpec{
   180  							ClientID: "clientid3",
   181  						},
   182  					},
   183  					{
   184  						ObjectMeta: metav1.ObjectMeta{
   185  							Name:      "azid4",
   186  							Namespace: "default",
   187  						},
   188  						Spec: aadpodid.AzureIdentitySpec{
   189  							ClientID: "clientid4",
   190  						},
   191  					},
   192  				},
   193  			},
   194  			expectedAzureIdentity: &aadpodid.AzureIdentity{},
   195  			expectedErr:           true,
   196  			podName:               "pod3",
   197  			podNamespace:          "default",
   198  		},
   199  		{
   200  			name: "no identity requested, found in assigned state",
   201  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   202  				aadpodid.AssignedIDAssigned: {
   203  					{
   204  						ObjectMeta: metav1.ObjectMeta{
   205  							Name:      "azid5",
   206  							Namespace: "default",
   207  						},
   208  						Spec: aadpodid.AzureIdentitySpec{
   209  							ClientID: "clientid5",
   210  						},
   211  					},
   212  					{
   213  						ObjectMeta: metav1.ObjectMeta{
   214  							Name:      "azid6",
   215  							Namespace: "default",
   216  						},
   217  						Spec: aadpodid.AzureIdentitySpec{
   218  							ClientID: "clientid6",
   219  						},
   220  					},
   221  				},
   222  			},
   223  			expectedErr: false,
   224  			expectedAzureIdentity: &aadpodid.AzureIdentity{
   225  				ObjectMeta: metav1.ObjectMeta{
   226  					Name:      "azid5",
   227  					Namespace: "default",
   228  				},
   229  				Spec: aadpodid.AzureIdentitySpec{
   230  					ClientID: "clientid5",
   231  				},
   232  			},
   233  			podName:      "pod4",
   234  			podNamespace: "default",
   235  		},
   236  		{
   237  			name: "client id in request, no identity with same client id in assigned state",
   238  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   239  				aadpodid.AssignedIDCreated: {
   240  					{
   241  						ObjectMeta: metav1.ObjectMeta{
   242  							Name:      "azid1",
   243  							Namespace: "default",
   244  						},
   245  						Spec: aadpodid.AzureIdentitySpec{
   246  							ClientID: "clientid1",
   247  						},
   248  					},
   249  				},
   250  				aadpodid.AssignedIDAssigned: {
   251  					{
   252  						ObjectMeta: metav1.ObjectMeta{
   253  							Name:      "azid2",
   254  							Namespace: "default",
   255  						},
   256  						Spec: aadpodid.AzureIdentitySpec{
   257  							ClientID:   "clientid2",
   258  							ResourceID: "clientid1", // ensure that we are matching against ClientID
   259  						},
   260  					},
   261  				},
   262  			},
   263  			expectedErr:           true,
   264  			expectedAzureIdentity: &aadpodid.AzureIdentity{},
   265  			podName:               "pod5",
   266  			podNamespace:          "default",
   267  			clientID:              "clientid1",
   268  		},
   269  		{
   270  			name: "resource id in request, no identity with same resource id in assigned state",
   271  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   272  				aadpodid.AssignedIDCreated: {
   273  					{
   274  						ObjectMeta: metav1.ObjectMeta{
   275  							Name:      "azid1",
   276  							Namespace: "default",
   277  						},
   278  						Spec: aadpodid.AzureIdentitySpec{
   279  							ResourceID: "resourceid1",
   280  						},
   281  					},
   282  				},
   283  				aadpodid.AssignedIDAssigned: {
   284  					{
   285  						ObjectMeta: metav1.ObjectMeta{
   286  							Name:      "azid2",
   287  							Namespace: "default",
   288  						},
   289  						Spec: aadpodid.AzureIdentitySpec{
   290  							ClientID:   "resourceid1", // ensure we are matching against ResourceID
   291  							ResourceID: "resourceid2",
   292  						},
   293  					},
   294  				},
   295  			},
   296  			expectedErr:           true,
   297  			expectedAzureIdentity: &aadpodid.AzureIdentity{},
   298  			podName:               "pod5",
   299  			podNamespace:          "default",
   300  			resourceID:            "resourceid1",
   301  		},
   302  		{
   303  			name: "client id in request, found matching identity",
   304  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   305  				aadpodid.AssignedIDCreated: {
   306  					{
   307  						ObjectMeta: metav1.ObjectMeta{
   308  							Name:      "azid1",
   309  							Namespace: "default",
   310  						},
   311  						Spec: aadpodid.AzureIdentitySpec{
   312  							ClientID: "clientid1",
   313  						},
   314  					},
   315  				},
   316  				aadpodid.AssignedIDAssigned: {
   317  					{
   318  						ObjectMeta: metav1.ObjectMeta{
   319  							Name:      "azid2",
   320  							Namespace: "default",
   321  						},
   322  						Spec: aadpodid.AzureIdentitySpec{
   323  							ClientID:   "clientid2",
   324  							ResourceID: "resourceid2",
   325  						},
   326  					},
   327  				},
   328  			},
   329  			expectedAzureIdentity: &aadpodid.AzureIdentity{
   330  				ObjectMeta: metav1.ObjectMeta{
   331  					Name:      "azid2",
   332  					Namespace: "default",
   333  				},
   334  				Spec: aadpodid.AzureIdentitySpec{
   335  					ClientID:   "clientid2",
   336  					ResourceID: "resourceid2",
   337  				},
   338  			},
   339  			podName:      "pod5",
   340  			podNamespace: "default",
   341  			clientID:     "clientid2",
   342  		},
   343  		{
   344  			name: "resource id in request, found matching identity",
   345  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   346  				aadpodid.AssignedIDCreated: {
   347  					{
   348  						ObjectMeta: metav1.ObjectMeta{
   349  							Name:      "azid1",
   350  							Namespace: "default",
   351  						},
   352  						Spec: aadpodid.AzureIdentitySpec{
   353  							ResourceID: "resourceid1",
   354  						},
   355  					},
   356  				},
   357  				aadpodid.AssignedIDAssigned: {
   358  					{
   359  						ObjectMeta: metav1.ObjectMeta{
   360  							Name:      "azid2",
   361  							Namespace: "default",
   362  						},
   363  						Spec: aadpodid.AzureIdentitySpec{
   364  							ClientID:   "resourceid2",
   365  							ResourceID: "resourceid2",
   366  						},
   367  					},
   368  				},
   369  			},
   370  			expectedAzureIdentity: &aadpodid.AzureIdentity{
   371  				ObjectMeta: metav1.ObjectMeta{
   372  					Name:      "azid2",
   373  					Namespace: "default",
   374  				},
   375  				Spec: aadpodid.AzureIdentitySpec{
   376  					ClientID:   "resourceid2",
   377  					ResourceID: "resourceid2",
   378  				},
   379  			},
   380  			podName:      "pod5",
   381  			podNamespace: "default",
   382  			resourceID:   "resourceid2",
   383  		},
   384  		{
   385  			name: "no identity requested, identity in same namespace returned with force namespace mode",
   386  			azureIdentities: map[string][]aadpodid.AzureIdentity{
   387  				aadpodid.AssignedIDAssigned: {
   388  					{
   389  						ObjectMeta: metav1.ObjectMeta{
   390  							Name:      "azid2",
   391  							Namespace: "default",
   392  						},
   393  						Spec: aadpodid.AzureIdentitySpec{
   394  							ClientID: "clientid2",
   395  						},
   396  					},
   397  					{
   398  						ObjectMeta: metav1.ObjectMeta{
   399  							Name:      "azid1",
   400  							Namespace: "default",
   401  						},
   402  						Spec: aadpodid.AzureIdentitySpec{
   403  							ClientID: "clientid1",
   404  						},
   405  					},
   406  					{
   407  						ObjectMeta: metav1.ObjectMeta{
   408  							Name:      "azid3",
   409  							Namespace: "testns",
   410  						},
   411  						Spec: aadpodid.AzureIdentitySpec{
   412  							ClientID: "clientid3",
   413  						},
   414  					},
   415  				},
   416  			},
   417  			expectedErr: false,
   418  			expectedAzureIdentity: &aadpodid.AzureIdentity{
   419  				ObjectMeta: metav1.ObjectMeta{
   420  					Name:      "azid3",
   421  					Namespace: "testns",
   422  				},
   423  				Spec: aadpodid.AzureIdentitySpec{
   424  					ClientID: "clientid3",
   425  				},
   426  			},
   427  			podName:      "pod8",
   428  			podNamespace: "testns",
   429  			isNamespaced: true,
   430  		},
   431  	}
   432  
   433  	for _, tc := range cases {
   434  		t.Run(tc.name, func(t *testing.T) {
   435  			tokenClient, err := NewStandardTokenClient(NewTestKubeClient(tc.azureIdentities), Config{
   436  				Mode:                               "standard",
   437  				RetryAttemptsForCreated:            2,
   438  				RetryAttemptsForAssigned:           1,
   439  				FindIdentityRetryIntervalInSeconds: 1,
   440  				Namespaced:                         tc.isNamespaced,
   441  			})
   442  			if err != nil {
   443  				t.Fatalf("expected err to be nil, got: %v", err)
   444  			}
   445  
   446  			azIdentity, err := tokenClient.GetIdentities(context.Background(), tc.podNamespace, tc.podName, tc.clientID, tc.resourceID)
   447  			if tc.expectedErr != (err != nil) {
   448  				t.Fatalf("expected error: %v, got: %v", tc.expectedErr, err)
   449  			}
   450  			if !reflect.DeepEqual(tc.expectedAzureIdentity, azIdentity) {
   451  				t.Fatalf("expected the azure identity to be equal")
   452  			}
   453  		})
   454  	}
   455  }