github.com/argoproj/argo-cd@v1.8.7/util/clusterauth/clusterauth_test.go (about) 1 package clusterauth 2 3 import ( 4 "context" 5 "io/ioutil" 6 "testing" 7 8 "github.com/ghodss/yaml" 9 "github.com/stretchr/testify/assert" 10 corev1 "k8s.io/api/core/v1" 11 apierr "k8s.io/apimachinery/pkg/api/errors" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/runtime" 14 "k8s.io/client-go/kubernetes/fake" 15 kubetesting "k8s.io/client-go/testing" 16 17 "github.com/argoproj/argo-cd/util/errors" 18 ) 19 20 const ( 21 testToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhcmdvY2QtbWFuYWdlci10b2tlbi10ajc5ciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhcmdvY2QtbWFuYWdlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjkxZGQzN2NmLThkOTItMTFlOS1hMDkxLWQ2NWYyYWU3ZmE4ZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTphcmdvY2QtbWFuYWdlciJ9.ytZjt2pDV8-A7DBMR06zQ3wt9cuVEfq262TQw7sdra-KRpDpMPnziMhc8bkwvgW-LGhTWUh5iu1y-1QhEx6mtbCt7vQArlBRxfvM5ys6ClFkplzq5c2TtZ7EzGSD0Up7tdxuG9dvR6TGXYdfFcG779yCdZo2H48sz5OSJfdEriduMEY1iL5suZd3ebOoVi1fGflmqFEkZX6SvxkoArl5mtNP6TvZ1eTcn64xh4ws152hxio42E-eSnl_CET4tpB5vgP5BVlSKW2xB7w2GJxqdETA5LJRI_OilY77dTOp8cMr_Ck3EOeda3zHfh4Okflg8rZFEeAuJYahQNeAILLkcA" 22 ) 23 24 var ( 25 testClaims = ServiceAccountClaims{ 26 Sub: "system:serviceaccount:kube-system:argocd-manager", 27 Iss: "kubernetes/serviceaccount", 28 Namespace: "kube-system", 29 SecretName: "argocd-manager-token-tj79r", 30 ServiceAccountName: "argocd-manager", 31 ServiceAccountUID: "91dd37cf-8d92-11e9-a091-d65f2ae7fa8d", 32 } 33 ) 34 35 func newServiceAccount() *corev1.ServiceAccount { 36 saBytes, err := ioutil.ReadFile("./testdata/argocd-manager-sa.yaml") 37 errors.CheckError(err) 38 var sa corev1.ServiceAccount 39 err = yaml.Unmarshal(saBytes, &sa) 40 errors.CheckError(err) 41 return &sa 42 } 43 44 func newServiceAccountSecret() *corev1.Secret { 45 secretBytes, err := ioutil.ReadFile("./testdata/argocd-manager-sa-token.yaml") 46 errors.CheckError(err) 47 var secret corev1.Secret 48 err = yaml.Unmarshal(secretBytes, &secret) 49 errors.CheckError(err) 50 return &secret 51 } 52 53 func TestParseServiceAccountToken(t *testing.T) { 54 claims, err := ParseServiceAccountToken(testToken) 55 assert.NoError(t, err) 56 assert.Equal(t, testClaims, *claims) 57 } 58 59 func TestCreateServiceAccount(t *testing.T) { 60 ns := &corev1.Namespace{ 61 ObjectMeta: metav1.ObjectMeta{ 62 Name: "kube-system", 63 }, 64 } 65 sa := &corev1.ServiceAccount{ 66 TypeMeta: metav1.TypeMeta{ 67 APIVersion: "v1", 68 Kind: "ServiceAccount", 69 }, 70 ObjectMeta: metav1.ObjectMeta{ 71 Name: "argocd-manager", 72 Namespace: "kube-system", 73 }, 74 } 75 76 t.Run("New SA", func(t *testing.T) { 77 cs := fake.NewSimpleClientset(ns) 78 err := CreateServiceAccount(cs, "argocd-manager", "kube-system") 79 assert.NoError(t, err) 80 rsa, err := cs.CoreV1().ServiceAccounts("kube-system").Get(context.Background(), "argocd-manager", metav1.GetOptions{}) 81 assert.NoError(t, err) 82 assert.NotNil(t, rsa) 83 }) 84 85 t.Run("SA exists already", func(t *testing.T) { 86 cs := fake.NewSimpleClientset(ns, sa) 87 err := CreateServiceAccount(cs, "argocd-manager", "kube-system") 88 assert.NoError(t, err) 89 rsa, err := cs.CoreV1().ServiceAccounts("kube-system").Get(context.Background(), "argocd-manager", metav1.GetOptions{}) 90 assert.NoError(t, err) 91 assert.NotNil(t, rsa) 92 }) 93 94 t.Run("Invalid name", func(t *testing.T) { 95 cs := fake.NewSimpleClientset(ns) 96 err := CreateServiceAccount(cs, "", "kube-system") 97 assert.NoError(t, err) 98 rsa, err := cs.CoreV1().ServiceAccounts("kube-system").Get(context.Background(), "argocd-manager", metav1.GetOptions{}) 99 assert.Error(t, err) 100 assert.Nil(t, rsa) 101 }) 102 103 t.Run("Invalid namespace", func(t *testing.T) { 104 cs := fake.NewSimpleClientset() 105 err := CreateServiceAccount(cs, "argocd-manager", "invalid") 106 assert.NoError(t, err) 107 rsa, err := cs.CoreV1().ServiceAccounts("invalid").Get(context.Background(), "argocd-manager", metav1.GetOptions{}) 108 assert.NoError(t, err) 109 assert.NotNil(t, rsa) 110 }) 111 } 112 113 func TestInstallClusterManagerRBAC(t *testing.T) { 114 ns := &corev1.Namespace{ 115 ObjectMeta: metav1.ObjectMeta{ 116 Name: "test", 117 }, 118 } 119 secret := &corev1.Secret{ 120 ObjectMeta: metav1.ObjectMeta{ 121 Name: "sa-secret", 122 Namespace: "test", 123 }, 124 Type: corev1.SecretTypeServiceAccountToken, 125 Data: map[string][]byte{ 126 "token": []byte("foobar"), 127 }, 128 } 129 sa := &corev1.ServiceAccount{ 130 ObjectMeta: metav1.ObjectMeta{ 131 Name: ArgoCDManagerServiceAccount, 132 Namespace: "test", 133 }, 134 Secrets: []corev1.ObjectReference{ 135 corev1.ObjectReference{ 136 Kind: secret.GetObjectKind().GroupVersionKind().Kind, 137 APIVersion: secret.APIVersion, 138 Name: secret.GetName(), 139 Namespace: secret.GetNamespace(), 140 UID: secret.GetUID(), 141 ResourceVersion: secret.GetResourceVersion(), 142 }, 143 }, 144 } 145 146 t.Run("Cluster Scope - Success", func(t *testing.T) { 147 cs := fake.NewSimpleClientset(ns, secret, sa) 148 token, err := InstallClusterManagerRBAC(cs, "test", nil) 149 assert.NoError(t, err) 150 assert.Equal(t, "foobar", token) 151 }) 152 153 t.Run("Cluster Scope - Missing data in secret", func(t *testing.T) { 154 nsecret := secret.DeepCopy() 155 nsecret.Data = make(map[string][]byte) 156 cs := fake.NewSimpleClientset(ns, nsecret, sa) 157 token, err := InstallClusterManagerRBAC(cs, "test", nil) 158 assert.Error(t, err) 159 assert.Empty(t, token) 160 }) 161 162 t.Run("Namespace Scope - Success", func(t *testing.T) { 163 cs := fake.NewSimpleClientset(ns, secret, sa) 164 token, err := InstallClusterManagerRBAC(cs, "test", []string{"nsa"}) 165 assert.NoError(t, err) 166 assert.Equal(t, "foobar", token) 167 }) 168 169 t.Run("Namespace Scope - Missing data in secret", func(t *testing.T) { 170 nsecret := secret.DeepCopy() 171 nsecret.Data = make(map[string][]byte) 172 cs := fake.NewSimpleClientset(ns, nsecret, sa) 173 token, err := InstallClusterManagerRBAC(cs, "test", []string{"nsa"}) 174 assert.Error(t, err) 175 assert.Empty(t, token) 176 }) 177 178 } 179 180 func TestUninstallClusterManagerRBAC(t *testing.T) { 181 t.Run("Success", func(t *testing.T) { 182 cs := fake.NewSimpleClientset(newServiceAccountSecret()) 183 err := UninstallClusterManagerRBAC(cs) 184 assert.NoError(t, err) 185 }) 186 } 187 188 func TestGenerateNewClusterManagerSecret(t *testing.T) { 189 kubeclientset := fake.NewSimpleClientset(newServiceAccountSecret()) 190 kubeclientset.ReactionChain = nil 191 192 generatedSecret := newServiceAccountSecret() 193 generatedSecret.Name = "argocd-manager-token-abc123" 194 generatedSecret.Data = map[string][]byte{ 195 "token": []byte("fake-token"), 196 } 197 198 kubeclientset.AddReactor("*", "secrets", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { 199 return true, generatedSecret, nil 200 }) 201 202 created, err := GenerateNewClusterManagerSecret(kubeclientset, &testClaims) 203 assert.NoError(t, err) 204 assert.Equal(t, "argocd-manager-token-abc123", created.Name) 205 assert.Equal(t, "fake-token", string(created.Data["token"])) 206 } 207 208 func TestRotateServiceAccountSecrets(t *testing.T) { 209 generatedSecret := newServiceAccountSecret() 210 generatedSecret.Name = "argocd-manager-token-abc123" 211 generatedSecret.Data = map[string][]byte{ 212 "token": []byte("fake-token"), 213 } 214 215 kubeclientset := fake.NewSimpleClientset(newServiceAccount(), newServiceAccountSecret(), generatedSecret) 216 217 err := RotateServiceAccountSecrets(kubeclientset, &testClaims, generatedSecret) 218 assert.NoError(t, err) 219 220 // Verify service account references new secret and old secret is deleted 221 saClient := kubeclientset.CoreV1().ServiceAccounts(testClaims.Namespace) 222 sa, err := saClient.Get(context.Background(), testClaims.ServiceAccountName, metav1.GetOptions{}) 223 assert.NoError(t, err) 224 assert.Equal(t, sa.Secrets, []corev1.ObjectReference{ 225 { 226 Name: "argocd-manager-token-abc123", 227 }, 228 }) 229 secretsClient := kubeclientset.CoreV1().Secrets(testClaims.Namespace) 230 _, err = secretsClient.Get(context.Background(), testClaims.SecretName, metav1.GetOptions{}) 231 assert.True(t, apierr.IsNotFound(err)) 232 } 233 234 func TestGetServiceAccountBearerToken(t *testing.T) { 235 sa := newServiceAccount() 236 tokenSecret := newServiceAccountSecret() 237 dockercfgSecret := &corev1.Secret{ 238 ObjectMeta: metav1.ObjectMeta{ 239 Name: "argocd-manager-dockercfg-d8j66", 240 Namespace: "kube-system", 241 }, 242 Type: corev1.SecretTypeDockercfg, 243 // Skipping data, doesn't really matter. 244 } 245 sa.Secrets = []corev1.ObjectReference{ 246 { 247 Name: dockercfgSecret.Name, 248 Namespace: dockercfgSecret.Namespace, 249 }, 250 { 251 Name: tokenSecret.Name, 252 Namespace: tokenSecret.Namespace, 253 }, 254 } 255 kubeclientset := fake.NewSimpleClientset(sa, dockercfgSecret, tokenSecret) 256 257 token, err := GetServiceAccountBearerToken(kubeclientset, "kube-system", sa.Name) 258 assert.NoError(t, err) 259 assert.Equal(t, testToken, token) 260 }