Extend the REST service to keep a CertIssuer.
Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
parent
07a71236aa
commit
d8c7a25487
@ -14,33 +14,27 @@ import (
|
|||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/server/dynamiccertificates"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/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"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||||
|
"k8s.io/apiserver/pkg/server/dynamiccertificates"
|
||||||
genericoptions "k8s.io/apiserver/pkg/server/options"
|
genericoptions "k8s.io/apiserver/pkg/server/options"
|
||||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
|
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
restclient "k8s.io/client-go/rest"
|
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"
|
aggregationv1client "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
|
||||||
|
|
||||||
placeholderv1alpha1 "github.com/suzerain-io/placeholder-name-api/pkg/apis/placeholder/v1alpha1"
|
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/apiserver"
|
||||||
"github.com/suzerain-io/placeholder-name/pkg/config"
|
"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
|
credential from somewhere to an internal credential to be used for
|
||||||
authenticating to the Kubernetes API.`,
|
authenticating to the Kubernetes API.`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
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),
|
// Load the Kubernetes client configuration (kubeconfig),
|
||||||
kubeConfig, err := restclient.InClusterConfig()
|
kubeConfig, err := restclient.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -169,9 +151,15 @@ func (a *App) run(
|
|||||||
return fmt.Errorf("could not load config: %w", err)
|
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)
|
webhookTokenAuthenticator, err := config.NewWebhook(cfg.WebhookConfig)
|
||||||
if err != nil {
|
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)
|
podinfo, err := downward.Load(a.downwardAPIPath)
|
||||||
@ -181,19 +169,14 @@ func (a *App) run(
|
|||||||
|
|
||||||
// TODO use the postStart hook to generate certs?
|
// 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("could not initialize CA: %w", err)
|
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"
|
const serviceName = "placeholder-name-api"
|
||||||
|
|
||||||
cert, err := ca.Issue(
|
cert, err := apiCA.Issue(
|
||||||
pkix.Name{CommonName: serviceName + "." + podinfo.Namespace + ".svc"},
|
pkix.Name{CommonName: serviceName + "." + podinfo.Namespace + ".svc"},
|
||||||
[]string{},
|
[]string{},
|
||||||
24*365*time.Hour,
|
24*365*time.Hour,
|
||||||
@ -224,7 +207,7 @@ func (a *App) run(
|
|||||||
Spec: apiregistrationv1.APIServiceSpec{
|
Spec: apiregistrationv1.APIServiceSpec{
|
||||||
Group: placeholderv1alpha1.GroupName,
|
Group: placeholderv1alpha1.GroupName,
|
||||||
Version: placeholderv1alpha1.SchemeGroupVersion.Version,
|
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
|
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
|
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)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -252,7 +235,7 @@ func (a *App) run(
|
|||||||
return server.GenericAPIServer.PrepareRun().Run(ctx.Done())
|
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)
|
provider, err := createStaticCertKeyProvider(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create static cert key provider: %w", err)
|
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,
|
GenericConfig: serverConfig,
|
||||||
ExtraConfig: apiserver.ExtraConfig{
|
ExtraConfig: apiserver.ExtraConfig{
|
||||||
Webhook: webhookTokenAuthenticator,
|
Webhook: webhookTokenAuthenticator,
|
||||||
|
Issuer: ca,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return apiServerConfig, nil
|
return apiServerConfig, nil
|
||||||
|
@ -57,6 +57,7 @@ type Config struct {
|
|||||||
|
|
||||||
type ExtraConfig struct {
|
type ExtraConfig struct {
|
||||||
Webhook authenticator.Token
|
Webhook authenticator.Token
|
||||||
|
Issuer loginrequest.CertIssuer
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlaceHolderServer struct {
|
type PlaceHolderServer struct {
|
||||||
@ -108,7 +109,7 @@ func (c completedConfig) New() (*PlaceHolderServer, error) {
|
|||||||
NegotiatedSerializer: Codecs,
|
NegotiatedSerializer: Codecs,
|
||||||
}
|
}
|
||||||
|
|
||||||
loginRequestStorage := loginrequest.NewREST(c.ExtraConfig.Webhook)
|
loginRequestStorage := loginrequest.NewREST(c.ExtraConfig.Webhook, c.ExtraConfig.Issuer)
|
||||||
|
|
||||||
v1alpha1Storage, ok := apiGroupInfo.VersionedResourcesStorageMap[gvr.Version]
|
v1alpha1Storage, ok := apiGroupInfo.VersionedResourcesStorageMap[gvr.Version]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -8,7 +8,9 @@ package loginrequest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/x509/pkix"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -28,14 +30,20 @@ var (
|
|||||||
_ rest.Storage = &REST{}
|
_ 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{
|
return &REST{
|
||||||
webhook: webhook,
|
webhook: webhook,
|
||||||
|
issuer: issuer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type REST struct {
|
type REST struct {
|
||||||
webhook authenticator.Token
|
webhook authenticator.Token
|
||||||
|
issuer CertIssuer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *REST) New() runtime.Object {
|
func (r *REST) New() runtime.Object {
|
||||||
|
Loading…
Reference in New Issue
Block a user