60 lines
1.5 KiB
Go
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
|
|
}
|