|
@@ -32,12 +32,10 @@ import (
|
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
|
|
|
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
|
|
- esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
|
|
|
|
"github.com/external-secrets/external-secrets/pkg/constants"
|
|
"github.com/external-secrets/external-secrets/pkg/constants"
|
|
|
"github.com/external-secrets/external-secrets/pkg/metrics"
|
|
"github.com/external-secrets/external-secrets/pkg/metrics"
|
|
|
"github.com/external-secrets/external-secrets/pkg/template/v2"
|
|
"github.com/external-secrets/external-secrets/pkg/template/v2"
|
|
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
|
|
- "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
|
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
type Webhook struct {
|
|
type Webhook struct {
|
|
@@ -134,19 +132,29 @@ func (w *Webhook) GetTemplateData(ctx context.Context, ref *esv1beta1.ExternalSe
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if err := w.getTemplatedSecrets(ctx, secrets, data); err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return data, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (w *Webhook) getTemplatedSecrets(ctx context.Context, secrets []Secret, data map[string]map[string]string) error {
|
|
|
for _, secref := range secrets {
|
|
for _, secref := range secrets {
|
|
|
if _, ok := data[secref.Name]; !ok {
|
|
if _, ok := data[secref.Name]; !ok {
|
|
|
data[secref.Name] = make(map[string]string)
|
|
data[secref.Name] = make(map[string]string)
|
|
|
}
|
|
}
|
|
|
secret, err := w.getStoreSecret(ctx, secref.SecretRef)
|
|
secret, err := w.getStoreSecret(ctx, secref.SecretRef)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
|
|
|
|
+ return err
|
|
|
}
|
|
}
|
|
|
for sKey, sVal := range secret.Data {
|
|
for sKey, sVal := range secret.Data {
|
|
|
data[secref.Name][sKey] = string(sVal)
|
|
data[secref.Name][sKey] = string(sVal)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return data, nil
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (w *Webhook) GetWebhookData(ctx context.Context, provider *Spec, ref *esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
|
func (w *Webhook) GetWebhookData(ctx context.Context, provider *Spec, ref *esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
|
@@ -176,10 +184,52 @@ func (w *Webhook) GetWebhookData(ctx context.Context, provider *Spec, ref *esv1b
|
|
|
return nil, fmt.Errorf("failed to parse body: %w", err)
|
|
return nil, fmt.Errorf("failed to parse body: %w", err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- req, err := http.NewRequestWithContext(ctx, method, url, &body)
|
|
|
|
|
|
|
+ return w.executeRequest(ctx, provider, body.Bytes(), url, method, rawData)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (w *Webhook) PushWebhookData(ctx context.Context, provider *Spec, data []byte, remoteKey esv1beta1.PushSecretData) error {
|
|
|
|
|
+ if w.HTTP == nil {
|
|
|
|
|
+ return errors.New("http client not initialized")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ method := provider.Method
|
|
|
|
|
+ if method == "" {
|
|
|
|
|
+ method = http.MethodPost
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rawData := map[string]map[string]string{
|
|
|
|
|
+ "remoteRef": {
|
|
|
|
|
+ "remoteKey": url.QueryEscape(remoteKey.GetRemoteKey()),
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+ if remoteKey.GetSecretKey() != "" {
|
|
|
|
|
+ rawData["remoteRef"]["secretKey"] = url.QueryEscape(remoteKey.GetSecretKey())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ turl, err := ExecuteTemplateString(provider.URL, rawData)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to parse url: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ dataMap := make(map[string]map[string]string)
|
|
|
|
|
+ if err := w.getTemplatedSecrets(ctx, provider.Secrets, dataMap); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // read the body into the void to prevent remaining garbage to be present
|
|
|
|
|
+ if _, err := w.executeRequest(ctx, provider, data, turl, method, dataMap); err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to push webhook data: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (w *Webhook) executeRequest(ctx context.Context, provider *Spec, data []byte, url, method string, rawData map[string]map[string]string) ([]byte, error) {
|
|
|
|
|
+ req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(data))
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
for hKey, hValueTpl := range provider.Headers {
|
|
for hKey, hValueTpl := range provider.Headers {
|
|
|
hValue, err := ExecuteTemplateString(hValueTpl, rawData)
|
|
hValue, err := ExecuteTemplateString(hValueTpl, rawData)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -251,56 +301,6 @@ func (w *Webhook) GetCACertPool(ctx context.Context, provider *Spec) (*x509.Cert
|
|
|
return caCertPool, nil
|
|
return caCertPool, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (w *Webhook) GetCertFromSecret(provider *Spec) ([]byte, error) {
|
|
|
|
|
- secretRef := esmeta.SecretKeySelector{
|
|
|
|
|
- Name: provider.CAProvider.Name,
|
|
|
|
|
- Namespace: &w.Namespace,
|
|
|
|
|
- Key: provider.CAProvider.Key,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if provider.CAProvider.Namespace != nil {
|
|
|
|
|
- secretRef.Namespace = provider.CAProvider.Namespace
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ctx := context.Background()
|
|
|
|
|
- cert, err := resolvers.SecretKeyRef(
|
|
|
|
|
- ctx,
|
|
|
|
|
- w.Kube,
|
|
|
|
|
- w.StoreKind,
|
|
|
|
|
- w.Namespace,
|
|
|
|
|
- &secretRef,
|
|
|
|
|
- )
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return nil, err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return []byte(cert), nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (w *Webhook) GetCertFromConfigMap(provider *Spec) ([]byte, error) {
|
|
|
|
|
- objKey := client.ObjectKey{
|
|
|
|
|
- Name: provider.CAProvider.Name,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if provider.CAProvider.Namespace != nil {
|
|
|
|
|
- objKey.Namespace = *provider.CAProvider.Namespace
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- configMapRef := &corev1.ConfigMap{}
|
|
|
|
|
- ctx := context.Background()
|
|
|
|
|
- err := w.Kube.Get(ctx, objKey, configMapRef)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- 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 []byte(val), nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
func ExecuteTemplateString(tmpl string, data map[string]map[string]string) (string, error) {
|
|
func ExecuteTemplateString(tmpl string, data map[string]map[string]string) (string, error) {
|
|
|
result, err := ExecuteTemplate(tmpl, data)
|
|
result, err := ExecuteTemplate(tmpl, data)
|
|
|
if err != nil {
|
|
if err != nil {
|