mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
Add support for Yandex Lockbox
This commit is contained in:
parent
328cf881b8
commit
7017935888
19 changed files with 365 additions and 10 deletions
|
@ -53,6 +53,10 @@ type SecretStoreProvider struct {
|
|||
// IBM configures this store to sync secrets using IBM Cloud provider
|
||||
// +optional
|
||||
IBM *IBMProvider `json:"ibm,omitempty"`
|
||||
|
||||
// YandexLockbox configures this store to sync secrets using Yandex Lockbox provider
|
||||
// +optional
|
||||
YandexLockbox *YandexLockboxProvider `json:"yandexlockbox,omitempty"`
|
||||
}
|
||||
|
||||
type SecretStoreConditionType string
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||
)
|
||||
|
||||
type YandexLockboxAuth struct {
|
||||
// The AuthorizedKey is used for authentication
|
||||
// +optional
|
||||
AuthorizedKey esmeta.SecretKeySelector `json:"authorizedKeySecretRef,omitempty"`
|
||||
}
|
||||
|
||||
// YandexLockboxProvider Configures a store to sync secrets using the Yandex Lockbox provider.
|
||||
type YandexLockboxProvider struct {
|
||||
// Auth defines the information necessary to authenticate against Yandex Lockbox
|
||||
Auth YandexLockboxAuth `json:"auth"`
|
||||
}
|
|
@ -644,6 +644,11 @@ func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
|
|||
*out = new(IBMProvider)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.YandexLockbox != nil {
|
||||
in, out := &in.YandexLockbox, &out.YandexLockbox
|
||||
*out = new(YandexLockboxProvider)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.
|
||||
|
@ -949,3 +954,35 @@ func (in *VaultProvider) DeepCopy() *VaultProvider {
|
|||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *YandexLockboxAuth) DeepCopyInto(out *YandexLockboxAuth) {
|
||||
*out = *in
|
||||
in.AuthorizedKey.DeepCopyInto(&out.AuthorizedKey)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new YandexLockboxAuth.
|
||||
func (in *YandexLockboxAuth) DeepCopy() *YandexLockboxAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(YandexLockboxAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *YandexLockboxProvider) DeepCopyInto(out *YandexLockboxProvider) {
|
||||
*out = *in
|
||||
in.Auth.DeepCopyInto(&out.Auth)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new YandexLockboxProvider.
|
||||
func (in *YandexLockboxProvider) DeepCopy() *YandexLockboxProvider {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(YandexLockboxProvider)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -608,6 +608,38 @@ spec:
|
|||
- path
|
||||
- server
|
||||
type: object
|
||||
yandexlockbox:
|
||||
description: YandexLockbox configures this store to sync secrets
|
||||
using Yandex Lockbox provider
|
||||
properties:
|
||||
auth:
|
||||
description: Auth defines the information necessary to authenticate
|
||||
against Yandex Lockbox
|
||||
properties:
|
||||
authorizedKeySecretRef:
|
||||
description: The AuthorizedKey is used for authentication
|
||||
properties:
|
||||
key:
|
||||
description: The key of the entry in the Secret resource's
|
||||
`data` field to be used. Some instances of this
|
||||
field may be defaulted, in others it may be required.
|
||||
type: string
|
||||
name:
|
||||
description: The name of the Secret resource being
|
||||
referred to.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the resource being referred
|
||||
to. Ignored if referent is not cluster-scoped. cluster-scoped
|
||||
defaults to the namespace of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- auth
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- provider
|
||||
|
|
|
@ -608,6 +608,38 @@ spec:
|
|||
- path
|
||||
- server
|
||||
type: object
|
||||
yandexlockbox:
|
||||
description: YandexLockbox configures this store to sync secrets
|
||||
using Yandex Lockbox provider
|
||||
properties:
|
||||
auth:
|
||||
description: Auth defines the information necessary to authenticate
|
||||
against Yandex Lockbox
|
||||
properties:
|
||||
authorizedKeySecretRef:
|
||||
description: The AuthorizedKey is used for authentication
|
||||
properties:
|
||||
key:
|
||||
description: The key of the entry in the Secret resource's
|
||||
`data` field to be used. Some instances of this
|
||||
field may be defaulted, in others it may be required.
|
||||
type: string
|
||||
name:
|
||||
description: The name of the Secret resource being
|
||||
referred to.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the resource being referred
|
||||
to. Ignored if referent is not cluster-scoped. cluster-scoped
|
||||
defaults to the namespace of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- auth
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- provider
|
||||
|
|
2
go.mod
2
go.mod
|
@ -64,6 +64,8 @@ require (
|
|||
github.com/spf13/cobra v1.1.3 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/tidwall/gjson v1.7.5
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20210809082946-a97da516c588
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20210809100642-c13c40a429fa
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
|
||||
go.uber.org/zap v1.17.0
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||
|
|
10
go.sum
10
go.sum
|
@ -98,6 +98,7 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
|
@ -135,6 +136,7 @@ github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D
|
|||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 h1:sgNeV1VRMDzs6rzyPpxyM0jp317hnwiq58Filgag2xw=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0/go.mod h1:J70FGZSbzsjecRTiTzER+3f1KZLNaXkuv+yeFTKoxM8=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
|
@ -166,6 +168,7 @@ github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq
|
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
@ -479,6 +482,7 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
|||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
|
@ -645,6 +649,10 @@ github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+
|
|||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20210809082946-a97da516c588 h1:Lbz8X5Nre0Lg5QgCblmo0AhScWxeN3CVnX+mZ5Hxksk=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20210809082946-a97da516c588/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20210809100642-c13c40a429fa h1:Un1jWl/YWbK1179aMbsEZ6uLlDjjBAjL8KXldho1Umo=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20210809100642-c13c40a429fa/go.mod h1:UkgAKjyQo+Pylt2HTYz/G0PgnxmKOJ9IX/3XiRYQ9Ns=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||
|
@ -763,6 +771,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
|
@ -996,6 +1005,7 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
|
|||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200323114720-3f67cca34472/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
|
|
|
@ -147,7 +147,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
|||
}
|
||||
|
||||
defer func() {
|
||||
err = secretClient.Close()
|
||||
err = secretClient.Close(ctx)
|
||||
if err != nil {
|
||||
log.Error(err, errCloseStoreClient)
|
||||
}
|
||||
|
|
|
@ -90,6 +90,6 @@ func (pm *ParameterStore) GetSecretMap(ctx context.Context, ref esv1alpha1.Exter
|
|||
return secretData, nil
|
||||
}
|
||||
|
||||
func (pm *ParameterStore) Close() error {
|
||||
func (pm *ParameterStore) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -103,6 +103,6 @@ func (sm *SecretsManager) GetSecretMap(ctx context.Context, ref esv1alpha1.Exter
|
|||
return secretData, nil
|
||||
}
|
||||
|
||||
func (sm *SecretsManager) Close() error {
|
||||
func (sm *SecretsManager) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ func (a *Azure) secretKeyRef(ctx context.Context, namespace string, secretRef sm
|
|||
return value, nil
|
||||
}
|
||||
|
||||
func (a *Azure) Close() error {
|
||||
func (a *Azure) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ func (v *Client) WithGetSecret(secData []byte, err error) *Client {
|
|||
func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||
return v.GetSecretMapFn(ctx, ref)
|
||||
}
|
||||
func (v *Client) Close() error {
|
||||
func (v *Client) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ func (sm *ProviderGCP) GetSecretMap(ctx context.Context, ref esv1alpha1.External
|
|||
return secretData, nil
|
||||
}
|
||||
|
||||
func (sm *ProviderGCP) Close() error {
|
||||
func (sm *ProviderGCP) Close(ctx context.Context) error {
|
||||
err := sm.SecretManagerClient.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf(errClientClose, err)
|
||||
|
|
|
@ -289,7 +289,7 @@ func (ibm *providerIBM) GetSecretMap(ctx context.Context, ref esv1alpha1.Externa
|
|||
}
|
||||
}
|
||||
|
||||
func (ibm *providerIBM) Close() error {
|
||||
func (ibm *providerIBM) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -35,5 +35,5 @@ type SecretsClient interface {
|
|||
|
||||
// GetSecretMap returns multiple k/v pairs from the provider
|
||||
GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
|
||||
Close() error
|
||||
Close(ctx context.Context) error
|
||||
}
|
||||
|
|
|
@ -22,4 +22,5 @@ import (
|
|||
_ "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
|
||||
_ "github.com/external-secrets/external-secrets/pkg/provider/ibm"
|
||||
_ "github.com/external-secrets/external-secrets/pkg/provider/vault"
|
||||
_ "github.com/external-secrets/external-secrets/pkg/provider/yandex/lockbox"
|
||||
)
|
||||
|
|
|
@ -41,7 +41,7 @@ func (p *PP) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretData
|
|||
return map[string][]byte{}, nil
|
||||
}
|
||||
|
||||
func (p *PP) Close() error {
|
||||
func (p *PP) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ func (v *client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecret
|
|||
return v.readSecret(ctx, ref.Key, ref.Version)
|
||||
}
|
||||
|
||||
func (v *client) Close() error {
|
||||
func (v *client) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
206
pkg/provider/yandex/lockbox/lockbox.go
Normal file
206
pkg/provider/yandex/lockbox/lockbox.go
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
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 lockbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/yandex-cloud/go-genproto/yandex/cloud/lockbox/v1"
|
||||
ycsdk "github.com/yandex-cloud/go-sdk"
|
||||
"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"
|
||||
|
||||
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider/schema"
|
||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||
)
|
||||
|
||||
// providerLockbox is a provider for Yandex Lockbox.
|
||||
type providerLockbox struct {
|
||||
sdk *ycsdk.SDK
|
||||
}
|
||||
|
||||
// NewClient constructs a Yandex Lockbox Provider.
|
||||
func (p *providerLockbox) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube kclient.Client, namespace string) (provider.SecretsClient, error) {
|
||||
storeSpec := store.GetSpec()
|
||||
if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.YandexLockbox == nil {
|
||||
return nil, fmt.Errorf("received invalid Yandex Lockbox SecretStore resource")
|
||||
}
|
||||
storeSpecYandexLockbox := storeSpec.Provider.YandexLockbox
|
||||
|
||||
authorizedKeySecretName := storeSpecYandexLockbox.Auth.AuthorizedKey.Name
|
||||
if authorizedKeySecretName == "" {
|
||||
return nil, fmt.Errorf("invalid Yandex Lockbox SecretStore resource: missing AuthorizedKey Name")
|
||||
}
|
||||
objectKey := types.NamespacedName{
|
||||
Name: authorizedKeySecretName,
|
||||
Namespace: namespace,
|
||||
}
|
||||
|
||||
// only ClusterStore is allowed to set namespace (and then it's required)
|
||||
if store.GetObjectKind().GroupVersionKind().Kind == esv1alpha1.ClusterSecretStoreKind {
|
||||
if storeSpecYandexLockbox.Auth.AuthorizedKey.Namespace == nil {
|
||||
return nil, fmt.Errorf("invalid ClusterSecretStore: missing AuthorizedKey Namespace")
|
||||
}
|
||||
objectKey.Namespace = *storeSpecYandexLockbox.Auth.AuthorizedKey.Namespace
|
||||
}
|
||||
|
||||
authorizedKeySecret := &corev1.Secret{}
|
||||
err := kube.Get(ctx, objectKey, authorizedKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch AuthorizedKey secret: %w", err)
|
||||
}
|
||||
|
||||
authorizedKeySecretData := authorizedKeySecret.Data[storeSpecYandexLockbox.Auth.AuthorizedKey.Key]
|
||||
if (authorizedKeySecretData == nil) || (len(authorizedKeySecretData) == 0) {
|
||||
return nil, fmt.Errorf("missing AuthorizedKey")
|
||||
}
|
||||
|
||||
var authorizedKey iamkey.Key
|
||||
err = json.Unmarshal(authorizedKeySecretData, &authorizedKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal authorized key: %w", err)
|
||||
}
|
||||
|
||||
credentials, err := ycsdk.ServiceAccountKey(&authorizedKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create credentials: %w", err)
|
||||
}
|
||||
|
||||
sdk, err := ycsdk.Build(ctx, ycsdk.Config{
|
||||
Credentials: credentials,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create Yandex.Cloud SDK: %w", err)
|
||||
}
|
||||
|
||||
p.sdk = sdk
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// GetSecret returns a single secret from the provider.
|
||||
func (p *providerLockbox) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||
entries, err := requestPayload(ctx, p.sdk, ref.Key, ref.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ref.Property == "" {
|
||||
keyToValue := make(map[string]interface{}, len(entries))
|
||||
for _, entry := range entries {
|
||||
value, err := getValueAsIs(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyToValue[entry.Key] = value
|
||||
}
|
||||
out, err := json.Marshal(keyToValue)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal secret: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
entry, err := findEntryByKey(entries, ref.Property)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getValueAsBinary(entry)
|
||||
}
|
||||
|
||||
// GetSecret returns a single secret from the provider.
|
||||
func requestPayload(ctx context.Context, sdk *ycsdk.SDK, secretID, versionID string) ([]*lockbox.Payload_Entry, error) {
|
||||
if utils.IsNil(sdk) {
|
||||
return nil, fmt.Errorf("provider Yandex Lockbox is not initialized")
|
||||
}
|
||||
|
||||
payload, err := sdk.LockboxPayload().Payload().Get(ctx, &lockbox.GetPayloadRequest{
|
||||
SecretId: secretID,
|
||||
VersionId: versionID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get secret payload: %w", err)
|
||||
}
|
||||
|
||||
return payload.Entries, nil
|
||||
}
|
||||
|
||||
// GetSecretMap returns multiple k/v pairs from the provider.
|
||||
func (p *providerLockbox) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||
entries, err := requestPayload(ctx, p.sdk, ref.Key, ref.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secretMap := make(map[string][]byte, len(entries))
|
||||
for _, entry := range entries {
|
||||
value, err := getValueAsBinary(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secretMap[entry.Key] = value
|
||||
}
|
||||
return secretMap, nil
|
||||
}
|
||||
|
||||
func (p *providerLockbox) Close(ctx context.Context) error {
|
||||
err := p.sdk.Shutdown(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to shutdown Yandex.Cloud SDK: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getValueAsIs(entry *lockbox.Payload_Entry) (interface{}, error) {
|
||||
switch entry.Value.(type) {
|
||||
case *lockbox.Payload_Entry_TextValue:
|
||||
return entry.GetTextValue(), nil
|
||||
case *lockbox.Payload_Entry_BinaryValue:
|
||||
return entry.GetBinaryValue(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported payload value type, key: %v", entry.Key)
|
||||
}
|
||||
}
|
||||
|
||||
func getValueAsBinary(entry *lockbox.Payload_Entry) ([]byte, error) {
|
||||
switch entry.Value.(type) {
|
||||
case *lockbox.Payload_Entry_TextValue:
|
||||
return []byte(entry.GetTextValue()), nil
|
||||
case *lockbox.Payload_Entry_BinaryValue:
|
||||
return entry.GetBinaryValue(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported payload value type, key: %v", entry.Key)
|
||||
}
|
||||
}
|
||||
|
||||
func findEntryByKey(entries []*lockbox.Payload_Entry, key string) (*lockbox.Payload_Entry, error) {
|
||||
for i := range entries {
|
||||
if entries[i].Key == key {
|
||||
return entries[i], nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("payload entry with key '%s' not found", key)
|
||||
}
|
||||
|
||||
func init() {
|
||||
schema.Register(&providerLockbox{}, &esv1alpha1.SecretStoreProvider{
|
||||
YandexLockbox: &esv1alpha1.YandexLockboxProvider{},
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue