Add kube-cert-agent controller for getting kube API keypair

This commit is contained in:
Andrew Keesler
2020-09-21 14:16:14 -04:00
parent 49145791cc
commit 5a608cc84c
16 changed files with 2456 additions and 166 deletions
+81 -8
View File
@@ -11,6 +11,8 @@ import (
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/authenticator"
genericapiserver "k8s.io/apiserver/pkg/server"
@@ -32,6 +34,22 @@ import (
"go.pinniped.dev/internal/provider"
"go.pinniped.dev/internal/registry/credentialrequest"
"go.pinniped.dev/pkg/config"
configapi "go.pinniped.dev/pkg/config/api"
)
// These constants are various label/annotation keys used in Pinniped. They are namespaced by
// a "pinniped.dev" child domain so they don't collide with other keys.
const (
// kubeCertAgentLabelKey is used to identify which pods are created by the kube-cert-agent
// controllers.
kubeCertAgentLabelKey = "kube-cert-agent.pinniped.dev"
// kubeCertAgentCertPathAnnotationKey is the annotation that the kube-cert-agent pod will use
// to communicate the in-pod path to the kube API's certificate.
kubeCertAgentCertPathAnnotationKey = "kube-cert-agent.pinniped.dev/cert-path"
// kubeCertAgentKeyPathAnnotationKey is the annotation that the kube-cert-agent pod will use
// to communicate the in-pod path to the kube API's key.
kubeCertAgentKeyPathAnnotationKey = "kube-cert-agent.pinniped.dev/key-path"
)
// App is an object that represents the pinniped-server application.
@@ -113,7 +131,15 @@ func (a *App) runServer(ctx context.Context) error {
serverInstallationNamespace := podInfo.Namespace
// Load the Kubernetes cluster signing CA.
k8sClusterCA, shutdownCA, err := getClusterCASigner(ctx, serverInstallationNamespace, cfg.NamesConfig.CredentialIssuerConfig)
kubeCertAgentTemplate, kubeCertAgentLabelSelector := createKubeCertAgentTemplate(
&cfg.KubeCertAgentConfig,
)
k8sClusterCA, shutdownCA, err := getClusterCASigner(
ctx,
serverInstallationNamespace,
cfg.NamesConfig.CredentialIssuerConfig,
kubeCertAgentLabelSelector,
)
if err != nil {
return err
}
@@ -132,13 +158,18 @@ func (a *App) runServer(ctx context.Context) error {
// Prepare to start the controllers, but defer actually starting them until the
// post start hook of the aggregated API server.
startControllersFunc, err := controllermanager.PrepareControllers(
serverInstallationNamespace,
cfg.NamesConfig,
cfg.DiscoveryInfo.URL,
dynamicCertProvider,
time.Duration(*cfg.APIConfig.ServingCertificateConfig.DurationSeconds)*time.Second,
time.Duration(*cfg.APIConfig.ServingCertificateConfig.RenewBeforeSeconds)*time.Second,
idpCache,
&controllermanager.Config{
ServerInstallationNamespace: serverInstallationNamespace,
NamesConfig: &cfg.NamesConfig,
DiscoveryURLOverride: cfg.DiscoveryInfo.URL,
DynamicCertProvider: dynamicCertProvider,
ServingCertDuration: time.Duration(*cfg.APIConfig.ServingCertificateConfig.DurationSeconds) * time.Second,
ServingCertRenewBefore: time.Duration(*cfg.APIConfig.ServingCertificateConfig.RenewBeforeSeconds) * time.Second,
IDPCache: idpCache,
KubeCertAgentTemplate: kubeCertAgentTemplate,
KubeCertAgentCertPathAnnotation: kubeCertAgentCertPathAnnotationKey,
KubeCertAgentKeyPathAnnotation: kubeCertAgentKeyPathAnnotationKey,
},
)
if err != nil {
return fmt.Errorf("could not prepare controllers: %w", err)
@@ -168,6 +199,7 @@ func (a *App) runServer(ctx context.Context) error {
func getClusterCASigner(
ctx context.Context, serverInstallationNamespace string,
credentialIssuerConfigResourceName string,
kubeCertAgentLabelSelector string,
) (credentialrequest.CertIssuer, kubecertauthority.ShutdownFunc, error) {
// Load the Kubernetes client configuration.
kubeConfig, err := restclient.InClusterConfig()
@@ -191,7 +223,14 @@ func getClusterCASigner(
ticker := time.NewTicker(5 * time.Minute)
// Make a CA which uses the Kubernetes cluster API server's signing certs.
kubeCertAgentInfo := kubecertauthority.AgentInfo{
Namespace: "kube-system",
LabelSelector: kubeCertAgentLabelSelector,
CertPathAnnotation: kubeCertAgentCertPathAnnotationKey,
KeyPathAnnotation: kubeCertAgentKeyPathAnnotationKey,
}
k8sClusterCA, shutdownCA := kubecertauthority.New(
&kubeCertAgentInfo,
kubeClient,
kubecertauthority.NewPodCommandExecutor(kubeConfig, kubeClient),
ticker.C,
@@ -282,3 +321,37 @@ func getAggregatedAPIServerConfig(
}
return apiServerConfig, nil
}
func createKubeCertAgentTemplate(cfg *configapi.KubeCertAgentSpec) (*corev1.Pod, string) {
terminateImmediately := int64(0)
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: *cfg.NamePrefix,
Labels: map[string]string{
kubeCertAgentLabelKey: "",
},
},
Spec: corev1.PodSpec{
TerminationGracePeriodSeconds: &terminateImmediately,
Containers: []corev1.Container{
{
Name: "sleeper",
Image: *cfg.Image,
Command: []string{"/bin/sleep", "infinity"},
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse("16Mi"),
corev1.ResourceCPU: resource.MustParse("10m"),
},
Requests: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse("16Mi"),
corev1.ResourceCPU: resource.MustParse("10m"),
},
},
},
},
},
}
labelSelector := kubeCertAgentLabelKey + "="
return pod, labelSelector
}