mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
chore: refactor/centralise secretKeyRef usage (#3022)
* chore: refactor/centralise secretKeyRef usage Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
parent
b6b4f12509
commit
26f9c3f1f4
43 changed files with 600 additions and 850 deletions
|
@ -27,12 +27,12 @@ type ConjurProvider struct {
|
||||||
|
|
||||||
type ConjurAuth struct {
|
type ConjurAuth struct {
|
||||||
// +optional
|
// +optional
|
||||||
Apikey *ConjurApikey `json:"apikey,omitempty"`
|
APIKey *ConjurAPIKey `json:"apikey,omitempty"`
|
||||||
// +optional
|
// +optional
|
||||||
Jwt *ConjurJWT `json:"jwt,omitempty"`
|
Jwt *ConjurJWT `json:"jwt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConjurApikey struct {
|
type ConjurAPIKey struct {
|
||||||
Account string `json:"account"`
|
Account string `json:"account"`
|
||||||
UserRef *esmeta.SecretKeySelector `json:"userRef"`
|
UserRef *esmeta.SecretKeySelector `json:"userRef"`
|
||||||
APIKeyRef *esmeta.SecretKeySelector `json:"apiKeyRef"`
|
APIKeyRef *esmeta.SecretKeySelector `json:"apiKeyRef"`
|
||||||
|
|
|
@ -654,7 +654,7 @@ func (in *ClusterSecretStoreList) DeepCopyObject() runtime.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ConjurApikey) DeepCopyInto(out *ConjurApikey) {
|
func (in *ConjurAPIKey) DeepCopyInto(out *ConjurAPIKey) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.UserRef != nil {
|
if in.UserRef != nil {
|
||||||
in, out := &in.UserRef, &out.UserRef
|
in, out := &in.UserRef, &out.UserRef
|
||||||
|
@ -668,12 +668,12 @@ func (in *ConjurApikey) DeepCopyInto(out *ConjurApikey) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConjurApikey.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConjurAPIKey.
|
||||||
func (in *ConjurApikey) DeepCopy() *ConjurApikey {
|
func (in *ConjurAPIKey) DeepCopy() *ConjurAPIKey {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(ConjurApikey)
|
out := new(ConjurAPIKey)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -681,9 +681,9 @@ func (in *ConjurApikey) DeepCopy() *ConjurApikey {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ConjurAuth) DeepCopyInto(out *ConjurAuth) {
|
func (in *ConjurAuth) DeepCopyInto(out *ConjurAuth) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Apikey != nil {
|
if in.APIKey != nil {
|
||||||
in, out := &in.Apikey, &out.Apikey
|
in, out := &in.APIKey, &out.APIKey
|
||||||
*out = new(ConjurApikey)
|
*out = new(ConjurAPIKey)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
if in.Jwt != nil {
|
if in.Jwt != nil {
|
||||||
|
|
|
@ -1691,7 +1691,7 @@ Kubernetes meta/v1.LabelSelector
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h3 id="external-secrets.io/v1beta1.ConjurApikey">ConjurApikey
|
<h3 id="external-secrets.io/v1beta1.ConjurAPIKey">ConjurAPIKey
|
||||||
</h3>
|
</h3>
|
||||||
<p>
|
<p>
|
||||||
(<em>Appears on:</em>
|
(<em>Appears on:</em>
|
||||||
|
@ -1763,8 +1763,8 @@ External Secrets meta/v1.SecretKeySelector
|
||||||
<td>
|
<td>
|
||||||
<code>apikey</code></br>
|
<code>apikey</code></br>
|
||||||
<em>
|
<em>
|
||||||
<a href="#external-secrets.io/v1beta1.ConjurApikey">
|
<a href="#external-secrets.io/v1beta1.ConjurAPIKey">
|
||||||
ConjurApikey
|
ConjurAPIKey
|
||||||
</a>
|
</a>
|
||||||
</em>
|
</em>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
|
genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
|
"github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Generator struct{}
|
type Generator struct{}
|
||||||
|
@ -65,7 +66,7 @@ func (g *Generator) generate(
|
||||||
ts, err := tokenSource(ctx, esv1beta1.GCPSMAuth{
|
ts, err := tokenSource(ctx, esv1beta1.GCPSMAuth{
|
||||||
SecretRef: (*esv1beta1.GCPSMAuthSecretRef)(res.Spec.Auth.SecretRef),
|
SecretRef: (*esv1beta1.GCPSMAuthSecretRef)(res.Spec.Auth.SecretRef),
|
||||||
WorkloadIdentity: (*esv1beta1.GCPWorkloadIdentity)(res.Spec.Auth.WorkloadIdentity),
|
WorkloadIdentity: (*esv1beta1.GCPWorkloadIdentity)(res.Spec.Auth.WorkloadIdentity),
|
||||||
}, res.Spec.ProjectID, false, kube, namespace)
|
}, res.Spec.ProjectID, resolvers.EmptyStoreKind, kube, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,7 @@ func (g *Generator) generate(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type tokenSourceFunc func(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID string, isClusterKind bool, kube client.Client, namespace string) (oauth2.TokenSource, error)
|
type tokenSourceFunc func(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID string, storeKind string, kube client.Client, namespace string) (oauth2.TokenSource, error)
|
||||||
|
|
||||||
func parseSpec(data []byte) (*genv1alpha1.GCRAccessToken, error) {
|
func parseSpec(data []byte) (*genv1alpha1.GCRAccessToken, error) {
|
||||||
var spec genv1alpha1.GCRAccessToken
|
var spec genv1alpha1.GCRAccessToken
|
||||||
|
|
|
@ -65,7 +65,7 @@ func TestGenerate(t *testing.T) {
|
||||||
"foo": []byte("bar"),
|
"foo": []byte("bar"),
|
||||||
},
|
},
|
||||||
}).Build(),
|
}).Build(),
|
||||||
fakeTokenSource: func(ctx context.Context, auth v1beta1.GCPSMAuth, projectID string, isClusterKind bool, kube client.Client, namespace string) (oauth2.TokenSource, error) {
|
fakeTokenSource: func(ctx context.Context, auth v1beta1.GCPSMAuth, projectID string, storeKind string, kube client.Client, namespace string) (oauth2.TokenSource, error) {
|
||||||
return oauth2.StaticTokenSource(&oauth2.Token{
|
return oauth2.StaticTokenSource(&oauth2.Token{
|
||||||
AccessToken: "1234",
|
AccessToken: "1234",
|
||||||
Expiry: time.Unix(5555, 0),
|
Expiry: time.Unix(5555, 0),
|
||||||
|
|
|
@ -39,6 +39,7 @@ import (
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/find"
|
"github.com/external-secrets/external-secrets/pkg/find"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -426,12 +427,14 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
|
||||||
}
|
}
|
||||||
ok := caCertPool.AppendCertsFromPEM(pem)
|
ok := caCertPool.AppendCertsFromPEM(pem)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to append cabundle")
|
return nil, fmt.Errorf("failed to append caBundle")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.CAProvider != nil && a.storeKind == esv1beta1.ClusterSecretStoreKind && provider.CAProvider.Namespace == nil {
|
if provider.CAProvider != nil &&
|
||||||
return nil, fmt.Errorf("missing namespace on CAProvider secret")
|
a.storeKind == esv1beta1.ClusterSecretStoreKind &&
|
||||||
|
provider.CAProvider.Namespace == nil {
|
||||||
|
return nil, fmt.Errorf("missing namespace on caProvider secret")
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.CAProvider != nil {
|
if provider.CAProvider != nil {
|
||||||
|
@ -444,7 +447,7 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
|
||||||
case esv1beta1.CAProviderTypeConfigMap:
|
case esv1beta1.CAProviderTypeConfigMap:
|
||||||
cert, err = a.getCertFromConfigMap(provider)
|
cert, err = a.getCertFromConfigMap(provider)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unknown caprovider type: %s", provider.CAProvider.Type)
|
err = fmt.Errorf("unknown CAProvider type: %s", provider.CAProvider.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -456,7 +459,7 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
|
||||||
}
|
}
|
||||||
ok := caCertPool.AppendCertsFromPEM(pem)
|
ok := caCertPool.AppendCertsFromPEM(pem)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to append cabundle")
|
return nil, fmt.Errorf("failed to append caBundle")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return caCertPool, nil
|
return caCertPool, nil
|
||||||
|
@ -473,12 +476,12 @@ func (a *akeylessBase) getCertFromSecret(provider *esv1beta1.AkeylessProvider) (
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res, err := a.secretKeyRef(ctx, &secretRef)
|
cert, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, &secretRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte(res), nil
|
return []byte(cert), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider) ([]byte, error) {
|
func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider) ([]byte, error) {
|
||||||
|
@ -494,12 +497,12 @@ func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := a.kube.Get(ctx, objKey, configMapRef)
|
err := a.kube.Get(ctx, objKey, configMapRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get caprovider secret %s: %w", objKey.Name, err)
|
return nil, fmt.Errorf("failed to get caProvider secret %s: %w", objKey.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
val, ok := configMapRef.Data[provider.CAProvider.Key]
|
val, ok := configMapRef.Data[provider.CAProvider.Key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to get caprovider configmap %s -> %s", objKey.Name, provider.CAProvider.Key)
|
return nil, fmt.Errorf("failed to get caProvider configMap %s -> %s", objKey.Name, provider.CAProvider.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte(val), nil
|
return []byte(val), nil
|
||||||
|
|
|
@ -35,6 +35,7 @@ import (
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var apiErr akeyless.GenericOpenAPIError
|
var apiErr akeyless.GenericOpenAPIError
|
||||||
|
@ -335,7 +336,7 @@ func (a *akeylessBase) getK8SServiceAccountJWT(ctx context.Context, kubernetesAu
|
||||||
tokenRef = kubernetesAuth.SecretRef.DeepCopy()
|
tokenRef = kubernetesAuth.SecretRef.DeepCopy()
|
||||||
tokenRef.Key = "token"
|
tokenRef.Key = "token"
|
||||||
}
|
}
|
||||||
jwt, err := a.secretKeyRef(ctx, tokenRef)
|
jwt, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, tokenRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -363,7 +364,7 @@ func (a *akeylessBase) getJWTFromServiceAccount(ctx context.Context, serviceAcco
|
||||||
return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
|
return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
|
||||||
}
|
}
|
||||||
for _, tokenRef := range serviceAccount.Secrets {
|
for _, tokenRef := range serviceAccount.Secrets {
|
||||||
retval, err := a.secretKeyRef(ctx, &esmeta.SecretKeySelector{
|
token, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, &esmeta.SecretKeySelector{
|
||||||
Name: tokenRef.Name,
|
Name: tokenRef.Name,
|
||||||
Namespace: &ref.Namespace,
|
Namespace: &ref.Namespace,
|
||||||
Key: "token",
|
Key: "token",
|
||||||
|
@ -372,36 +373,11 @@ func (a *akeylessBase) getJWTFromServiceAccount(ctx context.Context, serviceAcco
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
|
return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *akeylessBase) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
|
|
||||||
secret := &corev1.Secret{}
|
|
||||||
ref := types.NamespacedName{
|
|
||||||
Namespace: a.namespace,
|
|
||||||
Name: secretRef.Name,
|
|
||||||
}
|
|
||||||
if (a.storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
|
||||||
(secretRef.Namespace != nil) {
|
|
||||||
ref.Namespace = *secretRef.Namespace
|
|
||||||
}
|
|
||||||
err := a.kube.Get(ctx, ref, secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBytes, ok := secret.Data[secretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
value := string(keyBytes)
|
|
||||||
valueStr := strings.TrimSpace(value)
|
|
||||||
return valueStr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *akeylessBase) getJWTfromServiceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
|
func (a *akeylessBase) getJWTfromServiceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
|
||||||
audiences := serviceAccountRef.Audiences
|
audiences := serviceAccountRef.Audiences
|
||||||
if len(additionalAud) > 0 {
|
if len(additionalAud) > 0 {
|
||||||
|
|
|
@ -18,19 +18,15 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing Akeyless AccessID Namespace"
|
errFetchAccessIDSecret = "could not fetch accessID secret: %w"
|
||||||
errInvalidClusterStoreMissingSAKNamespace = "invalid ClusterSecretStore: missing Akeyless AccessType Namespace"
|
errFetchAccessTypeSecret = "could not fetch AccessType secret: %w"
|
||||||
errFetchAKIDSecret = "could not fetch accessID secret: %w"
|
errFetchAccessTypeParamSecret = "could not fetch AccessTypeParam secret: %w"
|
||||||
errFetchSAKSecret = "could not fetch AccessType secret: %w"
|
errMissingSAK = "missing SecretAccessKey"
|
||||||
errMissingSAK = "missing SecretAccessKey"
|
errMissingAKID = "missing AccessKeyID"
|
||||||
errMissingAKID = "missing AccessKeyID"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *akeylessBase) TokenFromSecretRef(ctx context.Context) (string, error) {
|
func (a *akeylessBase) TokenFromSecretRef(ctx context.Context) (string, error) {
|
||||||
|
@ -44,58 +40,36 @@ func (a *akeylessBase) TokenFromSecretRef(ctx context.Context) (string, error) {
|
||||||
return a.GetToken(auth.AccessID, "k8s", auth.K8sConfName, auth)
|
return a.GetToken(auth.AccessID, "k8s", auth.K8sConfName, auth)
|
||||||
}
|
}
|
||||||
|
|
||||||
ke := client.ObjectKey{
|
accessID, err := resolvers.SecretKeyRef(
|
||||||
Name: prov.Auth.SecretRef.AccessID.Name,
|
ctx,
|
||||||
Namespace: a.namespace, // default to ExternalSecret namespace
|
a.kube,
|
||||||
}
|
a.storeKind,
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
a.namespace,
|
||||||
if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
&prov.Auth.SecretRef.AccessID,
|
||||||
if prov.Auth.SecretRef.AccessID.Namespace == nil {
|
)
|
||||||
return "", fmt.Errorf(errInvalidClusterStoreMissingAKIDNamespace)
|
|
||||||
}
|
|
||||||
ke.Namespace = *prov.Auth.SecretRef.AccessID.Namespace
|
|
||||||
}
|
|
||||||
accessIDSecret := v1.Secret{}
|
|
||||||
err = a.kube.Get(ctx, ke, &accessIDSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(errFetchAKIDSecret, err)
|
return "", fmt.Errorf(errFetchAccessIDSecret, err)
|
||||||
}
|
}
|
||||||
ke = client.ObjectKey{
|
accessType, err := resolvers.SecretKeyRef(
|
||||||
Name: prov.Auth.SecretRef.AccessType.Name,
|
ctx,
|
||||||
Namespace: a.namespace, // default to ExternalSecret namespace
|
a.kube,
|
||||||
}
|
a.storeKind,
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
a.namespace,
|
||||||
if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
&prov.Auth.SecretRef.AccessType,
|
||||||
if prov.Auth.SecretRef.AccessType.Namespace == nil {
|
)
|
||||||
return "", fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
|
|
||||||
}
|
|
||||||
ke.Namespace = *prov.Auth.SecretRef.AccessType.Namespace
|
|
||||||
}
|
|
||||||
accessTypeSecret := v1.Secret{}
|
|
||||||
err = a.kube.Get(ctx, ke, &accessTypeSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(errFetchSAKSecret, err)
|
return "", fmt.Errorf(errFetchAccessTypeSecret, err)
|
||||||
}
|
}
|
||||||
|
accessTypeParam, err := resolvers.SecretKeyRef(
|
||||||
ke = client.ObjectKey{
|
ctx,
|
||||||
Name: prov.Auth.SecretRef.AccessTypeParam.Name,
|
a.kube,
|
||||||
Namespace: a.namespace, // default to ExternalSecret namespace
|
a.storeKind,
|
||||||
}
|
a.namespace,
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
&prov.Auth.SecretRef.AccessTypeParam,
|
||||||
if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
)
|
||||||
if prov.Auth.SecretRef.AccessType.Namespace == nil {
|
|
||||||
return "", fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
|
|
||||||
}
|
|
||||||
ke.Namespace = *prov.Auth.SecretRef.AccessType.Namespace
|
|
||||||
}
|
|
||||||
accessTypeParamSecret := v1.Secret{}
|
|
||||||
err = a.kube.Get(ctx, ke, &accessTypeParamSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(errFetchSAKSecret, err)
|
return "", fmt.Errorf(errFetchAccessTypeParamSecret, err)
|
||||||
}
|
}
|
||||||
accessID := string(accessIDSecret.Data[prov.Auth.SecretRef.AccessID.Key])
|
|
||||||
accessType := string(accessTypeSecret.Data[prov.Auth.SecretRef.AccessType.Key])
|
|
||||||
accessTypeParam := string(accessTypeSecret.Data[prov.Auth.SecretRef.AccessTypeParam.Key])
|
|
||||||
|
|
||||||
if accessID == "" {
|
if accessID == "" {
|
||||||
return "", fmt.Errorf(errMissingSAK)
|
return "", fmt.Errorf(errMissingSAK)
|
||||||
|
|
|
@ -26,22 +26,18 @@ import (
|
||||||
"github.com/avast/retry-go/v4"
|
"github.com/avast/retry-go/v4"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
errAlibabaClient = "cannot setup new Alibaba client: %w"
|
errAlibabaClient = "cannot setup new Alibaba client: %w"
|
||||||
errAlibabaCredSecretName = "invalid Alibaba SecretStore resource: missing Alibaba APIKey"
|
errUninitalizedAlibabaProvider = "provider Alibaba is not initialized"
|
||||||
errUninitalizedAlibabaProvider = "provider Alibaba is not initialized"
|
errFetchAccessKeyID = "could not fetch AccessKeyID secret: %w"
|
||||||
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterStore, missing AccessKeyID namespace"
|
errFetchAccessKeySecret = "could not fetch AccessKeySecret secret: %w"
|
||||||
errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
|
|
||||||
errFetchAKIDSecret = "could not fetch AccessKeyID secret: %w"
|
|
||||||
errMissingSAK = "missing AccessSecretKey"
|
|
||||||
errMissingAKID = "missing AccessKeyID"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://github.com/external-secrets/external-secrets/issues/644
|
// https://github.com/external-secrets/external-secrets/issues/644
|
||||||
|
@ -222,54 +218,17 @@ func newAccessKeyAuth(ctx context.Context, kube kclient.Client, store esv1beta1.
|
||||||
storeSpec := store.GetSpec()
|
storeSpec := store.GetSpec()
|
||||||
alibabaSpec := storeSpec.Provider.Alibaba
|
alibabaSpec := storeSpec.Provider.Alibaba
|
||||||
storeKind := store.GetObjectKind().GroupVersionKind().Kind
|
storeKind := store.GetObjectKind().GroupVersionKind().Kind
|
||||||
|
accessKeyID, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &alibabaSpec.Auth.SecretRef.AccessKeyID)
|
||||||
credentialsSecret := &corev1.Secret{}
|
|
||||||
credentialsSecretName := alibabaSpec.Auth.SecretRef.AccessKeyID.Name
|
|
||||||
if credentialsSecretName == "" {
|
|
||||||
return nil, fmt.Errorf(errAlibabaCredSecretName)
|
|
||||||
}
|
|
||||||
objectKey := types.NamespacedName{
|
|
||||||
Name: credentialsSecretName,
|
|
||||||
Namespace: namespace,
|
|
||||||
}
|
|
||||||
|
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
|
||||||
if storeKind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if alibabaSpec.Auth.SecretRef.AccessKeyID.Namespace == nil {
|
|
||||||
return nil, fmt.Errorf(errInvalidClusterStoreMissingAKIDNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *alibabaSpec.Auth.SecretRef.AccessKeyID.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
err := kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchAKIDSecret, err)
|
return nil, fmt.Errorf(errFetchAccessKeyID, err)
|
||||||
}
|
}
|
||||||
|
accessKeySecret, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &alibabaSpec.Auth.SecretRef.AccessKeySecret)
|
||||||
objectKey = types.NamespacedName{
|
if err != nil {
|
||||||
Name: alibabaSpec.Auth.SecretRef.AccessKeySecret.Name,
|
return nil, fmt.Errorf(errFetchAccessKeySecret, err)
|
||||||
Namespace: namespace,
|
|
||||||
}
|
}
|
||||||
if storeKind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if alibabaSpec.Auth.SecretRef.AccessKeySecret.Namespace == nil {
|
|
||||||
return nil, fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *alibabaSpec.Auth.SecretRef.AccessKeySecret.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
accessKeyID := credentialsSecret.Data[alibabaSpec.Auth.SecretRef.AccessKeyID.Key]
|
|
||||||
if (accessKeyID == nil) || (len(accessKeyID) == 0) {
|
|
||||||
return nil, fmt.Errorf(errMissingAKID)
|
|
||||||
}
|
|
||||||
|
|
||||||
accessKeySecret := credentialsSecret.Data[alibabaSpec.Auth.SecretRef.AccessKeySecret.Key]
|
|
||||||
if (accessKeySecret == nil) || (len(accessKeySecret) == 0) {
|
|
||||||
return nil, fmt.Errorf(errMissingSAK)
|
|
||||||
}
|
|
||||||
|
|
||||||
credentialConfig := &credential.Config{
|
credentialConfig := &credential.Config{
|
||||||
AccessKeyId: utils.Ptr(string(accessKeyID)),
|
AccessKeyId: utils.Ptr(accessKeyID),
|
||||||
AccessKeySecret: utils.Ptr(string(accessKeySecret)),
|
AccessKeySecret: utils.Ptr(accessKeySecret),
|
||||||
Type: utils.Ptr("access_key"),
|
Type: utils.Ptr("access_key"),
|
||||||
ConnectTimeout: utils.Ptr(30),
|
ConnectTimeout: utils.Ptr(30),
|
||||||
Timeout: utils.Ptr(60),
|
Timeout: utils.Ptr(60),
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/external-secrets/external-secrets/pkg/cache"
|
"github.com/external-secrets/external-secrets/pkg/cache"
|
||||||
"github.com/external-secrets/external-secrets/pkg/feature"
|
"github.com/external-secrets/external-secrets/pkg/feature"
|
||||||
"github.com/external-secrets/external-secrets/pkg/provider/aws/util"
|
"github.com/external-secrets/external-secrets/pkg/provider/aws/util"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains configuration to create a new AWS provider.
|
// Config contains configuration to create a new AWS provider.
|
||||||
|
@ -58,13 +59,9 @@ const (
|
||||||
audienceAnnotation = "eks.amazonaws.com/audience"
|
audienceAnnotation = "eks.amazonaws.com/audience"
|
||||||
defaultTokenAudience = "sts.amazonaws.com"
|
defaultTokenAudience = "sts.amazonaws.com"
|
||||||
|
|
||||||
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
|
errFetchAKIDSecret = "could not fetch accessKeyID secret: %w"
|
||||||
errInvalidClusterStoreMissingSAKNamespace = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
|
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||||
errFetchAKIDSecret = "could not fetch accessKeyID secret: %w"
|
errFetchSTSecret = "could not fetch SessionToken secret: %w"
|
||||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
|
||||||
errFetchSTSecret = "could not fetch SessionToken secret: %w"
|
|
||||||
errMissingSAK = "missing SecretAccessKey"
|
|
||||||
errMissingAKID = "missing AccessKeyID"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -98,11 +95,11 @@ func New(ctx context.Context, store esv1beta1.GenericStore, kube client.Client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use credentials from sercretRef
|
// use credentials from secretRef
|
||||||
secretRef := prov.Auth.SecretRef
|
secretRef := prov.Auth.SecretRef
|
||||||
if secretRef != nil {
|
if secretRef != nil {
|
||||||
log.V(1).Info("using credentials from secretRef")
|
log.V(1).Info("using credentials from secretRef")
|
||||||
creds, err = credsFromSecretRef(ctx, prov.Auth, isClusterKind, kube, namespace)
|
creds, err = credsFromSecretRef(ctx, prov.Auth, store.GetKind(), kube, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -176,11 +173,11 @@ func NewGeneratorSession(ctx context.Context, auth esv1beta1.AWSAuth, role, regi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use credentials from sercretRef
|
// use credentials from secretRef
|
||||||
secretRef := auth.SecretRef
|
secretRef := auth.SecretRef
|
||||||
if secretRef != nil {
|
if secretRef != nil {
|
||||||
log.V(1).Info("using credentials from secretRef")
|
log.V(1).Info("using credentials from secretRef")
|
||||||
creds, err = credsFromSecretRef(ctx, auth, false, kube, namespace)
|
creds, err = credsFromSecretRef(ctx, auth, "", kube, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -211,55 +208,22 @@ func NewGeneratorSession(ctx context.Context, auth esv1beta1.AWSAuth, role, regi
|
||||||
// construct a aws.Credentials object
|
// construct a aws.Credentials object
|
||||||
// The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
|
// The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
|
||||||
// If the ClusterSecretStore defines a namespace it will take precedence.
|
// If the ClusterSecretStore defines a namespace it will take precedence.
|
||||||
func credsFromSecretRef(ctx context.Context, auth esv1beta1.AWSAuth, isClusterKind bool, kube client.Client, namespace string) (*credentials.Credentials, error) {
|
func credsFromSecretRef(ctx context.Context, auth esv1beta1.AWSAuth, storeKind string, kube client.Client, namespace string) (*credentials.Credentials, error) {
|
||||||
ke := client.ObjectKey{
|
sak, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &auth.SecretRef.SecretAccessKey)
|
||||||
Name: auth.SecretRef.AccessKeyID.Name,
|
|
||||||
Namespace: namespace,
|
|
||||||
}
|
|
||||||
if isClusterKind && auth.SecretRef.AccessKeyID.Namespace != nil {
|
|
||||||
ke.Namespace = *auth.SecretRef.AccessKeyID.Namespace
|
|
||||||
}
|
|
||||||
akSecret := v1.Secret{}
|
|
||||||
err := kube.Get(ctx, ke, &akSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(errFetchAKIDSecret, err)
|
|
||||||
}
|
|
||||||
ke = client.ObjectKey{
|
|
||||||
Name: auth.SecretRef.SecretAccessKey.Name,
|
|
||||||
Namespace: namespace,
|
|
||||||
}
|
|
||||||
if isClusterKind && auth.SecretRef.SecretAccessKey.Namespace != nil {
|
|
||||||
ke.Namespace = *auth.SecretRef.SecretAccessKey.Namespace
|
|
||||||
}
|
|
||||||
sakSecret := v1.Secret{}
|
|
||||||
err = kube.Get(ctx, ke, &sakSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchSAKSecret, err)
|
return nil, fmt.Errorf(errFetchSAKSecret, err)
|
||||||
}
|
}
|
||||||
sak := string(sakSecret.Data[auth.SecretRef.SecretAccessKey.Key])
|
aks, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &auth.SecretRef.AccessKeyID)
|
||||||
aks := string(akSecret.Data[auth.SecretRef.AccessKeyID.Key])
|
if err != nil {
|
||||||
if sak == "" {
|
return nil, fmt.Errorf(errFetchAKIDSecret, err)
|
||||||
return nil, fmt.Errorf(errMissingSAK)
|
|
||||||
}
|
|
||||||
if aks == "" {
|
|
||||||
return nil, fmt.Errorf(errMissingAKID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionToken string
|
var sessionToken string
|
||||||
if auth.SecretRef.SessionToken != nil {
|
if auth.SecretRef.SessionToken != nil {
|
||||||
ke = client.ObjectKey{
|
sessionToken, err = resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, auth.SecretRef.SessionToken)
|
||||||
Name: auth.SecretRef.SessionToken.Name,
|
|
||||||
Namespace: namespace,
|
|
||||||
}
|
|
||||||
if isClusterKind && auth.SecretRef.SessionToken.Namespace != nil {
|
|
||||||
ke.Namespace = *auth.SecretRef.SessionToken.Namespace
|
|
||||||
}
|
|
||||||
stSecret := v1.Secret{}
|
|
||||||
err = kube.Get(ctx, ke, &stSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchSTSecret, err)
|
return nil, fmt.Errorf(errFetchSTSecret, err)
|
||||||
}
|
}
|
||||||
sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return credentials.NewStaticCredentials(aks, sak, sessionToken), err
|
return credentials.NewStaticCredentials(aks, sak, sessionToken), err
|
||||||
|
|
|
@ -224,7 +224,7 @@ func TestNewSession(t *testing.T) {
|
||||||
Data: map[string][]byte{},
|
Data: map[string][]byte{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectErr: "missing SecretAccessKey",
|
expectErr: "could not fetch SecretAccessKey secret: cannot find secret data for key: \"two\"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should not be able to access secrets from different namespace",
|
name: "should not be able to access secrets from different namespace",
|
||||||
|
|
|
@ -48,10 +48,10 @@ import (
|
||||||
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
|
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
smmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
|
||||||
"github.com/external-secrets/external-secrets/pkg/constants"
|
"github.com/external-secrets/external-secrets/pkg/constants"
|
||||||
"github.com/external-secrets/external-secrets/pkg/metrics"
|
"github.com/external-secrets/external-secrets/pkg/metrics"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -886,46 +886,28 @@ func (a *Azure) authorizerForServicePrincipal(ctx context.Context) (autorest.Aut
|
||||||
if a.provider.AuthSecretRef.ClientID == nil || a.provider.AuthSecretRef.ClientSecret == nil {
|
if a.provider.AuthSecretRef.ClientID == nil || a.provider.AuthSecretRef.ClientSecret == nil {
|
||||||
return nil, fmt.Errorf(errMissingClientIDSecret)
|
return nil, fmt.Errorf(errMissingClientIDSecret)
|
||||||
}
|
}
|
||||||
clusterScoped := false
|
clientID, err := resolvers.SecretKeyRef(
|
||||||
if a.store.GetKind() == esv1beta1.ClusterSecretStoreKind {
|
ctx,
|
||||||
clusterScoped = true
|
a.crClient,
|
||||||
}
|
a.store.GetKind(),
|
||||||
cid, err := a.secretKeyRef(ctx, a.namespace, *a.provider.AuthSecretRef.ClientID, clusterScoped)
|
a.namespace, a.provider.AuthSecretRef.ClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
csec, err := a.secretKeyRef(ctx, a.namespace, *a.provider.AuthSecretRef.ClientSecret, clusterScoped)
|
clientSecret, err := resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
a.crClient,
|
||||||
|
a.store.GetKind(),
|
||||||
|
a.namespace, a.provider.AuthSecretRef.ClientSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
clientCredentialsConfig := kvauth.NewClientCredentialsConfig(cid, csec, *a.provider.TenantID)
|
clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, *a.provider.TenantID)
|
||||||
clientCredentialsConfig.Resource = kvResourceForProviderConfig(a.provider.EnvironmentType)
|
clientCredentialsConfig.Resource = kvResourceForProviderConfig(a.provider.EnvironmentType)
|
||||||
clientCredentialsConfig.AADEndpoint = AadEndpointForType(a.provider.EnvironmentType)
|
clientCredentialsConfig.AADEndpoint = AadEndpointForType(a.provider.EnvironmentType)
|
||||||
return clientCredentialsConfig.Authorizer()
|
return clientCredentialsConfig.Authorizer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// secretKeyRef fetch a secret key.
|
|
||||||
func (a *Azure) secretKeyRef(ctx context.Context, namespace string, secretRef smmeta.SecretKeySelector, clusterScoped bool) (string, error) {
|
|
||||||
var secret corev1.Secret
|
|
||||||
ref := types.NamespacedName{
|
|
||||||
Name: secretRef.Name,
|
|
||||||
Namespace: namespace,
|
|
||||||
}
|
|
||||||
if clusterScoped && secretRef.Namespace != nil {
|
|
||||||
ref.Namespace = *secretRef.Namespace
|
|
||||||
}
|
|
||||||
err := a.crClient.Get(ctx, ref, &secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(errFindSecret, ref.Namespace, ref.Name, err)
|
|
||||||
}
|
|
||||||
keyBytes, ok := secret.Data[secretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf(errFindDataKey, secretRef.Key, secretRef.Name, namespace)
|
|
||||||
}
|
|
||||||
value := strings.TrimSpace(string(keyBytes))
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Azure) Close(_ context.Context) error {
|
func (a *Azure) Close(_ context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,7 +244,7 @@ func TestAuth(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad config: missing secret",
|
name: "bad config: missing secret",
|
||||||
expErr: "could not find secret default/password: secrets \"password\" not found",
|
expErr: "cannot get Kubernetes secret \"password\": secrets \"password\" not found",
|
||||||
store: &defaultStore,
|
store: &defaultStore,
|
||||||
provider: &esv1beta1.AzureKVProvider{
|
provider: &esv1beta1.AzureKVProvider{
|
||||||
AuthType: &authType,
|
AuthType: &authType,
|
||||||
|
@ -258,7 +258,7 @@ func TestAuth(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "cluster secret store",
|
name: "cluster secret store",
|
||||||
expErr: "could not find secret foo/password: secrets \"password\" not found",
|
expErr: "cannot get Kubernetes secret \"password\": secrets \"password\" not found",
|
||||||
store: &esv1beta1.ClusterSecretStore{
|
store: &esv1beta1.ClusterSecretStore{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: esv1beta1.ClusterSecretStoreKind,
|
Kind: esv1beta1.ClusterSecretStoreKind,
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const JwtLifespan = 600 // 10 minutes
|
const JwtLifespan = 600 // 10 minutes
|
||||||
|
@ -46,7 +47,12 @@ func (p *Client) getJWTToken(ctx context.Context, conjurJWTConfig *esv1beta1.Con
|
||||||
tokenRef = conjurJWTConfig.SecretRef.DeepCopy()
|
tokenRef = conjurJWTConfig.SecretRef.DeepCopy()
|
||||||
tokenRef.Key = "token"
|
tokenRef.Key = "token"
|
||||||
}
|
}
|
||||||
jwtToken, err := p.secretKeyRef(ctx, tokenRef)
|
jwtToken, err := resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
p.kube,
|
||||||
|
p.StoreKind,
|
||||||
|
p.namespace,
|
||||||
|
tokenRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import (
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/provider/conjur/util"
|
"github.com/external-secrets/external-secrets/pkg/provider/conjur/util"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -109,13 +110,22 @@ func (p *Client) GetConjurClient(ctx context.Context) (SecretsClient, error) {
|
||||||
SSLCert: cert,
|
SSLCert: cert,
|
||||||
}
|
}
|
||||||
|
|
||||||
if prov.Auth.Apikey != nil {
|
if prov.Auth.APIKey != nil {
|
||||||
config.Account = prov.Auth.Apikey.Account
|
config.Account = prov.Auth.APIKey.Account
|
||||||
conjUser, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.UserRef)
|
conjUser, secErr := resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
p.kube,
|
||||||
|
p.StoreKind,
|
||||||
|
p.namespace, prov.Auth.APIKey.UserRef)
|
||||||
if secErr != nil {
|
if secErr != nil {
|
||||||
return nil, fmt.Errorf(errBadServiceUser, secErr)
|
return nil, fmt.Errorf(errBadServiceUser, secErr)
|
||||||
}
|
}
|
||||||
conjAPIKey, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.APIKeyRef)
|
conjAPIKey, secErr := resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
p.kube,
|
||||||
|
p.StoreKind,
|
||||||
|
p.namespace,
|
||||||
|
prov.Auth.APIKey.APIKeyRef)
|
||||||
if secErr != nil {
|
if secErr != nil {
|
||||||
return nil, fmt.Errorf(errBadServiceAPIKey, secErr)
|
return nil, fmt.Errorf(errBadServiceAPIKey, secErr)
|
||||||
}
|
}
|
||||||
|
@ -224,20 +234,20 @@ func (c *Provider) ValidateStore(store esv1beta1.GenericStore) error {
|
||||||
if prov.URL == "" {
|
if prov.URL == "" {
|
||||||
return fmt.Errorf("conjur URL cannot be empty")
|
return fmt.Errorf("conjur URL cannot be empty")
|
||||||
}
|
}
|
||||||
if prov.Auth.Apikey != nil {
|
if prov.Auth.APIKey != nil {
|
||||||
if prov.Auth.Apikey.Account == "" {
|
if prov.Auth.APIKey.Account == "" {
|
||||||
return fmt.Errorf("missing Auth.ApiKey.Account")
|
return fmt.Errorf("missing Auth.ApiKey.Account")
|
||||||
}
|
}
|
||||||
if prov.Auth.Apikey.UserRef == nil {
|
if prov.Auth.APIKey.UserRef == nil {
|
||||||
return fmt.Errorf("missing Auth.Apikey.UserRef")
|
return fmt.Errorf("missing Auth.Apikey.UserRef")
|
||||||
}
|
}
|
||||||
if prov.Auth.Apikey.APIKeyRef == nil {
|
if prov.Auth.APIKey.APIKeyRef == nil {
|
||||||
return fmt.Errorf("missing Auth.Apikey.ApiKeyRef")
|
return fmt.Errorf("missing Auth.Apikey.ApiKeyRef")
|
||||||
}
|
}
|
||||||
if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.Apikey.UserRef); err != nil {
|
if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.APIKey.UserRef); err != nil {
|
||||||
return fmt.Errorf("invalid Auth.Apikey.UserRef: %w", err)
|
return fmt.Errorf("invalid Auth.Apikey.UserRef: %w", err)
|
||||||
}
|
}
|
||||||
if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.Apikey.APIKeyRef); err != nil {
|
if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.APIKey.APIKeyRef); err != nil {
|
||||||
return fmt.Errorf("invalid Auth.Apikey.ApiKeyRef: %w", err)
|
return fmt.Errorf("invalid Auth.Apikey.ApiKeyRef: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +275,7 @@ func (c *Provider) ValidateStore(store esv1beta1.GenericStore) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// At least one auth must be configured
|
// At least one auth must be configured
|
||||||
if prov.Auth.Apikey == nil && prov.Auth.Jwt == nil {
|
if prov.Auth.APIKey == nil && prov.Auth.Jwt == nil {
|
||||||
return fmt.Errorf("missing Auth.* configuration")
|
return fmt.Errorf("missing Auth.* configuration")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,32 +287,7 @@ func (c *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
|
||||||
return esv1beta1.SecretStoreReadOnly
|
return esv1beta1.SecretStoreReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
|
// configMapKeyRef returns the value of a key in a ConfigMap.
|
||||||
secret := &corev1.Secret{}
|
|
||||||
ref := client.ObjectKey{
|
|
||||||
Namespace: p.namespace,
|
|
||||||
Name: secretRef.Name,
|
|
||||||
}
|
|
||||||
if (p.StoreKind == esv1beta1.ClusterSecretStoreKind) &&
|
|
||||||
(secretRef.Namespace != nil) {
|
|
||||||
ref.Namespace = *secretRef.Namespace
|
|
||||||
}
|
|
||||||
err := p.kube.Get(ctx, ref, secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBytes, ok := secret.Data[secretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
value := string(keyBytes)
|
|
||||||
valueStr := strings.TrimSpace(value)
|
|
||||||
return valueStr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// configMapKeyRef returns the value of a key in a configmap.
|
|
||||||
func (p *Client) configMapKeyRef(ctx context.Context, cmRef *esmeta.SecretKeySelector) (string, error) {
|
func (p *Client) configMapKeyRef(ctx context.Context, cmRef *esmeta.SecretKeySelector) (string, error) {
|
||||||
configMap := &corev1.ConfigMap{}
|
configMap := &corev1.ConfigMap{}
|
||||||
ref := client.ObjectKey{
|
ref := client.ObjectKey{
|
||||||
|
@ -349,7 +334,12 @@ func (p *Client) getCA(ctx context.Context, provider *esv1beta1.ConjurProvider)
|
||||||
Namespace: provider.CAProvider.Namespace,
|
Namespace: provider.CAProvider.Namespace,
|
||||||
Key: provider.CAProvider.Key,
|
Key: provider.CAProvider.Key,
|
||||||
}
|
}
|
||||||
ca, err = p.secretKeyRef(ctx, &keySelector)
|
ca, err = resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
p.kube,
|
||||||
|
p.StoreKind,
|
||||||
|
p.namespace,
|
||||||
|
&keySelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(errUnableToFetchCAProviderSecret, err)
|
return "", fmt.Errorf(errUnableToFetchCAProviderSecret, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,7 +351,7 @@ func makeAPIKeySecretStore(svcURL, svcUser, svcApikey, svcAccount string) *esv1b
|
||||||
Conjur: &esv1beta1.ConjurProvider{
|
Conjur: &esv1beta1.ConjurProvider{
|
||||||
URL: svcURL,
|
URL: svcURL,
|
||||||
Auth: esv1beta1.ConjurAuth{
|
Auth: esv1beta1.ConjurAuth{
|
||||||
Apikey: &esv1beta1.ConjurApikey{
|
APIKey: &esv1beta1.ConjurAPIKey{
|
||||||
Account: svcAccount,
|
Account: svcAccount,
|
||||||
UserRef: uref,
|
UserRef: uref,
|
||||||
APIKeyRef: aref,
|
APIKeyRef: aref,
|
||||||
|
@ -465,7 +465,7 @@ func makeFakeCASource(kind, caData string) kclient.Object {
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"conjur-cert": []byte(caData),
|
"ca": []byte(caData),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,13 @@ package delinea
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
|
"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -38,8 +37,6 @@ var (
|
||||||
errMissingSecretName = errors.New("must specify a secret name")
|
errMissingSecretName = errors.New("must specify a secret name")
|
||||||
errMissingSecretKey = errors.New("must specify a secret key")
|
errMissingSecretKey = errors.New("must specify a secret key")
|
||||||
errClusterStoreRequiresNamespace = errors.New("when using a ClusterSecretStore, namespaces must be explicitly set")
|
errClusterStoreRequiresNamespace = errors.New("when using a ClusterSecretStore, namespaces must be explicitly set")
|
||||||
|
|
||||||
errNoSuchKeyFmt = "no such key in secret: %q"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Provider struct{}
|
type Provider struct{}
|
||||||
|
@ -62,12 +59,12 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
|
||||||
return nil, errClusterStoreRequiresNamespace
|
return nil, errClusterStoreRequiresNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
clientID, err := loadConfigSecret(ctx, cfg.ClientID, kube, namespace)
|
clientID, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientID, kube, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSecret, err := loadConfigSecret(ctx, cfg.ClientSecret, kube, namespace)
|
clientSecret, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientSecret, kube, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -90,33 +87,19 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfigSecret(ctx context.Context, ref *esv1beta1.DelineaProviderSecretRef, kube kubeClient.Client, defaultNamespace string) (string, error) {
|
func loadConfigSecret(
|
||||||
|
ctx context.Context,
|
||||||
|
storeKind string,
|
||||||
|
ref *esv1beta1.DelineaProviderSecretRef,
|
||||||
|
kube kubeClient.Client,
|
||||||
|
namespace string) (string, error) {
|
||||||
if ref.SecretRef == nil {
|
if ref.SecretRef == nil {
|
||||||
return ref.Value, nil
|
return ref.Value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateSecretRef(ref); err != nil {
|
if err := validateSecretRef(ref); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
return resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, ref.SecretRef)
|
||||||
namespace := defaultNamespace
|
|
||||||
if ref.SecretRef.Namespace != nil {
|
|
||||||
namespace = *ref.SecretRef.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
objKey := kubeClient.ObjectKey{Namespace: namespace, Name: ref.SecretRef.Name}
|
|
||||||
secret := corev1.Secret{}
|
|
||||||
err := kube.Get(ctx, objKey, &secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
value, ok := secret.Data[ref.SecretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf(errNoSuchKeyFmt, ref.SecretRef.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(value), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateStoreSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.DelineaProviderSecretRef) error {
|
func validateStoreSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.DelineaProviderSecretRef) error {
|
||||||
|
|
|
@ -15,7 +15,6 @@ package delinea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
|
"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
|
||||||
|
@ -283,7 +282,7 @@ func TestNewClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
|
kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
|
||||||
errCheck: func(t *testing.T, err error) {
|
errCheck: func(t *testing.T, err error) {
|
||||||
assert.EqualError(t, err, fmt.Sprintf(errNoSuchKeyFmt, "typo"))
|
assert.EqualError(t, err, "cannot find secret data for key: \"typo\"")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"valid secret refs": {
|
"valid secret refs": {
|
||||||
|
|
|
@ -23,13 +23,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/find"
|
"github.com/external-secrets/external-secrets/pkg/find"
|
||||||
dClient "github.com/external-secrets/external-secrets/pkg/provider/doppler/client"
|
dClient "github.com/external-secrets/external-secrets/pkg/provider/doppler/client"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,8 +41,6 @@ const (
|
||||||
secretsDownloadFileKey = "DOPPLER_SECRETS_FILE"
|
secretsDownloadFileKey = "DOPPLER_SECRETS_FILE"
|
||||||
errDopplerTokenSecretName = "missing auth.secretRef.dopplerToken.name"
|
errDopplerTokenSecretName = "missing auth.secretRef.dopplerToken.name"
|
||||||
errInvalidClusterStoreMissingDopplerTokenNamespace = "missing auth.secretRef.dopplerToken.namespace"
|
errInvalidClusterStoreMissingDopplerTokenNamespace = "missing auth.secretRef.dopplerToken.namespace"
|
||||||
errFetchDopplerTokenSecret = "unable to find find DopplerToken secret: %w"
|
|
||||||
errMissingDopplerToken = "auth.secretRef.dopplerToken.key '%s' not found in secret '%s'"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
@ -68,35 +66,16 @@ type SecretsClientInterface interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) setAuth(ctx context.Context) error {
|
func (c *Client) setAuth(ctx context.Context) error {
|
||||||
credentialsSecret := &corev1.Secret{}
|
token, err := resolvers.SecretKeyRef(
|
||||||
credentialsSecretName := c.store.Auth.SecretRef.DopplerToken.Name
|
ctx,
|
||||||
if credentialsSecretName == "" {
|
c.kube,
|
||||||
return fmt.Errorf(errDopplerTokenSecretName)
|
c.storeKind,
|
||||||
}
|
c.namespace,
|
||||||
objectKey := types.NamespacedName{
|
&c.store.Auth.SecretRef.DopplerToken)
|
||||||
Name: credentialsSecretName,
|
|
||||||
Namespace: c.namespace,
|
|
||||||
}
|
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
|
||||||
if c.storeKind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if c.store.Auth.SecretRef.DopplerToken.Namespace == nil {
|
|
||||||
return fmt.Errorf(errInvalidClusterStoreMissingDopplerTokenNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *c.store.Auth.SecretRef.DopplerToken.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
err := c.kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(errFetchDopplerTokenSecret, err)
|
return err
|
||||||
}
|
}
|
||||||
|
c.dopplerToken = token
|
||||||
dopplerToken := credentialsSecret.Data[c.store.Auth.SecretRef.DopplerToken.Key]
|
|
||||||
if (dopplerToken == nil) || (len(dopplerToken) == 0) {
|
|
||||||
return fmt.Errorf(errMissingDopplerToken, c.store.Auth.SecretRef.DopplerToken.Key, credentialsSecretName)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.dopplerToken = string(dopplerToken)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,14 @@ import (
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID string, isClusterKind bool, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
|
func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID, storeKind string, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
|
||||||
ts, err := serviceAccountTokenSource(ctx, auth, isClusterKind, kube, namespace)
|
ts, err := serviceAccountTokenSource(ctx, auth, storeKind, kube, namespace)
|
||||||
if ts != nil || err != nil {
|
if ts != nil || err != nil {
|
||||||
return ts, err
|
return ts, err
|
||||||
}
|
}
|
||||||
|
@ -36,6 +35,7 @@ func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID str
|
||||||
return nil, fmt.Errorf("unable to initialize workload identity")
|
return nil, fmt.Errorf("unable to initialize workload identity")
|
||||||
}
|
}
|
||||||
defer wi.Close()
|
defer wi.Close()
|
||||||
|
isClusterKind := storeKind == esv1beta1.ClusterSecretStoreKind
|
||||||
ts, err = wi.TokenSource(ctx, auth, isClusterKind, kube, namespace)
|
ts, err = wi.TokenSource(ctx, auth, isClusterKind, kube, namespace)
|
||||||
if ts != nil || err != nil {
|
if ts != nil || err != nil {
|
||||||
return ts, err
|
return ts, err
|
||||||
|
@ -43,29 +43,21 @@ func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID str
|
||||||
return google.DefaultTokenSource(ctx, CloudPlatformRole)
|
return google.DefaultTokenSource(ctx, CloudPlatformRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
func serviceAccountTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, isClusterKind bool, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
|
func serviceAccountTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, storeKind string, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
|
||||||
sr := auth.SecretRef
|
sr := auth.SecretRef
|
||||||
if sr == nil {
|
if sr == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
credentialsSecret := &v1.Secret{}
|
credentials, err := resolvers.SecretKeyRef(
|
||||||
credentialsSecretName := sr.SecretAccessKey.Name
|
ctx,
|
||||||
objectKey := types.NamespacedName{
|
kube,
|
||||||
Name: credentialsSecretName,
|
storeKind,
|
||||||
Namespace: namespace,
|
namespace,
|
||||||
}
|
&auth.SecretRef.SecretAccessKey)
|
||||||
if isClusterKind && sr.SecretAccessKey.Namespace != nil {
|
|
||||||
objectKey.Namespace = *sr.SecretAccessKey.Namespace
|
|
||||||
}
|
|
||||||
err := kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchSAKSecret, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
credentials := credentialsSecret.Data[sr.SecretAccessKey.Key]
|
config, err := google.JWTConfigFromJSON([]byte(credentials), CloudPlatformRole)
|
||||||
if (credentials == nil) || (len(credentials) == 0) {
|
|
||||||
return nil, fmt.Errorf(errMissingSAK)
|
|
||||||
}
|
|
||||||
config, err := google.JWTConfigFromJSON(credentials, CloudPlatformRole)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errUnableProcessJSONCredentials, err)
|
return nil, fmt.Errorf(errUnableProcessJSONCredentials, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ const (
|
||||||
errClientClose = "unable to close SecretManager client: %w"
|
errClientClose = "unable to close SecretManager client: %w"
|
||||||
errMissingStoreSpec = "invalid: missing store spec"
|
errMissingStoreSpec = "invalid: missing store spec"
|
||||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||||
errMissingSAK = "missing SecretAccessKey"
|
|
||||||
errUnableProcessJSONCredentials = "failed to process the provided JSON credentials: %w"
|
errUnableProcessJSONCredentials = "failed to process the provided JSON credentials: %w"
|
||||||
errUnableCreateGCPSMClient = "failed to create GCP secretmanager client: %w"
|
errUnableCreateGCPSMClient = "failed to create GCP secretmanager client: %w"
|
||||||
errUninitalizedGCPProvider = "provider GCP is not initialized"
|
errUninitalizedGCPProvider = "provider GCP is not initialized"
|
||||||
|
|
|
@ -90,7 +90,7 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ts, err := NewTokenSource(ctx, gcpStore.Auth, clusterProjectID, isClusterKind, kube, namespace)
|
ts, err := NewTokenSource(ctx, gcpStore.Auth, clusterProjectID, store.GetKind(), kube, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errUnableCreateGCPSMClient, err)
|
return nil, fmt.Errorf(errUnableCreateGCPSMClient, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"github.com/xanzy/go-gitlab"
|
"github.com/xanzy/go-gitlab"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
@ -33,13 +32,13 @@ import (
|
||||||
"github.com/external-secrets/external-secrets/pkg/find"
|
"github.com/external-secrets/external-secrets/pkg/find"
|
||||||
"github.com/external-secrets/external-secrets/pkg/metrics"
|
"github.com/external-secrets/external-secrets/pkg/metrics"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
errGitlabCredSecretName = "credentials are empty"
|
errGitlabCredSecretName = "credentials are empty"
|
||||||
errInvalidClusterStoreMissingSAKNamespace = "invalid clusterStore missing SAK namespace"
|
errInvalidClusterStoreMissingSAKNamespace = "invalid clusterStore missing SAK namespace"
|
||||||
errFetchSAKSecret = "couldn't find secret on cluster: %w"
|
errFetchSAKSecret = "couldn't find secret on cluster: %w"
|
||||||
errMissingSAK = "missing credentials while setting auth"
|
|
||||||
errList = "could not verify whether the gilabClient is valid: %w"
|
errList = "could not verify whether the gilabClient is valid: %w"
|
||||||
errProjectAuth = "gitlabClient is not allowed to get secrets for project id [%s]"
|
errProjectAuth = "gitlabClient is not allowed to get secrets for project id [%s]"
|
||||||
errGroupAuth = "gitlabClient is not allowed to get secrets for group id [%s]"
|
errGroupAuth = "gitlabClient is not allowed to get secrets for group id [%s]"
|
||||||
|
@ -78,34 +77,13 @@ func (a ProjectGroupPathSorter) Less(i, j int) bool { return len(a[i].FullPath)
|
||||||
var log = ctrl.Log.WithName("provider").WithName("gitlab")
|
var log = ctrl.Log.WithName("provider").WithName("gitlab")
|
||||||
|
|
||||||
// Set gitlabBase credentials to Access Token.
|
// Set gitlabBase credentials to Access Token.
|
||||||
func (g *gitlabBase) getAuth(ctx context.Context) ([]byte, error) {
|
func (g *gitlabBase) getAuth(ctx context.Context) (string, error) {
|
||||||
credentialsSecret := &corev1.Secret{}
|
return resolvers.SecretKeyRef(
|
||||||
credentialsSecretName := g.store.Auth.SecretRef.AccessToken.Name
|
ctx,
|
||||||
if credentialsSecretName == "" {
|
g.kube,
|
||||||
return nil, fmt.Errorf(errGitlabCredSecretName)
|
g.storeKind,
|
||||||
}
|
g.namespace,
|
||||||
objectKey := types.NamespacedName{
|
&g.store.Auth.SecretRef.AccessToken)
|
||||||
Name: credentialsSecretName,
|
|
||||||
Namespace: g.namespace,
|
|
||||||
}
|
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
|
||||||
if g.storeKind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if g.store.Auth.SecretRef.AccessToken.Namespace == nil {
|
|
||||||
return nil, fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *g.store.Auth.SecretRef.AccessToken.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
err := g.kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(errFetchSAKSecret, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
credentials := credentialsSecret.Data[g.store.Auth.SecretRef.AccessToken.Key]
|
|
||||||
if len(credentials) == 0 {
|
|
||||||
return nil, fmt.Errorf(errMissingSAK)
|
|
||||||
}
|
|
||||||
return credentials, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gitlabBase) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
|
func (g *gitlabBase) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
|
||||||
|
|
|
@ -46,7 +46,7 @@ const (
|
||||||
groupvalue = "groupvalue"
|
groupvalue = "groupvalue"
|
||||||
groupid = "groupId"
|
groupid = "groupId"
|
||||||
defaultErrorMessage = "[%d] unexpected error: [%s], expected: [%s]"
|
defaultErrorMessage = "[%d] unexpected error: [%s], expected: [%s]"
|
||||||
errMissingCredentials = "credentials are empty"
|
errMissingCredentials = "cannot get Kubernetes secret \"\": secrets \"\" not found"
|
||||||
testKey = "testKey"
|
testKey = "testKey"
|
||||||
findTestPrefix = "test.*"
|
findTestPrefix = "test.*"
|
||||||
)
|
)
|
||||||
|
@ -351,7 +351,7 @@ func TestNewClient(t *testing.T) {
|
||||||
store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Name = authorizedKeySecretName
|
store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Name = authorizedKeySecretName
|
||||||
store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Key = authorizedKeySecretKey
|
store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Key = authorizedKeySecretKey
|
||||||
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
||||||
tassert.EqualError(t, err, "couldn't find secret on cluster: secrets \"authorizedKeySecretName\" not found")
|
tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
|
||||||
tassert.Nil(t, secretClient)
|
tassert.Nil(t, secretClient)
|
||||||
|
|
||||||
err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
|
err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
|
||||||
|
|
|
@ -86,7 +86,7 @@ func (g *gitlabBase) getClient(ctx context.Context, provider *esv1beta1.GitlabPr
|
||||||
// in a similar way to extend functionality of the provider
|
// in a similar way to extend functionality of the provider
|
||||||
|
|
||||||
// Create a new GitLab Client using credentials and options
|
// Create a new GitLab Client using credentials and options
|
||||||
client, err := gitlab.NewClient(string(credentials), opts...)
|
client, err := gitlab.NewClient(credentials, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,13 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/constants"
|
"github.com/external-secrets/external-secrets/pkg/constants"
|
||||||
"github.com/external-secrets/external-secrets/pkg/metrics"
|
"github.com/external-secrets/external-secrets/pkg/metrics"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -51,15 +51,13 @@ const (
|
||||||
payloadConst = "payload"
|
payloadConst = "payload"
|
||||||
smAPIKeyConst = "api_key"
|
smAPIKeyConst = "api_key"
|
||||||
|
|
||||||
errIBMClient = "cannot setup new ibm client: %w"
|
errIBMClient = "cannot setup new ibm client: %w"
|
||||||
errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
|
errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
|
||||||
errUninitalizedIBMProvider = "provider IBM is not initialized"
|
errUninitalizedIBMProvider = "provider IBM is not initialized"
|
||||||
errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
|
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
|
||||||
errMissingSAK = "missing SecretAccessKey"
|
errJSONSecretMarshal = "unable to marshal secret: %w"
|
||||||
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
|
errExtractingSecret = "unable to extract the fetched secret %s of type %s while performing %s"
|
||||||
errJSONSecretMarshal = "unable to marshal secret: %w"
|
|
||||||
errExtractingSecret = "unable to extract the fetched secret %s of type %s while performing %s"
|
|
||||||
|
|
||||||
defaultCacheSize = 100
|
defaultCacheSize = 100
|
||||||
defaultCacheExpiry = 1 * time.Hour
|
defaultCacheExpiry = 1 * time.Hour
|
||||||
|
@ -93,33 +91,11 @@ type client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) setAuth(ctx context.Context) error {
|
func (c *client) setAuth(ctx context.Context) error {
|
||||||
credentialsSecret := &corev1.Secret{}
|
apiKey, err := resolvers.SecretKeyRef(ctx, c.kube, c.storeKind, c.namespace, &c.store.Auth.SecretRef.SecretAPIKey)
|
||||||
credentialsSecretName := c.store.Auth.SecretRef.SecretAPIKey.Name
|
|
||||||
if credentialsSecretName == "" {
|
|
||||||
return fmt.Errorf(errIBMCredSecretName)
|
|
||||||
}
|
|
||||||
objectKey := types.NamespacedName{
|
|
||||||
Name: credentialsSecretName,
|
|
||||||
Namespace: c.namespace,
|
|
||||||
}
|
|
||||||
|
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
|
||||||
if c.storeKind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if c.store.Auth.SecretRef.SecretAPIKey.Namespace == nil {
|
|
||||||
return fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *c.store.Auth.SecretRef.SecretAPIKey.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
err := c.kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(errFetchSAKSecret, err)
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
|
|
||||||
if (c.credentials == nil) || (len(c.credentials) == 0) {
|
|
||||||
return fmt.Errorf(errMissingSAK)
|
|
||||||
}
|
}
|
||||||
|
c.credentials = []byte(apiKey)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,11 @@ import (
|
||||||
|
|
||||||
ksm "github.com/keeper-security/secrets-manager-go/core"
|
ksm "github.com/keeper-security/secrets-manager-go/core"
|
||||||
"github.com/keeper-security/secrets-manager-go/core/logger"
|
"github.com/keeper-security/secrets-manager-go/core/logger"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -66,8 +65,7 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
|
||||||
|
|
||||||
keeperStore := storeSpec.Provider.KeeperSecurity
|
keeperStore := storeSpec.Provider.KeeperSecurity
|
||||||
|
|
||||||
isClusterKind := store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind
|
clientConfig, err := getKeeperSecurityAuth(ctx, keeperStore, kube, store.GetKind(), namespace)
|
||||||
clientConfig, err := getKeeperSecurityAuth(ctx, keeperStore, kube, isClusterKind, namespace)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errKeeperSecurityUnableToCreateConfig, err)
|
return nil, fmt.Errorf(errKeeperSecurityUnableToCreateConfig, err)
|
||||||
}
|
}
|
||||||
|
@ -112,33 +110,11 @@ func (p *Provider) ValidateStore(store esv1beta1.GenericStore) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKeeperSecurityAuth(ctx context.Context, store *esv1beta1.KeeperSecurityProvider, kube kclient.Client, isClusterKind bool, namespace string) (string, error) {
|
func getKeeperSecurityAuth(ctx context.Context, store *esv1beta1.KeeperSecurityProvider, kube kclient.Client, storeKind, namespace string) (string, error) {
|
||||||
auth := store.Auth
|
return resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
credentialsSecret := &v1.Secret{}
|
kube,
|
||||||
credentialsSecretName := auth.Name
|
storeKind,
|
||||||
objectKey := types.NamespacedName{
|
namespace,
|
||||||
Name: credentialsSecretName,
|
&store.Auth)
|
||||||
Namespace: namespace,
|
|
||||||
}
|
|
||||||
|
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
|
||||||
if isClusterKind {
|
|
||||||
if credentialsSecretName != "" && auth.Namespace == nil {
|
|
||||||
return "", fmt.Errorf(errInvalidClusterStoreMissingK8sSecretNamespace)
|
|
||||||
} else if credentialsSecretName != "" {
|
|
||||||
objectKey.Namespace = *auth.Namespace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(errFetchK8sSecret, err)
|
|
||||||
}
|
|
||||||
data := credentialsSecret.Data[auth.Key]
|
|
||||||
if (data == nil) || (len(data) == 0) {
|
|
||||||
return "", fmt.Errorf(errMissingK8sSecretKey, auth.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data), nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -128,31 +129,18 @@ func (c *Client) serviceAccountToken(ctx context.Context, serviceAccountRef *esm
|
||||||
return []byte(tr.Status.Token), nil
|
return []byte(tr.Status.Token), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) fetchSecretKey(ctx context.Context, key esmeta.SecretKeySelector) ([]byte, error) {
|
func (c *Client) fetchSecretKey(ctx context.Context, ref esmeta.SecretKeySelector) ([]byte, error) {
|
||||||
keySecret := &corev1.Secret{}
|
secret, err := resolvers.SecretKeyRef(
|
||||||
objectKey := types.NamespacedName{
|
ctx,
|
||||||
Name: key.Name,
|
c.ctrlClient,
|
||||||
Namespace: c.namespace,
|
c.storeKind,
|
||||||
}
|
c.namespace,
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
&ref,
|
||||||
if c.storeKind == esv1beta1.ClusterSecretStoreKind {
|
)
|
||||||
if key.Namespace == nil {
|
|
||||||
return nil, fmt.Errorf(errInvalidClusterStoreMissingNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *key.Namespace
|
|
||||||
}
|
|
||||||
err := c.ctrlClient.Get(ctx, objectKey, keySecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchCredentials, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
val, ok := keySecret.Data[key.Key]
|
return []byte(secret), nil
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf(errMissingCredentials, key.Key)
|
|
||||||
}
|
|
||||||
if len(val) == 0 {
|
|
||||||
return nil, fmt.Errorf(errEmptyKey, key.Key)
|
|
||||||
}
|
|
||||||
return val, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) fetchConfigMapKey(ctx context.Context, key esmeta.SecretKeySelector) ([]byte, error) {
|
func (c *Client) fetchConfigMapKey(ctx context.Context, key esmeta.SecretKeySelector) ([]byte, error) {
|
||||||
|
|
|
@ -23,12 +23,12 @@ import (
|
||||||
"github.com/1Password/connect-sdk-go/connect"
|
"github.com/1Password/connect-sdk-go/connect"
|
||||||
"github.com/1Password/connect-sdk-go/onepassword"
|
"github.com/1Password/connect-sdk-go/onepassword"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/find"
|
"github.com/external-secrets/external-secrets/pkg/find"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -95,29 +95,18 @@ func (provider *ProviderOnePassword) Capabilities() esv1beta1.SecretStoreCapabil
|
||||||
// NewClient constructs a 1Password Provider.
|
// NewClient constructs a 1Password Provider.
|
||||||
func (provider *ProviderOnePassword) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
|
func (provider *ProviderOnePassword) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
|
||||||
config := store.GetSpec().Provider.OnePassword
|
config := store.GetSpec().Provider.OnePassword
|
||||||
|
token, err := resolvers.SecretKeyRef(
|
||||||
credentialsSecret := &corev1.Secret{}
|
ctx,
|
||||||
objectKey := types.NamespacedName{
|
kube,
|
||||||
Name: config.Auth.SecretRef.ConnectToken.Name,
|
store.GetKind(),
|
||||||
Namespace: namespace,
|
namespace,
|
||||||
}
|
&config.Auth.SecretRef.ConnectToken,
|
||||||
|
)
|
||||||
// only ClusterSecretStore is allowed to set namespace (and then it's required)
|
|
||||||
if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
objectKey.Namespace = *config.Auth.SecretRef.ConnectToken.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
err := kube.Get(ctx, objectKey, credentialsSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchK8sSecret, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
token := credentialsSecret.Data[config.Auth.SecretRef.ConnectToken.Key]
|
provider.client = connect.NewClientWithUserAgent(config.ConnectHost, token, userAgent)
|
||||||
if (token == nil) || (len(token) == 0) {
|
|
||||||
return nil, fmt.Errorf(errMissingToken)
|
|
||||||
}
|
|
||||||
provider.client = connect.NewClientWithUserAgent(config.ConnectHost, string(token), userAgent)
|
|
||||||
provider.vaults = config.Vaults
|
provider.vaults = config.Vaults
|
||||||
|
|
||||||
return provider, nil
|
return provider, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ import (
|
||||||
"github.com/oracle/oci-go-sdk/v65/vault"
|
"github.com/oracle/oci-go-sdk/v65/vault"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
|
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||||
|
@ -40,23 +39,23 @@ import (
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
errOracleClient = "cannot setup new oracle client: %w"
|
errOracleClient = "cannot setup new oracle client: %w"
|
||||||
errORACLECredSecretName = "invalid oracle SecretStore resource: missing oracle APIKey"
|
errORACLECredSecretName = "invalid oracle SecretStore resource: missing oracle APIKey"
|
||||||
errUninitalizedOracleProvider = "provider oracle is not initialized"
|
errUninitalizedOracleProvider = "provider oracle is not initialized"
|
||||||
errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
|
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
errMissingPK = "missing PrivateKey"
|
||||||
errMissingPK = "missing PrivateKey"
|
errMissingUser = "missing User ID"
|
||||||
errMissingUser = "missing User ID"
|
errMissingTenancy = "missing Tenancy ID"
|
||||||
errMissingTenancy = "missing Tenancy ID"
|
errMissingRegion = "missing Region"
|
||||||
errMissingRegion = "missing Region"
|
errMissingFingerprint = "missing Fingerprint"
|
||||||
errMissingFingerprint = "missing Fingerprint"
|
errMissingVault = "missing Vault"
|
||||||
errMissingVault = "missing Vault"
|
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
|
||||||
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
|
errMissingKey = "missing Key in secret: %s"
|
||||||
errMissingKey = "missing Key in secret: %s"
|
errUnexpectedContent = "unexpected secret bundle content"
|
||||||
errUnexpectedContent = "unexpected secret bundle content"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://github.com/external-secrets/external-secrets/issues/644
|
// https://github.com/external-secrets/external-secrets/issues/644
|
||||||
|
@ -398,27 +397,17 @@ func getSecretData(ctx context.Context, kube kclient.Client, namespace, storeKin
|
||||||
if secretRef.Name == "" {
|
if secretRef.Name == "" {
|
||||||
return "", fmt.Errorf(errORACLECredSecretName)
|
return "", fmt.Errorf(errORACLECredSecretName)
|
||||||
}
|
}
|
||||||
|
secret, err := resolvers.SecretKeyRef(
|
||||||
objectKey := types.NamespacedName{
|
ctx,
|
||||||
Name: secretRef.Name,
|
kube,
|
||||||
Namespace: namespace,
|
storeKind,
|
||||||
}
|
namespace,
|
||||||
|
&secretRef,
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
)
|
||||||
if storeKind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if secretRef.Namespace == nil {
|
|
||||||
return "", fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *secretRef.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
secret := corev1.Secret{}
|
|
||||||
err := kube.Get(ctx, objectKey, &secret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(errFetchSAKSecret, err)
|
return "", fmt.Errorf(errFetchSAKSecret, err)
|
||||||
}
|
}
|
||||||
|
return secret, nil
|
||||||
return string(secret.Data[secretRef.Key]), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserAuthConfigurationProvider(ctx context.Context, kube kclient.Client, store *esv1beta1.OracleProvider, namespace, storeKind, region string) (common.ConfigurationProvider, error) {
|
func getUserAuthConfigurationProvider(ctx context.Context, kube kclient.Client, store *esv1beta1.OracleProvider, namespace, storeKind, region string) (common.ConfigurationProvider, error) {
|
||||||
|
|
|
@ -440,7 +440,7 @@ func TestVaultManagementService_NewClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedErr: `could not fetch SecretAccessKey secret: secrets "non-existing-secret"`,
|
expectedErr: `cannot get Kubernetes secret "non-existing-secret": secrets "non-existing-secret" not found`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "invalid retry interval",
|
desc: "invalid retry interval",
|
||||||
|
|
|
@ -21,12 +21,12 @@ import (
|
||||||
smapi "github.com/scaleway/scaleway-sdk-go/api/secret/v1alpha1"
|
smapi "github.com/scaleway/scaleway-sdk-go/api/secret/v1alpha1"
|
||||||
"github.com/scaleway/scaleway-sdk-go/scw"
|
"github.com/scaleway/scaleway-sdk-go/scw"
|
||||||
"github.com/scaleway/scaleway-sdk-go/validation"
|
"github.com/scaleway/scaleway-sdk-go/validation"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -52,12 +52,12 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
|
||||||
return nil, fmt.Errorf("when using a ClusterSecretStore, namespaces must be explicitly set")
|
return nil, fmt.Errorf("when using a ClusterSecretStore, namespaces must be explicitly set")
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey, err := loadConfigSecret(ctx, cfg.AccessKey, kube, namespace)
|
accessKey, err := loadConfigSecret(ctx, cfg.AccessKey, kube, namespace, store.GetKind())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
secretKey, err := loadConfigSecret(ctx, cfg.SecretKey, kube, namespace)
|
secretKey, err := loadConfigSecret(ctx, cfg.SecretKey, kube, namespace, store.GetKind())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -80,42 +80,17 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfigSecret(ctx context.Context, ref *esv1beta1.ScalewayProviderSecretRef, kube kubeClient.Client, defaultNamespace string) (string, error) {
|
func loadConfigSecret(ctx context.Context, ref *esv1beta1.ScalewayProviderSecretRef, kube kubeClient.Client, defaultNamespace, storeKind string) (string, error) {
|
||||||
if ref.SecretRef == nil {
|
if ref.SecretRef == nil {
|
||||||
return ref.Value, nil
|
return ref.Value, nil
|
||||||
}
|
}
|
||||||
|
return resolvers.SecretKeyRef(
|
||||||
namespace := defaultNamespace
|
ctx,
|
||||||
if ref.SecretRef.Namespace != nil {
|
kube,
|
||||||
namespace = *ref.SecretRef.Namespace
|
storeKind,
|
||||||
}
|
defaultNamespace,
|
||||||
|
ref.SecretRef,
|
||||||
if ref.SecretRef.Name == "" {
|
)
|
||||||
return "", fmt.Errorf("must specify a value or a reference to a secret")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ref.SecretRef.Key == "" {
|
|
||||||
return "", fmt.Errorf("must specify a secret key")
|
|
||||||
}
|
|
||||||
|
|
||||||
objKey := kubeClient.ObjectKey{
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: ref.SecretRef.Name,
|
|
||||||
}
|
|
||||||
|
|
||||||
secret := corev1.Secret{}
|
|
||||||
|
|
||||||
err := kube.Get(ctx, objKey, &secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
value, ok := secret.Data[ref.SecretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("no such key in secret: %v", ref.SecretRef.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(value), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.ScalewayProviderSecretRef) error {
|
func validateSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.ScalewayProviderSecretRef) error {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ISOInterface interface {
|
type ISOInterface interface {
|
||||||
|
@ -76,12 +77,18 @@ func Authenticate(ctx context.Context, store esv1beta1.GenericStore, provider *e
|
||||||
IsoSessionFromSecretRef initialize an ISO OAuth2 flow with .spec.provider.senhasegura.auth.isoSecretRef parameters.
|
IsoSessionFromSecretRef initialize an ISO OAuth2 flow with .spec.provider.senhasegura.auth.isoSecretRef parameters.
|
||||||
*/
|
*/
|
||||||
func (s *SenhaseguraIsoSession) IsoSessionFromSecretRef(ctx context.Context, provider *esv1beta1.SenhaseguraProvider, store esv1beta1.GenericStore, kube client.Client, namespace string) (*SenhaseguraIsoSession, error) {
|
func (s *SenhaseguraIsoSession) IsoSessionFromSecretRef(ctx context.Context, provider *esv1beta1.SenhaseguraProvider, store esv1beta1.GenericStore, kube client.Client, namespace string) (*SenhaseguraIsoSession, error) {
|
||||||
clientSecret, err := getKubernetesSecret(ctx, provider.Auth.ClientSecret, store, kube, namespace)
|
secret, err := resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
kube,
|
||||||
|
store.GetKind(),
|
||||||
|
namespace,
|
||||||
|
&provider.Auth.ClientSecret,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &SenhaseguraIsoSession{}, err
|
return &SenhaseguraIsoSession{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
isoToken, err := s.GetIsoToken(provider.Auth.ClientID, clientSecret, provider.URL, provider.IgnoreSslCertificate)
|
isoToken, err := s.GetIsoToken(provider.Auth.ClientID, secret, provider.URL, provider.IgnoreSslCertificate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &SenhaseguraIsoSession{}, err
|
return &SenhaseguraIsoSession{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
errRequiredNamespaceNotFound = "invalid ClusterSecretStore: missing namespace in %s"
|
|
||||||
errCannotFetchKubernetesSecret = "could not fetch Kubernetes secret %s"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
getKubernetesSecret get Kubernetes Secret based on object parameter in namespace where ESO is installed or another, if ClusterSecretStore is used.
|
|
||||||
*/
|
|
||||||
func getKubernetesSecret(ctx context.Context, object esmeta.SecretKeySelector, store esv1beta1.GenericStore, kube client.Client, namespace string) (string, error) {
|
|
||||||
ke := client.ObjectKey{
|
|
||||||
Name: object.Name,
|
|
||||||
Namespace: namespace, // Default to ExternalSecret namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only ClusterStore is allowed to set namespace (and then it's required)
|
|
||||||
if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
|
||||||
if object.Namespace == nil {
|
|
||||||
return "", fmt.Errorf(errRequiredNamespaceNotFound, object.Key)
|
|
||||||
}
|
|
||||||
ke.Namespace = *object.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
secret := v1.Secret{}
|
|
||||||
err := kube.Get(ctx, ke, &secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(errCannotFetchKubernetesSecret, object.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(secret.Data[object.Key]), nil
|
|
||||||
}
|
|
|
@ -41,6 +41,7 @@ import (
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
|
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -54,14 +55,6 @@ const (
|
||||||
|
|
||||||
STSEndpointEnv = "AWS_STS_ENDPOINT"
|
STSEndpointEnv = "AWS_STS_ENDPOINT"
|
||||||
AWSWebIdentityTokenFileEnvVar = "AWS_WEB_IDENTITY_TOKEN_FILE"
|
AWSWebIdentityTokenFileEnvVar = "AWS_WEB_IDENTITY_TOKEN_FILE"
|
||||||
|
|
||||||
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
|
|
||||||
errInvalidClusterStoreMissingSAKNamespace = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
|
|
||||||
errFetchAKIDSecret = "could not fetch accessKeyID secret: %w"
|
|
||||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
|
||||||
errFetchSTSecret = "could not fetch SessionToken secret: %w"
|
|
||||||
errMissingSAK = "missing SecretAccessKey"
|
|
||||||
errMissingAKID = "missing AccessKeyID"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultJWTProvider returns a credentials.Provider that calls the AssumeRoleWithWebidentity
|
// DefaultJWTProvider returns a credentials.Provider that calls the AssumeRoleWithWebidentity
|
||||||
|
@ -232,58 +225,37 @@ func CredsFromControllerServiceAccount(ctx context.Context, saname, ns, region s
|
||||||
// construct a aws.Credentials object
|
// construct a aws.Credentials object
|
||||||
// The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
|
// The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
|
||||||
// If the ClusterSecretStore defines a namespace it will take precedence.
|
// If the ClusterSecretStore defines a namespace it will take precedence.
|
||||||
func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, isClusterKind bool, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
|
func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, storeKind string, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
|
||||||
ke := kclient.ObjectKey{
|
akid, err := resolvers.SecretKeyRef(
|
||||||
Name: auth.SecretRef.AccessKeyID.Name,
|
ctx,
|
||||||
Namespace: namespace,
|
kube,
|
||||||
}
|
storeKind,
|
||||||
if isClusterKind && auth.SecretRef.AccessKeyID.Namespace != nil {
|
namespace,
|
||||||
ke.Namespace = *auth.SecretRef.AccessKeyID.Namespace
|
&auth.SecretRef.AccessKeyID,
|
||||||
}
|
)
|
||||||
akSecret := v1.Secret{}
|
|
||||||
err := kube.Get(ctx, ke, &akSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchAKIDSecret, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
ke = kclient.ObjectKey{
|
sak, err := resolvers.SecretKeyRef(
|
||||||
Name: auth.SecretRef.SecretAccessKey.Name,
|
ctx,
|
||||||
Namespace: namespace,
|
kube,
|
||||||
}
|
storeKind,
|
||||||
if isClusterKind && auth.SecretRef.SecretAccessKey.Namespace != nil {
|
namespace,
|
||||||
ke.Namespace = *auth.SecretRef.SecretAccessKey.Namespace
|
&auth.SecretRef.SecretAccessKey,
|
||||||
}
|
)
|
||||||
sakSecret := v1.Secret{}
|
|
||||||
err = kube.Get(ctx, ke, &sakSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errFetchSAKSecret, err)
|
return nil, err
|
||||||
}
|
|
||||||
sak := string(sakSecret.Data[auth.SecretRef.SecretAccessKey.Key])
|
|
||||||
aks := string(akSecret.Data[auth.SecretRef.AccessKeyID.Key])
|
|
||||||
if sak == "" {
|
|
||||||
return nil, fmt.Errorf(errMissingSAK)
|
|
||||||
}
|
|
||||||
if aks == "" {
|
|
||||||
return nil, fmt.Errorf(errMissingAKID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionToken string
|
// session token is optional
|
||||||
if auth.SecretRef.SessionToken != nil {
|
sessionToken, _ := resolvers.SecretKeyRef(
|
||||||
ke = kclient.ObjectKey{
|
ctx,
|
||||||
Name: auth.SecretRef.SessionToken.Name,
|
kube,
|
||||||
Namespace: namespace,
|
storeKind,
|
||||||
}
|
namespace,
|
||||||
if isClusterKind && auth.SecretRef.SessionToken.Namespace != nil {
|
auth.SecretRef.SessionToken,
|
||||||
ke.Namespace = *auth.SecretRef.SessionToken.Namespace
|
)
|
||||||
}
|
return credentials.NewStaticCredentials(akid, sak, sessionToken), err
|
||||||
stSecret := v1.Secret{}
|
|
||||||
err = kube.Get(ctx, ke, &stSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(errFetchSTSecret, err)
|
|
||||||
}
|
|
||||||
sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
|
|
||||||
}
|
|
||||||
|
|
||||||
return credentials.NewStaticCredentials(aks, sak, sessionToken), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type STSProvider func(*session.Session) stsiface.STSAPI
|
type STSProvider func(*session.Session) stsiface.STSAPI
|
||||||
|
|
|
@ -40,7 +40,7 @@ import (
|
||||||
authuserpass "github.com/hashicorp/vault/api/auth/userpass"
|
authuserpass "github.com/hashicorp/vault/api/auth/userpass"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
authenticationv1 "k8s.io/api/authentication/v1"
|
authv1 "k8s.io/api/authentication/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
@ -60,6 +60,7 @@ import (
|
||||||
vaultiamauth "github.com/external-secrets/external-secrets/pkg/provider/vault/iamauth"
|
vaultiamauth "github.com/external-secrets/external-secrets/pkg/provider/vault/iamauth"
|
||||||
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
|
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -1088,7 +1089,7 @@ func (v *client) configureClientTLS(ctx context.Context, cfg *vault.Config) erro
|
||||||
if clientTLS.KeySecretRef.Key == "" {
|
if clientTLS.KeySecretRef.Key == "" {
|
||||||
clientTLS.KeySecretRef.Key = corev1.TLSPrivateKeyKey
|
clientTLS.KeySecretRef.Key = corev1.TLSPrivateKeyKey
|
||||||
}
|
}
|
||||||
clientKey, err := v.secretKeyRef(ctx, clientTLS.KeySecretRef)
|
clientKey, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, clientTLS.KeySecretRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1096,7 +1097,7 @@ func (v *client) configureClientTLS(ctx context.Context, cfg *vault.Config) erro
|
||||||
if clientTLS.CertSecretRef.Key == "" {
|
if clientTLS.CertSecretRef.Key == "" {
|
||||||
clientTLS.CertSecretRef.Key = corev1.TLSCertKey
|
clientTLS.CertSecretRef.Key = corev1.TLSCertKey
|
||||||
}
|
}
|
||||||
clientCert, err := v.secretKeyRef(ctx, clientTLS.CertSecretRef)
|
clientCert, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, clientTLS.CertSecretRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1125,7 +1126,7 @@ func getCertFromSecret(v *client) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res, err := v.secretKeyRef(ctx, &secretRef)
|
res, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &secretRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(errVaultCert, err)
|
return nil, fmt.Errorf(errVaultCert, err)
|
||||||
}
|
}
|
||||||
|
@ -1226,7 +1227,7 @@ func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
|
||||||
func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
|
func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
|
||||||
tokenRef := v.store.Auth.TokenSecretRef
|
tokenRef := v.store.Auth.TokenSecretRef
|
||||||
if tokenRef != nil {
|
if tokenRef != nil {
|
||||||
token, err := v.secretKeyRef(ctx, tokenRef)
|
token, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, tokenRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
@ -1339,71 +1340,19 @@ func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccou
|
||||||
return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
|
return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
|
||||||
}
|
}
|
||||||
for _, tokenRef := range serviceAccount.Secrets {
|
for _, tokenRef := range serviceAccount.Secrets {
|
||||||
retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
|
token, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &esmeta.SecretKeySelector{
|
||||||
Name: tokenRef.Name,
|
Name: tokenRef.Name,
|
||||||
Namespace: &ref.Namespace,
|
Namespace: &ref.Namespace,
|
||||||
Key: "token",
|
Key: "token",
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
return token, nil
|
||||||
return retval, nil
|
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
|
return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
|
|
||||||
secret := &corev1.Secret{}
|
|
||||||
ref := types.NamespacedName{
|
|
||||||
Namespace: v.namespace,
|
|
||||||
Name: secretRef.Name,
|
|
||||||
}
|
|
||||||
if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
|
||||||
(secretRef.Namespace != nil) {
|
|
||||||
ref.Namespace = *secretRef.Namespace
|
|
||||||
}
|
|
||||||
err := v.kube.Get(ctx, ref, secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(errGetKubeSecret, ref.Name, ref.Namespace, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBytes, ok := secret.Data[secretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
value := string(keyBytes)
|
|
||||||
valueStr := strings.TrimSpace(value)
|
|
||||||
return valueStr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
|
|
||||||
audiences := serviceAccountRef.Audiences
|
|
||||||
if len(additionalAud) > 0 {
|
|
||||||
audiences = append(audiences, additionalAud...)
|
|
||||||
}
|
|
||||||
tokenRequest := &authenticationv1.TokenRequest{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Namespace: v.namespace,
|
|
||||||
},
|
|
||||||
Spec: authenticationv1.TokenRequestSpec{
|
|
||||||
Audiences: audiences,
|
|
||||||
ExpirationSeconds: &expirationSeconds,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
|
||||||
(serviceAccountRef.Namespace != nil) {
|
|
||||||
tokenRequest.Namespace = *serviceAccountRef.Namespace
|
|
||||||
}
|
|
||||||
tokenResponse, err := v.corev1.ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
|
|
||||||
}
|
|
||||||
return tokenResponse.Status.Token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkToken does a lookup and checks if the provided token exists.
|
// checkToken does a lookup and checks if the provided token exists.
|
||||||
func checkToken(ctx context.Context, token util.Token) (bool, error) {
|
func checkToken(ctx context.Context, token util.Token) (bool, error) {
|
||||||
// https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
|
// https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
|
||||||
|
@ -1447,7 +1396,7 @@ func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1be
|
||||||
if appRole.RoleID != "" { // use roleId from CRD, if configured
|
if appRole.RoleID != "" { // use roleId from CRD, if configured
|
||||||
roleID = strings.TrimSpace(appRole.RoleID)
|
roleID = strings.TrimSpace(appRole.RoleID)
|
||||||
} else if appRole.RoleRef != nil { // use RoleID from Secret, if configured
|
} else if appRole.RoleRef != nil { // use RoleID from Secret, if configured
|
||||||
roleID, err = v.secretKeyRef(ctx, appRole.RoleRef)
|
roleID, err = resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, appRole.RoleRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1455,7 +1404,7 @@ func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1be
|
||||||
return fmt.Errorf(errInvalidAppRoleID)
|
return fmt.Errorf(errInvalidAppRoleID)
|
||||||
}
|
}
|
||||||
|
|
||||||
secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
|
secretID, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &appRole.SecretRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1503,7 +1452,14 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
|
||||||
// Kubernetes >=v1.24: fetch token via TokenRequest API
|
// Kubernetes >=v1.24: fetch token via TokenRequest API
|
||||||
// note: this is a massive change from vault perspective: the `iss` claim will very likely change.
|
// note: this is a massive change from vault perspective: the `iss` claim will very likely change.
|
||||||
// Vault 1.9 deprecated issuer validation by default, and authentication with Vault clusters <1.9 will likely fail.
|
// Vault 1.9 deprecated issuer validation by default, and authentication with Vault clusters <1.9 will likely fail.
|
||||||
jwt, err = v.serviceAccountToken(ctx, *kubernetesAuth.ServiceAccountRef, nil, 600)
|
jwt, err = createServiceAccountToken(
|
||||||
|
ctx,
|
||||||
|
v.corev1,
|
||||||
|
v.storeKind,
|
||||||
|
v.namespace,
|
||||||
|
*kubernetesAuth.ServiceAccountRef,
|
||||||
|
nil,
|
||||||
|
600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -1514,7 +1470,7 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
|
||||||
tokenRef = kubernetesAuth.SecretRef.DeepCopy()
|
tokenRef = kubernetesAuth.SecretRef.DeepCopy()
|
||||||
tokenRef.Key = "token"
|
tokenRef.Key = "token"
|
||||||
}
|
}
|
||||||
jwt, err := v.secretKeyRef(ctx, tokenRef)
|
jwt, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, tokenRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -1536,8 +1492,7 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
|
||||||
|
|
||||||
func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
|
func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
|
||||||
username := strings.TrimSpace(ldapAuth.Username)
|
username := strings.TrimSpace(ldapAuth.Username)
|
||||||
|
password, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &ldapAuth.SecretRef)
|
||||||
password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1556,8 +1511,7 @@ func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1bet
|
||||||
|
|
||||||
func (v *client) requestTokenWithUserPassAuth(ctx context.Context, userPassAuth *esv1beta1.VaultUserPassAuth) error {
|
func (v *client) requestTokenWithUserPassAuth(ctx context.Context, userPassAuth *esv1beta1.VaultUserPassAuth) error {
|
||||||
username := strings.TrimSpace(userPassAuth.Username)
|
username := strings.TrimSpace(userPassAuth.Username)
|
||||||
|
password, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &userPassAuth.SecretRef)
|
||||||
password, err := v.secretKeyRef(ctx, &userPassAuth.SecretRef)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1579,7 +1533,7 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
|
||||||
var jwt string
|
var jwt string
|
||||||
var err error
|
var err error
|
||||||
if jwtAuth.SecretRef != nil {
|
if jwtAuth.SecretRef != nil {
|
||||||
jwt, err = v.secretKeyRef(ctx, jwtAuth.SecretRef)
|
jwt, err = resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, jwtAuth.SecretRef)
|
||||||
} else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
|
} else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
|
||||||
audiences := k8sServiceAccountToken.Audiences
|
audiences := k8sServiceAccountToken.Audiences
|
||||||
if audiences == nil {
|
if audiences == nil {
|
||||||
|
@ -1590,7 +1544,14 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
|
||||||
tmp := int64(600)
|
tmp := int64(600)
|
||||||
expirationSeconds = &tmp
|
expirationSeconds = &tmp
|
||||||
}
|
}
|
||||||
jwt, err = v.serviceAccountToken(ctx, k8sServiceAccountToken.ServiceAccountRef, *audiences, *expirationSeconds)
|
jwt, err = createServiceAccountToken(
|
||||||
|
ctx,
|
||||||
|
v.corev1,
|
||||||
|
v.storeKind,
|
||||||
|
v.namespace,
|
||||||
|
k8sServiceAccountToken.ServiceAccountRef,
|
||||||
|
*audiences,
|
||||||
|
*expirationSeconds)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf(errJwtNoTokenSource)
|
err = fmt.Errorf(errJwtNoTokenSource)
|
||||||
}
|
}
|
||||||
|
@ -1618,12 +1579,12 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
|
func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
|
||||||
clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
|
clientKey, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &certAuth.SecretRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
|
clientCert, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &certAuth.ClientCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1651,7 +1612,40 @@ func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1bet
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1.VaultIamAuth, ick bool, k kclient.Client, n string, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) error {
|
func createServiceAccountToken(
|
||||||
|
ctx context.Context,
|
||||||
|
corev1Client typedcorev1.CoreV1Interface,
|
||||||
|
storeKind string,
|
||||||
|
namespace string,
|
||||||
|
serviceAccountRef esmeta.ServiceAccountSelector,
|
||||||
|
additionalAud []string,
|
||||||
|
expirationSeconds int64) (string, error) {
|
||||||
|
audiences := serviceAccountRef.Audiences
|
||||||
|
if len(additionalAud) > 0 {
|
||||||
|
audiences = append(audiences, additionalAud...)
|
||||||
|
}
|
||||||
|
tokenRequest := &authv1.TokenRequest{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Spec: authv1.TokenRequestSpec{
|
||||||
|
Audiences: audiences,
|
||||||
|
ExpirationSeconds: &expirationSeconds,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
||||||
|
(serviceAccountRef.Namespace != nil) {
|
||||||
|
tokenRequest.Namespace = *serviceAccountRef.Namespace
|
||||||
|
}
|
||||||
|
tokenResponse, err := corev1Client.ServiceAccounts(tokenRequest.Namespace).
|
||||||
|
CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
|
||||||
|
}
|
||||||
|
return tokenResponse.Status.Token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1.VaultIamAuth, isClusterKind bool, k kclient.Client, n string, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) error {
|
||||||
jwtAuth := iamAuth.JWTAuth
|
jwtAuth := iamAuth.JWTAuth
|
||||||
secretRefAuth := iamAuth.SecretRef
|
secretRefAuth := iamAuth.SecretRef
|
||||||
regionAWS := defaultAWSRegion
|
regionAWS := defaultAWSRegion
|
||||||
|
@ -1665,13 +1659,13 @@ func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1
|
||||||
var creds *credentials.Credentials
|
var creds *credentials.Credentials
|
||||||
var err error
|
var err error
|
||||||
if jwtAuth != nil { // use credentials from a sa explicitly defined and referenced. Highest preference is given to this method/configuration.
|
if jwtAuth != nil { // use credentials from a sa explicitly defined and referenced. Highest preference is given to this method/configuration.
|
||||||
creds, err = vaultiamauth.CredsFromServiceAccount(ctx, *iamAuth, regionAWS, ick, k, n, jwtProvider)
|
creds, err = vaultiamauth.CredsFromServiceAccount(ctx, *iamAuth, regionAWS, isClusterKind, k, n, jwtProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if secretRefAuth != nil { // if jwtAuth is not defined, check if secretRef is defined. Second preference.
|
} else if secretRefAuth != nil { // if jwtAuth is not defined, check if secretRef is defined. Second preference.
|
||||||
logger.V(1).Info("using credentials from secretRef")
|
logger.V(1).Info("using credentials from secretRef")
|
||||||
creds, err = vaultiamauth.CredsFromSecretRef(ctx, *iamAuth, ick, k, n)
|
creds, err = vaultiamauth.CredsFromSecretRef(ctx, *iamAuth, v.storeKind, k, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -332,7 +332,7 @@ MIIFkTCCA3mgAwIBAgIUBEUg3m/WqAsWHG4Q/II3IePFfuowDQYJKoZIhvcNAQELBQAwWDELMAkGA1UE
|
||||||
kube: clientfake.NewClientBuilder().Build(),
|
kube: clientfake.NewClientBuilder().Build(),
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
err: fmt.Errorf(errGetKubeSecret, "vault-secret", "default", errors.New("secrets \"vault-secret\" not found")),
|
err: fmt.Errorf(`cannot get Kubernetes secret "vault-secret": %w`, errors.New(`secrets "vault-secret" not found`)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"SuccessfulVaultStoreWithCertAuth": {
|
"SuccessfulVaultStoreWithCertAuth": {
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
tpl "text/template"
|
tpl "text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -39,6 +38,7 @@ import (
|
||||||
"github.com/external-secrets/external-secrets/pkg/metrics"
|
"github.com/external-secrets/external-secrets/pkg/metrics"
|
||||||
"github.com/external-secrets/external-secrets/pkg/template/v2"
|
"github.com/external-secrets/external-secrets/pkg/template/v2"
|
||||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://github.com/external-secrets/external-secrets/issues/644
|
// https://github.com/external-secrets/external-secrets/issues/644
|
||||||
|
@ -383,8 +383,9 @@ func (w *WebHook) getCACertPool(provider *esv1beta1.WebhookProvider) (*x509.Cert
|
||||||
|
|
||||||
func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte, error) {
|
func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte, error) {
|
||||||
secretRef := esmeta.SecretKeySelector{
|
secretRef := esmeta.SecretKeySelector{
|
||||||
Name: provider.CAProvider.Name,
|
Name: provider.CAProvider.Name,
|
||||||
Key: provider.CAProvider.Key,
|
Namespace: &w.namespace,
|
||||||
|
Key: provider.CAProvider.Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.CAProvider.Namespace != nil {
|
if provider.CAProvider.Namespace != nil {
|
||||||
|
@ -392,37 +393,18 @@ func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res, err := w.secretKeyRef(ctx, &secretRef)
|
cert, err := resolvers.SecretKeyRef(
|
||||||
|
ctx,
|
||||||
|
w.kube,
|
||||||
|
w.storeKind,
|
||||||
|
w.namespace,
|
||||||
|
&secretRef,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte(res), nil
|
return []byte(cert), nil
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WebHook) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
|
|
||||||
secret := &corev1.Secret{}
|
|
||||||
ref := client.ObjectKey{
|
|
||||||
Namespace: w.namespace,
|
|
||||||
Name: secretRef.Name,
|
|
||||||
}
|
|
||||||
if (w.storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
|
||||||
(secretRef.Namespace != nil) {
|
|
||||||
ref.Namespace = *secretRef.Namespace
|
|
||||||
}
|
|
||||||
err := w.kube.Get(ctx, ref, secret)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBytes, ok := secret.Data[secretRef.Key]
|
|
||||||
if !ok {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
value := string(keyBytes)
|
|
||||||
valueStr := strings.TrimSpace(value)
|
|
||||||
return valueStr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebHook) getCertFromConfigMap(provider *esv1beta1.WebhookProvider) ([]byte, error) {
|
func (w *WebHook) getCertFromConfigMap(provider *esv1beta1.WebhookProvider) ([]byte, error) {
|
||||||
|
|
|
@ -80,7 +80,7 @@ func TestNewClient(t *testing.T) {
|
||||||
store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Name = authorizedKeySecretName
|
store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Name = authorizedKeySecretName
|
||||||
store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Key = authorizedKeySecretKey
|
store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Key = authorizedKeySecretKey
|
||||||
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
||||||
tassert.EqualError(t, err, "could not fetch AuthorizedKey secret: secrets \"authorizedKeySecretName\" not found")
|
tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
|
||||||
tassert.Nil(t, secretClient)
|
tassert.Nil(t, secretClient)
|
||||||
|
|
||||||
err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
|
err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
|
||||||
|
@ -95,7 +95,7 @@ func TestNewClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
||||||
tassert.EqualError(t, err, "could not fetch CA certificate secret: secrets \"caCertificateSecretName\" not found")
|
tassert.EqualError(t, err, "cannot get Kubernetes secret \"caCertificateSecretName\": secrets \"caCertificateSecretName\" not found")
|
||||||
tassert.Nil(t, secretClient)
|
tassert.Nil(t, secretClient)
|
||||||
|
|
||||||
err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))
|
err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))
|
||||||
|
|
|
@ -24,13 +24,12 @@ import (
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"github.com/yandex-cloud/go-sdk/iamkey"
|
"github.com/yandex-cloud/go-sdk/iamkey"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
clock2 "github.com/external-secrets/external-secrets/pkg/provider/yandex/common/clock"
|
clock2 "github.com/external-secrets/external-secrets/pkg/provider/yandex/common/clock"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxSecretsClientLifetime = 5 * time.Minute // supposed SecretsClient lifetime is quite short
|
const maxSecretsClientLifetime = 5 * time.Minute // supposed SecretsClient lifetime is quite short
|
||||||
|
@ -115,61 +114,36 @@ func (p *YandexCloudProvider) NewClient(ctx context.Context, store esv1beta1.Gen
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
objectKey := types.NamespacedName{
|
key, err := resolvers.SecretKeyRef(
|
||||||
Name: input.AuthorizedKey.Name,
|
ctx,
|
||||||
Namespace: namespace,
|
kube,
|
||||||
}
|
store.GetKind(),
|
||||||
|
namespace,
|
||||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
&input.AuthorizedKey,
|
||||||
if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
)
|
||||||
if input.AuthorizedKey.Namespace == nil {
|
|
||||||
return nil, fmt.Errorf("invalid ClusterSecretStore: missing AuthorizedKey Namespace")
|
|
||||||
}
|
|
||||||
objectKey.Namespace = *input.AuthorizedKey.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
authorizedKeySecret := &corev1.Secret{}
|
|
||||||
err = kube.Get(ctx, objectKey, authorizedKeySecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not fetch AuthorizedKey secret: %w", err)
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
authorizedKeySecretData := authorizedKeySecret.Data[input.AuthorizedKey.Key]
|
|
||||||
if (authorizedKeySecretData == nil) || (len(authorizedKeySecretData) == 0) {
|
|
||||||
return nil, fmt.Errorf("missing AuthorizedKey")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var authorizedKey iamkey.Key
|
var authorizedKey iamkey.Key
|
||||||
err = json.Unmarshal(authorizedKeySecretData, &authorizedKey)
|
err = json.Unmarshal([]byte(key), &authorizedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to unmarshal authorized key: %w", err)
|
return nil, fmt.Errorf("unable to unmarshal authorized key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var caCertificateData []byte
|
var caCertificateData []byte
|
||||||
|
|
||||||
if input.CACertificate != nil {
|
if input.CACertificate != nil {
|
||||||
certObjectKey := types.NamespacedName{
|
caCert, err := resolvers.SecretKeyRef(
|
||||||
Name: input.CACertificate.Name,
|
ctx,
|
||||||
Namespace: namespace,
|
kube,
|
||||||
}
|
store.GetKind(),
|
||||||
|
namespace,
|
||||||
if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
input.CACertificate,
|
||||||
if input.CACertificate.Namespace == nil {
|
)
|
||||||
return nil, fmt.Errorf("invalid ClusterSecretStore: missing CA certificate Namespace")
|
|
||||||
}
|
|
||||||
certObjectKey.Namespace = *input.CACertificate.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
caCertificateSecret := &corev1.Secret{}
|
|
||||||
err := kube.Get(ctx, certObjectKey, caCertificateSecret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not fetch CA certificate secret: %w", err)
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
caCertificateData = caCertificateSecret.Data[input.CACertificate.Key]
|
|
||||||
if (caCertificateData == nil) || (len(caCertificateData) == 0) {
|
|
||||||
return nil, fmt.Errorf("missing CA Certificate")
|
|
||||||
}
|
}
|
||||||
|
caCertificateData = []byte(caCert)
|
||||||
}
|
}
|
||||||
|
|
||||||
secretGetter, err := p.getOrCreateSecretGetter(ctx, input.APIEndpoint, &authorizedKey, caCertificateData)
|
secretGetter, err := p.getOrCreateSecretGetter(ctx, input.APIEndpoint, &authorizedKey, caCertificateData)
|
||||||
|
|
|
@ -80,7 +80,7 @@ func TestNewClient(t *testing.T) {
|
||||||
store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Name = authorizedKeySecretName
|
store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Name = authorizedKeySecretName
|
||||||
store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Key = authorizedKeySecretKey
|
store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Key = authorizedKeySecretKey
|
||||||
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
||||||
tassert.EqualError(t, err, "could not fetch AuthorizedKey secret: secrets \"authorizedKeySecretName\" not found")
|
tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
|
||||||
tassert.Nil(t, secretClient)
|
tassert.Nil(t, secretClient)
|
||||||
|
|
||||||
err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
|
err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
|
||||||
|
@ -95,7 +95,7 @@ func TestNewClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
|
||||||
tassert.EqualError(t, err, "could not fetch CA certificate secret: secrets \"caCertificateSecretName\" not found")
|
tassert.EqualError(t, err, "cannot get Kubernetes secret \"caCertificateSecretName\": secrets \"caCertificateSecretName\" not found")
|
||||||
tassert.Nil(t, secretClient)
|
tassert.Nil(t, secretClient)
|
||||||
|
|
||||||
err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))
|
err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))
|
||||||
|
|
71
pkg/utils/resolvers/secret_ref.go
Normal file
71
pkg/utils/resolvers/secret_ref.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// This is used to determine if a store is cluster-scoped or not.
|
||||||
|
// The EmptyStoreKind is not cluster-scoped, hence resources
|
||||||
|
// cannot be resolved across namespaces.
|
||||||
|
// TODO: when we implement cluster-scoped generators
|
||||||
|
// we can remove this and replace it with a interface.
|
||||||
|
EmptyStoreKind = "EmptyStoreKind"
|
||||||
|
|
||||||
|
errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
|
||||||
|
errSecretKeyFmt = "cannot find secret data for key: %q"
|
||||||
|
errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecretKeyRef resolves a metav1.SecretKeySelector and returns the value of the secret it points to.
|
||||||
|
// A user must pass the namespace of the originating ExternalSecret, as this may differ
|
||||||
|
// from the namespace defined in the SecretKeySelector.
|
||||||
|
// This func ensures that only a ClusterSecretStore is able to request secrets across namespaces.
|
||||||
|
func SecretKeyRef(
|
||||||
|
ctx context.Context,
|
||||||
|
c client.Client,
|
||||||
|
storeKind string,
|
||||||
|
esNamespace string,
|
||||||
|
ref *esmeta.SecretKeySelector) (string, error) {
|
||||||
|
key := types.NamespacedName{
|
||||||
|
Namespace: esNamespace,
|
||||||
|
Name: ref.Name,
|
||||||
|
}
|
||||||
|
if (storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
||||||
|
(ref.Namespace != nil) {
|
||||||
|
key.Namespace = *ref.Namespace
|
||||||
|
}
|
||||||
|
secret := &corev1.Secret{}
|
||||||
|
err := c.Get(ctx, key, secret)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
|
||||||
|
}
|
||||||
|
val, ok := secret.Data[ref.Key]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf(errSecretKeyFmt, ref.Key)
|
||||||
|
}
|
||||||
|
return string(val), nil
|
||||||
|
}
|
129
pkg/utils/resolvers/secret_ref_test.go
Normal file
129
pkg/utils/resolvers/secret_ref_test.go
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||||
|
|
||||||
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolveSecretKeyRef(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
c := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||||
|
testNamespace := "test-namespace"
|
||||||
|
testSecret := "test-secret"
|
||||||
|
testKey := "test-key"
|
||||||
|
testValue := "test-value"
|
||||||
|
secret := &corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Name: testSecret,
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
testKey: []byte(testValue),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := c.Create(ctx, secret)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
namespace string
|
||||||
|
storeKind string
|
||||||
|
selector *esmeta.SecretKeySelector
|
||||||
|
expected string
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "namespaced secret store can access secret in same namespace",
|
||||||
|
namespace: testNamespace,
|
||||||
|
storeKind: "SecretStore",
|
||||||
|
selector: &esmeta.SecretKeySelector{
|
||||||
|
Name: testSecret,
|
||||||
|
Namespace: ptr.To(testNamespace),
|
||||||
|
Key: testKey,
|
||||||
|
},
|
||||||
|
expected: testValue,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "omitting namespace in secret store defaults to same namespace",
|
||||||
|
namespace: testNamespace,
|
||||||
|
storeKind: "SecretStore",
|
||||||
|
selector: &esmeta.SecretKeySelector{
|
||||||
|
Name: testSecret,
|
||||||
|
Key: testKey,
|
||||||
|
},
|
||||||
|
expected: testValue,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "namespaced secret store can not access secret in different namespace",
|
||||||
|
namespace: "other-namespace",
|
||||||
|
storeKind: "SecretStore",
|
||||||
|
selector: &esmeta.SecretKeySelector{
|
||||||
|
Name: testSecret,
|
||||||
|
Namespace: ptr.To(testNamespace),
|
||||||
|
Key: testKey,
|
||||||
|
},
|
||||||
|
err: errors.New(`cannot get Kubernetes secret "test-secret": secrets "test-secret" not found`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cluster secret store may access all namespaces",
|
||||||
|
storeKind: "ClusterSecretStore",
|
||||||
|
selector: &esmeta.SecretKeySelector{
|
||||||
|
Name: testSecret,
|
||||||
|
Namespace: ptr.To(testNamespace),
|
||||||
|
Key: testKey,
|
||||||
|
},
|
||||||
|
expected: testValue,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "key not found in secret",
|
||||||
|
namespace: testNamespace,
|
||||||
|
storeKind: "SecretStore",
|
||||||
|
selector: &esmeta.SecretKeySelector{
|
||||||
|
Name: testSecret,
|
||||||
|
Namespace: ptr.To(testNamespace),
|
||||||
|
Key: "xxxxxxxx",
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
err: errors.New(`cannot find secret data for key: "xxxxxxxx"`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
resolvedValue, err := SecretKeyRef(ctx, c, tc.storeKind, tc.namespace, tc.selector)
|
||||||
|
if tc.err != nil {
|
||||||
|
assert.EqualError(t, err, tc.err.Error())
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.expected, resolvedValue)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue