~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
73 lines · 1.6 KB Raw History
package kubeconfig

import (
	"errors"
	"fmt"
	"net/url"

	"sigs.k8s.io/yaml"
)

var ErrNotHTTPS = errors.New("kubeconfig: server must be https")

type ClientCertInput struct {
	ClusterName string

	Server string

	CACertPEM []byte

	CertPEM []byte

	KeyPEM []byte
}

func BuildClientCert(in ClientCertInput) (string, error) {
	if in.ClusterName == "" {
		return "", errors.New("kubeconfig: empty cluster name")
	}
	if in.Server == "" {
		return "", errors.New("kubeconfig: empty server")
	}
	u, err := url.Parse(in.Server)
	if err != nil {
		return "", fmt.Errorf("kubeconfig: unparseable server: %w", err)
	}
	if u.Scheme != "https" {
		return "", fmt.Errorf("%w (got %q)", ErrNotHTTPS, u.Scheme)
	}
	if len(in.CertPEM) == 0 || len(in.KeyPEM) == 0 {
		return "", errors.New("kubeconfig: a client certificate and its key are required")
	}

	cluster := map[string]any{"server": in.Server}
	if len(in.CACertPEM) > 0 {
		cluster["certificate-authority-data"] = in.CACertPEM
	}
	user := map[string]any{
		"client-certificate-data": in.CertPEM,
		"client-key-data":         in.KeyPEM,
	}
	doc := map[string]any{
		"apiVersion": "v1",
		"kind":       "Config",
		"clusters": []map[string]any{
			{"name": in.ClusterName, "cluster": cluster},
		},
		"users": []map[string]any{
			{"name": in.ClusterName, "user": user},
		},
		"contexts": []map[string]any{
			{"name": in.ClusterName, "context": map[string]any{
				"cluster": in.ClusterName,
				"user":    in.ClusterName,
			}},
		},
		"current-context": in.ClusterName,
	}
	raw, err := yaml.Marshal(doc)
	if err != nil {
		return "", fmt.Errorf("kubeconfig: marshal: %w", err)
	}
	return string(raw), nil
}