pkg/secretref/secretref.go (81 lines of code) (raw):

package secretref import ( "context" "fmt" "strings" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) const ( secretRefPrefix = "$" keycloakSecretRefPrefix = "${" ) //go:generate mockery --name RefClient --filename ref_mock.go type RefClient interface { MapConfigSecretsRefs(ctx context.Context, config map[string]string, namespace string) error MapComponentConfigSecretsRefs(ctx context.Context, config map[string][]string, namespace string) error GetSecretFromRef(ctx context.Context, refVal, secretNamespace string) (string, error) } // SecretRef provides methods to work with secret references. type SecretRef struct { client client.Client } // NewSecretRef returns a new instance of SecretRef. func NewSecretRef(client client.Client) *SecretRef { return &SecretRef{client: client} } // MapConfigSecretsRefs maps secret references in config map to actual values. func (s *SecretRef) MapConfigSecretsRefs(ctx context.Context, config map[string]string, namespace string) error { for k, v := range config { if !HasSecretRef(v) { continue } secretVal, err := s.GetSecretFromRef(ctx, v, namespace) if err != nil { return err } config[k] = secretVal } return nil } // MapConfigSecretsRefs maps secret references in config map to actual values. func (s *SecretRef) MapComponentConfigSecretsRefs(ctx context.Context, config map[string][]string, namespace string) error { for k, values := range config { for i, v := range values { if !HasSecretRef(v) { continue } secretVal, err := s.GetSecretFromRef(ctx, v, namespace) if err != nil { return err } config[k][i] = secretVal } } return nil } // GetSecretFromRef returns secret value from secret reference. func (s *SecretRef) GetSecretFromRef(ctx context.Context, refVal, secretNamespace string) (string, error) { if !HasSecretRef(refVal) { return "", fmt.Errorf("invalid config secret reference %s is not in format '$secretName:secretKey'", refVal) } // Skip keycloak references format. This mapping is managed by the Keycloak service. if strings.HasPrefix(refVal, keycloakSecretRefPrefix) { return refVal, nil } ref := strings.Split(refVal[1:], ":") if len(ref) != 2 { return "", fmt.Errorf("invalid config secret reference %s is not in format '$secretName:secretKey'", refVal) } secret := &corev1.Secret{} if err := s.client.Get(ctx, client.ObjectKey{ Namespace: secretNamespace, Name: ref[0], }, secret); err != nil { return "", fmt.Errorf("failed to get secret %s: %w", ref[0], err) } secretVal, ok := secret.Data[ref[1]] if !ok { return "", fmt.Errorf("secret %s does not contain key %s", ref[0], ref[1]) } return string(secretVal), nil } // HasSecretRef checks if value has secret reference. func HasSecretRef(val string) bool { return strings.HasPrefix(val, secretRefPrefix) } // GenerateSecretRef generates secret reference. func GenerateSecretRef(secretName, secretFiled string) string { return fmt.Sprintf("%s%s:%s", secretRefPrefix, secretName, secretFiled) }