Skip to content

Commit

Permalink
improve: read kube config from client config
Browse files Browse the repository at this point in the history
Previously we would only look for in-cluster config. This change allows
the connector to fall back to the cli config if there is no in-cluster
config.

Also read the CA cert from the existing config, instead of reading the
file again.
  • Loading branch information
dnephin committed Sep 27, 2022
1 parent a1f771a commit d699f2f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 52 deletions.
20 changes: 5 additions & 15 deletions internal/connector/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,10 @@ func Run(ctx context.Context, options Options) error {
return err
}

chksm, err := k8s.Checksum()
if err != nil {
logging.Errorf("k8s checksum error: %s", err)
return err
}
checkSum := k8s.Checksum()

if options.Name == "" {
autoname, err := k8s.Name(chksm)
autoname, err := k8s.Name(checkSum)
if err != nil {
logging.Errorf("k8s name error: %s", err)
return err
Expand Down Expand Up @@ -103,7 +99,7 @@ func Run(ctx context.Context, options Options) error {

destination := &api.Destination{
Name: options.Name,
UniqueID: chksm,
UniqueID: checkSum,
}

// clone the default http transport which sets reasonable defaults
Expand Down Expand Up @@ -133,7 +129,7 @@ func Run(ctx context.Context, options Options) error {
Transport: httpTransportFromOptions(options.Server),
},
Headers: http.Header{
"Infra-Destination": {chksm},
"Infra-Destination": {checkSum},
},
OnUnauthorized: func() {
logging.Errorf("Unauthorized error; token invalid or expired. exiting.")
Expand Down Expand Up @@ -172,14 +168,8 @@ func Run(ctx context.Context, options Options) error {
return fmt.Errorf("parsing host config: %w", err)
}

clusterCACert, err := kubernetes.CA()
if err != nil {
return fmt.Errorf("reading CA file: %w", err)
}

certPool := x509.NewCertPool()

if ok := certPool.AppendCertsFromPEM(clusterCACert); !ok {
if ok := certPool.AppendCertsFromPEM(k8s.Config.CAData); !ok {
return errors.New("could not append CA to client cert bundle")
}

Expand Down
63 changes: 26 additions & 37 deletions internal/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,44 +24,48 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
rest "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"

"github.com/infrahq/infra/internal/logging"
)

const (
podLabelsFilePath = "/etc/podinfo/labels"
namespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
caFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)

type Kubernetes struct {
Config *rest.Config
SecretReader secrets.SecretStorage
Namespace string
}

func NewKubernetes() (*Kubernetes, error) {
k := &Kubernetes{}

config, err := rest.InClusterConfig()
if err != nil {
return k, err
logging.Warnf("failed to create in cluster config: %v", err)

loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
cfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
config, err = cfg.ClientConfig()
if err != nil {
return nil, fmt.Errorf("failed to read kube config: %w", err)
}
}

k.Config = config

namespace, err := Namespace()
// TODO: there should be a way to get the namespace from the config
k.Namespace, err = readNamespaceFromFile()
if err != nil {
return k, err
logging.Warnf("failed to read namespace file: %v", err)
k.Namespace = "default"
}

clientset, err := kubernetes.NewForConfig(k.Config)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create kube clientset: %w", err)
}

k.SecretReader = secrets.NewKubernetesSecretProvider(clientset, namespace)

return k, err
k.SecretReader = secrets.NewKubernetesSecretProvider(clientset, k.Namespace)
return k, nil
}

// namespaceRole is used as a tuple to pair namespaces and grants as a map key
Expand Down Expand Up @@ -461,16 +465,11 @@ func (k *Kubernetes) kubeControllerManagerClusterName() (string, error) {
return opts.ClusterName, nil
}

func (k *Kubernetes) Checksum() (string, error) {
ca, err := CA()
if err != nil {
return "", err
}

func (k *Kubernetes) Checksum() string {
h := sha256.New()
h.Write(ca)
h.Write(k.Config.CAData)
hash := h.Sum(nil)
return hex.EncodeToString(hash), nil
return hex.EncodeToString(hash)
}

func (k *Kubernetes) Name(chksm string) (string, error) {
Expand Down Expand Up @@ -501,6 +500,8 @@ func (k *Kubernetes) Name(chksm string) (string, error) {
return name, nil
}

const podLabelsFilePath = "/etc/podinfo/labels"

func PodLabels() ([]string, error) {
contents, err := ioutil.ReadFile(podLabelsFilePath)
if err != nil {
Expand Down Expand Up @@ -528,7 +529,9 @@ func InstancePodLabels() ([]string, error) {
return instanceLabels, nil
}

func Namespace() (string, error) {
const namespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"

func readNamespaceFromFile() (string, error) {
contents, err := ioutil.ReadFile(namespaceFilePath)
if err != nil {
return "", err
Expand All @@ -537,34 +540,20 @@ func Namespace() (string, error) {
return string(contents), nil
}

func CA() ([]byte, error) {
contents, err := ioutil.ReadFile(caFilePath)
if err != nil {
return nil, err
}

return contents, nil
}

// Find the first suitable Service, filtering on infrahq.com/component
func (k *Kubernetes) Service(component string, labels ...string) (*corev1.Service, error) {
clientset, err := kubernetes.NewForConfig(k.Config)
if err != nil {
return nil, err
}

namespace, err := Namespace()
if err != nil {
return nil, err
}

selector := []string{
fmt.Sprintf("app.infrahq.com/component=%s", component),
}

selector = append(selector, labels...)

services, err := clientset.CoreV1().Services(namespace).List(context.Background(), metav1.ListOptions{
services, err := clientset.CoreV1().Services(k.Namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: strings.Join(selector, ","),
})
if err != nil {
Expand Down

0 comments on commit d699f2f

Please sign in to comment.