authn.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 authenticator
  14. import (
  15. "crypto/rsa"
  16. "time"
  17. "k8s.io/kubernetes/pkg/auth/authenticator"
  18. "k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
  19. "k8s.io/kubernetes/pkg/serviceaccount"
  20. "k8s.io/kubernetes/pkg/util/crypto"
  21. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/password/keystone"
  22. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/password/passwordfile"
  23. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/basicauth"
  24. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
  25. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/x509"
  26. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/oidc"
  27. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/tokenfile"
  28. "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/webhook"
  29. )
  30. type AuthenticatorConfig struct {
  31. BasicAuthFile string
  32. ClientCAFile string
  33. TokenAuthFile string
  34. OIDCIssuerURL string
  35. OIDCClientID string
  36. OIDCCAFile string
  37. OIDCUsernameClaim string
  38. OIDCGroupsClaim string
  39. ServiceAccountKeyFile string
  40. ServiceAccountLookup bool
  41. ServiceAccountTokenGetter serviceaccount.ServiceAccountTokenGetter
  42. KeystoneURL string
  43. WebhookTokenAuthnConfigFile string
  44. WebhookTokenAuthnCacheTTL time.Duration
  45. }
  46. // New returns an authenticator.Request or an error that supports the standard
  47. // Kubernetes authentication mechanisms.
  48. func New(config AuthenticatorConfig) (authenticator.Request, error) {
  49. var authenticators []authenticator.Request
  50. if len(config.BasicAuthFile) > 0 {
  51. basicAuth, err := newAuthenticatorFromBasicAuthFile(config.BasicAuthFile)
  52. if err != nil {
  53. return nil, err
  54. }
  55. authenticators = append(authenticators, basicAuth)
  56. }
  57. if len(config.ClientCAFile) > 0 {
  58. certAuth, err := newAuthenticatorFromClientCAFile(config.ClientCAFile)
  59. if err != nil {
  60. return nil, err
  61. }
  62. authenticators = append(authenticators, certAuth)
  63. }
  64. if len(config.TokenAuthFile) > 0 {
  65. tokenAuth, err := newAuthenticatorFromTokenFile(config.TokenAuthFile)
  66. if err != nil {
  67. return nil, err
  68. }
  69. authenticators = append(authenticators, tokenAuth)
  70. }
  71. if len(config.ServiceAccountKeyFile) > 0 {
  72. serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountKeyFile, config.ServiceAccountLookup, config.ServiceAccountTokenGetter)
  73. if err != nil {
  74. return nil, err
  75. }
  76. authenticators = append(authenticators, serviceAccountAuth)
  77. }
  78. // NOTE(ericchiang): Keep the OpenID Connect after Service Accounts.
  79. //
  80. // Because both plugins verify JWTs whichever comes first in the union experiences
  81. // cache misses for all requests using the other. While the service account plugin
  82. // simply returns an error, the OpenID Connect plugin may query the provider to
  83. // update the keys, causing performance hits.
  84. if len(config.OIDCIssuerURL) > 0 && len(config.OIDCClientID) > 0 {
  85. oidcAuth, err := newAuthenticatorFromOIDCIssuerURL(config.OIDCIssuerURL, config.OIDCClientID, config.OIDCCAFile, config.OIDCUsernameClaim, config.OIDCGroupsClaim)
  86. if err != nil {
  87. return nil, err
  88. }
  89. authenticators = append(authenticators, oidcAuth)
  90. }
  91. if len(config.KeystoneURL) > 0 {
  92. keystoneAuth, err := newAuthenticatorFromKeystoneURL(config.KeystoneURL)
  93. if err != nil {
  94. return nil, err
  95. }
  96. authenticators = append(authenticators, keystoneAuth)
  97. }
  98. if len(config.WebhookTokenAuthnConfigFile) > 0 {
  99. webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL)
  100. if err != nil {
  101. return nil, err
  102. }
  103. authenticators = append(authenticators, webhookTokenAuth)
  104. }
  105. switch len(authenticators) {
  106. case 0:
  107. return nil, nil
  108. case 1:
  109. return authenticators[0], nil
  110. default:
  111. return union.New(authenticators...), nil
  112. }
  113. }
  114. // IsValidServiceAccountKeyFile returns true if a valid public RSA key can be read from the given file
  115. func IsValidServiceAccountKeyFile(file string) bool {
  116. _, err := serviceaccount.ReadPublicKey(file)
  117. return err == nil
  118. }
  119. // newAuthenticatorFromBasicAuthFile returns an authenticator.Request or an error
  120. func newAuthenticatorFromBasicAuthFile(basicAuthFile string) (authenticator.Request, error) {
  121. basicAuthenticator, err := passwordfile.NewCSV(basicAuthFile)
  122. if err != nil {
  123. return nil, err
  124. }
  125. return basicauth.New(basicAuthenticator), nil
  126. }
  127. // newAuthenticatorFromTokenFile returns an authenticator.Request or an error
  128. func newAuthenticatorFromTokenFile(tokenAuthFile string) (authenticator.Request, error) {
  129. tokenAuthenticator, err := tokenfile.NewCSV(tokenAuthFile)
  130. if err != nil {
  131. return nil, err
  132. }
  133. return bearertoken.New(tokenAuthenticator), nil
  134. }
  135. // newAuthenticatorFromOIDCIssuerURL returns an authenticator.Request or an error.
  136. func newAuthenticatorFromOIDCIssuerURL(issuerURL, clientID, caFile, usernameClaim, groupsClaim string) (authenticator.Request, error) {
  137. tokenAuthenticator, err := oidc.New(oidc.OIDCOptions{
  138. IssuerURL: issuerURL,
  139. ClientID: clientID,
  140. CAFile: caFile,
  141. UsernameClaim: usernameClaim,
  142. GroupsClaim: groupsClaim,
  143. })
  144. if err != nil {
  145. return nil, err
  146. }
  147. return bearertoken.New(tokenAuthenticator), nil
  148. }
  149. // newServiceAccountAuthenticator returns an authenticator.Request or an error
  150. func newServiceAccountAuthenticator(keyfile string, lookup bool, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Request, error) {
  151. publicKey, err := serviceaccount.ReadPublicKey(keyfile)
  152. if err != nil {
  153. return nil, err
  154. }
  155. tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{publicKey}, lookup, serviceAccountGetter)
  156. return bearertoken.New(tokenAuthenticator), nil
  157. }
  158. // newAuthenticatorFromClientCAFile returns an authenticator.Request or an error
  159. func newAuthenticatorFromClientCAFile(clientCAFile string) (authenticator.Request, error) {
  160. roots, err := crypto.CertPoolFromFile(clientCAFile)
  161. if err != nil {
  162. return nil, err
  163. }
  164. opts := x509.DefaultVerifyOptions()
  165. opts.Roots = roots
  166. return x509.New(opts, x509.CommonNameUserConversion), nil
  167. }
  168. // newAuthenticatorFromTokenFile returns an authenticator.Request or an error
  169. func newAuthenticatorFromKeystoneURL(keystoneURL string) (authenticator.Request, error) {
  170. keystoneAuthenticator, err := keystone.NewKeystoneAuthenticator(keystoneURL)
  171. if err != nil {
  172. return nil, err
  173. }
  174. return basicauth.New(keystoneAuthenticator), nil
  175. }
  176. func newWebhookTokenAuthenticator(webhookConfigFile string, ttl time.Duration) (authenticator.Request, error) {
  177. webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, ttl)
  178. if err != nil {
  179. return nil, err
  180. }
  181. return bearertoken.New(webhookTokenAuthenticator), nil
  182. }