auth.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package vault
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. vault "github.com/hashicorp/vault/api"
  18. authv1 "k8s.io/api/authentication/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  21. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  22. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  23. "github.com/external-secrets/external-secrets/pkg/constants"
  24. "github.com/external-secrets/external-secrets/pkg/metrics"
  25. vaultiamauth "github.com/external-secrets/external-secrets/pkg/provider/vault/iamauth"
  26. "github.com/external-secrets/external-secrets/pkg/provider/vault/util"
  27. )
  28. const (
  29. errAuthFormat = "cannot initialize Vault client: no valid auth method specified"
  30. errVaultToken = "cannot parse Vault authentication token: %w"
  31. errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
  32. errVaultRevokeToken = "error while revoking token: %w"
  33. )
  34. // setAuth gets a new token using the configured mechanism.
  35. // If there's already a valid token, does nothing.
  36. func (c *client) setAuth(ctx context.Context, cfg *vault.Config) error {
  37. tokenExists := false
  38. var err error
  39. if c.client.Token() != "" {
  40. tokenExists, err = checkToken(ctx, c.token)
  41. }
  42. if tokenExists {
  43. c.log.V(1).Info("Re-using existing token")
  44. return err
  45. }
  46. tokenExists, err = setSecretKeyToken(ctx, c)
  47. if tokenExists {
  48. c.log.V(1).Info("Set token from secret")
  49. return err
  50. }
  51. tokenExists, err = setAppRoleToken(ctx, c)
  52. if tokenExists {
  53. c.log.V(1).Info("Retrieved new token using AppRole auth")
  54. return err
  55. }
  56. tokenExists, err = setKubernetesAuthToken(ctx, c)
  57. if tokenExists {
  58. c.log.V(1).Info("Retrieved new token using Kubernetes auth")
  59. return err
  60. }
  61. tokenExists, err = setLdapAuthToken(ctx, c)
  62. if tokenExists {
  63. c.log.V(1).Info("Retrieved new token using LDAP auth")
  64. return err
  65. }
  66. tokenExists, err = setUserPassAuthToken(ctx, c)
  67. if tokenExists {
  68. c.log.V(1).Info("Retrieved new token using userPass auth")
  69. return err
  70. }
  71. tokenExists, err = setJwtAuthToken(ctx, c)
  72. if tokenExists {
  73. c.log.V(1).Info("Retrieved new token using JWT auth")
  74. return err
  75. }
  76. tokenExists, err = setCertAuthToken(ctx, c, cfg)
  77. if tokenExists {
  78. c.log.V(1).Info("Retrieved new token using certificate auth")
  79. return err
  80. }
  81. tokenExists, err = setIamAuthToken(ctx, c, vaultiamauth.DefaultJWTProvider, vaultiamauth.DefaultSTSProvider)
  82. if tokenExists {
  83. c.log.V(1).Info("Retrieved new token using IAM auth")
  84. return err
  85. }
  86. return errors.New(errAuthFormat)
  87. }
  88. func createServiceAccountToken(
  89. ctx context.Context,
  90. corev1Client typedcorev1.CoreV1Interface,
  91. storeKind string,
  92. namespace string,
  93. serviceAccountRef esmeta.ServiceAccountSelector,
  94. additionalAud []string,
  95. expirationSeconds int64) (string, error) {
  96. audiences := serviceAccountRef.Audiences
  97. if len(additionalAud) > 0 {
  98. audiences = append(audiences, additionalAud...)
  99. }
  100. tokenRequest := &authv1.TokenRequest{
  101. ObjectMeta: metav1.ObjectMeta{
  102. Namespace: namespace,
  103. },
  104. Spec: authv1.TokenRequestSpec{
  105. Audiences: audiences,
  106. ExpirationSeconds: &expirationSeconds,
  107. },
  108. }
  109. if (storeKind == esv1beta1.ClusterSecretStoreKind) &&
  110. (serviceAccountRef.Namespace != nil) {
  111. tokenRequest.Namespace = *serviceAccountRef.Namespace
  112. }
  113. tokenResponse, err := corev1Client.ServiceAccounts(tokenRequest.Namespace).
  114. CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
  115. if err != nil {
  116. return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
  117. }
  118. return tokenResponse.Status.Token, nil
  119. }
  120. // checkToken does a lookup and checks if the provided token exists.
  121. func checkToken(ctx context.Context, token util.Token) (bool, error) {
  122. // https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
  123. resp, err := token.LookupSelfWithContext(ctx)
  124. metrics.ObserveAPICall(constants.ProviderHCVault, constants.CallHCVaultLookupSelf, err)
  125. if err != nil {
  126. return false, err
  127. }
  128. t, ok := resp.Data["type"]
  129. if !ok {
  130. return false, fmt.Errorf("could not assert token type")
  131. }
  132. tokenType := t.(string)
  133. if tokenType == "batch" {
  134. return false, nil
  135. }
  136. return true, nil
  137. }
  138. func revokeTokenIfValid(ctx context.Context, client util.Client) error {
  139. valid, err := checkToken(ctx, client.AuthToken())
  140. if err != nil {
  141. return fmt.Errorf(errVaultRevokeToken, err)
  142. }
  143. if valid {
  144. err = client.AuthToken().RevokeSelfWithContext(ctx, client.Token())
  145. metrics.ObserveAPICall(constants.ProviderHCVault, constants.CallHCVaultRevokeSelf, err)
  146. if err != nil {
  147. return fmt.Errorf(errVaultRevokeToken, err)
  148. }
  149. client.ClearToken()
  150. }
  151. return nil
  152. }