Raise error when OpenBao API response includes warnings

Related: #530732

What does this MR do and why?

To ensure that we catch unexpected failures in during development and testing, we should raise an error when the OpenBao API response includes a warning. Currently, this is ignored by the secrets manager client and so some test failures can be hard to debug.

This MR adds categorized handling of OpenBao warnings, translating them into appropriate internal errors.

We parse all OpenBao warnings once and classify them as safe, critical, or unknown, based on regex patterns and HTTP method context.

During the experimental phase, all unknown warnings are treated as errors to surface unhandled cases and validate coverage.

This approach ensures strict testing while letting us refine and categorize warnings.

After the experiment, only critical warnings will raise errors, becoming the main source of failure signals.

References

Here is the list of possible warnings parsed from openbao repo
   4 Tidy operation successfully started. Any information from the operation will be printed to OpenBao's server logs.
   3 Tidy operation already in progress.
   3 This mount hasn't configured any authority information access (AIA) fields; this may make it harder for systems to find missing certificates in the chain or to validate revocation status of certificates. Consider updating /config/urls or the newly generated issuer with this information.
   3 		resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning))
   2 Unable to update this new root as the default issuer: 
   2 Unable to fetch default issuers configuration to update default issuer if necessary: 
   2 This issuer certificate was generated without a Subject; this makes it likely that issuing leaf certs with this certificate will cause TLS validation libraries to reject this certificate.
   2 \
   2 		response.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning))
   2 			response.AddWarning(fmt.Sprintf("issuance may fail: %v\n\nConsider setting the cluster-local address if it is not already set.", aiaErr))
   2 			resp.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning))
   1 token_max_ttl is greater than the backend mount's maximum TTL value; issued tokens' max TTL value will be truncated
   1 token max ttl is greater than the system or backend mount's maximum TTL value; issued tokens' max TTL value will be truncated
   1 Tidy operation cannot be cancelled as none is currently running.
   1 This mount hasn't configured any authority information access (AIA) fields; this may make it harder for systems to find missing certificates in the chain or to validate revocation status of certificates. Consider updating /config/urls or the newly generated issuer with this information. Since this certificate is an intermediate, it might be useful to regenerate this certificate after fixing this problem for the root mount.
   1 This issuer lacks another parent issuer within the mount. This means it will not appear on any other CRLs and may not be considered revoked by clients. Consider adding this issuer to its issuer's CRL as well if it is not self-signed.
   1 This issuer is currently configured as the default issuer for this mount; operations such as certificate issuance may not work until a new default issuer is selected.
   1 This issuer is a self-signed (potentially root) certificate. This means it may not be considered revoked if there is not an external, cross-signed variant of this certificate. This issuer's serial number will not appear on its own CRL.
   1 The expiration time for the signed certificate is after the CA's expiration time. If the new certificate is not treated as a root, validation paths with the certificate past the issuing CA's expiration time will fail.
   1 The default issuer is already set to the specified issuer.
   1 the common_name field was provided but the role is set with \
   1 the alt_names field was provided but the role is set with \
   1 Supplying a custom ID for the token uses the weaker SHA1 hashing instead of the more secure SHA2-256 HMAC for token obfuscation. SHA1 hashed tokens on the wire leads to less secure lookups.
   1 Role identifier was missing an index back to role name. A new index has been added. Please report this observation.
   1 Role does not have any constraints set on it. Updates to this role will require a constraint to be set
   1 requested rebuild of delta CRL when delta CRL is not enabled; this is a no-op
   1 requested namespace does not exist
   1 Reading from 'cubbyhole/response' is deprecated. Please use sys/wrapping/unwrap to unwrap responses, as it provides additional security checks and other benefits.
   1 Password found in connection_url, use a templated url to enable root rotation and prevent read access to password information.
   1 partial response due to timeout
   1 parameters key_type and key_bits ignored as role had specific values
   1 overriding default Content-Security-Policy which is secure by default, proceed with caution
   1 Non-listing operations on the root of a K/V v2 mount are not supported.
   1 No token found with this accessor
   1 No redirect address set in Vault so none could be encoded in the token. You may need to supply Vault's API address when unwrapping the token.
   1 No key id found with id: 
   1 Name successfully deleted, you will now need to reference this key by it's Id: 
   1 Mount move has been queued. Progress will be reported in OpenBao's server log, tagged with the returned migration_id
   1 max_ttl is greater than the system or backend mount's maximum TTL value; issued tokens' max TTL value will be truncated
   1 Max path length of the signed certificate is zero. This certificate cannot be used to issue intermediate CA certificates.
   1 Max path length of the generated certificate is zero. This certificate cannot be used to issue intermediate CA certificates.
   1 Manual tidy requested but no tidy operations were set. Enable at least one tidy operation to be run (
   1 key was already restored
   1 key was already marked as soft deleted
   1 Key already imported, use key/ endpoint to update name.
   1 Issuing Certificate was set to default, but no default issuing certificate (configurable at /config/issuers) is currently set
   1 Issuer uses a PSS Revocation Signature Algorithm. This algorithm will be downgraded to PKCS#1v1.5 signature scheme on OCSP responses, due to limitations in the OCSP library.
   1 Found MFA header but failed to find MFA Enforcement Config
   1 error checking oidc discovery URL
   1 error checking jwks URL
   1 DELETE /root deletes all keys and issuers; prefer the new DELETE /key/:key_ref and DELETE /issuer/:issuer_ref for finer granularity, unless removal of all keys and issuers is desired.
   1 default-service has no useful meaning; adjusting to service
   1 default-batch has no useful meaning; adjusting to batch
   1 default_extension templating enabled with at least one extension requiring identity templating. However, this request lacked identity entity information, causing one or more extensions to be skipped from the generated certificate.
   1 Default issuer left unchanged: could not select new issuer automatically as multiple imported issuers had key material in Vault.
   1 Certificates in storage are still being counted, current counts provided may be 
   1 Both 'token_period' and deprecated 'period' value supplied, ignoring the deprecated value
   1 Both 'token_explicit_max_ttl' and deprecated 'explicit_max_ttl' value supplied, ignoring the deprecated value
   1 Both 'token_bound_cidrs' and deprecated 'bound_cidrs' value supplied, ignoring the deprecated value
   1 Attempted creation of the key during the encrypt operation, but it was created beforehand
   1 An issuer with the provided public key already exists, returning the existing issuer
   1 A login request was issued that is subject to MFA validation. Please make sure to validate the login by sending another request to mfa/validate endpoint.
   1 'rules' is deprecated, please use 'policy' instead
   1 		retResp.AddWarning(fmt.Sprintf("a role's token ttl cannot be longer "+
   1 		response.AddWarning(fmt.Sprintf("Deleted issuer %v (via issuer_ref %v); this was configured as the default issuer. Operations without an explicit issuer will not work until a new default is configured.", ref, issuerName))
   1 		response.AddWarning(fmt.Sprintf("certificate with serial %s already expired; refusing to add to CRL. Enable 'AllowExpiredCertRevocation' to allow revoking expired certificates.", colonSerial))
   1 		resp.AddWarning(fmt.Sprintf("key %s already existed", name))
   1 		resp.AddWarning(fmt.Sprintf("Invalid path for a versioned K/V secrets engine. See the API docs for the appropriate API endpoints to use. If using the OpenBao CLI, use 'bao kv %s' for this operation.", subCommand))
   1 		resp.AddWarning(fmt.Sprintf("Given ttl of %d seconds is greater than current mount/system default of %d seconds", cert.TokenTTL/time.Second, systemDefaultTTL/time.Second))
   1 		resp.AddWarning(fmt.Sprintf("Given period of %d seconds is greater than the backend's maximum TTL of %d seconds", cert.TokenPeriod/time.Second, systemMaxTTL/time.Second))
   1 		resp.AddWarning(fmt.Sprintf("Given max_ttl of %d seconds is greater than current mount/system default of %d seconds", cert.TokenMaxTTL/time.Second, systemMaxTTL/time.Second))
   1 		resp.AddWarning(fmt.Sprintf("failed to construct JWK validator: %v", err))
   1 		resp.AddWarning(fmt.Sprintf("Deprecated API endpoint, cannot read plugin information from catalog for %q", pluginName))
   1 		resp.AddWarning(fmt.Sprintf("Deprecated API endpoint, cannot deregister plugin from catalog for %q", pluginName))
   1 		resp.AddWarning(`If "issuer" is set explicitly, all tokens must be ` +
   1 		resp.AddWarning(`Both "issuer" and OpenBao's "api_addr" are empty. ` +
   1 			response.AddWarning(fmt.Sprintf("Warning %d during CRL rebuild: %v", index+1, warning))
   1 			response.AddWarning(fmt.Sprintf("Deleted issuer %v (via issuer_ref %v); this was configured as the default issuer. Operations without an explicit issuer will not work until a new default is configured.", id, issuerRef))
   1 			response.AddWarning(fmt.Sprintf("Deleted %d issuers, including default issuer if configured.", issuersDeleted))
   1 			resp.AddWarning(fmt.Sprintf("Unable to check if any roles referenced this issuer by '%s'", name))
   1 			resp.AddWarning(fmt.Sprintf("The name '%s' was in use by at least %d roles", name, inUseBy))
   1 			resp.AddWarning(fmt.Sprintf("policy name was converted to %s", policy.Name))
   1 			resp.AddWarning(fmt.Sprintf("Policy %q does not exist", p))
   1 			resp.AddWarning(fmt.Sprintf("Found an accessor entry that could not be successfully decoded; associated error is %q", err.Error()))
   1 			resp.AddWarning(fmt.Sprintf("Found an accessor entry missing a token: %v", aEntry.AccessorID))
   1 			resp.AddWarning(fmt.Sprintf("Entity already has a secret for MFA method %q", mConfig.Name))
   1 			resp.AddWarning(fmt.Sprintf("Endpoint replaced the value of these parameters with the values captured from the endpoint's path: %v", replaced))
   1 			resp.AddWarning(fmt.Sprintf("Endpoint ignored these unrecognized parameters: %v", ignored))
   1 			resp.AddWarning(fmt.Sprintf("%s does not support password policies - upgrade to the latest version of "+
   1 			resp.AddWarning(fmt.Sprintf("%d roles reference '%s'", inUseBy, name))
   1 			resp.AddWarning(fmt.Sprint(inUseBy, " roles reference ", name))
   1 			resp.AddWarning(fmt.Sprint("Unable to check if any roles referenced this issuer by ", name))
   1 			resp.AddWarning(fmt.Sprint("The name ", name, " was in use by at least ", inUseBy, " roles"))
   1 			resp.AddWarning(`The "bound_cidr_list" field is deprecated and will be removed. Please use "secret_id_bound_cidrs" instead.`)
   1 				resp.AddWarning(fmt.Sprintf("Upgrading mount from version %d to version %d. This mount will be unavailable for a brief period and will resume service shortly.", meVersion, optVersion))
   1 				resp.AddWarning(fmt.Sprintf("Period specified both during creation call and in role; using the lesser value of %d seconds", int64(periodToUse.Seconds())))
   1 				resp.AddWarning(fmt.Sprintf("issuance may fail: %v\n\nConsider setting the cluster-local address if it is not already set.", err))
   1 				resp.AddWarning(fmt.Sprintf("invalid HTTP response code override from partial_failure_response_code, reverting to %d", code))
   1 				resp.AddWarning(fmt.Sprintf("Found scope templates with conflicting top-level keys: "+
   1 				resp.AddWarning(fmt.Sprintf("Explicit max TTL specified both during creation call and in role; using the lesser value of %d seconds", int64(explicitMaxTTLToUse.Seconds())))
   1 					resp.AddWarning(fmt.Sprintf("Issuing Certificate was set to %s but no issuing certificate currently has that name", entry.Issuer))

Screenshots or screen recordings

Before After

How to set up and validate locally

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Dmytro Biryukov

Merge request reports

Loading