2023-03-15 16:00:52 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2022-11-17 20:31:58 +00:00
package healthcheck
import (
"fmt"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/go-secure-stdlib/parseutil"
)
type RoleNoStoreFalse struct {
Enabled bool
UnsupportedVersion bool
AllowedRoles map [ string ] bool
2023-02-24 18:00:09 +00:00
RoleListFetchIssue * PathFetch
RoleFetchIssues map [ string ] * PathFetch
RoleEntryMap map [ string ] map [ string ] interface { }
CRLConfig * PathFetch
2022-11-17 20:31:58 +00:00
}
func NewRoleNoStoreFalseCheck ( ) Check {
return & RoleNoStoreFalse {
2023-02-24 18:00:09 +00:00
RoleFetchIssues : make ( map [ string ] * PathFetch ) ,
AllowedRoles : make ( map [ string ] bool ) ,
RoleEntryMap : make ( map [ string ] map [ string ] interface { } ) ,
2022-11-17 20:31:58 +00:00
}
}
func ( h * RoleNoStoreFalse ) Name ( ) string {
return "role_no_store_false"
}
func ( h * RoleNoStoreFalse ) IsEnabled ( ) bool {
return h . Enabled
}
func ( h * RoleNoStoreFalse ) DefaultConfig ( ) map [ string ] interface { } {
return map [ string ] interface { } {
"allowed_roles" : [ ] string { } ,
}
}
func ( h * RoleNoStoreFalse ) LoadConfig ( config map [ string ] interface { } ) error {
value , present := config [ "allowed_roles" ] . ( [ ] interface { } )
if present {
for _ , rawValue := range value {
h . AllowedRoles [ rawValue . ( string ) ] = true
}
}
enabled , err := parseutil . ParseBool ( config [ "enabled" ] )
if err != nil {
return fmt . Errorf ( "error parsing %v.enabled: %w" , h . Name ( ) , err )
}
h . Enabled = enabled
return nil
}
func ( h * RoleNoStoreFalse ) FetchResources ( e * Executor ) error {
2022-11-23 14:42:19 +00:00
exit , f , roles , err := pkiFetchRolesList ( e , func ( ) {
2022-11-17 20:31:58 +00:00
h . UnsupportedVersion = true
} )
if exit || err != nil {
2022-11-23 14:42:19 +00:00
if f != nil && f . IsSecretPermissionsError ( ) {
2023-02-24 18:00:09 +00:00
h . RoleListFetchIssue = f
2022-11-23 14:42:19 +00:00
}
2022-11-17 20:31:58 +00:00
return err
}
for _ , role := range roles {
2022-11-23 14:42:19 +00:00
skip , f , entry , err := pkiFetchRole ( e , role , func ( ) {
2022-11-17 20:31:58 +00:00
h . UnsupportedVersion = true
} )
if skip || err != nil || entry == nil {
2022-11-23 14:42:19 +00:00
if f != nil && f . IsSecretPermissionsError ( ) {
2023-02-24 18:00:09 +00:00
h . RoleFetchIssues [ role ] = f
2022-11-23 14:42:19 +00:00
}
2022-11-17 20:31:58 +00:00
if err != nil {
return err
}
continue
}
h . RoleEntryMap [ role ] = entry
}
// Check if the issuer is fetched yet.
configRet , err := e . FetchIfNotFetched ( logical . ReadOperation , "/{{mount}}/config/crl" )
if err != nil {
return err
}
h . CRLConfig = configRet
return nil
}
func ( h * RoleNoStoreFalse ) Evaluate ( e * Executor ) ( results [ ] * Result , err error ) {
if h . UnsupportedVersion {
// Shouldn't happen; roles have been around forever.
ret := Result {
Status : ResultInvalidVersion ,
Endpoint : "/{{mount}}/roles" ,
Message : "This health check requires Vault 1.11+ but an earlier version of Vault Server was contacted, preventing this health check from running." ,
}
return [ ] * Result { & ret } , nil
}
2023-02-24 18:00:09 +00:00
if h . RoleListFetchIssue != nil && h . RoleListFetchIssue . IsSecretPermissionsError ( ) {
2022-11-23 14:42:19 +00:00
ret := Result {
Status : ResultInsufficientPermissions ,
2023-02-24 18:00:09 +00:00
Endpoint : h . RoleListFetchIssue . Path ,
Message : "lacks permission either to list the roles. This restricts the ability to fully execute this health check." ,
2022-11-23 14:42:19 +00:00
}
if e . Client . Token ( ) == "" {
ret . Message = "No token available and so this health check " + ret . Message
} else {
ret . Message = "This token " + ret . Message
}
2023-02-24 18:00:09 +00:00
return [ ] * Result { & ret } , nil
}
for role , fetchPath := range h . RoleFetchIssues {
if fetchPath != nil && fetchPath . IsSecretPermissionsError ( ) {
delete ( h . RoleEntryMap , role )
ret := Result {
Status : ResultInsufficientPermissions ,
Endpoint : fetchPath . Path ,
Message : "Without this information, this health check is unable to function." ,
}
if e . Client . Token ( ) == "" {
ret . Message = "No token available so unable for the endpoint for this mount. " + ret . Message
} else {
ret . Message = "This token lacks permission the endpoint for this mount. " + ret . Message
}
results = append ( results , & ret )
}
2022-11-23 14:42:19 +00:00
}
2022-11-17 20:31:58 +00:00
crlAutoRebuild := false
if h . CRLConfig != nil {
if h . CRLConfig . IsSecretPermissionsError ( ) {
ret := Result {
Status : ResultInsufficientPermissions ,
Endpoint : "/{{mount}}/config/crl" ,
Message : "This prevents the health check from seeing if the CRL is set to auto_rebuild=true and lowering the severity of check results appropriately." ,
}
if e . Client . Token ( ) == "" {
ret . Message = "No token available so unable read authenticated CRL configuration for this mount. " + ret . Message
} else {
ret . Message = "This token lacks so permission to read the CRL configuration for this mount. " + ret . Message
}
results = append ( results , & ret )
} else if h . CRLConfig . Secret != nil && h . CRLConfig . Secret . Data [ "auto_rebuild" ] != nil {
crlAutoRebuild = h . CRLConfig . Secret . Data [ "auto_rebuild" ] . ( bool )
}
}
for role , entry := range h . RoleEntryMap {
noStore := entry [ "no_store" ] . ( bool )
if noStore {
continue
}
ret := Result {
Status : ResultWarning ,
2023-02-21 19:48:50 +00:00
Endpoint : "/{{mount}}/roles/" + role ,
2022-11-17 20:31:58 +00:00
Message : "Role currently stores every issued certificate (no_store=false). Too many issued and/or revoked certificates can exceed Vault's storage limits and make operations slow. It is encouraged to enable auto-rebuild of CRLs to prevent every revocation from creating a new CRL, and to limit the number of certificates issued under roles with no_store=false: use shorter lifetimes and/or BYOC revocation instead." ,
}
if crlAutoRebuild {
ret . Status = ResultInformational
ret . Message = "Role currently stores every issued certificate (no_store=false). With auto-rebuild CRL enabled, less performance impact occur on CRL rebuilding, but note that too many issued and/or revoked certificates can exceed Vault's storage limits and make operations slow. It is suggested to limit the number of certificates issued under roles with no_store=false: use shorter lifetimes to avoid revocation and/or BYOC revocation instead."
}
results = append ( results , & ret )
}
2022-11-23 14:42:19 +00:00
if len ( results ) == 0 && len ( h . RoleEntryMap ) > 0 {
ret := Result {
Status : ResultOK ,
Endpoint : "/{{mount}}/roles" ,
Message : "Roles follow best practices regarding certificate storage." ,
}
results = append ( results , & ret )
}
2022-11-17 20:31:58 +00:00
return
}