maidn-cli/internal/k8s/external_secret.go

132 lines
3.9 KiB
Go

package k8s
import (
"bytes"
"fmt"
"os/exec"
"strings"
"github.com/Pingu-Studio/MaidnCLI/internal/vault"
"gopkg.in/yaml.v3"
)
// ExternalSecret Structs to represent the YAML structure
type ExternalSecret struct {
ApiVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Metadata Metadata `yaml:"metadata"`
Spec ExternalSecretSpec `yaml:"spec"`
}
type Metadata struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
}
type ExternalSecretSpec struct {
SecretStoreRef SecretStoreRef `yaml:"secretStoreRef"`
Target ExternalSecretTarget `yaml:"target"`
Data []ExternalSecretData `yaml:"data"`
}
type SecretStoreRef struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
}
type ExternalSecretTarget struct {
Name string `yaml:"name"`
CreationPolicy string `yaml:"creationPolicy"`
Template ExternalSecretTemplate `yaml:"template,omitempty"`
}
type ExternalSecretTemplate struct {
Type string `yaml:"type"`
Data map[string]string `yaml:"data"`
}
type ExternalSecretData struct {
SecretKey string `yaml:"secretKey"`
RemoteRef ExternalSecretDataRemoteRef `yaml:"remoteRef"`
}
type ExternalSecretDataRemoteRef struct {
Key string `yaml:"key"`
Property string `yaml:"property"`
}
// CheckExternalSecretCRD checks if the ExternalSecret CRD is installed on the cluster.
func CheckExternalSecretCRD() error {
fmt.Println("[INFO] Verifying that the ExternalSecret CRD is installed...")
// Use api-resources to check if the resource kind exists in the specified API group
cmd := exec.Command("kubectl", "api-resources", "--api-group=external-secrets.io", "-o", "name")
output, err := cmd.CombinedOutput()
if err != nil {
// This error occurs if kubectl fails or the API group doesn't exist at all.
return fmt.Errorf("failed to query for ExternalSecret CRD. Is kubectl configured correctly? Error: %w\nOutput: %s", err, string(output))
}
// We expect the output to contain "externalsecrets.external-secrets.io"
if !strings.Contains(string(output), "externalsecrets.external-secrets.io") {
return fmt.Errorf("the 'ExternalSecret' CRD was not found on the cluster. Please install the External Secrets Operator first.\nSee: https://external-secrets.io/latest/getting-started/installation/")
}
fmt.Println("[SUCCESS] ExternalSecret CRD found.")
return nil
}
// CreateDockerHubExternalSecret generates and applies the ExternalSecret for Docker Hub.
func CreateDockerHubExternalSecret() error {
fmt.Println("[INFO] Creating ExternalSecret for Docker Hub in 'flux-system' namespace...")
externalSecret := ExternalSecret{
ApiVersion: "external-secrets.io/v1",
Kind: "ExternalSecret",
Metadata: Metadata{
Name: "dockerhub-auth",
Namespace: "flux-system",
},
Spec: ExternalSecretSpec{
SecretStoreRef: SecretStoreRef{
Name: "vault-backend",
Kind: "ClusterSecretStore",
},
Target: ExternalSecretTarget{
Name: "dockerhub-auth",
CreationPolicy: "Owner",
Template: ExternalSecretTemplate{
Type: "kubernetes.io/dockerconfigjson",
Data: map[string]string{
".dockerconfigjson": "{{ .dockerconfigjson }}",
},
},
},
Data: []ExternalSecretData{
{
SecretKey: "dockerconfigjson",
RemoteRef: ExternalSecretDataRemoteRef{
Key: vault.DockerHubSecretPath,
Property: vault.DockerConfigJSONKey,
},
},
},
},
}
yamlData, err := yaml.Marshal(&externalSecret)
if err != nil {
return fmt.Errorf("failed to marshal ExternalSecret to YAML: %w", err)
}
cmd := exec.Command("kubectl", "apply", "-f", "-")
cmd.Stdin = bytes.NewReader(yamlData)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to apply ExternalSecret: %s\n%w", string(output), err)
}
fmt.Printf("[SUCCESS] Applied ExternalSecret 'dockerhub-auth' in 'flux-system' namespace.\n")
return nil
}