jwt_test.go 13 KB

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