mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
Merge pull request #896 from burak-yuksel/feature/validate-kubernetes-provider
Validate for Kubernetes Provider
This commit is contained in:
commit
8527fe1d13
3 changed files with 79 additions and 3 deletions
|
@ -4,6 +4,8 @@ External Secrets Operator allows to retrieve in-cluster secrets or from a remote
|
|||
|
||||
It's possible to authenticate against the Kubernetes API using client certificates, a bearer token or a service account (not implemented yet). The operator enforces that exactly one authentication method is used.
|
||||
|
||||
**NOTE:** `SelfSubjectAccessReview` permission is required for the service account in order to validation work properly.
|
||||
|
||||
## Example
|
||||
|
||||
### In-cluster secrets using Client certificates
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
authv1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
@ -44,9 +45,15 @@ type KClient interface {
|
|||
Get(ctx context.Context, name string, opts metav1.GetOptions) (*corev1.Secret, error)
|
||||
}
|
||||
|
||||
type RClient interface {
|
||||
Create(ctx context.Context, SelfSubjectAccessReview *authv1.SelfSubjectAccessReview, opts metav1.CreateOptions) (*authv1.SelfSubjectAccessReview, error)
|
||||
}
|
||||
|
||||
// ProviderKubernetes is a provider for Kubernetes.
|
||||
type ProviderKubernetes struct {
|
||||
Client KClient
|
||||
Client KClient
|
||||
ReviewClient RClient
|
||||
Namespace string
|
||||
}
|
||||
|
||||
var _ esv1beta1.SecretsClient = &ProviderKubernetes{}
|
||||
|
@ -104,6 +111,8 @@ func (k *ProviderKubernetes) NewClient(ctx context.Context, store esv1beta1.Gene
|
|||
}
|
||||
|
||||
k.Client = kubeClientSet.CoreV1().Secrets(bStore.store.RemoteNamespace)
|
||||
k.Namespace = bStore.store.RemoteNamespace
|
||||
k.ReviewClient = kubeClientSet.AuthorizationV1().SelfSubjectAccessReviews()
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
@ -229,6 +238,26 @@ func (k *BaseClient) fetchSecretKey(ctx context.Context, key esmeta.SecretKeySel
|
|||
}
|
||||
|
||||
func (k *ProviderKubernetes) Validate() error {
|
||||
ctx := context.Background()
|
||||
|
||||
authReview, err := k.ReviewClient.Create(ctx, &authv1.SelfSubjectAccessReview{
|
||||
Spec: authv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authv1.ResourceAttributes{
|
||||
Resource: "secrets",
|
||||
Namespace: k.Namespace,
|
||||
Verb: "get",
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not verify if client is valid: %w", err)
|
||||
}
|
||||
|
||||
if !authReview.Status.Allowed {
|
||||
return fmt.Errorf("client is not allowed to get secrets")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
authv1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
fclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
@ -32,6 +33,7 @@ import (
|
|||
const (
|
||||
errTestFetchCredentialsSecret = "test could not fetch Credentials secret failed"
|
||||
errTestAuthValue = "test failed key didn't match expected value"
|
||||
errSomethingWentWrong = "Something went wrong"
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
|
@ -42,11 +44,22 @@ func (fk fakeClient) Get(ctx context.Context, name string, opts metav1.GetOption
|
|||
secret, ok := fk.secretMap[name]
|
||||
|
||||
if !ok {
|
||||
return nil, errors.New("Something went wrong")
|
||||
return nil, errors.New(errSomethingWentWrong)
|
||||
}
|
||||
return &secret, nil
|
||||
}
|
||||
|
||||
type fakeReviewClient struct {
|
||||
authReview *authv1.SelfSubjectAccessReview
|
||||
}
|
||||
|
||||
func (fk fakeReviewClient) Create(ctx context.Context, selfSubjectAccessReview *authv1.SelfSubjectAccessReview, opts metav1.CreateOptions) (*authv1.SelfSubjectAccessReview, error) {
|
||||
if fk.authReview == nil {
|
||||
return nil, errors.New(errSomethingWentWrong)
|
||||
}
|
||||
return fk.authReview, nil
|
||||
}
|
||||
|
||||
func TestKubernetesSecretManagerGetSecret(t *testing.T) {
|
||||
expected := make(map[string][]byte)
|
||||
value := "bar"
|
||||
|
@ -70,7 +83,7 @@ func TestKubernetesSecretManagerGetSecret(t *testing.T) {
|
|||
ref = esv1beta1.ExternalSecretDataRemoteRef{Key: "Key2", Property: "foo"}
|
||||
_, err := kp.GetSecret(ctx, ref)
|
||||
|
||||
if err.Error() != "Something went wrong" {
|
||||
if err.Error() != errSomethingWentWrong {
|
||||
t.Error("test failed")
|
||||
}
|
||||
|
||||
|
@ -258,3 +271,35 @@ func ErrorContains(out error, want string) bool {
|
|||
}
|
||||
return strings.Contains(out.Error(), want)
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
authReview := authv1.SelfSubjectAccessReview{
|
||||
Status: authv1.SubjectAccessReviewStatus{
|
||||
Allowed: true,
|
||||
},
|
||||
}
|
||||
fakeClient := fakeReviewClient{authReview: &authReview}
|
||||
k := ProviderKubernetes{ReviewClient: fakeClient}
|
||||
err := k.Validate()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed! %v", err)
|
||||
}
|
||||
authReview = authv1.SelfSubjectAccessReview{
|
||||
Status: authv1.SubjectAccessReviewStatus{
|
||||
Allowed: false,
|
||||
},
|
||||
}
|
||||
fakeClient = fakeReviewClient{authReview: &authReview}
|
||||
k = ProviderKubernetes{ReviewClient: fakeClient}
|
||||
err = k.Validate()
|
||||
if err.Error() != "client is not allowed to get secrets" {
|
||||
t.Errorf("Test Failed! Wanted client is not allowed to get secrets got: %v", err)
|
||||
}
|
||||
|
||||
fakeClient = fakeReviewClient{}
|
||||
k = ProviderKubernetes{ReviewClient: fakeClient}
|
||||
err = k.Validate()
|
||||
if err.Error() != "could not verify if client is valid: Something went wrong" {
|
||||
t.Errorf("Test Failed! Wanted could not verify if client is valid: Something went wrong got: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue