* Secrets manager: create secure value using the active keeper * SecureValueService.Update: fetch secure value from db to get the keeper * fix keeper_store_test.go * SecureValueService: fix bug in update where the current version keeper wasn't being passed to the createNewVersion method * make gofmt * remove outdated test * update TestModel * undo enterprise_imports changes * use xkube.Namespace * migrator: set secret_secure_value.keeper to 'system' when the column is null * indent cue * fix tests * fix enterprise imports * properly fix enterprise imports * make update-workspace * go mod tidy --------- Co-authored-by: Matheus Macabu <macabu.matheus@gmail.com>
170 lines
5.1 KiB
Go
170 lines
5.1 KiB
Go
package validator
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"k8s.io/apimachinery/pkg/util/validation"
|
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
|
"k8s.io/apiserver/pkg/admission"
|
|
|
|
secretv1beta1 "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1"
|
|
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
|
)
|
|
|
|
type keeperValidator struct{}
|
|
|
|
var _ contracts.KeeperValidator = &keeperValidator{}
|
|
|
|
func ProvideKeeperValidator() contracts.KeeperValidator {
|
|
return &keeperValidator{}
|
|
}
|
|
|
|
func (v *keeperValidator) Validate(keeper *secretv1beta1.Keeper, oldKeeper *secretv1beta1.Keeper, operation admission.Operation) field.ErrorList {
|
|
errs := make(field.ErrorList, 0)
|
|
|
|
// General validations.
|
|
if err := validation.IsDNS1123Subdomain(keeper.Name); len(err) > 0 {
|
|
errs = append(
|
|
errs,
|
|
field.Invalid(field.NewPath("metadata", "name"), keeper.Name, strings.Join(err, ",")),
|
|
)
|
|
}
|
|
if err := validation.IsDNS1123Subdomain(keeper.Namespace); len(err) > 0 {
|
|
errs = append(
|
|
errs,
|
|
field.Invalid(field.NewPath("metadata", "namespace"), keeper.Name, strings.Join(err, ",")),
|
|
)
|
|
}
|
|
|
|
// Only validate Create and Update for now.
|
|
if operation != admission.Create && operation != admission.Update {
|
|
return errs
|
|
}
|
|
|
|
if keeper.Name == contracts.SystemKeeperName {
|
|
errs = append(errs, field.Forbidden(field.NewPath("name"), "the keeper name `system` is reserved"))
|
|
}
|
|
|
|
if keeper.Spec.Description == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "description"), "a `description` is required"))
|
|
}
|
|
|
|
// Only one keeper type can be configured. Return early and don't validate the specific keeper fields.
|
|
if err := validateKeepers(keeper); err != nil {
|
|
errs = append(errs, err)
|
|
|
|
return errs
|
|
}
|
|
|
|
if keeper.Spec.Aws != nil {
|
|
if err := validateCredentialValue(field.NewPath("spec", "aws", "accessKeyID"), keeper.Spec.Aws.AccessKeyID); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
|
|
if err := validateCredentialValue(field.NewPath("spec", "aws", "secretAccessKey"), keeper.Spec.Aws.SecretAccessKey); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
if keeper.Spec.Azure != nil {
|
|
if keeper.Spec.Azure.KeyVaultName == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "azure", "keyVaultName"), "a `keyVaultName` is required"))
|
|
}
|
|
|
|
if keeper.Spec.Azure.TenantID == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "azure", "tenantID"), "a `tenantID` is required"))
|
|
}
|
|
|
|
if keeper.Spec.Azure.ClientID == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "azure", "clientID"), "a `clientID` is required"))
|
|
}
|
|
|
|
if err := validateCredentialValue(field.NewPath("spec", "azure", "clientSecret"), keeper.Spec.Azure.ClientSecret); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
if keeper.Spec.Gcp != nil {
|
|
if keeper.Spec.Gcp.ProjectID == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "gcp", "projectID"), "a `projectID` is required"))
|
|
}
|
|
|
|
if keeper.Spec.Gcp.CredentialsFile == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "gcp", "credentialsFile"), "a `credentialsFile` is required"))
|
|
}
|
|
}
|
|
|
|
if keeper.Spec.HashiCorpVault != nil {
|
|
if keeper.Spec.HashiCorpVault.Address == "" {
|
|
errs = append(errs, field.Required(field.NewPath("spec", "hashiCorpVault", "address"), "an `address` is required"))
|
|
}
|
|
|
|
if err := validateCredentialValue(field.NewPath("spec", "hashiCorpVault", "token"), keeper.Spec.HashiCorpVault.Token); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
return errs
|
|
}
|
|
|
|
func validateKeepers(keeper *secretv1beta1.Keeper) *field.Error {
|
|
availableKeepers := map[string]bool{
|
|
"aws": keeper.Spec.Aws != nil,
|
|
"azure": keeper.Spec.Azure != nil,
|
|
"gcp": keeper.Spec.Gcp != nil,
|
|
"hashiCorpVault": keeper.Spec.HashiCorpVault != nil,
|
|
}
|
|
|
|
configuredKeepers := make([]string, 0)
|
|
|
|
for keeperKind, notNil := range availableKeepers {
|
|
if notNil {
|
|
configuredKeepers = append(configuredKeepers, keeperKind)
|
|
}
|
|
}
|
|
|
|
if len(configuredKeepers) == 0 {
|
|
return field.Required(field.NewPath("spec"), "at least one `keeper` must be present")
|
|
}
|
|
|
|
if len(configuredKeepers) > 1 {
|
|
return field.Invalid(
|
|
field.NewPath("spec"),
|
|
strings.Join(configuredKeepers, " & "),
|
|
"only one `keeper` can be present at a time but found more",
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateCredentialValue(path *field.Path, credentials secretv1beta1.KeeperCredentialValue) *field.Error {
|
|
availableOptions := map[string]bool{
|
|
"secureValueName": credentials.SecureValueName != "",
|
|
"valueFromEnv": credentials.ValueFromEnv != "",
|
|
"valueFromConfig": credentials.ValueFromConfig != "",
|
|
}
|
|
|
|
configuredCredentials := make([]string, 0)
|
|
|
|
for credentialKind, notEmpty := range availableOptions {
|
|
if notEmpty {
|
|
configuredCredentials = append(configuredCredentials, credentialKind)
|
|
}
|
|
}
|
|
|
|
if len(configuredCredentials) == 0 {
|
|
return field.Required(path, "one of `secureValueName`, `valueFromEnv` or `valueFromConfig` must be present")
|
|
}
|
|
|
|
if len(configuredCredentials) > 1 {
|
|
return field.Invalid(
|
|
path,
|
|
strings.Join(configuredCredentials, " & "),
|
|
"only one of `secureValueName`, `valueFromEnv` or `valueFromConfig` must be present at a time but found more",
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|