From 3f06be224658ee811fddd6382ce3764689177d81 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Thu, 24 Sep 2020 09:23:29 -0700 Subject: [PATCH] Remove kubecertauthority pkg All of its functionality was refactored to move elsewhere or to not be needed anymore by previous commits --- .../kubecertauthority/kubecertauthority.go | 262 ----------- .../kubecertauthority_test.go | 426 ------------------ .../kubecertauthority/testdata/test.crt | 17 - .../kubecertauthority/testdata/test.key | 27 -- .../kubecertauthority/testdata/test2.crt | 17 - .../kubecertauthority/testdata/test2.key | 27 -- 6 files changed, 776 deletions(-) delete mode 100644 internal/certauthority/kubecertauthority/kubecertauthority.go delete mode 100644 internal/certauthority/kubecertauthority/kubecertauthority_test.go delete mode 100644 internal/certauthority/kubecertauthority/testdata/test.crt delete mode 100644 internal/certauthority/kubecertauthority/testdata/test.key delete mode 100644 internal/certauthority/kubecertauthority/testdata/test2.crt delete mode 100644 internal/certauthority/kubecertauthority/testdata/test2.key diff --git a/internal/certauthority/kubecertauthority/kubecertauthority.go b/internal/certauthority/kubecertauthority/kubecertauthority.go deleted file mode 100644 index a966c2e4..00000000 --- a/internal/certauthority/kubecertauthority/kubecertauthority.go +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2020 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -// Package kubecertauthority implements a signer backed by the kubernetes controller-manager signing -// keys (accessed via the kubernetes Exec API). -package kubecertauthority - -import ( - "bytes" - "context" - "crypto/x509/pkix" - "fmt" - "sync" - "time" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/deprecated/scheme" - "k8s.io/client-go/kubernetes" - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/remotecommand" - "k8s.io/klog/v2" - - "go.pinniped.dev/internal/certauthority" - "go.pinniped.dev/internal/constable" -) - -// ErrNoKubeCertAgentPod is returned when no kube-cert-agent pod is found on the cluster. -const ErrNoKubeCertAgentPod = constable.Error("did not find kube-cert-agent pod") -const ErrIncapableOfIssuingCertificates = constable.Error("this cluster is not currently capable of issuing certificates") - -const k8sAPIServerCACertPEMDefaultPath = "/etc/kubernetes/ca/ca.pem" -const k8sAPIServerCAKeyPEMDefaultPath = "/etc/kubernetes/ca/ca.key" - -type signer interface { - IssuePEM(subject pkix.Name, dnsNames []string, ttl time.Duration) ([]byte, []byte, error) -} - -type PodCommandExecutor interface { - Exec(podNamespace string, podName string, commandAndArgs ...string) (stdoutResult string, err error) -} - -type kubeClientPodCommandExecutor struct { - kubeConfig *restclient.Config - kubeClient kubernetes.Interface -} - -func NewPodCommandExecutor(kubeConfig *restclient.Config, kubeClient kubernetes.Interface) PodCommandExecutor { - return &kubeClientPodCommandExecutor{kubeConfig: kubeConfig, kubeClient: kubeClient} -} - -func (s *kubeClientPodCommandExecutor) Exec(podNamespace string, podName string, commandAndArgs ...string) (string, error) { - request := s.kubeClient. - CoreV1(). - RESTClient(). - Post(). - Namespace(podNamespace). - Resource("pods"). - Name(podName). - SubResource("exec"). - VersionedParams(&v1.PodExecOptions{ - Stdin: false, - Stdout: true, - Stderr: false, - TTY: false, - Command: commandAndArgs, - }, scheme.ParameterCodec) - - executor, err := remotecommand.NewSPDYExecutor(s.kubeConfig, "POST", request.URL()) - if err != nil { - return "", err - } - - var stdoutBuf bytes.Buffer - if err := executor.Stream(remotecommand.StreamOptions{Stdout: &stdoutBuf}); err != nil { - return "", err - } - return stdoutBuf.String(), nil -} - -// AgentInfo is a data object that holds the fields necessary for a CA to communicate with an agent -// pod. -type AgentInfo struct { - // Namespace is the namespace in which the agent pod is running. - Namespace string - // LabelSelector is a label selector (e.g., "label-key=label=value") that can be used to filter - // the agent pods. - LabelSelector string - // CertPathAnnotation is the annotation used by the agent pod to indicate the path to the CA cert - // inside the pod. - CertPathAnnotation string - // KeyPathAnnotation is the annotation used by the agent pod to indicate the path to the CA key - // inside the pod. - KeyPathAnnotation string -} - -type CA struct { - agentInfo *AgentInfo - - kubeClient kubernetes.Interface - podCommandExecutor PodCommandExecutor - - shutdown, done chan struct{} - - onSuccessfulRefresh SuccessCallback - onFailedRefresh FailureCallback - - lock sync.RWMutex - activeSigner signer -} - -type ShutdownFunc func() -type SuccessCallback func() -type FailureCallback func(error) - -// New creates a new instance of a CA. It tries to load the kube API server's private key -// immediately. If that succeeds then it calls the success callback and it is ready to issue certs. -// When it fails to get the kube API server's private key, then it calls the failure callback and -// it will try again on the next tick. It starts a goroutine to periodically reload the kube -// API server's private key in case it failed previously or case the key has changed. It returns -// a function that can be used to shut down that goroutine. Future attempts made by that goroutine -// to get the key will also result in success or failure callbacks. -// -// The CA will try to read (via cat(1)) the kube API server's private key from an agent pod located -// via the provided agentInfo. -func New( - agentInfo *AgentInfo, - kubeClient kubernetes.Interface, - podCommandExecutor PodCommandExecutor, - tick <-chan time.Time, - onSuccessfulRefresh SuccessCallback, - onFailedRefresh FailureCallback, -) (*CA, ShutdownFunc) { - signer, err := createSignerWithAPIServerSecret(agentInfo, kubeClient, podCommandExecutor) - if err != nil { - klog.Errorf("could not initially fetch the API server's signing key: %s", err) - signer = nil - onFailedRefresh(err) - } else { - onSuccessfulRefresh() - } - result := &CA{ - agentInfo: agentInfo, - kubeClient: kubeClient, - podCommandExecutor: podCommandExecutor, - shutdown: make(chan struct{}), - done: make(chan struct{}), - onSuccessfulRefresh: onSuccessfulRefresh, - onFailedRefresh: onFailedRefresh, - activeSigner: signer, - } - go result.refreshLoop(tick) - return result, result.shutdownRefresh -} - -func createSignerWithAPIServerSecret( - agentInfo *AgentInfo, - kubeClient kubernetes.Interface, - podCommandExecutor PodCommandExecutor, -) (signer, error) { - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - - pod, err := findCertAgentPod(ctx, kubeClient, agentInfo.Namespace, agentInfo.LabelSelector) - if err != nil { - return nil, err - } - certPath, keyPath := getKeypairFilePaths(pod, agentInfo) - - certPEM, err := podCommandExecutor.Exec(pod.Namespace, pod.Name, "cat", certPath) - if err != nil { - return nil, err - } - - keyPEM, err := podCommandExecutor.Exec(pod.Namespace, pod.Name, "cat", keyPath) - if err != nil { - return nil, err - } - - return certauthority.Load(certPEM, keyPEM) -} - -func (c *CA) refreshLoop(tick <-chan time.Time) { - for { - select { - case <-c.shutdown: - close(c.done) - return - case <-tick: - c.updateSigner() - } - } -} - -func (c *CA) updateSigner() { - newSigner, err := createSignerWithAPIServerSecret( - c.agentInfo, - c.kubeClient, - c.podCommandExecutor, - ) - if err != nil { - klog.Errorf("could not create signer with API server secret: %s", err) - c.onFailedRefresh(err) - return - } - c.lock.Lock() - c.activeSigner = newSigner - c.lock.Unlock() - c.onSuccessfulRefresh() -} - -func (c *CA) shutdownRefresh() { - close(c.shutdown) - <-c.done -} - -// IssuePEM issues a new server certificate for the given identity and duration, returning it as a pair of -// PEM-formatted byte slices for the certificate and private key. -func (c *CA) IssuePEM(subject pkix.Name, dnsNames []string, ttl time.Duration) ([]byte, []byte, error) { - c.lock.RLock() - signer := c.activeSigner - c.lock.RUnlock() - - if signer == nil { - return nil, nil, ErrIncapableOfIssuingCertificates - } - - return signer.IssuePEM(subject, dnsNames, ttl) -} - -func findCertAgentPod(ctx context.Context, kubeClient kubernetes.Interface, namespace, labelSelector string) (*v1.Pod, error) { - pods, err := kubeClient.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{ - LabelSelector: labelSelector, - FieldSelector: "status.phase=Running", - }) - if err != nil { - return nil, fmt.Errorf("could not check for kube-cert-agent pod: %w", err) - } - for _, pod := range pods.Items { - return &pod, nil - } - return nil, ErrNoKubeCertAgentPod -} - -func getKeypairFilePaths(pod *v1.Pod, agentInfo *AgentInfo) (string, string) { - annotations := pod.Annotations - if annotations == nil { - annotations = make(map[string]string) - } - - certPath, ok := annotations[agentInfo.CertPathAnnotation] - if !ok { - certPath = k8sAPIServerCACertPEMDefaultPath - } - - keyPath, ok := annotations[agentInfo.KeyPathAnnotation] - if !ok { - keyPath = k8sAPIServerCAKeyPEMDefaultPath - } - - return certPath, keyPath -} diff --git a/internal/certauthority/kubecertauthority/kubecertauthority_test.go b/internal/certauthority/kubecertauthority/kubecertauthority_test.go deleted file mode 100644 index 3807778d..00000000 --- a/internal/certauthority/kubecertauthority/kubecertauthority_test.go +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright 2020 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package kubecertauthority - -import ( - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "io/ioutil" - "sync" - "testing" - "time" - - "github.com/sclevine/spec" - "github.com/sclevine/spec/report" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kubernetesfake "k8s.io/client-go/kubernetes/fake" - "k8s.io/klog/v2" - - "go.pinniped.dev/internal/testutil" -) - -type fakePodExecutor struct { - resultsToReturn []string - errorsToReturn []error - - calledWithPodName []string - calledWithPodNamespace []string - calledWithCommandAndArgs [][]string - - callCount int -} - -func (s *fakePodExecutor) Exec(podNamespace string, podName string, commandAndArgs ...string) (string, error) { - s.calledWithPodNamespace = append(s.calledWithPodNamespace, podNamespace) - s.calledWithPodName = append(s.calledWithPodName, podName) - s.calledWithCommandAndArgs = append(s.calledWithCommandAndArgs, commandAndArgs) - result := s.resultsToReturn[s.callCount] - var err error = nil - if s.errorsToReturn != nil { - err = s.errorsToReturn[s.callCount] - } - s.callCount++ - if err != nil { - return "", err - } - return result, nil -} - -type callbackRecorder struct { - numberOfTimesSuccessCalled int - numberOfTimesFailureCalled int - failureErrors []error - mutex sync.Mutex -} - -func (c *callbackRecorder) OnSuccess() { - c.mutex.Lock() - defer c.mutex.Unlock() - c.numberOfTimesSuccessCalled++ -} - -func (c *callbackRecorder) OnFailure(err error) { - c.mutex.Lock() - defer c.mutex.Unlock() - c.numberOfTimesFailureCalled++ - c.failureErrors = append(c.failureErrors, err) -} - -func (c *callbackRecorder) NumberOfTimesSuccessCalled() int { - c.mutex.Lock() - defer c.mutex.Unlock() - return c.numberOfTimesSuccessCalled -} - -func (c *callbackRecorder) NumberOfTimesFailureCalled() int { - c.mutex.Lock() - defer c.mutex.Unlock() - return c.numberOfTimesFailureCalled -} - -func (c *callbackRecorder) FailureErrors() []error { - c.mutex.Lock() - defer c.mutex.Unlock() - var errs = make([]error, len(c.failureErrors)) - copy(errs, c.failureErrors) - return errs -} - -func TestCA(t *testing.T) { - spec.Run(t, "CA", func(t *testing.T, when spec.G, it spec.S) { - var r *require.Assertions - var fakeCertPEM, fakeKeyPEM string - var fakeCert2PEM, fakeKey2PEM string - var fakePod *corev1.Pod - var kubeAPIClient *kubernetesfake.Clientset - var fakeExecutor *fakePodExecutor - var neverTicker <-chan time.Time - var callbacks *callbackRecorder - var logger *testutil.TranscriptLogger - var agentInfo AgentInfo - - var requireInitialFailureLogMessage = func(specificErrorMessage string) { - r.Len(logger.Transcript(), 1) - r.Equal( - fmt.Sprintf("could not initially fetch the API server's signing key: %s\n", specificErrorMessage), - logger.Transcript()[0].Message, - ) - r.Equal(logger.Transcript()[0].Level, "error") - } - - var requireNotCapableOfIssuingCerts = func(subject *CA) { - certPEM, keyPEM, err := subject.IssuePEM( - pkix.Name{CommonName: "Test Server"}, - []string{"example.com"}, - 10*time.Minute, - ) - r.Nil(certPEM) - r.Nil(keyPEM) - r.EqualError(err, "this cluster is not currently capable of issuing certificates") - } - - it.Before(func() { - r = require.New(t) - - loadFile := func(filename string) string { - bytes, err := ioutil.ReadFile(filename) - r.NoError(err) - return string(bytes) - } - fakeCertPEM = loadFile("./testdata/test.crt") - fakeKeyPEM = loadFile("./testdata/test.key") - fakeCert2PEM = loadFile("./testdata/test2.crt") - fakeKey2PEM = loadFile("./testdata/test2.key") - - agentInfo = AgentInfo{ - Namespace: "some-agent-namespace", - LabelSelector: "some-label-key=some-label-value", - CertPathAnnotation: "some-cert-path-annotation", - KeyPathAnnotation: "some-key-path-annotation", - } - fakePod = &corev1.Pod{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "fake-pod", - Namespace: agentInfo.Namespace, - Labels: map[string]string{ - "some-label-key": "some-label-value", - }, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{Name: "some-agent-container-name"}}, - }, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - }, - } - - kubeAPIClient = kubernetesfake.NewSimpleClientset() - - fakeExecutor = &fakePodExecutor{ - resultsToReturn: []string{ - fakeCertPEM, - fakeKeyPEM, - fakeCert2PEM, - fakeKey2PEM, - }, - } - - callbacks = &callbackRecorder{} - - logger = testutil.NewTranscriptLogger(t) - klog.SetLogger(logger) // this is unfortunately a global logger, so can't run these tests in parallel :( - }) - - it.After(func() { - klog.SetLogger(nil) - }) - - when("the agent pod is found with default CLI flag values", func() { - it.Before(func() { - err := kubeAPIClient.Tracker().Add(fakePod) - r.NoError(err) - }) - - when("the exec commands return the API server's keypair", func() { - it("finds the API server's signing key and uses it to issue certificates", func() { - fakeTicker := make(chan time.Time) - - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, fakeTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - - r.Equal(2, fakeExecutor.callCount) - - r.Equal(agentInfo.Namespace, fakeExecutor.calledWithPodNamespace[0]) - r.Equal("fake-pod", fakeExecutor.calledWithPodName[0]) - r.Equal([]string{"cat", "/etc/kubernetes/ca/ca.pem"}, fakeExecutor.calledWithCommandAndArgs[0]) - - r.Equal(agentInfo.Namespace, fakeExecutor.calledWithPodNamespace[1]) - r.Equal("fake-pod", fakeExecutor.calledWithPodName[1]) - r.Equal([]string{"cat", "/etc/kubernetes/ca/ca.key"}, fakeExecutor.calledWithCommandAndArgs[1]) - - r.Equal(1, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(0, callbacks.NumberOfTimesFailureCalled()) - - // Validate that we can issue a certificate signed by the original API server CA. - certPEM, keyPEM, err := subject.IssuePEM( - pkix.Name{CommonName: "Test Server"}, - []string{"example.com"}, - 10*time.Minute, - ) - r.NoError(err) - validCert := testutil.ValidateCertificate(t, fakeCertPEM, string(certPEM)) - validCert.RequireDNSName("example.com") - validCert.RequireLifetime(time.Now(), time.Now().Add(10*time.Minute), 6*time.Minute) - validCert.RequireMatchesPrivateKey(string(keyPEM)) - - // Tick the timer and wait for another refresh loop to complete. - fakeTicker <- time.Now() - - // Eventually it starts issuing certs using the new signing key. - var secondCertPEM, secondKeyPEM string - r.Eventually(func() bool { - certPEM, keyPEM, err := subject.IssuePEM( - pkix.Name{CommonName: "Test Server"}, - []string{"example.com"}, - 10*time.Minute, - ) - r.NoError(err) - secondCertPEM = string(certPEM) - secondKeyPEM = string(keyPEM) - - block, _ := pem.Decode(certPEM) - require.NotNil(t, block) - parsed, err := x509.ParseCertificate(block.Bytes) - require.NoError(t, err) - - // Validate the created cert using the second API server CA. - roots := x509.NewCertPool() - require.True(t, roots.AppendCertsFromPEM([]byte(fakeCert2PEM))) - opts := x509.VerifyOptions{Roots: roots} - _, err = parsed.Verify(opts) - return err == nil - }, 5*time.Second, 100*time.Millisecond) - - r.Equal(2, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(0, callbacks.NumberOfTimesFailureCalled()) - - validCert2 := testutil.ValidateCertificate(t, fakeCert2PEM, secondCertPEM) - validCert2.RequireDNSName("example.com") - validCert2.RequireLifetime(time.Now(), time.Now().Add(15*time.Minute), 6*time.Minute) - validCert2.RequireMatchesPrivateKey(secondKeyPEM) - }) - }) - - when("the exec commands return the API server's keypair the first time but subsequently fails", func() { - it.Before(func() { - fakeExecutor.errorsToReturn = []error{nil, nil, fmt.Errorf("some exec error")} - }) - - it("logs an error message", func() { - fakeTicker := make(chan time.Time) - - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, fakeTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - r.Equal(2, fakeExecutor.callCount) - r.Equal(1, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(0, callbacks.NumberOfTimesFailureCalled()) - - // Tick the timer and wait for another refresh loop to complete. - fakeTicker <- time.Now() - - // Wait for there to be a log output and require that it matches our expectation. - r.Eventually(func() bool { return len(logger.Transcript()) >= 1 }, 5*time.Second, 10*time.Millisecond) - r.Contains(logger.Transcript()[0].Message, "could not create signer with API server secret: some exec error") - r.Equal(logger.Transcript()[0].Level, "error") - - r.Equal(1, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - r.EqualError(callbacks.FailureErrors()[0], "some exec error") - - // Validate that we can still issue a certificate signed by the original API server CA. - certPEM, _, err := subject.IssuePEM( - pkix.Name{CommonName: "Test Server"}, - []string{"example.com"}, - 10*time.Minute, - ) - r.NoError(err) - testutil.ValidateCertificate(t, fakeCertPEM, string(certPEM)) - }) - }) - - when("the exec commands fail the first time but subsequently returns the API server's keypair", func() { - it.Before(func() { - fakeExecutor.errorsToReturn = []error{fmt.Errorf("some exec error"), nil, nil} - fakeExecutor.resultsToReturn = []string{"", fakeCertPEM, fakeKeyPEM} - }) - - it("logs an error message and fails to issue certs until it can get the API server's keypair", func() { - fakeTicker := make(chan time.Time) - - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, fakeTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - r.Equal(1, fakeExecutor.callCount) - r.Equal(0, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - r.EqualError(callbacks.FailureErrors()[0], "some exec error") - - requireInitialFailureLogMessage("some exec error") - requireNotCapableOfIssuingCerts(subject) - - // Tick the timer and wait for another refresh loop to complete. - fakeTicker <- time.Now() - - // Wait until it can start to issue certs, and then validate the issued cert. - var certPEM, keyPEM []byte - r.Eventually(func() bool { - var err error - certPEM, keyPEM, err = subject.IssuePEM( - pkix.Name{CommonName: "Test Server"}, - []string{"example.com"}, - 10*time.Minute, - ) - return err == nil - }, 5*time.Second, 10*time.Millisecond) - validCert := testutil.ValidateCertificate(t, fakeCertPEM, string(certPEM)) - validCert.RequireDNSName("example.com") - validCert.RequireLifetime(time.Now().Add(-5*time.Minute), time.Now().Add(10*time.Minute), 1*time.Minute) - validCert.RequireMatchesPrivateKey(string(keyPEM)) - - r.Equal(1, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - }) - }) - - when("the exec commands succeed but return garbage", func() { - it.Before(func() { - fakeExecutor.resultsToReturn = []string{"not a cert", "not a private key"} - }) - - it("returns a CA who cannot issue certs", func() { - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, neverTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - requireInitialFailureLogMessage("could not load CA: tls: failed to find any PEM data in certificate input") - requireNotCapableOfIssuingCerts(subject) - r.Equal(0, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - r.EqualError(callbacks.FailureErrors()[0], "could not load CA: tls: failed to find any PEM data in certificate input") - }) - }) - - when("the first exec command returns an error", func() { - it.Before(func() { - fakeExecutor.errorsToReturn = []error{fmt.Errorf("some error"), nil} - }) - - it("returns a CA who cannot issue certs", func() { - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, neverTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - requireInitialFailureLogMessage("some error") - requireNotCapableOfIssuingCerts(subject) - r.Equal(0, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - r.EqualError(callbacks.FailureErrors()[0], "some error") - }) - }) - - when("the second exec command returns an error", func() { - it.Before(func() { - fakeExecutor.errorsToReturn = []error{nil, fmt.Errorf("some error")} - }) - - it("returns a CA who cannot issue certs", func() { - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, neverTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - requireInitialFailureLogMessage("some error") - requireNotCapableOfIssuingCerts(subject) - r.Equal(0, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - r.EqualError(callbacks.FailureErrors()[0], "some error") - }) - }) - }) - - when("the agent pod is found with non-default CLI flag values", func() { - it.Before(func() { - fakePod.Annotations = make(map[string]string) - fakePod.Annotations[agentInfo.CertPathAnnotation] = "/etc/kubernetes/ca/non-default.pem" - fakePod.Annotations[agentInfo.KeyPathAnnotation] = "/etc/kubernetes/ca/non-default.key" - err := kubeAPIClient.Tracker().Add(fakePod) - r.NoError(err) - }) - - it("finds the API server's signing key and uses it to issue certificates", func() { - _, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, neverTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - - r.Equal(2, fakeExecutor.callCount) - - r.Equal(agentInfo.Namespace, fakeExecutor.calledWithPodNamespace[0]) - r.Equal("fake-pod", fakeExecutor.calledWithPodName[0]) - r.Equal([]string{"cat", "/etc/kubernetes/ca/non-default.pem"}, fakeExecutor.calledWithCommandAndArgs[0]) - - r.Equal(agentInfo.Namespace, fakeExecutor.calledWithPodNamespace[1]) - r.Equal("fake-pod", fakeExecutor.calledWithPodName[1]) - r.Equal([]string{"cat", "/etc/kubernetes/ca/non-default.key"}, fakeExecutor.calledWithCommandAndArgs[1]) - }) - }) - - when("the agent pod is not found", func() { - it("returns an error", func() { - subject, shutdownFunc := New(&agentInfo, kubeAPIClient, fakeExecutor, neverTicker, callbacks.OnSuccess, callbacks.OnFailure) - defer shutdownFunc() - requireInitialFailureLogMessage("did not find kube-cert-agent pod") - requireNotCapableOfIssuingCerts(subject) - r.Equal(0, callbacks.NumberOfTimesSuccessCalled()) - r.Equal(1, callbacks.NumberOfTimesFailureCalled()) - r.EqualError(callbacks.FailureErrors()[0], "did not find kube-cert-agent pod") - }) - }) - }, spec.Sequential(), spec.Report(report.Terminal{})) -} diff --git a/internal/certauthority/kubecertauthority/testdata/test.crt b/internal/certauthority/kubecertauthority/testdata/test.crt deleted file mode 100644 index 796a7690..00000000 --- a/internal/certauthority/kubecertauthority/testdata/test.crt +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICyDCCAbCgAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl -cm5ldGVzMB4XDTIwMDcyNTIxMDQxOFoXDTMwMDcyMzIxMDQxOFowFTETMBEGA1UE -AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3K -hYv2gIQ1Dwzh2cWMid+ofAnvLIfV2Xv61vTLGprUI+XUqB4/gtf6X6UNn0Lett2n -d8p4wy7hw73hU/ggdvmWJvqBrSjc3JGfy+kj66fKXX+PTlbL7QbwiRvcSqIXIWlV -lHHxECWrED8jCulw/NVqfook/h5iNUCT9yswSJr/0fImiVnoTlIoEYG2eCNejZ5c -g39uD3ZTqd9ZxWwSLLnI+2kpJnZBPcd1ZQ8AQqzDgZtYRCqacn5gckQUKZWKQlxo -Eft6g1XHJouAWAZw7hEtk0v8rG0/eKF7wamxFi6BFVlbjWBsB4T9rApbdBWTKeCJ -Hv8fv5RMFSzpT3uzTO8CAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACh5RhbxqJe+Z/gc17cZhKNmdiwu -I2pLp3QBfwvN+Wbmajzw/7rYhY0d8JYVTJzXSCPWi6UAKxAtXOLF8WIIf9i39n6R -uKOBGW14FzzGyRJiD3qaG/JTvEW+SLhwl68Ndr5LHSnbugAqq31abcQy6Zl9v5A8 -JKC97Lj/Sn8rj7opKy4W3oq7NCQsAb0zh4IllRF6UvSnJySfsg7xdXHHpxYDHtOS -XcOu5ySUIZTgFe9RfeUZlGZ5xn0ckMlQ7qW2Wx1q0OVWw5us4NtkGqKrHG4Tn1X7 -uwo/Yytn5sDxrDv1/oii6AZOCsTPre4oD3wz4nmVzCVJcgrqH4Q24hT8WNg= ------END CERTIFICATE----- diff --git a/internal/certauthority/kubecertauthority/testdata/test.key b/internal/certauthority/kubecertauthority/testdata/test.key deleted file mode 100644 index 7ad653ae..00000000 --- a/internal/certauthority/kubecertauthority/testdata/test.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAvcqFi/aAhDUPDOHZxYyJ36h8Ce8sh9XZe/rW9MsamtQj5dSo -Hj+C1/pfpQ2fQt623ad3ynjDLuHDveFT+CB2+ZYm+oGtKNzckZ/L6SPrp8pdf49O -VsvtBvCJG9xKohchaVWUcfEQJasQPyMK6XD81Wp+iiT+HmI1QJP3KzBImv/R8iaJ -WehOUigRgbZ4I16NnlyDf24PdlOp31nFbBIsucj7aSkmdkE9x3VlDwBCrMOBm1hE -KppyfmByRBQplYpCXGgR+3qDVccmi4BYBnDuES2TS/ysbT94oXvBqbEWLoEVWVuN -YGwHhP2sClt0FZMp4Ike/x+/lEwVLOlPe7NM7wIDAQABAoIBAFC1tUEmHNUcM0BJ -M3D9KQzB+63F1mwVlx1QOOV1EeVR3co5Ox1R6PSr9sycFGQ9jgqI0zp5TJe9Tp6L -GkhklfPh1MWnK9o6wlnzWKXWrrp2Jni+mpPyuOPAmq4Maniv2XeP+0bROwqpyojv -AA7yC7M+TH226ZJGNVs3EV9+cwHml0yuzBfIJn/rv/w2g+WRKM/MC0S7k2d8bRlA -NycKVGAGBhKTltjoVYOeh6aHEpSjK8zfaePjo5dYJvoVIli60YCgcJOU/8jXT+Np -1Fm7tRvAtj3pUp0Sqdaf2RUzh9jfJp2VFCHuSJ6TPqArOyQojtMcTHF0TiW7xrHP -xOCRIAECgYEAwGBPU7vdthMJBg+ORUoGQQaItTeJvQwIqJvbKD2osp4jhS1dGZBw -W30GKEc/gd8JNtOq9BBnMicPF7hktuy+bSPv41XPud67rSSO7Tsw20C10gFRq06B -zIJWFAUqK3IkvVc3VDmtSLSDox4QZ/BdqaMlQ5y5JCsC5kThmkZFlO8CgYEA/I9X -YHi6RioMJE1fqOHJL4DDjlezmcuRrD7fE5InKbtJZ2JhGYOX/C0KXnHTOWTCDxxN -FBvpvD6Xv5o3PhB9Z6k2fqvJ4GS8urkG/KU4xcC+bak+9ava8oaiSqG16zD9NH2P -jJ60NrbLl1J0pU9fiwuFVUKJ4hDZOfN9RqYdyAECgYAVwo8WhJiGgM6zfcz073OX -pVqPTPHqjVLpZ3+5pIfRdGvGI6R1QM5EuvaYVb7MPOM47WZX5wcVOC/P2g6iVlMP -21HGIC2384a9BfaYxOo40q/+SiHnw6CQ9mkwKIllkqqvNA9RGpkMMUb2i28For2l -c4vCgxa6DZdtXns6TRqPxwKBgCfY5cxOv/T6BVhk7MbUeM2J31DB/ZAyUhV/Bess -kAlBh19MYk2IOZ6L7KriApV3lDaWHIMjtEkDByYvyq98Io0MYZCywfMpca10K+oI -l2B7/I+IuGpCZxUEsO5dfTpSTGDPvqpND9niFVUWqVi7oTNq6ep9yQtl5SADjqxq -4SABAoGAIm0hUg1wtcS46cGLy6PIkPM5tocTSghtz4vFsuk/i4QA9GBoBO2gH6ty -+kJHmeaXt2dmgySp0QAWit5UlceEumB0NXnAdJZQxeGSFSyYkDWhwXd8wDceKo/1 -LfCU6Dk8IN/SsppVUWXQ2rlORvxlrHeCio8o0kS9Yiu55WMYg4g= ------END RSA PRIVATE KEY----- diff --git a/internal/certauthority/kubecertauthority/testdata/test2.crt b/internal/certauthority/kubecertauthority/testdata/test2.crt deleted file mode 100644 index 108e6e00..00000000 --- a/internal/certauthority/kubecertauthority/testdata/test2.crt +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICyDCCAbCgAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl -cm5ldGVzMB4XDTIwMDgxODE2NDEzNloXDTMwMDgxNjE2NDEzNlowFTETMBEGA1UE -AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALH7 -C2JpttDi3mxpD4bd+BZucCrS8XF2YwqYAr42HePp++PBnlUFqWmtPc9/bmo+7+7z -iAAlnAV0pJWP+HR/PskX8MRcFAA1HoXLa37Q4SuBBQG+JE+AeaOObmQYaCFv55ej -UF4+JIoQOdlbYEMYSI07el0cxQL4Io/CHJ3p7AtNElxjDuMK4B9W8NiCse3p7Uf+ -Qje4we1TYOfcpAM0jpBPHK9vCBCpX+j52S5DUTRVIk9kye3lCDmWOXH/fhj/aJTM -1MP/hThbl2wIbFuv1bpa0kXNZs8xB63dtqROQ+lCghDmuayRmzwXl2PX6IgFFcjV -yAgjXrZqjihs+mY8eT0CAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE+Saqk2EyuIx1rxFWrOwpTi5q/B -p/TwEtrmrFIRVPnGeBnhyfbGXPDMkzIY1mEvztu8H+pm5RPyhQYLsuwzYiYMQyxX -yL9VvO7uydn7+3zX7oknQ5qAvN3nmItNyOKw3MRIKGsySNuTQ5JPtU/ufGlEivbK -vNaDBqjKrBvwhIKMdV9/xYSyeBhSSWr/6W1tAk+XbHhQH1M78rdwGN5SI75L4FGu -13kn/W2n8pE17TAY88B1YGKhsLSvf8KrFNYv+UUmzh2WstECKSlnbrSM+boMlGJn -XahE8M23fieB+SaenQdOezrY4GAnXQ3qToDlhdYAOkWhcGDct47VRM93whY= ------END CERTIFICATE----- diff --git a/internal/certauthority/kubecertauthority/testdata/test2.key b/internal/certauthority/kubecertauthority/testdata/test2.key deleted file mode 100644 index 951d1c99..00000000 --- a/internal/certauthority/kubecertauthority/testdata/test2.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAsfsLYmm20OLebGkPht34Fm5wKtLxcXZjCpgCvjYd4+n748Ge -VQWpaa09z39uaj7v7vOIACWcBXSklY/4dH8+yRfwxFwUADUehctrftDhK4EFAb4k -T4B5o45uZBhoIW/nl6NQXj4kihA52VtgQxhIjTt6XRzFAvgij8IcnensC00SXGMO -4wrgH1bw2IKx7entR/5CN7jB7VNg59ykAzSOkE8cr28IEKlf6PnZLkNRNFUiT2TJ -7eUIOZY5cf9+GP9olMzUw/+FOFuXbAhsW6/VulrSRc1mzzEHrd22pE5D6UKCEOa5 -rJGbPBeXY9foiAUVyNXICCNetmqOKGz6Zjx5PQIDAQABAoIBAD06klYO7De8dKxz -EEZjgn+lCq2Q2EMiaTwxw2/QikPoMSHPcDrrsbaLROJngoLGmCBqY3U5ew1dbWmO -l/jr9ZuUwt2ql67il1eL/bUpAu3GewR4d2FqX25nB48j3l7ycof2RSXG1ycwIdam -2tz6M6tytMvno9c7qhguvU2ONghEreXG3YYLdf9l97aB+p6GdXhwty22b7tAVwp1 -GKn79kVYgmL86lph9hBPqtHuG1LHZUiFodr2iWXSu3H/265OD58a33ZO3iyfFI0s -PPy87ZN0r+1hGpoKKkDe63udOYgAG6xmIea/1Pdn9Eg87tueoeC7XcUpdaCJlKaF -tqCusEECgYEA60rWyXxTFKJ4QdVaqXoWMA4cQkT73RxznSKwkN/Svk8TVv+p5s5Y -oYKN4qyMzxvQzu+QNWpd1yTveCmmEynz457ELpGtidtiJdm7xZMdMGrU02eCL9mZ -ERbtfAkbEAKvN8D73fWyzghKv4dgcQptmsqZlYYc4vpwHveK+/N5lukCgYEAwaT3 -iMTWCv7Vp87iKrzNUAH4iBWlazwbE+EDEnHVw26Y82fhgEgxiU2UvFSaIVhGpaCz -MYSXSdRcQTHgCoJLPfWHUHTJPqf36KfAJfdaxxjzTTbNYjUOkdcUD1bcNrm0yjoY -nR4zK1FPw86ODMYtBpfkyL7ZX8G1v5pRL/6/gzUCgYBzgwQ7Wmu3H6QGPeYKecNW -yDabWh6ECKnBpPwlw5xEjbGi7lTM2NSuRde+RpPCQZebYATeFGAJdTqTNW8wzVHM -l28cpawal7dxeZkzf+u+j1P4jUJel2cL+sOQNzAwBgFbT8TWzP6BI5T+vklcdZAl -g/0uaO7Zh7Vvnnt/AaLZsQKBgGfbHzuGPjoFdPecOKatPfxUIkRyP5bk1KzzuF8T -GI/JaFTbeREBJzg5mLTtNwD9RF6ecpzzPOTG9Xet1Tgtq0cewSUAjdKB6a8pESAL -qu8vTYYzBzJNvHOxg7u6XT8omHMBd6QEx3LLGFmvFXZ6bzmjC3wzB4iY7u5FSJfS -LEqlAoGAb0rbJ85vrJopbx8lzhJjyaJfM8+A3oQg1K3TphHrcgkUc8qx8QEosziM -wzYKSBlXd2bxMibyd0mTEMNl4/BqofaKoqof9gBIbkamwXOO8s7IgKxQAfr1R/z8 -tHBW/g0QWPB+qtaVDtHwyQLlxjx8HD7atIo8d/do9ruwVaf+r6g= ------END RSA PRIVATE KEY-----