1
0
Fork 0
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:
Moritz Johner 2024-01-21 08:19:57 +01:00 committed by GitHub
parent b6b4f12509
commit 26f9c3f1f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 600 additions and 850 deletions

View file

@ -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"`

View file

@ -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 {

View file

@ -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>

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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),

View file

@ -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

View file

@ -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",

View file

@ -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
} }

View file

@ -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,

View file

@ -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
} }

View file

@ -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)
} }

View file

@ -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),
}, },
} }
} }

View file

@ -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 {

View file

@ -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": {

View file

@ -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
} }

View file

@ -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)
} }

View file

@ -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"

View file

@ -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)
} }

View file

@ -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 {

View file

@ -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()))

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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) {

View file

@ -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
} }

View file

@ -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) {

View file

@ -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",

View file

@ -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 {

View file

@ -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
} }

View file

@ -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
}

View file

@ -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

View file

@ -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
} }

View file

@ -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": {

View file

@ -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) {

View file

@ -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"))

View file

@ -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)

View file

@ -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"))

View 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
}

View 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)
})
}
}