k8s_connection_validate.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. Copyright © The ESO 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. https://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 esutils
  14. import (
  15. "errors"
  16. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  17. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  18. )
  19. // WarnNoCAConfigured is the admission warning emitted when a Kubernetes-style
  20. // connection configures neither an inline CA bundle nor a CA provider, so TLS
  21. // falls back to the system certificate roots. Shared by the kubernetes and CRD
  22. // providers so the wording stays identical across both.
  23. const WarnNoCAConfigured = "No caBundle or caProvider specified; TLS connections will use system certificate roots."
  24. // IsReferentKubernetesAuth reports whether a Kubernetes-style auth spec uses
  25. // referent authentication: any credential selector whose namespace is omitted
  26. // is resolved against the consuming ExternalSecret's namespace, which is not
  27. // known at store-validation time. Shared by the kubernetes and CRD providers,
  28. // which both embed the KubernetesAuth type.
  29. func IsReferentKubernetesAuth(auth *esv1.KubernetesAuth) bool {
  30. if auth == nil {
  31. return false
  32. }
  33. if auth.Cert != nil {
  34. if auth.Cert.ClientCert.Namespace == nil {
  35. return true
  36. }
  37. if auth.Cert.ClientKey.Namespace == nil {
  38. return true
  39. }
  40. }
  41. if auth.ServiceAccount != nil {
  42. if auth.ServiceAccount.Namespace == nil {
  43. return true
  44. }
  45. }
  46. if auth.Token != nil {
  47. if auth.Token.BearerToken.Namespace == nil {
  48. return true
  49. }
  50. }
  51. return false
  52. }
  53. // ValidateKubernetesConnection validates the server/auth/authRef fields common
  54. // to any provider that reaches a Kubernetes API using the Kubernetes provider's
  55. // connection model (currently the kubernetes and CRD providers). It returns the
  56. // admission warnings accumulated so far alongside the first validation error, so
  57. // callers can surface warnings even when validation fails. The return type is a
  58. // plain []string, assignable to admission.Warnings, to keep this package free of
  59. // the webhook import.
  60. func ValidateKubernetesConnection(store esv1.GenericStore, server esv1.KubernetesServer, auth *esv1.KubernetesAuth, authRef *esmeta.SecretKeySelector) ([]string, error) {
  61. var warnings []string
  62. if authRef == nil && server.CABundle == nil && server.CAProvider == nil {
  63. warnings = append(warnings, WarnNoCAConfigured)
  64. }
  65. // GetKind returns the store kind reliably (a constant per concrete type),
  66. // unlike GetObjectKind().GroupVersionKind().Kind which depends on TypeMeta
  67. // being populated on the decoded object.
  68. kind := store.GetKind()
  69. if kind == esv1.ClusterSecretStoreKind &&
  70. server.CAProvider != nil &&
  71. server.CAProvider.Namespace == nil {
  72. return warnings, errors.New("CAProvider.namespace must not be empty with ClusterSecretStore")
  73. }
  74. if kind == esv1.SecretStoreKind &&
  75. server.CAProvider != nil &&
  76. server.CAProvider.Namespace != nil {
  77. return warnings, errors.New("CAProvider.namespace must be empty with SecretStore")
  78. }
  79. if auth != nil && auth.Cert != nil {
  80. if auth.Cert.ClientCert.Name == "" {
  81. return warnings, errors.New("ClientCert.Name cannot be empty")
  82. }
  83. if auth.Cert.ClientCert.Key == "" {
  84. return warnings, errors.New("ClientCert.Key cannot be empty")
  85. }
  86. if err := ValidateSecretSelector(store, auth.Cert.ClientCert); err != nil {
  87. return warnings, err
  88. }
  89. }
  90. if auth != nil && auth.Token != nil {
  91. if auth.Token.BearerToken.Name == "" {
  92. return warnings, errors.New("BearerToken.Name cannot be empty")
  93. }
  94. if auth.Token.BearerToken.Key == "" {
  95. return warnings, errors.New("BearerToken.Key cannot be empty")
  96. }
  97. if err := ValidateSecretSelector(store, auth.Token.BearerToken); err != nil {
  98. return warnings, err
  99. }
  100. }
  101. if auth != nil && auth.ServiceAccount != nil {
  102. if err := ValidateReferentServiceAccountSelector(store, *auth.ServiceAccount); err != nil {
  103. return warnings, err
  104. }
  105. }
  106. return warnings, nil
  107. }