Extend the REST service to keep a CertIssuer.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
Matt Moyer 2020-07-27 07:55:33 -05:00 committed by Ryan Richard
parent f7b0cf8f8a
commit 8a8a278029
3 changed files with 31 additions and 38 deletions

View File

@ -14,33 +14,27 @@ import (
"encoding/pem"
"fmt"
"io"
"io/ioutil"
"log"
"time"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
"github.com/suzerain-io/placeholder-name/internal/autoregistration"
"github.com/suzerain-io/placeholder-name/internal/certauthority"
"github.com/suzerain-io/placeholder-name/internal/downward"
"k8s.io/apimachinery/pkg/runtime"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/intstr"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
"k8s.io/client-go/kubernetes"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
restclient "k8s.io/client-go/rest"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
aggregationv1client "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
placeholderv1alpha1 "github.com/suzerain-io/placeholder-name-api/pkg/apis/placeholder/v1alpha1"
"github.com/suzerain-io/placeholder-name/internal/autoregistration"
"github.com/suzerain-io/placeholder-name/internal/certauthority"
"github.com/suzerain-io/placeholder-name/internal/downward"
"github.com/suzerain-io/placeholder-name/pkg/apiserver"
"github.com/suzerain-io/placeholder-name/pkg/config"
)
@ -79,18 +73,6 @@ func New(ctx context.Context, args []string, stdout, stderr io.Writer) *App {
credential from somewhere to an internal credential to be used for
authenticating to the Kubernetes API.`,
RunE: func(cmd *cobra.Command, args []string) error {
clusterSigningCertificatePEM, err := ioutil.ReadFile(a.clusterSigningCertFilePath)
if err != nil {
return fmt.Errorf("could not read cluster signing certificate: %w", err)
}
clusterSigningPrivateKeyPEM, err := ioutil.ReadFile(a.clusterSigningKeyFilePath)
if err != nil {
return fmt.Errorf("could not read cluster signing private key: %w", err)
}
// TODO: use these value for something useful
_ = clusterSigningCertificatePEM
_ = clusterSigningPrivateKeyPEM
// Load the Kubernetes client configuration (kubeconfig),
kubeConfig, err := restclient.InClusterConfig()
if err != nil {
@ -169,9 +151,15 @@ func (a *App) run(
return fmt.Errorf("could not load config: %w", err)
}
// Load the Kubernetes cluster signing CA.
clientCA, err := certauthority.Load(a.clusterSigningCertFilePath, a.clusterSigningKeyFilePath)
if err != nil {
return fmt.Errorf("could not load cluster signing CA: %w", err)
}
webhookTokenAuthenticator, err := config.NewWebhook(cfg.WebhookConfig)
if err != nil {
return fmt.Errorf("could create webhook client: %w", err)
return fmt.Errorf("could not create webhook client: %w", err)
}
podinfo, err := downward.Load(a.downwardAPIPath)
@ -181,19 +169,14 @@ func (a *App) run(
// TODO use the postStart hook to generate certs?
ca, err := certauthority.New(pkix.Name{CommonName: "Placeholder CA"})
apiCA, err := certauthority.New(pkix.Name{CommonName: "Placeholder CA"})
if err != nil {
return fmt.Errorf("could not initialize CA: %w", err)
}
caBundle, err := ca.Bundle()
if err != nil {
return fmt.Errorf("could not read CA bundle: %w", err)
}
log.Printf("initialized CA bundle:\n%s", string(caBundle))
const serviceName = "placeholder-name-api"
cert, err := ca.Issue(
cert, err := apiCA.Issue(
pkix.Name{CommonName: serviceName + "." + podinfo.Namespace + ".svc"},
[]string{},
24*365*time.Hour,
@ -224,7 +207,7 @@ func (a *App) run(
Spec: apiregistrationv1.APIServiceSpec{
Group: placeholderv1alpha1.GroupName,
Version: placeholderv1alpha1.SchemeGroupVersion.Version,
CABundle: caBundle,
CABundle: apiCA.Bundle(),
GroupPriorityMinimum: 2500, // TODO what is the right value? https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#apiservicespec-v1beta1-apiregistration-k8s-io
VersionPriority: 10, // TODO what is the right value? https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#apiservicespec-v1beta1-apiregistration-k8s-io
},
@ -239,7 +222,7 @@ func (a *App) run(
return fmt.Errorf("could not register API service: %w", err)
}
apiServerConfig, err := a.ConfigServer(cert, webhookTokenAuthenticator)
apiServerConfig, err := a.ConfigServer(cert, webhookTokenAuthenticator, clientCA)
if err != nil {
return err
}
@ -252,7 +235,7 @@ func (a *App) run(
return server.GenericAPIServer.PrepareRun().Run(ctx.Done())
}
func (a *App) ConfigServer(cert *tls.Certificate, webhookTokenAuthenticator *webhook.WebhookTokenAuthenticator) (*apiserver.Config, error) {
func (a *App) ConfigServer(cert *tls.Certificate, webhookTokenAuthenticator *webhook.WebhookTokenAuthenticator, ca *certauthority.CA) (*apiserver.Config, error) {
provider, err := createStaticCertKeyProvider(cert)
if err != nil {
return nil, fmt.Errorf("could not create static cert key provider: %w", err)
@ -268,6 +251,7 @@ func (a *App) ConfigServer(cert *tls.Certificate, webhookTokenAuthenticator *web
GenericConfig: serverConfig,
ExtraConfig: apiserver.ExtraConfig{
Webhook: webhookTokenAuthenticator,
Issuer: ca,
},
}
return apiServerConfig, nil

View File

@ -57,6 +57,7 @@ type Config struct {
type ExtraConfig struct {
Webhook authenticator.Token
Issuer loginrequest.CertIssuer
}
type PlaceHolderServer struct {
@ -108,7 +109,7 @@ func (c completedConfig) New() (*PlaceHolderServer, error) {
NegotiatedSerializer: Codecs,
}
loginRequestStorage := loginrequest.NewREST(c.ExtraConfig.Webhook)
loginRequestStorage := loginrequest.NewREST(c.ExtraConfig.Webhook, c.ExtraConfig.Issuer)
v1alpha1Storage, ok := apiGroupInfo.VersionedResourcesStorageMap[gvr.Version]
if !ok {

View File

@ -8,7 +8,9 @@ package loginrequest
import (
"context"
"crypto/x509/pkix"
"fmt"
"time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -28,14 +30,20 @@ var (
_ rest.Storage = &REST{}
)
func NewREST(webhook authenticator.Token) *REST {
type CertIssuer interface {
IssuePEM(subject pkix.Name, dnsNames []string, ttl time.Duration) ([]byte, []byte, error)
}
func NewREST(webhook authenticator.Token, issuer CertIssuer) *REST {
return &REST{
webhook: webhook,
issuer: issuer,
}
}
type REST struct {
webhook authenticator.Token
issuer CertIssuer
}
func (r *REST) New() runtime.Object {