jwt_test.go 13 KB

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