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 } // CreateGhcrExternalSecret generates and applies the ExternalSecret for GHCR. func CreateGhcrExternalSecret() error { fmt.Println("[INFO] Creating ExternalSecret for GHCR in 'flux-system' namespace...") externalSecret := ExternalSecret{ ApiVersion: "external-secrets.io/v1", Kind: "ExternalSecret", Metadata: Metadata{ Name: "ghcr-auth", Namespace: "flux-system", }, Spec: ExternalSecretSpec{ SecretStoreRef: SecretStoreRef{ Name: "vault-backend", Kind: "ClusterSecretStore", }, Target: ExternalSecretTarget{ Name: "ghcr-auth", CreationPolicy: "Owner", Template: ExternalSecretTemplate{ Type: "kubernetes.io/dockerconfigjson", Data: map[string]string{ ".dockerconfigjson": `{{ index . ".dockerconfigjson" | toString }}`, }, }, }, Data: []ExternalSecretData{ { SecretKey: ".dockerconfigjson", RemoteRef: ExternalSecretDataRemoteRef{ Key: vault.GhcrSecretPath, 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 'ghcr-auth' in 'flux-system' namespace.\n") 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 }