186 lines
5.4 KiB
Go
186 lines
5.4 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
|
|
}
|
|
|
|
// 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
|
|
}
|