|
@@ -49,6 +49,8 @@ const (
|
|
|
errMissingProvider = "storeSpec is missing provider"
|
|
errMissingProvider = "storeSpec is missing provider"
|
|
|
errInvalidProvider = "invalid provider spec. Missing field in store %s"
|
|
errInvalidProvider = "invalid provider spec. Missing field in store %s"
|
|
|
errInvalidHostURL = "invalid host URL"
|
|
errInvalidHostURL = "invalid host URL"
|
|
|
|
|
+ errMissingAuthMethod = "no authentication method configured: set auth.apiKey, or auth.clientId and auth.clientSecret"
|
|
|
|
|
+ errIncompleteOAuth = "both clientId and clientSecret must be set for OAuth authentication"
|
|
|
errNoSuchKeyFmt = "no such key in secret: %q"
|
|
errNoSuchKeyFmt = "no such key in secret: %q"
|
|
|
errInvalidRetrievalPath = "invalid retrieval path. Provide one path, separator and name"
|
|
errInvalidRetrievalPath = "invalid retrieval path. Provide one path, separator and name"
|
|
|
errNotImplemented = "not implemented"
|
|
errNotImplemented = "not implemented"
|
|
@@ -401,24 +403,73 @@ func (p *Provider) ValidateStore(store esv1.GenericStore) (admission.Warnings, e
|
|
|
return nil, fmt.Errorf(errInvalidProvider, store.GetObjectMeta().String())
|
|
return nil, fmt.Errorf(errInvalidProvider, store.GetObjectMeta().String())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if provider.Server == nil {
|
|
|
|
|
+ return nil, errors.New(errInvalidHostURL)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
apiURL, err := url.Parse(provider.Server.APIURL)
|
|
apiURL, err := url.Parse(provider.Server.APIURL)
|
|
|
- if err != nil {
|
|
|
|
|
|
|
+ if err != nil || apiURL.Host == "" {
|
|
|
return nil, errors.New(errInvalidHostURL)
|
|
return nil, errors.New(errInvalidHostURL)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if provider.Auth.ClientID.SecretRef != nil {
|
|
|
|
|
- return nil, err
|
|
|
|
|
|
|
+ if provider.Auth == nil {
|
|
|
|
|
+ return nil, errors.New(errMissingAuthMethod)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if provider.Auth.ClientSecret.SecretRef != nil {
|
|
|
|
|
- return nil, err
|
|
|
|
|
|
|
+ // Auth method requirements must stay in sync with loadCredentialsFromConfig.
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case provider.Auth.APIKey != nil:
|
|
|
|
|
+ if err := validateAuthRef(store, "apiKey", provider.Auth.APIKey); err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ case provider.Auth.ClientID != nil && provider.Auth.ClientSecret != nil:
|
|
|
|
|
+ if err := validateAuthRef(store, "clientId", provider.Auth.ClientID); err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := validateAuthRef(store, "clientSecret", provider.Auth.ClientSecret); err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ case provider.Auth.ClientID != nil || provider.Auth.ClientSecret != nil:
|
|
|
|
|
+ return nil, errors.New(errIncompleteOAuth)
|
|
|
|
|
+ default:
|
|
|
|
|
+ return nil, errors.New(errMissingAuthMethod)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if apiURL.Host == "" {
|
|
|
|
|
- return nil, errors.New(errInvalidHostURL)
|
|
|
|
|
|
|
+ // loadCertificateFromConfig silently ignores an incomplete certificate pair,
|
|
|
|
|
+ // so warn instead of rejecting the store.
|
|
|
|
|
+ var warnings admission.Warnings
|
|
|
|
|
+ hasCertificate := provider.Auth.Certificate != nil
|
|
|
|
|
+ hasCertificateKey := provider.Auth.CertificateKey != nil
|
|
|
|
|
+ if hasCertificate != hasCertificateKey {
|
|
|
|
|
+ warnings = append(warnings, "certificate and certificateKey must both be set for client-certificate authentication; the incomplete pair is ignored")
|
|
|
|
|
+ }
|
|
|
|
|
+ if hasCertificate {
|
|
|
|
|
+ if err := validateAuthRef(store, "certificate", provider.Auth.Certificate); err != nil {
|
|
|
|
|
+ return warnings, err
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ if hasCertificateKey {
|
|
|
|
|
+ if err := validateAuthRef(store, "certificateKey", provider.Auth.CertificateKey); err != nil {
|
|
|
|
|
+ return warnings, err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return warnings, nil
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- return nil, nil
|
|
|
|
|
|
|
+func validateAuthRef(store esv1.GenericStore, field string, ref *esv1.BeyondTrustProviderSecretRef) error {
|
|
|
|
|
+ if ref.SecretRef == nil && ref.Value == "" {
|
|
|
|
|
+ return fmt.Errorf("%s: either secretRef or value must be set", field)
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := validateSecretRef(ref); err != nil {
|
|
|
|
|
+ return fmt.Errorf("%s: %w", field, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if ref.SecretRef != nil {
|
|
|
|
|
+ if err := esutils.ValidateReferentSecretSelector(store, *ref.SecretRef); err != nil {
|
|
|
|
|
+ return fmt.Errorf("%s: %w", field, err)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// NewProvider creates a new Provider instance.
|
|
// NewProvider creates a new Provider instance.
|