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 {
// +optional
Apikey *ConjurApikey `json:"apikey,omitempty"`
APIKey *ConjurAPIKey `json:"apikey,omitempty"`
// +optional
Jwt *ConjurJWT `json:"jwt,omitempty"`
}
type ConjurApikey struct {
type ConjurAPIKey struct {
Account string `json:"account"`
UserRef *esmeta.SecretKeySelector `json:"userRef"`
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.
func (in *ConjurApikey) DeepCopyInto(out *ConjurApikey) {
func (in *ConjurAPIKey) DeepCopyInto(out *ConjurAPIKey) {
*out = *in
if in.UserRef != nil {
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.
func (in *ConjurApikey) DeepCopy() *ConjurApikey {
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConjurAPIKey.
func (in *ConjurAPIKey) DeepCopy() *ConjurAPIKey {
if in == nil {
return nil
}
out := new(ConjurApikey)
out := new(ConjurAPIKey)
in.DeepCopyInto(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.
func (in *ConjurAuth) DeepCopyInto(out *ConjurAuth) {
*out = *in
if in.Apikey != nil {
in, out := &in.Apikey, &out.Apikey
*out = new(ConjurApikey)
if in.APIKey != nil {
in, out := &in.APIKey, &out.APIKey
*out = new(ConjurAPIKey)
(*in).DeepCopyInto(*out)
}
if in.Jwt != nil {

View file

@ -1691,7 +1691,7 @@ Kubernetes meta/v1.LabelSelector
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1beta1.ConjurApikey">ConjurApikey
<h3 id="external-secrets.io/v1beta1.ConjurAPIKey">ConjurAPIKey
</h3>
<p>
(<em>Appears on:</em>
@ -1763,8 +1763,8 @@ External Secrets meta/v1.SecretKeySelector
<td>
<code>apikey</code></br>
<em>
<a href="#external-secrets.io/v1beta1.ConjurApikey">
ConjurApikey
<a href="#external-secrets.io/v1beta1.ConjurAPIKey">
ConjurAPIKey
</a>
</em>
</td>

View file

@ -27,6 +27,7 @@ import (
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
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/utils/resolvers"
)
type Generator struct{}
@ -65,7 +66,7 @@ func (g *Generator) generate(
ts, err := tokenSource(ctx, esv1beta1.GCPSMAuth{
SecretRef: (*esv1beta1.GCPSMAuthSecretRef)(res.Spec.Auth.SecretRef),
WorkloadIdentity: (*esv1beta1.GCPWorkloadIdentity)(res.Spec.Auth.WorkloadIdentity),
}, res.Spec.ProjectID, false, kube, namespace)
}, res.Spec.ProjectID, resolvers.EmptyStoreKind, kube, namespace)
if err != nil {
return nil, err
}
@ -81,7 +82,7 @@ func (g *Generator) generate(
}, 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) {
var spec genv1alpha1.GCRAccessToken

View file

@ -65,7 +65,7 @@ func TestGenerate(t *testing.T) {
"foo": []byte("bar"),
},
}).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{
AccessToken: "1234",
Expiry: time.Unix(5555, 0),

View file

@ -39,6 +39,7 @@ import (
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/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const (
@ -426,12 +427,14 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
}
ok := caCertPool.AppendCertsFromPEM(pem)
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 {
return nil, fmt.Errorf("missing namespace on CAProvider secret")
if provider.CAProvider != nil &&
a.storeKind == esv1beta1.ClusterSecretStoreKind &&
provider.CAProvider.Namespace == nil {
return nil, fmt.Errorf("missing namespace on caProvider secret")
}
if provider.CAProvider != nil {
@ -444,7 +447,7 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
case esv1beta1.CAProviderTypeConfigMap:
cert, err = a.getCertFromConfigMap(provider)
default:
err = fmt.Errorf("unknown caprovider type: %s", provider.CAProvider.Type)
err = fmt.Errorf("unknown CAProvider type: %s", provider.CAProvider.Type)
}
if err != nil {
@ -456,7 +459,7 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
}
ok := caCertPool.AppendCertsFromPEM(pem)
if !ok {
return nil, fmt.Errorf("failed to append cabundle")
return nil, fmt.Errorf("failed to append caBundle")
}
}
return caCertPool, nil
@ -473,12 +476,12 @@ func (a *akeylessBase) getCertFromSecret(provider *esv1beta1.AkeylessProvider) (
}
ctx := context.Background()
res, err := a.secretKeyRef(ctx, &secretRef)
cert, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, &secretRef)
if err != nil {
return nil, err
}
return []byte(res), nil
return []byte(cert), nil
}
func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider) ([]byte, error) {
@ -494,12 +497,12 @@ func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider
ctx := context.Background()
err := a.kube.Get(ctx, objKey, configMapRef)
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]
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

View file

@ -35,6 +35,7 @@ import (
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
var apiErr akeyless.GenericOpenAPIError
@ -335,7 +336,7 @@ func (a *akeylessBase) getK8SServiceAccountJWT(ctx context.Context, kubernetesAu
tokenRef = kubernetesAuth.SecretRef.DeepCopy()
tokenRef.Key = "token"
}
jwt, err := a.secretKeyRef(ctx, tokenRef)
jwt, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, tokenRef)
if err != nil {
return "", err
}
@ -363,7 +364,7 @@ func (a *akeylessBase) getJWTFromServiceAccount(ctx context.Context, serviceAcco
return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
}
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,
Namespace: &ref.Namespace,
Key: "token",
@ -372,36 +373,11 @@ func (a *akeylessBase) getJWTFromServiceAccount(ctx context.Context, serviceAcco
continue
}
return retval, nil
return token, nil
}
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) {
audiences := serviceAccountRef.Audiences
if len(additionalAud) > 0 {

View file

@ -18,17 +18,13 @@ 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"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const (
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing Akeyless AccessID Namespace"
errInvalidClusterStoreMissingSAKNamespace = "invalid ClusterSecretStore: missing Akeyless AccessType Namespace"
errFetchAKIDSecret = "could not fetch accessID secret: %w"
errFetchSAKSecret = "could not fetch AccessType secret: %w"
errFetchAccessIDSecret = "could not fetch accessID secret: %w"
errFetchAccessTypeSecret = "could not fetch AccessType secret: %w"
errFetchAccessTypeParamSecret = "could not fetch AccessTypeParam secret: %w"
errMissingSAK = "missing SecretAccessKey"
errMissingAKID = "missing AccessKeyID"
)
@ -44,58 +40,36 @@ func (a *akeylessBase) TokenFromSecretRef(ctx context.Context) (string, error) {
return a.GetToken(auth.AccessID, "k8s", auth.K8sConfName, auth)
}
ke := client.ObjectKey{
Name: prov.Auth.SecretRef.AccessID.Name,
Namespace: a.namespace, // default to ExternalSecret namespace
}
// only ClusterStore is allowed to set namespace (and then it's required)
if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
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)
accessID, err := resolvers.SecretKeyRef(
ctx,
a.kube,
a.storeKind,
a.namespace,
&prov.Auth.SecretRef.AccessID,
)
if err != nil {
return "", fmt.Errorf(errFetchAKIDSecret, err)
return "", fmt.Errorf(errFetchAccessIDSecret, err)
}
ke = client.ObjectKey{
Name: prov.Auth.SecretRef.AccessType.Name,
Namespace: a.namespace, // default to ExternalSecret namespace
}
// only ClusterStore is allowed to set namespace (and then it's required)
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
}
accessTypeSecret := v1.Secret{}
err = a.kube.Get(ctx, ke, &accessTypeSecret)
accessType, err := resolvers.SecretKeyRef(
ctx,
a.kube,
a.storeKind,
a.namespace,
&prov.Auth.SecretRef.AccessType,
)
if err != nil {
return "", fmt.Errorf(errFetchSAKSecret, err)
return "", fmt.Errorf(errFetchAccessTypeSecret, err)
}
ke = client.ObjectKey{
Name: prov.Auth.SecretRef.AccessTypeParam.Name,
Namespace: a.namespace, // default to ExternalSecret namespace
}
// only ClusterStore is allowed to set namespace (and then it's required)
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)
accessTypeParam, err := resolvers.SecretKeyRef(
ctx,
a.kube,
a.storeKind,
a.namespace,
&prov.Auth.SecretRef.AccessTypeParam,
)
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 == "" {
return "", fmt.Errorf(errMissingSAK)

View file

@ -26,22 +26,18 @@ import (
"github.com/avast/retry-go/v4"
"github.com/tidwall/gjson"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
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/resolvers"
)
const (
errAlibabaClient = "cannot setup new Alibaba client: %w"
errAlibabaCredSecretName = "invalid Alibaba SecretStore resource: missing Alibaba APIKey"
errUninitalizedAlibabaProvider = "provider Alibaba is not initialized"
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterStore, missing AccessKeyID namespace"
errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
errFetchAKIDSecret = "could not fetch AccessKeyID secret: %w"
errMissingSAK = "missing AccessSecretKey"
errMissingAKID = "missing AccessKeyID"
errFetchAccessKeyID = "could not fetch AccessKeyID secret: %w"
errFetchAccessKeySecret = "could not fetch AccessKeySecret secret: %w"
)
// 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()
alibabaSpec := storeSpec.Provider.Alibaba
storeKind := store.GetObjectKind().GroupVersionKind().Kind
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)
accessKeyID, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &alibabaSpec.Auth.SecretRef.AccessKeyID)
if err != nil {
return nil, fmt.Errorf(errFetchAKIDSecret, err)
return nil, fmt.Errorf(errFetchAccessKeyID, err)
}
objectKey = types.NamespacedName{
Name: alibabaSpec.Auth.SecretRef.AccessKeySecret.Name,
Namespace: namespace,
accessKeySecret, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &alibabaSpec.Auth.SecretRef.AccessKeySecret)
if err != nil {
return nil, fmt.Errorf(errFetchAccessKeySecret, err)
}
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{
AccessKeyId: utils.Ptr(string(accessKeyID)),
AccessKeySecret: utils.Ptr(string(accessKeySecret)),
AccessKeyId: utils.Ptr(accessKeyID),
AccessKeySecret: utils.Ptr(accessKeySecret),
Type: utils.Ptr("access_key"),
ConnectTimeout: utils.Ptr(30),
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/feature"
"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.
@ -58,13 +59,9 @@ const (
audienceAnnotation = "eks.amazonaws.com/audience"
defaultTokenAudience = "sts.amazonaws.com"
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"
)
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
if secretRef != nil {
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 {
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
if secretRef != nil {
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 {
return nil, err
}
@ -211,55 +208,22 @@ func NewGeneratorSession(ctx context.Context, auth esv1beta1.AWSAuth, role, regi
// construct a aws.Credentials object
// 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.
func credsFromSecretRef(ctx context.Context, auth esv1beta1.AWSAuth, isClusterKind bool, kube client.Client, namespace string) (*credentials.Credentials, error) {
ke := client.ObjectKey{
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)
func credsFromSecretRef(ctx context.Context, auth esv1beta1.AWSAuth, storeKind string, kube client.Client, namespace string) (*credentials.Credentials, error) {
sak, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &auth.SecretRef.SecretAccessKey)
if err != nil {
return nil, fmt.Errorf(errFetchSAKSecret, 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)
aks, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &auth.SecretRef.AccessKeyID)
if err != nil {
return nil, fmt.Errorf(errFetchAKIDSecret, err)
}
var sessionToken string
if auth.SecretRef.SessionToken != nil {
ke = client.ObjectKey{
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)
sessionToken, err = resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, auth.SecretRef.SessionToken)
if err != nil {
return nil, fmt.Errorf(errFetchSTSecret, err)
}
sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
}
return credentials.NewStaticCredentials(aks, sak, sessionToken), err

View file

@ -224,7 +224,7 @@ func TestNewSession(t *testing.T) {
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",

View file

@ -48,10 +48,10 @@ import (
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
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/metrics"
"github.com/external-secrets/external-secrets/pkg/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
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 {
return nil, fmt.Errorf(errMissingClientIDSecret)
}
clusterScoped := false
if a.store.GetKind() == esv1beta1.ClusterSecretStoreKind {
clusterScoped = true
}
cid, err := a.secretKeyRef(ctx, a.namespace, *a.provider.AuthSecretRef.ClientID, clusterScoped)
clientID, err := resolvers.SecretKeyRef(
ctx,
a.crClient,
a.store.GetKind(),
a.namespace, a.provider.AuthSecretRef.ClientID)
if err != nil {
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 {
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.AADEndpoint = AadEndpointForType(a.provider.EnvironmentType)
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 {
return nil
}

View file

@ -244,7 +244,7 @@ func TestAuth(t *testing.T) {
},
{
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,
provider: &esv1beta1.AzureKVProvider{
AuthType: &authType,
@ -258,7 +258,7 @@ func TestAuth(t *testing.T) {
},
{
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{
TypeMeta: metav1.TypeMeta{
Kind: esv1beta1.ClusterSecretStoreKind,

View file

@ -27,6 +27,7 @@ import (
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const JwtLifespan = 600 // 10 minutes
@ -46,7 +47,12 @@ func (p *Client) getJWTToken(ctx context.Context, conjurJWTConfig *esv1beta1.Con
tokenRef = conjurJWTConfig.SecretRef.DeepCopy()
tokenRef.Key = "token"
}
jwtToken, err := p.secretKeyRef(ctx, tokenRef)
jwtToken, err := resolvers.SecretKeyRef(
ctx,
p.kube,
p.StoreKind,
p.namespace,
tokenRef)
if err != nil {
return "", err
}

View file

@ -32,6 +32,7 @@ import (
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/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
var (
@ -109,13 +110,22 @@ func (p *Client) GetConjurClient(ctx context.Context) (SecretsClient, error) {
SSLCert: cert,
}
if prov.Auth.Apikey != nil {
config.Account = prov.Auth.Apikey.Account
conjUser, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.UserRef)
if prov.Auth.APIKey != nil {
config.Account = prov.Auth.APIKey.Account
conjUser, secErr := resolvers.SecretKeyRef(
ctx,
p.kube,
p.StoreKind,
p.namespace, prov.Auth.APIKey.UserRef)
if secErr != nil {
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 {
return nil, fmt.Errorf(errBadServiceAPIKey, secErr)
}
@ -224,20 +234,20 @@ func (c *Provider) ValidateStore(store esv1beta1.GenericStore) error {
if prov.URL == "" {
return fmt.Errorf("conjur URL cannot be empty")
}
if prov.Auth.Apikey != nil {
if prov.Auth.Apikey.Account == "" {
if prov.Auth.APIKey != nil {
if prov.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")
}
if prov.Auth.Apikey.APIKeyRef == nil {
if prov.Auth.APIKey.APIKeyRef == nil {
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)
}
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)
}
}
@ -265,7 +275,7 @@ func (c *Provider) ValidateStore(store esv1beta1.GenericStore) error {
}
// 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")
}
@ -277,32 +287,7 @@ func (c *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
return esv1beta1.SecretStoreReadOnly
}
func (p *Client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
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.
// configMapKeyRef returns the value of a key in a ConfigMap.
func (p *Client) configMapKeyRef(ctx context.Context, cmRef *esmeta.SecretKeySelector) (string, error) {
configMap := &corev1.ConfigMap{}
ref := client.ObjectKey{
@ -349,7 +334,12 @@ func (p *Client) getCA(ctx context.Context, provider *esv1beta1.ConjurProvider)
Namespace: provider.CAProvider.Namespace,
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 {
return "", fmt.Errorf(errUnableToFetchCAProviderSecret, err)
}

View file

@ -351,7 +351,7 @@ func makeAPIKeySecretStore(svcURL, svcUser, svcApikey, svcAccount string) *esv1b
Conjur: &esv1beta1.ConjurProvider{
URL: svcURL,
Auth: esv1beta1.ConjurAuth{
Apikey: &esv1beta1.ConjurApikey{
APIKey: &esv1beta1.ConjurAPIKey{
Account: svcAccount,
UserRef: uref,
APIKeyRef: aref,
@ -465,7 +465,7 @@ func makeFakeCASource(kind, caData string) kclient.Object {
Namespace: "default",
},
Data: map[string][]byte{
"conjur-cert": []byte(caData),
"ca": []byte(caData),
},
}
}

View file

@ -17,14 +17,13 @@ package delinea
import (
"context"
"errors"
"fmt"
"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
corev1 "k8s.io/api/core/v1"
kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
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/resolvers"
)
var (
@ -38,8 +37,6 @@ var (
errMissingSecretName = errors.New("must specify a secret name")
errMissingSecretKey = errors.New("must specify a secret key")
errClusterStoreRequiresNamespace = errors.New("when using a ClusterSecretStore, namespaces must be explicitly set")
errNoSuchKeyFmt = "no such key in secret: %q"
)
type Provider struct{}
@ -62,12 +59,12 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
return nil, errClusterStoreRequiresNamespace
}
clientID, err := loadConfigSecret(ctx, cfg.ClientID, kube, namespace)
clientID, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientID, kube, namespace)
if err != nil {
return nil, err
}
clientSecret, err := loadConfigSecret(ctx, cfg.ClientSecret, kube, namespace)
clientSecret, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientSecret, kube, namespace)
if err != nil {
return nil, err
}
@ -90,33 +87,19 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
}, 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 {
return ref.Value, nil
}
if err := validateSecretRef(ref); err != nil {
return "", err
}
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
return resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, ref.SecretRef)
}
func validateStoreSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.DelineaProviderSecretRef) error {

View file

@ -15,7 +15,6 @@ package delinea
import (
"context"
"fmt"
"testing"
"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
@ -283,7 +282,7 @@ func TestNewClient(t *testing.T) {
},
kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
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": {

View file

@ -23,13 +23,13 @@ import (
"time"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
"github.com/external-secrets/external-secrets/pkg/find"
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/resolvers"
)
const (
@ -41,8 +41,6 @@ const (
secretsDownloadFileKey = "DOPPLER_SECRETS_FILE"
errDopplerTokenSecretName = "missing auth.secretRef.dopplerToken.name"
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 {
@ -68,35 +66,16 @@ type SecretsClientInterface interface {
}
func (c *Client) setAuth(ctx context.Context) error {
credentialsSecret := &corev1.Secret{}
credentialsSecretName := c.store.Auth.SecretRef.DopplerToken.Name
if credentialsSecretName == "" {
return fmt.Errorf(errDopplerTokenSecretName)
}
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.DopplerToken.Namespace == nil {
return fmt.Errorf(errInvalidClusterStoreMissingDopplerTokenNamespace)
}
objectKey.Namespace = *c.store.Auth.SecretRef.DopplerToken.Namespace
}
err := c.kube.Get(ctx, objectKey, credentialsSecret)
token, err := resolvers.SecretKeyRef(
ctx,
c.kube,
c.storeKind,
c.namespace,
&c.store.Auth.SecretRef.DopplerToken)
if err != nil {
return fmt.Errorf(errFetchDopplerTokenSecret, err)
return err
}
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)
c.dopplerToken = token
return nil
}

View file

@ -19,15 +19,14 @@ import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
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) {
ts, err := serviceAccountTokenSource(ctx, auth, isClusterKind, kube, namespace)
func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID, storeKind string, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
ts, err := serviceAccountTokenSource(ctx, auth, storeKind, kube, namespace)
if ts != nil || err != nil {
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")
}
defer wi.Close()
isClusterKind := storeKind == esv1beta1.ClusterSecretStoreKind
ts, err = wi.TokenSource(ctx, auth, isClusterKind, kube, namespace)
if ts != nil || err != nil {
return ts, err
@ -43,29 +43,21 @@ func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID str
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
if sr == nil {
return nil, nil
}
credentialsSecret := &v1.Secret{}
credentialsSecretName := sr.SecretAccessKey.Name
objectKey := types.NamespacedName{
Name: credentialsSecretName,
Namespace: namespace,
}
if isClusterKind && sr.SecretAccessKey.Namespace != nil {
objectKey.Namespace = *sr.SecretAccessKey.Namespace
}
err := kube.Get(ctx, objectKey, credentialsSecret)
credentials, err := resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
namespace,
&auth.SecretRef.SecretAccessKey)
if err != nil {
return nil, fmt.Errorf(errFetchSAKSecret, err)
return nil, err
}
credentials := credentialsSecret.Data[sr.SecretAccessKey.Key]
if (credentials == nil) || (len(credentials) == 0) {
return nil, fmt.Errorf(errMissingSAK)
}
config, err := google.JWTConfigFromJSON(credentials, CloudPlatformRole)
config, err := google.JWTConfigFromJSON([]byte(credentials), CloudPlatformRole)
if err != nil {
return nil, fmt.Errorf(errUnableProcessJSONCredentials, err)
}

View file

@ -50,7 +50,6 @@ const (
errClientClose = "unable to close SecretManager client: %w"
errMissingStoreSpec = "invalid: missing store spec"
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
errMissingSAK = "missing SecretAccessKey"
errUnableProcessJSONCredentials = "failed to process the provided JSON credentials: %w"
errUnableCreateGCPSMClient = "failed to create GCP secretmanager client: %w"
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
}
ts, err := NewTokenSource(ctx, gcpStore.Auth, clusterProjectID, isClusterKind, kube, namespace)
ts, err := NewTokenSource(ctx, gcpStore.Auth, clusterProjectID, store.GetKind(), kube, namespace)
if err != nil {
return nil, fmt.Errorf(errUnableCreateGCPSMClient, err)
}

View file

@ -25,7 +25,6 @@ import (
"github.com/tidwall/gjson"
"github.com/xanzy/go-gitlab"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
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/metrics"
"github.com/external-secrets/external-secrets/pkg/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const (
errGitlabCredSecretName = "credentials are empty"
errInvalidClusterStoreMissingSAKNamespace = "invalid clusterStore missing SAK namespace"
errFetchSAKSecret = "couldn't find secret on cluster: %w"
errMissingSAK = "missing credentials while setting auth"
errList = "could not verify whether the gilabClient is valid: %w"
errProjectAuth = "gitlabClient is not allowed to get secrets for project 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")
// Set gitlabBase credentials to Access Token.
func (g *gitlabBase) getAuth(ctx context.Context) ([]byte, error) {
credentialsSecret := &corev1.Secret{}
credentialsSecretName := g.store.Auth.SecretRef.AccessToken.Name
if credentialsSecretName == "" {
return nil, fmt.Errorf(errGitlabCredSecretName)
}
objectKey := types.NamespacedName{
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) getAuth(ctx context.Context) (string, error) {
return resolvers.SecretKeyRef(
ctx,
g.kube,
g.storeKind,
g.namespace,
&g.store.Auth.SecretRef.AccessToken)
}
func (g *gitlabBase) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {

View file

@ -46,7 +46,7 @@ const (
groupvalue = "groupvalue"
groupid = "groupId"
defaultErrorMessage = "[%d] unexpected error: [%s], expected: [%s]"
errMissingCredentials = "credentials are empty"
errMissingCredentials = "cannot get Kubernetes secret \"\": secrets \"\" not found"
testKey = "testKey"
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.Key = authorizedKeySecretKey
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)
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
// 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 {
return nil, err
}

View file

@ -26,13 +26,13 @@ import (
"github.com/google/uuid"
"github.com/tidwall/gjson"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
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/metrics"
"github.com/external-secrets/external-secrets/pkg/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const (
@ -54,9 +54,7 @@ const (
errIBMClient = "cannot setup new ibm client: %w"
errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
errUninitalizedIBMProvider = "provider IBM is not initialized"
errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
errMissingSAK = "missing SecretAccessKey"
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
errJSONSecretMarshal = "unable to marshal secret: %w"
errExtractingSecret = "unable to extract the fetched secret %s of type %s while performing %s"
@ -93,33 +91,11 @@ type client struct {
}
func (c *client) setAuth(ctx context.Context) error {
credentialsSecret := &corev1.Secret{}
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)
apiKey, err := resolvers.SecretKeyRef(ctx, c.kube, c.storeKind, c.namespace, &c.store.Auth.SecretRef.SecretAPIKey)
if err != nil {
return fmt.Errorf(errFetchSAKSecret, err)
}
c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
if (c.credentials == nil) || (len(c.credentials) == 0) {
return fmt.Errorf(errMissingSAK)
return err
}
c.credentials = []byte(apiKey)
return nil
}

View file

@ -19,12 +19,11 @@ import (
ksm "github.com/keeper-security/secrets-manager-go/core"
"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"
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/resolvers"
)
const (
@ -66,8 +65,7 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
keeperStore := storeSpec.Provider.KeeperSecurity
isClusterKind := store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind
clientConfig, err := getKeeperSecurityAuth(ctx, keeperStore, kube, isClusterKind, namespace)
clientConfig, err := getKeeperSecurityAuth(ctx, keeperStore, kube, store.GetKind(), namespace)
if err != nil {
return nil, fmt.Errorf(errKeeperSecurityUnableToCreateConfig, err)
}
@ -112,33 +110,11 @@ func (p *Provider) ValidateStore(store esv1beta1.GenericStore) error {
return nil
}
func getKeeperSecurityAuth(ctx context.Context, store *esv1beta1.KeeperSecurityProvider, kube kclient.Client, isClusterKind bool, namespace string) (string, error) {
auth := store.Auth
credentialsSecret := &v1.Secret{}
credentialsSecretName := auth.Name
objectKey := types.NamespacedName{
Name: credentialsSecretName,
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
func getKeeperSecurityAuth(ctx context.Context, store *esv1beta1.KeeperSecurityProvider, kube kclient.Client, storeKind, namespace string) (string, error) {
return resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
namespace,
&store.Auth)
}

View file

@ -25,6 +25,7 @@ import (
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const (
@ -128,31 +129,18 @@ func (c *Client) serviceAccountToken(ctx context.Context, serviceAccountRef *esm
return []byte(tr.Status.Token), nil
}
func (c *Client) fetchSecretKey(ctx context.Context, key esmeta.SecretKeySelector) ([]byte, error) {
keySecret := &corev1.Secret{}
objectKey := types.NamespacedName{
Name: key.Name,
Namespace: c.namespace,
}
// only ClusterStore is allowed to set namespace (and then it's required)
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)
func (c *Client) fetchSecretKey(ctx context.Context, ref esmeta.SecretKeySelector) ([]byte, error) {
secret, err := resolvers.SecretKeyRef(
ctx,
c.ctrlClient,
c.storeKind,
c.namespace,
&ref,
)
if err != nil {
return nil, fmt.Errorf(errFetchCredentials, err)
return nil, err
}
val, ok := keySecret.Data[key.Key]
if !ok {
return nil, fmt.Errorf(errMissingCredentials, key.Key)
}
if len(val) == 0 {
return nil, fmt.Errorf(errEmptyKey, key.Key)
}
return val, nil
return []byte(secret), nil
}
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/onepassword"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
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/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
const (
@ -95,29 +95,18 @@ func (provider *ProviderOnePassword) Capabilities() esv1beta1.SecretStoreCapabil
// NewClient constructs a 1Password Provider.
func (provider *ProviderOnePassword) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
config := store.GetSpec().Provider.OnePassword
credentialsSecret := &corev1.Secret{}
objectKey := types.NamespacedName{
Name: config.Auth.SecretRef.ConnectToken.Name,
Namespace: namespace,
}
// 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)
token, err := resolvers.SecretKeyRef(
ctx,
kube,
store.GetKind(),
namespace,
&config.Auth.SecretRef.ConnectToken,
)
if err != nil {
return nil, fmt.Errorf(errFetchK8sSecret, err)
return nil, err
}
token := credentialsSecret.Data[config.Auth.SecretRef.ConnectToken.Key]
if (token == nil) || (len(token) == 0) {
return nil, fmt.Errorf(errMissingToken)
}
provider.client = connect.NewClientWithUserAgent(config.ConnectHost, string(token), userAgent)
provider.client = connect.NewClientWithUserAgent(config.ConnectHost, token, userAgent)
provider.vaults = config.Vaults
return provider, nil
}

View file

@ -32,7 +32,6 @@ import (
"github.com/oracle/oci-go-sdk/v65/vault"
"github.com/tidwall/gjson"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
@ -40,13 +39,13 @@ import (
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
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/resolvers"
)
const (
errOracleClient = "cannot setup new oracle client: %w"
errORACLECredSecretName = "invalid oracle SecretStore resource: missing oracle APIKey"
errUninitalizedOracleProvider = "provider oracle is not initialized"
errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
errMissingPK = "missing PrivateKey"
errMissingUser = "missing User ID"
@ -398,27 +397,17 @@ func getSecretData(ctx context.Context, kube kclient.Client, namespace, storeKin
if secretRef.Name == "" {
return "", fmt.Errorf(errORACLECredSecretName)
}
objectKey := types.NamespacedName{
Name: secretRef.Name,
Namespace: namespace,
}
// 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)
secret, err := resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
namespace,
&secretRef,
)
if err != nil {
return "", fmt.Errorf(errFetchSAKSecret, err)
}
return string(secret.Data[secretRef.Key]), nil
return secret, nil
}
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",

View file

@ -21,12 +21,12 @@ import (
smapi "github.com/scaleway/scaleway-sdk-go/api/secret/v1alpha1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/scaleway-sdk-go/validation"
corev1 "k8s.io/api/core/v1"
ctrl "sigs.k8s.io/controller-runtime"
kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
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/resolvers"
)
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")
}
accessKey, err := loadConfigSecret(ctx, cfg.AccessKey, kube, namespace)
accessKey, err := loadConfigSecret(ctx, cfg.AccessKey, kube, namespace, store.GetKind())
if err != nil {
return nil, err
}
secretKey, err := loadConfigSecret(ctx, cfg.SecretKey, kube, namespace)
secretKey, err := loadConfigSecret(ctx, cfg.SecretKey, kube, namespace, store.GetKind())
if err != nil {
return nil, err
}
@ -80,42 +80,17 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
}, 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 {
return ref.Value, nil
}
namespace := defaultNamespace
if ref.SecretRef.Namespace != nil {
namespace = *ref.SecretRef.Namespace
}
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
return resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
defaultNamespace,
ref.SecretRef,
)
}
func validateSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.ScalewayProviderSecretRef) error {

View file

@ -28,6 +28,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
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.
*/
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 {
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 {
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"
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
var (
@ -54,14 +55,6 @@ const (
STSEndpointEnv = "AWS_STS_ENDPOINT"
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
@ -232,58 +225,37 @@ func CredsFromControllerServiceAccount(ctx context.Context, saname, ns, region s
// construct a aws.Credentials object
// 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.
func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, isClusterKind bool, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
ke := kclient.ObjectKey{
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)
func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, storeKind string, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
akid, err := resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
namespace,
&auth.SecretRef.AccessKeyID,
)
if err != nil {
return nil, fmt.Errorf(errFetchAKIDSecret, err)
return nil, err
}
ke = kclient.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)
sak, err := resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
namespace,
&auth.SecretRef.SecretAccessKey,
)
if err != nil {
return nil, fmt.Errorf(errFetchSAKSecret, 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)
return nil, err
}
var sessionToken string
if auth.SecretRef.SessionToken != nil {
ke = kclient.ObjectKey{
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 {
return nil, fmt.Errorf(errFetchSTSecret, err)
}
sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
}
return credentials.NewStaticCredentials(aks, sak, sessionToken), err
// session token is optional
sessionToken, _ := resolvers.SecretKeyRef(
ctx,
kube,
storeKind,
namespace,
auth.SecretRef.SessionToken,
)
return credentials.NewStaticCredentials(akid, sak, sessionToken), err
}
type STSProvider func(*session.Session) stsiface.STSAPI

View file

@ -40,7 +40,7 @@ import (
authuserpass "github.com/hashicorp/vault/api/auth/userpass"
"github.com/spf13/pflag"
"github.com/tidwall/gjson"
authenticationv1 "k8s.io/api/authentication/v1"
authv1 "k8s.io/api/authentication/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@ -60,6 +60,7 @@ import (
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/utils"
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
)
var (
@ -1088,7 +1089,7 @@ func (v *client) configureClientTLS(ctx context.Context, cfg *vault.Config) erro
if clientTLS.KeySecretRef.Key == "" {
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 {
return err
}
@ -1096,7 +1097,7 @@ func (v *client) configureClientTLS(ctx context.Context, cfg *vault.Config) erro
if clientTLS.CertSecretRef.Key == "" {
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 {
return err
}
@ -1125,7 +1126,7 @@ func getCertFromSecret(v *client) ([]byte, error) {
}
ctx := context.Background()
res, err := v.secretKeyRef(ctx, &secretRef)
res, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &secretRef)
if err != nil {
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) {
tokenRef := v.store.Auth.TokenSecretRef
if tokenRef != nil {
token, err := v.secretKeyRef(ctx, tokenRef)
token, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, tokenRef)
if err != nil {
return true, err
}
@ -1339,71 +1340,19 @@ func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccou
return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
}
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,
Namespace: &ref.Namespace,
Key: "token",
})
if err != nil {
continue
}
return retval, nil
return token, nil
}
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.
func checkToken(ctx context.Context, token util.Token) (bool, error) {
// 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
roleID = strings.TrimSpace(appRole.RoleID)
} 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 {
return err
}
@ -1455,7 +1404,7 @@ func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1be
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 {
return err
}
@ -1503,7 +1452,14 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
// Kubernetes >=v1.24: fetch token via TokenRequest API
// 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.
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 {
return "", err
}
@ -1514,7 +1470,7 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
tokenRef = kubernetesAuth.SecretRef.DeepCopy()
tokenRef.Key = "token"
}
jwt, err := v.secretKeyRef(ctx, tokenRef)
jwt, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, tokenRef)
if err != nil {
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 {
username := strings.TrimSpace(ldapAuth.Username)
password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
password, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &ldapAuth.SecretRef)
if err != nil {
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 {
username := strings.TrimSpace(userPassAuth.Username)
password, err := v.secretKeyRef(ctx, &userPassAuth.SecretRef)
password, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &userPassAuth.SecretRef)
if err != nil {
return err
}
@ -1579,7 +1533,7 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
var jwt string
var err error
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 {
audiences := k8sServiceAccountToken.Audiences
if audiences == nil {
@ -1590,7 +1544,14 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
tmp := int64(600)
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 {
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 {
clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
clientKey, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &certAuth.SecretRef)
if err != nil {
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 {
return err
}
@ -1651,7 +1612,40 @@ func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1bet
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
secretRefAuth := iamAuth.SecretRef
regionAWS := defaultAWSRegion
@ -1665,13 +1659,13 @@ func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1
var creds *credentials.Credentials
var err error
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 {
return err
}
} else if secretRefAuth != nil { // if jwtAuth is not defined, check if secretRef is defined. Second preference.
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 {
return err
}

View file

@ -332,7 +332,7 @@ MIIFkTCCA3mgAwIBAgIUBEUg3m/WqAsWHG4Q/II3IePFfuowDQYJKoZIhvcNAQELBQAwWDELMAkGA1UE
kube: clientfake.NewClientBuilder().Build(),
},
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": {

View file

@ -25,7 +25,6 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
tpl "text/template"
"time"
@ -39,6 +38,7 @@ import (
"github.com/external-secrets/external-secrets/pkg/metrics"
"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/resolvers"
)
// https://github.com/external-secrets/external-secrets/issues/644
@ -384,6 +384,7 @@ func (w *WebHook) getCACertPool(provider *esv1beta1.WebhookProvider) (*x509.Cert
func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte, error) {
secretRef := esmeta.SecretKeySelector{
Name: provider.CAProvider.Name,
Namespace: &w.namespace,
Key: provider.CAProvider.Key,
}
@ -392,37 +393,18 @@ func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte
}
ctx := context.Background()
res, err := w.secretKeyRef(ctx, &secretRef)
cert, err := resolvers.SecretKeyRef(
ctx,
w.kube,
w.storeKind,
w.namespace,
&secretRef,
)
if err != nil {
return nil, err
}
return []byte(res), 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
return []byte(cert), nil
}
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.Key = authorizedKeySecretKey
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)
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)
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)
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/yandex-cloud/go-sdk/iamkey"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
kclient "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"
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
@ -115,61 +114,36 @@ func (p *YandexCloudProvider) NewClient(ctx context.Context, store esv1beta1.Gen
return nil, err
}
objectKey := types.NamespacedName{
Name: input.AuthorizedKey.Name,
Namespace: namespace,
}
// only ClusterStore is allowed to set namespace (and then it's required)
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)
key, err := resolvers.SecretKeyRef(
ctx,
kube,
store.GetKind(),
namespace,
&input.AuthorizedKey,
)
if err != nil {
return nil, fmt.Errorf("could not fetch AuthorizedKey secret: %w", err)
}
authorizedKeySecretData := authorizedKeySecret.Data[input.AuthorizedKey.Key]
if (authorizedKeySecretData == nil) || (len(authorizedKeySecretData) == 0) {
return nil, fmt.Errorf("missing AuthorizedKey")
return nil, err
}
var authorizedKey iamkey.Key
err = json.Unmarshal(authorizedKeySecretData, &authorizedKey)
err = json.Unmarshal([]byte(key), &authorizedKey)
if err != nil {
return nil, fmt.Errorf("unable to unmarshal authorized key: %w", err)
}
var caCertificateData []byte
if input.CACertificate != nil {
certObjectKey := types.NamespacedName{
Name: input.CACertificate.Name,
Namespace: namespace,
}
if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
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)
caCert, err := resolvers.SecretKeyRef(
ctx,
kube,
store.GetKind(),
namespace,
input.CACertificate,
)
if err != nil {
return nil, fmt.Errorf("could not fetch CA certificate secret: %w", err)
}
caCertificateData = caCertificateSecret.Data[input.CACertificate.Key]
if (caCertificateData == nil) || (len(caCertificateData) == 0) {
return nil, fmt.Errorf("missing CA Certificate")
return nil, err
}
caCertificateData = []byte(caCert)
}
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.Key = authorizedKeySecretKey
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)
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)
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)
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)
})
}
}