jwt_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package serviceaccount_test
  14. import (
  15. "context"
  16. "reflect"
  17. "strings"
  18. "testing"
  19. v1 "k8s.io/api/core/v1"
  20. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  21. "k8s.io/apiserver/pkg/authentication/authenticator"
  22. clientset "k8s.io/client-go/kubernetes"
  23. "k8s.io/client-go/kubernetes/fake"
  24. v1listers "k8s.io/client-go/listers/core/v1"
  25. "k8s.io/client-go/tools/cache"
  26. "k8s.io/client-go/util/keyutil"
  27. serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
  28. "k8s.io/kubernetes/pkg/serviceaccount"
  29. )
  30. const otherPublicKey = `-----BEGIN PUBLIC KEY-----
  31. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArXz0QkIG1B5Bj2/W69GH
  32. rsm5e+RC3kE+VTgocge0atqlLBek35tRqLgUi3AcIrBZ/0YctMSWDVcRt5fkhWwe
  33. Lqjj6qvAyNyOkrkBi1NFDpJBjYJtuKHgRhNxXbOzTSNpdSKXTfOkzqv56MwHOP25
  34. yP/NNAODUtr92D5ySI5QX8RbXW+uDn+ixul286PBW/BCrE4tuS88dA0tYJPf8LCu
  35. sqQOwlXYH/rNUg4Pyl9xxhR5DIJR0OzNNfChjw60zieRIt2LfM83fXhwk8IxRGkc
  36. gPZm7ZsipmfbZK2Tkhnpsa4QxDg7zHJPMsB5kxRXW0cQipXcC3baDyN9KBApNXa0
  37. PwIDAQAB
  38. -----END PUBLIC KEY-----`
  39. const rsaPublicKey = `-----BEGIN PUBLIC KEY-----
  40. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA249XwEo9k4tM8fMxV7zx
  41. OhcrP+WvXn917koM5Qr2ZXs4vo26e4ytdlrV0bQ9SlcLpQVSYjIxNfhTZdDt+ecI
  42. zshKuv1gKIxbbLQMOuK1eA/4HALyEkFgmS/tleLJrhc65tKPMGD+pKQ/xhmzRuCG
  43. 51RoiMgbQxaCyYxGfNLpLAZK9L0Tctv9a0mJmGIYnIOQM4kC1A1I1n3EsXMWmeJU
  44. j7OTh/AjjCnMnkgvKT2tpKxYQ59PgDgU8Ssc7RDSmSkLxnrv+OrN80j6xrw0OjEi
  45. B4Ycr0PqfzZcvy8efTtFQ/Jnc4Bp1zUtFXt7+QeevePtQ2EcyELXE0i63T1CujRM
  46. WwIDAQAB
  47. -----END PUBLIC KEY-----
  48. `
  49. const rsaPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
  50. MIIEowIBAAKCAQEA249XwEo9k4tM8fMxV7zxOhcrP+WvXn917koM5Qr2ZXs4vo26
  51. e4ytdlrV0bQ9SlcLpQVSYjIxNfhTZdDt+ecIzshKuv1gKIxbbLQMOuK1eA/4HALy
  52. EkFgmS/tleLJrhc65tKPMGD+pKQ/xhmzRuCG51RoiMgbQxaCyYxGfNLpLAZK9L0T
  53. ctv9a0mJmGIYnIOQM4kC1A1I1n3EsXMWmeJUj7OTh/AjjCnMnkgvKT2tpKxYQ59P
  54. gDgU8Ssc7RDSmSkLxnrv+OrN80j6xrw0OjEiB4Ycr0PqfzZcvy8efTtFQ/Jnc4Bp
  55. 1zUtFXt7+QeevePtQ2EcyELXE0i63T1CujRMWwIDAQABAoIBAHJx8GqyCBDNbqk7
  56. e7/hI9iE1S10Wwol5GH2RWxqX28cYMKq+8aE2LI1vPiXO89xOgelk4DN6urX6xjK
  57. ZBF8RRIMQy/e/O2F4+3wl+Nl4vOXV1u6iVXMsD6JRg137mqJf1Fr9elg1bsaRofL
  58. Q7CxPoB8dhS+Qb+hj0DhlqhgA9zG345CQCAds0ZYAZe8fP7bkwrLqZpMn7Dz9WVm
  59. ++YgYYKjuE95kPuup/LtWfA9rJyE/Fws8/jGvRSpVn1XglMLSMKhLd27sE8ZUSV0
  60. 2KUzbfRGE0+AnRULRrjpYaPu0XQ2JjdNvtkjBnv27RB89W9Gklxq821eH1Y8got8
  61. FZodjxECgYEA93pz7AQZ2xDs67d1XLCzpX84GxKzttirmyj3OIlxgzVHjEMsvw8v
  62. sjFiBU5xEEQDosrBdSknnlJqyiq1YwWG/WDckr13d8G2RQWoySN7JVmTQfXcLoTu
  63. YGRiiTuoEi3ab3ZqrgGrFgX7T/cHuasbYvzCvhM2b4VIR3aSxU2DTUMCgYEA4x7J
  64. T/ErP6GkU5nKstu/mIXwNzayEO1BJvPYsy7i7EsxTm3xe/b8/6cYOz5fvJLGH5mT
  65. Q8YvuLqBcMwZardrYcwokD55UvNLOyfADDFZ6l3WntIqbA640Ok2g1X4U8J09xIq
  66. ZLIWK1yWbbvi4QCeN5hvWq47e8sIj5QHjIIjRwkCgYEAyNqjltxFN9zmzPDa2d24
  67. EAvOt3pYTYBQ1t9KtqImdL0bUqV6fZ6PsWoPCgt+DBuHb+prVPGP7Bkr/uTmznU/
  68. +AlTO+12NsYLbr2HHagkXE31DEXE7CSLa8RNjN/UKtz4Ohq7vnowJvG35FCz/mb3
  69. FUHbtHTXa2+bGBUOTf/5Hw0CgYBxw0r9EwUhw1qnUYJ5op7OzFAtp+T7m4ul8kCa
  70. SCL8TxGsgl+SQ34opE775dtYfoBk9a0RJqVit3D8yg71KFjOTNAIqHJm/Vyyjc+h
  71. i9rJDSXiuczsAVfLtPVMRfS0J9QkqeG4PIfkQmVLI/CZ2ZBmsqEcX+eFs4ZfPLun
  72. Qsxe2QKBgGuPilIbLeIBDIaPiUI0FwU8v2j8CEQBYvoQn34c95hVQsig/o5z7zlo
  73. UsO0wlTngXKlWdOcCs1kqEhTLrstf48djDxAYAxkw40nzeJOt7q52ib/fvf4/UBy
  74. X024wzbiw1q07jFCyfQmODzURAx1VNT7QVUMdz/N8vy47/H40AZJ
  75. -----END RSA PRIVATE KEY-----
  76. `
  77. // openssl ecparam -name prime256v1 -genkey -noout -out ecdsa256.pem
  78. const ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
  79. MHcCAQEEIEZmTmUhuanLjPA2CLquXivuwBDHTt5XYwgIr/kA1LtRoAoGCCqGSM49
  80. AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
  81. /IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
  82. -----END EC PRIVATE KEY-----`
  83. // openssl ec -in ecdsa256.pem -pubout -out ecdsa256pub.pem
  84. const ecdsaPublicKey = `-----BEGIN PUBLIC KEY-----
  85. MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPL
  86. X2i8uIp/C/ASqiIGUeeKQtX0/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
  87. -----END PUBLIC KEY-----`
  88. func getPrivateKey(data string) interface{} {
  89. key, _ := keyutil.ParsePrivateKeyPEM([]byte(data))
  90. return key
  91. }
  92. func getPublicKey(data string) interface{} {
  93. keys, _ := keyutil.ParsePublicKeysPEM([]byte(data))
  94. return keys[0]
  95. }
  96. func TestTokenGenerateAndValidate(t *testing.T) {
  97. expectedUserName := "system:serviceaccount:test:my-service-account"
  98. expectedUserUID := "12345"
  99. // Related API objects
  100. serviceAccount := &v1.ServiceAccount{
  101. ObjectMeta: metav1.ObjectMeta{
  102. Name: "my-service-account",
  103. UID: "12345",
  104. Namespace: "test",
  105. },
  106. }
  107. rsaSecret := &v1.Secret{
  108. ObjectMeta: metav1.ObjectMeta{
  109. Name: "my-rsa-secret",
  110. Namespace: "test",
  111. },
  112. }
  113. ecdsaSecret := &v1.Secret{
  114. ObjectMeta: metav1.ObjectMeta{
  115. Name: "my-ecdsa-secret",
  116. Namespace: "test",
  117. },
  118. }
  119. // Generate the RSA token
  120. rsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(rsaPrivateKey))
  121. if err != nil {
  122. t.Fatalf("error making generator: %v", err)
  123. }
  124. rsaToken, err := rsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
  125. if err != nil {
  126. t.Fatalf("error generating token: %v", err)
  127. }
  128. if len(rsaToken) == 0 {
  129. t.Fatalf("no token generated")
  130. }
  131. rsaSecret.Data = map[string][]byte{
  132. "token": []byte(rsaToken),
  133. }
  134. // Generate the ECDSA token
  135. ecdsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(ecdsaPrivateKey))
  136. if err != nil {
  137. t.Fatalf("error making generator: %v", err)
  138. }
  139. ecdsaToken, err := ecdsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *ecdsaSecret))
  140. if err != nil {
  141. t.Fatalf("error generating token: %v", err)
  142. }
  143. if len(ecdsaToken) == 0 {
  144. t.Fatalf("no token generated")
  145. }
  146. ecdsaSecret.Data = map[string][]byte{
  147. "token": []byte(ecdsaToken),
  148. }
  149. // Generate signer with same keys as RSA signer but different issuer
  150. badIssuerGenerator, err := serviceaccount.JWTTokenGenerator("foo", getPrivateKey(rsaPrivateKey))
  151. if err != nil {
  152. t.Fatalf("error making generator: %v", err)
  153. }
  154. badIssuerToken, err := badIssuerGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
  155. if err != nil {
  156. t.Fatalf("error generating token: %v", err)
  157. }
  158. testCases := map[string]struct {
  159. Client clientset.Interface
  160. Keys []interface{}
  161. Token string
  162. ExpectedErr bool
  163. ExpectedOK bool
  164. ExpectedUserName string
  165. ExpectedUserUID string
  166. ExpectedGroups []string
  167. }{
  168. "no keys": {
  169. Token: rsaToken,
  170. Client: nil,
  171. Keys: []interface{}{},
  172. ExpectedErr: false,
  173. ExpectedOK: false,
  174. },
  175. "invalid keys (rsa)": {
  176. Token: rsaToken,
  177. Client: nil,
  178. Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(ecdsaPublicKey)},
  179. ExpectedErr: true,
  180. ExpectedOK: false,
  181. },
  182. "invalid keys (ecdsa)": {
  183. Token: ecdsaToken,
  184. Client: nil,
  185. Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(rsaPublicKey)},
  186. ExpectedErr: true,
  187. ExpectedOK: false,
  188. },
  189. "valid key (rsa)": {
  190. Token: rsaToken,
  191. Client: nil,
  192. Keys: []interface{}{getPublicKey(rsaPublicKey)},
  193. ExpectedErr: false,
  194. ExpectedOK: true,
  195. ExpectedUserName: expectedUserName,
  196. ExpectedUserUID: expectedUserUID,
  197. ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
  198. },
  199. "valid key, invalid issuer (rsa)": {
  200. Token: badIssuerToken,
  201. Client: nil,
  202. Keys: []interface{}{getPublicKey(rsaPublicKey)},
  203. ExpectedErr: false,
  204. ExpectedOK: false,
  205. },
  206. "valid key (ecdsa)": {
  207. Token: ecdsaToken,
  208. Client: nil,
  209. Keys: []interface{}{getPublicKey(ecdsaPublicKey)},
  210. ExpectedErr: false,
  211. ExpectedOK: true,
  212. ExpectedUserName: expectedUserName,
  213. ExpectedUserUID: expectedUserUID,
  214. ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
  215. },
  216. "rotated keys (rsa)": {
  217. Token: rsaToken,
  218. Client: nil,
  219. Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(ecdsaPublicKey), getPublicKey(rsaPublicKey)},
  220. ExpectedErr: false,
  221. ExpectedOK: true,
  222. ExpectedUserName: expectedUserName,
  223. ExpectedUserUID: expectedUserUID,
  224. ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
  225. },
  226. "rotated keys (ecdsa)": {
  227. Token: ecdsaToken,
  228. Client: nil,
  229. Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(rsaPublicKey), getPublicKey(ecdsaPublicKey)},
  230. ExpectedErr: false,
  231. ExpectedOK: true,
  232. ExpectedUserName: expectedUserName,
  233. ExpectedUserUID: expectedUserUID,
  234. ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
  235. },
  236. "valid lookup": {
  237. Token: rsaToken,
  238. Client: fake.NewSimpleClientset(serviceAccount, rsaSecret, ecdsaSecret),
  239. Keys: []interface{}{getPublicKey(rsaPublicKey)},
  240. ExpectedErr: false,
  241. ExpectedOK: true,
  242. ExpectedUserName: expectedUserName,
  243. ExpectedUserUID: expectedUserUID,
  244. ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
  245. },
  246. "invalid secret lookup": {
  247. Token: rsaToken,
  248. Client: fake.NewSimpleClientset(serviceAccount),
  249. Keys: []interface{}{getPublicKey(rsaPublicKey)},
  250. ExpectedErr: true,
  251. ExpectedOK: false,
  252. },
  253. "invalid serviceaccount lookup": {
  254. Token: rsaToken,
  255. Client: fake.NewSimpleClientset(rsaSecret, ecdsaSecret),
  256. Keys: []interface{}{getPublicKey(rsaPublicKey)},
  257. ExpectedErr: true,
  258. ExpectedOK: false,
  259. },
  260. }
  261. for k, tc := range testCases {
  262. auds := authenticator.Audiences{"api"}
  263. getter := serviceaccountcontroller.NewGetterFromClient(
  264. tc.Client,
  265. v1listers.NewSecretLister(newIndexer(func(namespace, name string) (interface{}, error) {
  266. return tc.Client.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{})
  267. })),
  268. v1listers.NewServiceAccountLister(newIndexer(func(namespace, name string) (interface{}, error) {
  269. return tc.Client.CoreV1().ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
  270. })),
  271. v1listers.NewPodLister(newIndexer(func(namespace, name string) (interface{}, error) {
  272. return tc.Client.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
  273. })),
  274. )
  275. authn := serviceaccount.JWTTokenAuthenticator(serviceaccount.LegacyIssuer, tc.Keys, auds, serviceaccount.NewLegacyValidator(tc.Client != nil, getter))
  276. // An invalid, non-JWT token should always fail
  277. ctx := authenticator.WithAudiences(context.Background(), auds)
  278. if _, ok, err := authn.AuthenticateToken(ctx, "invalid token"); err != nil || ok {
  279. t.Errorf("%s: Expected err=nil, ok=false for non-JWT token", k)
  280. continue
  281. }
  282. resp, ok, err := authn.AuthenticateToken(ctx, tc.Token)
  283. if (err != nil) != tc.ExpectedErr {
  284. t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedErr, err)
  285. continue
  286. }
  287. if ok != tc.ExpectedOK {
  288. t.Errorf("%s: Expected ok=%v, got %v", k, tc.ExpectedOK, ok)
  289. continue
  290. }
  291. if err != nil || !ok {
  292. continue
  293. }
  294. if resp.User.GetName() != tc.ExpectedUserName {
  295. t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName())
  296. continue
  297. }
  298. if resp.User.GetUID() != tc.ExpectedUserUID {
  299. t.Errorf("%s: Expected userUID=%v, got %v", k, tc.ExpectedUserUID, resp.User.GetUID())
  300. continue
  301. }
  302. if !reflect.DeepEqual(resp.User.GetGroups(), tc.ExpectedGroups) {
  303. t.Errorf("%s: Expected groups=%v, got %v", k, tc.ExpectedGroups, resp.User.GetGroups())
  304. continue
  305. }
  306. }
  307. }
  308. func newIndexer(get func(namespace, name string) (interface{}, error)) cache.Indexer {
  309. return &fakeIndexer{get: get}
  310. }
  311. type fakeIndexer struct {
  312. cache.Indexer
  313. get func(namespace, name string) (interface{}, error)
  314. }
  315. func (f *fakeIndexer) GetByKey(key string) (interface{}, bool, error) {
  316. parts := strings.SplitN(key, "/", 2)
  317. namespace := parts[0]
  318. name := ""
  319. if len(parts) == 2 {
  320. name = parts[1]
  321. }
  322. obj, err := f.get(namespace, name)
  323. return obj, err == nil, err
  324. }