kube-1password-secrets/main.go

132 lines
3.0 KiB
Go

package main
import (
"context"
"fmt"
"os"
"os/user"
"time"
"git.cloud.cluster.fun/AverageMarcus/kube-1password-secrets/internal/onepassword"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
const (
idAnnotation = "kube-1password"
vaultAnnotation = "kube-1password/vault"
usernameAnnotation = "kube-1password/username-key"
passwordAnnotation = "kube-1password/password-key"
secretTextAnnotation = "kube-1password/secret-text-key"
)
func main() {
opClient, err := buildOpClient()
if err != nil {
panic(err.Error())
}
config, err := rest.InClusterConfig()
if err != nil {
panic(err.Error())
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
for {
list, err := clientset.CoreV1().Secrets(apiv1.NamespaceAll).List(context.Background(), metav1.ListOptions{})
if err != nil {
panic(err)
}
for _, s := range list.Items {
if passwordID, exists := s.ObjectMeta.Annotations[idAnnotation]; exists {
keys := parseAnnotations(s.ObjectMeta.Annotations)
vault := keys["vault"]
item, err := opClient.GetSecret(vault, passwordID)
if err != nil {
fmt.Println("[ERROR] Could not get secret", err)
continue
}
s.Data = make(map[string][]byte)
if item.Username != "" {
s.Data[keys["username"]] = []byte(item.Username)
}
if item.Password != "" {
s.Data[keys["password"]] = []byte(item.Password)
}
if item.SecretText != "" {
s.Data[keys["secretText"]] = []byte(item.SecretText)
}
if _, err := clientset.CoreV1().Secrets(s.GetNamespace()).Update(context.Background(), &s, metav1.UpdateOptions{}); err != nil {
fmt.Println("[ERROR] Could not update secret value", err)
continue
}
}
}
time.Sleep(5 * time.Minute)
}
}
func buildOpClient() (*onepassword.Client, error) {
usr, _ := user.Current()
err := os.Chmod(usr.HomeDir+"/.op", 0700)
if err != nil {
panic(err.Error())
}
domain, ok := os.LookupEnv("OP_DOMAIN")
if !ok {
return nil, fmt.Errorf("OP_DOMAIN not specified")
}
email, ok := os.LookupEnv("OP_EMAIL")
if !ok {
return nil, fmt.Errorf("OP_EMAIL not specified")
}
password, ok := os.LookupEnv("OP_PASSWORD")
if !ok {
return nil, fmt.Errorf("OP_PASSWORD not specified")
}
secretKey, ok := os.LookupEnv("OP_SECRET_KEY")
if !ok {
return nil, fmt.Errorf("OP_SECRET_KEY not specified")
}
return onepassword.New(domain, email, password, secretKey)
}
func parseAnnotations(annotations map[string]string) map[string]string {
keys := map[string]string{
"username": "username",
"password": "password",
"secretText": "secretText",
"vault": os.Getenv("OP_VAULT"),
}
for k, v := range annotations {
switch k {
case vaultAnnotation:
keys["vault"] = v
case usernameAnnotation:
keys["username"] = v
case passwordAnnotation:
keys["password"] = v
case secretTextAnnotation:
keys["secretText"] = v
}
}
return keys
}