smartconfig/resolver_k8s.go
sneak 8a38afba5e passes tests, has cli filter now.
* still has not been *really* tested yet
2025-07-20 15:29:06 +02:00

60 lines
1.5 KiB
Go

package smartconfig
import (
"context"
"fmt"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// K8SSecretResolver retrieves secrets from Kubernetes.
// Usage: ${K8SS:namespace/secretname:key}
type K8SSecretResolver struct{}
// Resolve retrieves the secret value from Kubernetes.
func (r *K8SSecretResolver) Resolve(value string) (string, error) {
// Expect format: "namespace/secretname:key"
parts := strings.SplitN(value, ":", 2)
if len(parts) != 2 {
return "", fmt.Errorf("invalid K8S secret format, expected NAMESPACE/SECRET:KEY")
}
secretPath := parts[0]
key := parts[1]
pathParts := strings.SplitN(secretPath, "/", 2)
if len(pathParts) != 2 {
return "", fmt.Errorf("invalid K8S secret path format, expected NAMESPACE/SECRET")
}
namespace := pathParts[0]
secretName := pathParts[1]
config, err := rest.InClusterConfig()
if err != nil {
// Fall back to kubeconfig
return "", fmt.Errorf("failed to get K8S config: %w", err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return "", fmt.Errorf("failed to create K8S client: %w", err)
}
ctx := context.Background()
secret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{})
if err != nil {
return "", fmt.Errorf("failed to get secret %s/%s: %w", namespace, secretName, err)
}
data, ok := secret.Data[key]
if !ok {
return "", fmt.Errorf("key %s not found in secret %s/%s", key, namespace, secretName)
}
return string(data), nil
}