mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
chore: refactor/centralise secretKeyRef usage (#3022)
* chore: refactor/centralise secretKeyRef usage Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
parent
b6b4f12509
commit
26f9c3f1f4
43 changed files with 600 additions and 850 deletions
|
@ -27,12 +27,12 @@ type ConjurProvider struct {
|
|||
|
||||
type ConjurAuth struct {
|
||||
// +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"`
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -18,19 +18,15 @@ 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"
|
||||
errMissingSAK = "missing SecretAccessKey"
|
||||
errMissingAKID = "missing AccessKeyID"
|
||||
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"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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"
|
||||
errAlibabaClient = "cannot setup new Alibaba client: %w"
|
||||
errUninitalizedAlibabaProvider = "provider Alibaba is not initialized"
|
||||
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),
|
||||
|
|
|
@ -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"
|
||||
errFetchAKIDSecret = "could not fetch accessKeyID secret: %w"
|
||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||
errFetchSTSecret = "could not fetch SessionToken secret: %w"
|
||||
)
|
||||
|
||||
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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
|
@ -51,15 +51,13 @@ const (
|
|||
payloadConst = "payload"
|
||||
smAPIKeyConst = "api_key"
|
||||
|
||||
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"
|
||||
errIBMClient = "cannot setup new ibm client: %w"
|
||||
errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
|
||||
errUninitalizedIBMProvider = "provider IBM is not initialized"
|
||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||
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"
|
||||
|
||||
defaultCacheSize = 100
|
||||
defaultCacheExpiry = 1 * time.Hour
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,23 +39,23 @@ 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"
|
||||
errMissingTenancy = "missing Tenancy ID"
|
||||
errMissingRegion = "missing Region"
|
||||
errMissingFingerprint = "missing Fingerprint"
|
||||
errMissingVault = "missing Vault"
|
||||
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
|
||||
errMissingKey = "missing Key in secret: %s"
|
||||
errUnexpectedContent = "unexpected secret bundle content"
|
||||
errOracleClient = "cannot setup new oracle client: %w"
|
||||
errORACLECredSecretName = "invalid oracle SecretStore resource: missing oracle APIKey"
|
||||
errUninitalizedOracleProvider = "provider oracle is not initialized"
|
||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||
errMissingPK = "missing PrivateKey"
|
||||
errMissingUser = "missing User ID"
|
||||
errMissingTenancy = "missing Tenancy ID"
|
||||
errMissingRegion = "missing Region"
|
||||
errMissingFingerprint = "missing Fingerprint"
|
||||
errMissingVault = "missing Vault"
|
||||
errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
|
||||
errMissingKey = "missing Key in secret: %s"
|
||||
errUnexpectedContent = "unexpected secret bundle content"
|
||||
)
|
||||
|
||||
// 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 == "" {
|
||||
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) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
errRequiredNamespaceNotFound = "invalid ClusterSecretStore: missing namespace in %s"
|
||||
errCannotFetchKubernetesSecret = "could not fetch Kubernetes secret %s"
|
||||
)
|
||||
|
||||
/*
|
||||
getKubernetesSecret get Kubernetes Secret based on object parameter in namespace where ESO is installed or another, if ClusterSecretStore is used.
|
||||
*/
|
||||
func getKubernetesSecret(ctx context.Context, object esmeta.SecretKeySelector, store esv1beta1.GenericStore, kube client.Client, namespace string) (string, error) {
|
||||
ke := client.ObjectKey{
|
||||
Name: object.Name,
|
||||
Namespace: namespace, // Default to ExternalSecret namespace
|
||||
}
|
||||
|
||||
// Only ClusterStore is allowed to set namespace (and then it's required)
|
||||
if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
|
||||
if object.Namespace == nil {
|
||||
return "", fmt.Errorf(errRequiredNamespaceNotFound, object.Key)
|
||||
}
|
||||
ke.Namespace = *object.Namespace
|
||||
}
|
||||
|
||||
secret := v1.Secret{}
|
||||
err := kube.Get(ctx, ke, &secret)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(errCannotFetchKubernetesSecret, object.Name)
|
||||
}
|
||||
|
||||
return string(secret.Data[object.Key]), nil
|
||||
}
|
|
@ -41,6 +41,7 @@ import (
|
|||
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
"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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
|
@ -383,8 +383,9 @@ 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,
|
||||
Key: provider.CAProvider.Key,
|
||||
Name: provider.CAProvider.Name,
|
||||
Namespace: &w.namespace,
|
||||
Key: provider.CAProvider.Key,
|
||||
}
|
||||
|
||||
if provider.CAProvider.Namespace != nil {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"))
|
||||
|
|
71
pkg/utils/resolvers/secret_ref.go
Normal file
71
pkg/utils/resolvers/secret_ref.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// This is used to determine if a store is cluster-scoped or not.
|
||||
// The EmptyStoreKind is not cluster-scoped, hence resources
|
||||
// cannot be resolved across namespaces.
|
||||
// TODO: when we implement cluster-scoped generators
|
||||
// we can remove this and replace it with a interface.
|
||||
EmptyStoreKind = "EmptyStoreKind"
|
||||
|
||||
errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
|
||||
errSecretKeyFmt = "cannot find secret data for key: %q"
|
||||
errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
|
||||
)
|
||||
|
||||
// SecretKeyRef resolves a metav1.SecretKeySelector and returns the value of the secret it points to.
|
||||
// A user must pass the namespace of the originating ExternalSecret, as this may differ
|
||||
// from the namespace defined in the SecretKeySelector.
|
||||
// This func ensures that only a ClusterSecretStore is able to request secrets across namespaces.
|
||||
func SecretKeyRef(
|
||||
ctx context.Context,
|
||||
c client.Client,
|
||||
storeKind string,
|
||||
esNamespace string,
|
||||
ref *esmeta.SecretKeySelector) (string, error) {
|
||||
key := types.NamespacedName{
|
||||
Namespace: esNamespace,
|
||||
Name: ref.Name,
|
||||
}
|
||||
if (storeKind == esv1beta1.ClusterSecretStoreKind) &&
|
||||
(ref.Namespace != nil) {
|
||||
key.Namespace = *ref.Namespace
|
||||
}
|
||||
secret := &corev1.Secret{}
|
||||
err := c.Get(ctx, key, secret)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
|
||||
}
|
||||
val, ok := secret.Data[ref.Key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf(errSecretKeyFmt, ref.Key)
|
||||
}
|
||||
return string(val), nil
|
||||
}
|
129
pkg/utils/resolvers/secret_ref_test.go
Normal file
129
pkg/utils/resolvers/secret_ref_test.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/utils/ptr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestResolveSecretKeyRef(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
c := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
testNamespace := "test-namespace"
|
||||
testSecret := "test-secret"
|
||||
testKey := "test-key"
|
||||
testValue := "test-value"
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testNamespace,
|
||||
Name: testSecret,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
testKey: []byte(testValue),
|
||||
},
|
||||
}
|
||||
err := c.Create(ctx, secret)
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
namespace string
|
||||
storeKind string
|
||||
selector *esmeta.SecretKeySelector
|
||||
expected string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "namespaced secret store can access secret in same namespace",
|
||||
namespace: testNamespace,
|
||||
storeKind: "SecretStore",
|
||||
selector: &esmeta.SecretKeySelector{
|
||||
Name: testSecret,
|
||||
Namespace: ptr.To(testNamespace),
|
||||
Key: testKey,
|
||||
},
|
||||
expected: testValue,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "omitting namespace in secret store defaults to same namespace",
|
||||
namespace: testNamespace,
|
||||
storeKind: "SecretStore",
|
||||
selector: &esmeta.SecretKeySelector{
|
||||
Name: testSecret,
|
||||
Key: testKey,
|
||||
},
|
||||
expected: testValue,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "namespaced secret store can not access secret in different namespace",
|
||||
namespace: "other-namespace",
|
||||
storeKind: "SecretStore",
|
||||
selector: &esmeta.SecretKeySelector{
|
||||
Name: testSecret,
|
||||
Namespace: ptr.To(testNamespace),
|
||||
Key: testKey,
|
||||
},
|
||||
err: errors.New(`cannot get Kubernetes secret "test-secret": secrets "test-secret" not found`),
|
||||
},
|
||||
{
|
||||
name: "cluster secret store may access all namespaces",
|
||||
storeKind: "ClusterSecretStore",
|
||||
selector: &esmeta.SecretKeySelector{
|
||||
Name: testSecret,
|
||||
Namespace: ptr.To(testNamespace),
|
||||
Key: testKey,
|
||||
},
|
||||
expected: testValue,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "key not found in secret",
|
||||
namespace: testNamespace,
|
||||
storeKind: "SecretStore",
|
||||
selector: &esmeta.SecretKeySelector{
|
||||
Name: testSecret,
|
||||
Namespace: ptr.To(testNamespace),
|
||||
Key: "xxxxxxxx",
|
||||
},
|
||||
expected: "",
|
||||
err: errors.New(`cannot find secret data for key: "xxxxxxxx"`),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resolvedValue, err := SecretKeyRef(ctx, c, tc.storeKind, tc.namespace, tc.selector)
|
||||
if tc.err != nil {
|
||||
assert.EqualError(t, err, tc.err.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, tc.expected, resolvedValue)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue