mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-23 22:49:43 -05:00
Use Certificate Requests to issue Kubelet Certificates and set CA (#261)
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
49e98286a9
commit
c6ff34f4d2
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/diskencryption"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubelet"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/nodestate"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/role"
|
||||
"github.com/edgelesssys/constellation/internal/cloud/metadata"
|
||||
@ -39,6 +40,7 @@ type JoinClient struct {
|
||||
diskUUID string
|
||||
nodeName string
|
||||
role role.Role
|
||||
validIPs []net.IP
|
||||
disk encryptedDisk
|
||||
fileHandler file.Handler
|
||||
|
||||
@ -190,6 +192,11 @@ func (c *JoinClient) join(serviceEndpoint string) error {
|
||||
ctx, cancel := c.timeoutCtx()
|
||||
defer cancel()
|
||||
|
||||
certificateRequest, kubeletKey, err := kubelet.GetCertificateRequest(c.nodeName, c.validIPs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := c.dialer.Dial(ctx, serviceEndpoint)
|
||||
if err != nil {
|
||||
c.log.With(zap.String("endpoint", serviceEndpoint), zap.Error(err)).Errorf("Join service unreachable")
|
||||
@ -199,9 +206,9 @@ func (c *JoinClient) join(serviceEndpoint string) error {
|
||||
|
||||
protoClient := joinproto.NewAPIClient(conn)
|
||||
req := &joinproto.IssueJoinTicketRequest{
|
||||
DiskUuid: c.diskUUID,
|
||||
NodeName: c.nodeName,
|
||||
IsControlPlane: c.role == role.ControlPlane,
|
||||
DiskUuid: c.diskUUID,
|
||||
CertificateRequest: certificateRequest,
|
||||
IsControlPlane: c.role == role.ControlPlane,
|
||||
}
|
||||
ticket, err := protoClient.IssueJoinTicket(ctx, req)
|
||||
if err != nil {
|
||||
@ -209,10 +216,10 @@ func (c *JoinClient) join(serviceEndpoint string) error {
|
||||
return fmt.Errorf("issuing join ticket: %w", err)
|
||||
}
|
||||
|
||||
return c.startNodeAndJoin(ticket)
|
||||
return c.startNodeAndJoin(ticket, kubeletKey)
|
||||
}
|
||||
|
||||
func (c *JoinClient) startNodeAndJoin(ticket *joinproto.IssueJoinTicketResponse) (retErr error) {
|
||||
func (c *JoinClient) startNodeAndJoin(ticket *joinproto.IssueJoinTicketResponse, kubeletKey []byte) (retErr error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), c.joinTimeout)
|
||||
defer cancel()
|
||||
|
||||
@ -244,6 +251,12 @@ func (c *JoinClient) startNodeAndJoin(ticket *joinproto.IssueJoinTicketResponse)
|
||||
return fmt.Errorf("writing control plane files: %w", err)
|
||||
}
|
||||
}
|
||||
if err := c.fileHandler.Write(kubelet.CertificateFilename, ticket.KubeletCert, file.OptMkdirAll); err != nil {
|
||||
return fmt.Errorf("writing kubelet certificate: %w", err)
|
||||
}
|
||||
if err := c.fileHandler.Write(kubelet.KeyFilename, kubeletKey, file.OptMkdirAll); err != nil {
|
||||
return fmt.Errorf("writing kubelet key: %w", err)
|
||||
}
|
||||
|
||||
state := nodestate.NodeState{
|
||||
Role: c.role,
|
||||
@ -285,8 +298,17 @@ func (c *JoinClient) getNodeMetadata() error {
|
||||
return errors.New("got instance metadata with unknown role")
|
||||
}
|
||||
|
||||
var ips []net.IP
|
||||
for _, ip := range inst.PrivateIPs {
|
||||
ips = append(ips, net.ParseIP(ip))
|
||||
}
|
||||
for _, ip := range inst.PublicIPs {
|
||||
ips = append(ips, net.ParseIP(ip))
|
||||
}
|
||||
|
||||
c.nodeName = inst.Name
|
||||
c.role = inst.Role
|
||||
c.validIPs = ips
|
||||
|
||||
return nil
|
||||
}
|
||||
|
49
bootstrapper/internal/kubelet/kubelet.go
Normal file
49
bootstrapper/internal/kubelet/kubelet.go
Normal file
@ -0,0 +1,49 @@
|
||||
package kubelet
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"net"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
// CertificateFilename is the path to the kubelets certificate.
|
||||
CertificateFilename = "/run/state/kubelet/pki/kubelet-client-crt.pem"
|
||||
// KeyFilename is the path to the kubelets private key.
|
||||
KeyFilename = "/run/state/kubelet/pki/kubelet-client-key.pem"
|
||||
)
|
||||
|
||||
// GetCertificateRequest returns a certificate request and macthing private key for the kubelet.
|
||||
func GetCertificateRequest(nodeName string, ips []net.IP) (certificateRequest []byte, privateKey []byte, err error) {
|
||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyBytes, err := x509.MarshalECPrivateKey(privK)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
kubeletKey := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{constants.NodesGroup},
|
||||
CommonName: constants.NodesUserPrefix + nodeName,
|
||||
},
|
||||
IPAddresses: ips,
|
||||
}
|
||||
certificateRequest, err = x509.CreateCertificateRequest(rand.Reader, csrTemplate, privK)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return certificateRequest, kubeletKey, nil
|
||||
}
|
@ -3,12 +3,14 @@ package k8sapi
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubelet"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubernetes/k8sapi/resources"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeletconf "k8s.io/kubelet/config/v1beta1"
|
||||
kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
|
||||
kubeconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
// Uses types defined here: https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/
|
||||
@ -62,6 +64,11 @@ func (c *CoreOSConfiguration) InitConfiguration(externalCloudProvider bool) Kube
|
||||
"audit-log-maxbackup": "10", // CIS benchmark - Default value of Rancher
|
||||
"audit-log-maxsize": "100", // CIS benchmark - Default value of Rancher
|
||||
"profiling": "false", // CIS benchmark
|
||||
"kubelet-certificate-authority": filepath.Join(
|
||||
kubeconstants.KubernetesDir,
|
||||
kubeconstants.DefaultCertificateDir,
|
||||
kubeconstants.CACertName,
|
||||
),
|
||||
"tls-cipher-suites": "TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256," +
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," +
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," +
|
||||
@ -134,6 +141,8 @@ func (c *CoreOSConfiguration) InitConfiguration(externalCloudProvider bool) Kube
|
||||
Effect: corev1.TaintEffectPreferNoSchedule,
|
||||
},
|
||||
},
|
||||
TLSCertFile: kubelet.CertificateFilename,
|
||||
TLSPrivateKeyFile: kubelet.KeyFilename,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,28 @@ package k8sapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubelet"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubernetes/k8sapi/resources"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/util"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/logger"
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/zap"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,12 +45,14 @@ type Client interface {
|
||||
// KubernetesUtil provides low level management of the kubernetes cluster.
|
||||
type KubernetesUtil struct {
|
||||
inst installer
|
||||
file file.Handler
|
||||
}
|
||||
|
||||
// NewKubernetesUtil creates a new KubernetesUtil.
|
||||
func NewKubernetesUtil() *KubernetesUtil {
|
||||
return &KubernetesUtil{
|
||||
inst: newOSInstaller(),
|
||||
file: file.NewHandler(afero.NewOsFs()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +70,9 @@ func (k *KubernetesUtil) InstallComponents(ctx context.Context, version string)
|
||||
return enableSystemdUnit(ctx, kubeletServiceEtcPath)
|
||||
}
|
||||
|
||||
func (k *KubernetesUtil) InitCluster(ctx context.Context, initConfig []byte, log *logger.Logger) error {
|
||||
func (k *KubernetesUtil) InitCluster(
|
||||
ctx context.Context, initConfig []byte, nodeName string, ips []net.IP, log *logger.Logger,
|
||||
) error {
|
||||
// TODO: audit policy should be user input
|
||||
auditPolicy, err := resources.NewDefaultAuditPolicy().Marshal()
|
||||
if err != nil {
|
||||
@ -77,8 +91,40 @@ func (k *KubernetesUtil) InitCluster(ctx context.Context, initConfig []byte, log
|
||||
return fmt.Errorf("writing kubeadm init yaml config %v: %w", initConfigFile.Name(), err)
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, kubeadmPath, "init", "-v=5", "--config", initConfigFile.Name())
|
||||
// preflight
|
||||
log.Infof("Running kubeadm preflight checks")
|
||||
cmd := exec.CommandContext(ctx, kubeadmPath, "init", "phase", "preflight", "-v=5", "--config", initConfigFile.Name())
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
return fmt.Errorf("kubeadm init phase preflight failed (code %v) with: %s", exitErr.ExitCode(), out)
|
||||
}
|
||||
return fmt.Errorf("kubeadm init: %w", err)
|
||||
}
|
||||
|
||||
// create CA certs
|
||||
log.Infof("Creating Kubernetes control-plane certificates and keys")
|
||||
cmd = exec.CommandContext(ctx, kubeadmPath, "init", "phase", "certs", "all", "-v=5", "--config", initConfigFile.Name())
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
return fmt.Errorf("kubeadm init phase certs all failed (code %v) with: %s", exitErr.ExitCode(), out)
|
||||
}
|
||||
return fmt.Errorf("kubeadm init: %w", err)
|
||||
}
|
||||
|
||||
// create kubelet key and CA signed certificate for the node
|
||||
log.Infof("Creating signed kubelet certificate")
|
||||
if err := k.createSignedKubeletCert(nodeName, ips); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initialize the cluster
|
||||
log.Infof("Initializing the cluster using kubeadm init")
|
||||
cmd = exec.CommandContext(ctx, kubeadmPath, "init", "-v=5", "--skip-phases=preflight,certs", "--config", initConfigFile.Name())
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
@ -312,3 +358,92 @@ func (k *KubernetesUtil) RestartKubelet() error {
|
||||
defer cancel()
|
||||
return restartSystemdUnit(ctx, "kubelet.service")
|
||||
}
|
||||
|
||||
// createSignedKubeletCert manually creates a Kubernetes CA signed kubelet certificate for the bootstrapper node.
|
||||
// This is necessary because this node does not request a certificate from the join service.
|
||||
func (k *KubernetesUtil) createSignedKubeletCert(nodeName string, ips []net.IP) error {
|
||||
certRequestRaw, kubeletKey, err := kubelet.GetCertificateRequest(nodeName, ips)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.file.Write(kubelet.KeyFilename, kubeletKey, file.OptMkdirAll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parentCertRaw, err := k.file.Read(filepath.Join(
|
||||
constants.KubernetesDir,
|
||||
constants.DefaultCertificateDir,
|
||||
constants.CACertName,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parentCertPEM, _ := pem.Decode(parentCertRaw)
|
||||
parentCert, err := x509.ParseCertificate(parentCertPEM.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parentKeyRaw, err := k.file.Read(filepath.Join(
|
||||
constants.KubernetesDir,
|
||||
constants.DefaultCertificateDir,
|
||||
constants.CAKeyName,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parentKeyPEM, _ := pem.Decode(parentKeyRaw)
|
||||
var parentKey any
|
||||
switch parentKeyPEM.Type {
|
||||
case "EC PRIVATE KEY":
|
||||
parentKey, err = x509.ParseECPrivateKey(parentKeyPEM.Bytes)
|
||||
case "RSA PRIVATE KEY":
|
||||
parentKey, err = x509.ParsePKCS1PrivateKey(parentKeyPEM.Bytes)
|
||||
case "PRIVATE KEY":
|
||||
parentKey, err = x509.ParsePKCS8PrivateKey(parentKeyPEM.Bytes)
|
||||
default:
|
||||
err = fmt.Errorf("unsupported key type %q", parentCertPEM.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certRequest, err := x509.ParseCertificateRequest(certRequestRaw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serialNumber, err := util.GenerateCertificateSerialNumber()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
// Create the kubelet certificate
|
||||
// For a reference on the certificate fields, see: https://kubernetes.io/docs/setup/best-practices/certificates/
|
||||
certTmpl := &x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
NotBefore: now.Add(-2 * time.Hour),
|
||||
NotAfter: now.Add(24 * 365 * time.Hour),
|
||||
Subject: certRequest.Subject,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
},
|
||||
IsCA: false,
|
||||
BasicConstraintsValid: true,
|
||||
IPAddresses: certRequest.IPAddresses,
|
||||
}
|
||||
|
||||
certRaw, err := x509.CreateCertificate(rand.Reader, certTmpl, parentCert, certRequest.PublicKey, parentKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeletCert := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certRaw,
|
||||
})
|
||||
|
||||
return k.file.Write(kubelet.CertificateFilename, kubeletCert, file.OptMkdirAll)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubernetes/k8sapi"
|
||||
"github.com/edgelesssys/constellation/bootstrapper/internal/kubernetes/k8sapi/resources"
|
||||
@ -10,7 +11,7 @@ import (
|
||||
|
||||
type clusterUtil interface {
|
||||
InstallComponents(ctx context.Context, version string) error
|
||||
InitCluster(ctx context.Context, initConfig []byte, log *logger.Logger) error
|
||||
InitCluster(ctx context.Context, initConfig []byte, nodeName string, ips []net.IP, log *logger.Logger) error
|
||||
JoinCluster(ctx context.Context, joinConfig []byte, log *logger.Logger) error
|
||||
SetupPodNetwork(context.Context, k8sapi.SetupPodNetworkInput) error
|
||||
SetupAccessManager(kubectl k8sapi.Client, sshUsers resources.Marshaler) error
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
@ -96,6 +97,7 @@ func (k *KubeWrapper) InitCluster(
|
||||
var subnetworkPodCIDR string
|
||||
var controlPlaneEndpointIP string // this is the IP in "kubeadm init --control-plane-endpoint=<IP/DNS>:<port>" hence the unfortunate name
|
||||
var nodeIP string
|
||||
var validIPs []net.IP
|
||||
|
||||
// Step 1: retrieve cloud metadata for Kubernetes configuration
|
||||
if k.providerMetadata.Supported() {
|
||||
@ -104,6 +106,12 @@ func (k *KubeWrapper) InitCluster(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("retrieving own instance metadata failed: %w", err)
|
||||
}
|
||||
for _, ip := range instance.PrivateIPs {
|
||||
validIPs = append(validIPs, net.ParseIP(ip))
|
||||
}
|
||||
for _, ip := range instance.PublicIPs {
|
||||
validIPs = append(validIPs, net.ParseIP(ip))
|
||||
}
|
||||
nodeName = k8sCompliantHostname(instance.Name)
|
||||
providerID = instance.ProviderID
|
||||
if len(instance.PrivateIPs) > 0 {
|
||||
@ -152,7 +160,7 @@ func (k *KubeWrapper) InitCluster(
|
||||
return nil, fmt.Errorf("encoding kubeadm init configuration as YAML: %w", err)
|
||||
}
|
||||
log.Infof("Initializing Kubernetes cluster")
|
||||
if err := k.clusterUtil.InitCluster(ctx, initConfigYAML, log); err != nil {
|
||||
if err := k.clusterUtil.InitCluster(ctx, initConfigYAML, nodeName, validIPs, log); err != nil {
|
||||
return nil, fmt.Errorf("kubeadm init: %w", err)
|
||||
}
|
||||
kubeConfig, err := k.GetKubeconfig()
|
||||
|
@ -3,6 +3,7 @@ package kubernetes
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
@ -496,7 +497,7 @@ func (s *stubClusterUtil) InstallComponents(ctx context.Context, version string)
|
||||
return s.installComponentsErr
|
||||
}
|
||||
|
||||
func (s *stubClusterUtil) InitCluster(ctx context.Context, initConfig []byte, log *logger.Logger) error {
|
||||
func (s *stubClusterUtil) InitCluster(ctx context.Context, initConfig []byte, nodeName string, ips []net.IP, log *logger.Logger) error {
|
||||
s.initConfigs = append(s.initConfigs, initConfig)
|
||||
return s.initClusterErr
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
package kubernetesca
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/bootstrapper/util"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/logger"
|
||||
kubeconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,22 +35,22 @@ func New(log *logger.Logger, fileHandler file.Handler) *KubernetesCA {
|
||||
}
|
||||
|
||||
// GetCertificate creates a certificate for a node and signs it using the Kubernetes root CA.
|
||||
func (c KubernetesCA) GetCertificate(nodeName string) (cert []byte, key []byte, err error) {
|
||||
func (c KubernetesCA) GetCertificate(csr []byte) (cert []byte, err error) {
|
||||
c.log.Debugf("Loading Kubernetes CA certificate")
|
||||
parentCertRaw, err := c.file.Read(caCertFilename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
parentCertPEM, _ := pem.Decode(parentCertRaw)
|
||||
parentCert, err := x509.ParseCertificate(parentCertPEM.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.log.Debugf("Loading Kubernetes CA private key")
|
||||
parentKeyRaw, err := c.file.Read(caKeyFilename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
parentKeyPEM, _ := pem.Decode(parentKeyRaw)
|
||||
var parentKey any
|
||||
@ -62,30 +62,34 @@ func (c KubernetesCA) GetCertificate(nodeName string) (cert []byte, key []byte,
|
||||
case "PRIVATE KEY":
|
||||
parentKey, err = x509.ParsePKCS8PrivateKey(parentKeyPEM.Bytes)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unsupported key type %q", parentCertPEM.Type)
|
||||
return nil, fmt.Errorf("unsupported key type %q", parentCertPEM.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.log.Infof("Creating kubelet private key")
|
||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
certRequest, err := x509.ParseCertificateRequest(csr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
keyBytes, err := x509.MarshalECPrivateKey(privK)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
if err := certRequest.CheckSignature(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeletKey := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
|
||||
c.log.Infof("Creating kubelet certificate")
|
||||
if len(certRequest.Subject.Organization) != 1 {
|
||||
return nil, errors.New("certificate request must have exactly one organization")
|
||||
}
|
||||
if certRequest.Subject.Organization[0] != kubeconstants.NodesGroup {
|
||||
return nil, fmt.Errorf("certificate request must have organization %q but has %q", kubeconstants.NodesGroup, certRequest.Subject.Organization[0])
|
||||
}
|
||||
if !strings.HasPrefix(certRequest.Subject.CommonName, kubeconstants.NodesUserPrefix) {
|
||||
return nil, fmt.Errorf("certificate request must have common name prefix %q but is %q", kubeconstants.NodesUserPrefix, certRequest.Subject.CommonName)
|
||||
}
|
||||
|
||||
serialNumber, err := util.GenerateCertificateSerialNumber()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
@ -95,25 +99,25 @@ func (c KubernetesCA) GetCertificate(nodeName string) (cert []byte, key []byte,
|
||||
SerialNumber: serialNumber,
|
||||
NotBefore: now.Add(-2 * time.Hour),
|
||||
NotAfter: now.Add(24 * 365 * time.Hour),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"system:nodes"},
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
},
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
Subject: certRequest.Subject,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
},
|
||||
IsCA: false,
|
||||
BasicConstraintsValid: true,
|
||||
IPAddresses: certRequest.IPAddresses,
|
||||
}
|
||||
certRaw, err := x509.CreateCertificate(rand.Reader, certTmpl, parentCert, &privK.PublicKey, parentKey)
|
||||
|
||||
certRaw, err := x509.CreateCertificate(rand.Reader, certTmpl, parentCert, certRequest.PublicKey, parentKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
kubeletCert := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certRaw,
|
||||
})
|
||||
|
||||
return kubeletCert, kubeletKey, nil
|
||||
return kubeletCert, nil
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -19,6 +20,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/goleak"
|
||||
kubeconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@ -38,45 +40,126 @@ Q29uc3RlbGxhdGlvbg==
|
||||
invalidCert := []byte(`-----BEGIN CERTIFICATE-----
|
||||
Q29uc3RlbGxhdGlvbg==
|
||||
-----END CERTIFICATE-----`)
|
||||
defaultSigningRequestFunc := func() ([]byte, error) {
|
||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{kubeconstants.NodesGroup},
|
||||
CommonName: kubeconstants.NodesUserPrefix + "test-node",
|
||||
},
|
||||
}
|
||||
return x509.CreateCertificateRequest(rand.Reader, csrTemplate, privK)
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
caCert []byte
|
||||
caKey []byte
|
||||
wantErr bool
|
||||
caCert []byte
|
||||
caKey []byte
|
||||
createSigningRequest func() ([]byte, error)
|
||||
wantErr bool
|
||||
}{
|
||||
"success ec key": {
|
||||
caCert: ecCert,
|
||||
caKey: ecKey,
|
||||
caCert: ecCert,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
},
|
||||
"success rsa key": {
|
||||
caCert: rsaCert,
|
||||
caKey: rsaKey,
|
||||
caCert: rsaCert,
|
||||
caKey: rsaKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
},
|
||||
"success any key": {
|
||||
caCert: testCert,
|
||||
caKey: testKey,
|
||||
caCert: testCert,
|
||||
caKey: testKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
},
|
||||
"unsupported key": {
|
||||
caCert: ecCert,
|
||||
caKey: unsupportedKey,
|
||||
wantErr: true,
|
||||
caCert: ecCert,
|
||||
caKey: unsupportedKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid key": {
|
||||
caCert: ecCert,
|
||||
caKey: invalidKey,
|
||||
wantErr: true,
|
||||
caCert: ecCert,
|
||||
caKey: invalidKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid certificate": {
|
||||
caCert: invalidCert,
|
||||
caKey: ecKey,
|
||||
wantErr: true,
|
||||
caCert: invalidCert,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
wantErr: true,
|
||||
},
|
||||
"no ca certificate": {
|
||||
caKey: ecKey,
|
||||
wantErr: true,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
wantErr: true,
|
||||
},
|
||||
"no ca key": {
|
||||
caCert: ecCert,
|
||||
caCert: ecCert,
|
||||
createSigningRequest: defaultSigningRequestFunc,
|
||||
wantErr: true,
|
||||
},
|
||||
"no signing request": {
|
||||
caCert: ecCert,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: func() ([]byte, error) { return nil, nil },
|
||||
wantErr: true,
|
||||
},
|
||||
"incorrect common name format": {
|
||||
caCert: ecCert,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: func() ([]byte, error) {
|
||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{kubeconstants.NodesGroup},
|
||||
CommonName: "test-node",
|
||||
},
|
||||
}
|
||||
return x509.CreateCertificateRequest(rand.Reader, csrTemplate, privK)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"incorrect organization format": {
|
||||
caCert: ecCert,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: func() ([]byte, error) {
|
||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"test"},
|
||||
CommonName: kubeconstants.NodesUserPrefix + "test-node",
|
||||
},
|
||||
}
|
||||
return x509.CreateCertificateRequest(rand.Reader, csrTemplate, privK)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"no organization": {
|
||||
caCert: ecCert,
|
||||
caKey: ecKey,
|
||||
createSigningRequest: func() ([]byte, error) {
|
||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: kubeconstants.NodesUserPrefix + "test-node",
|
||||
},
|
||||
}
|
||||
return x509.CreateCertificateRequest(rand.Reader, csrTemplate, privK)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
@ -100,8 +183,9 @@ Q29uc3RlbGxhdGlvbg==
|
||||
file,
|
||||
)
|
||||
|
||||
nodeName := "test"
|
||||
kubeCert, kubeKey, err := ca.GetCertificate(nodeName)
|
||||
signingRequest, err := tc.createSigningRequest()
|
||||
require.NoError(err)
|
||||
kubeCert, err := ca.GetCertificate(signingRequest)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
@ -112,19 +196,12 @@ Q29uc3RlbGxhdGlvbg==
|
||||
require.NotNil(certPEM)
|
||||
cert, err := x509.ParseCertificate(certPEM.Bytes)
|
||||
require.NoError(err)
|
||||
assert.Equal("system:node:"+nodeName, cert.Subject.CommonName)
|
||||
assert.Equal("system:nodes", cert.Subject.Organization[0])
|
||||
assert.True(strings.HasPrefix(cert.Subject.CommonName, kubeconstants.NodesUserPrefix))
|
||||
assert.Equal(kubeconstants.NodesGroup, cert.Subject.Organization[0])
|
||||
assert.Equal(x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment, cert.KeyUsage)
|
||||
assert.Equal(x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[0])
|
||||
assert.False(cert.IsCA)
|
||||
assert.True(cert.BasicConstraintsValid)
|
||||
|
||||
keyPEM, _ := pem.Decode(kubeKey)
|
||||
require.NotNil(keyPEM)
|
||||
key, err := x509.ParseECPrivateKey(keyPEM.Bytes)
|
||||
require.NoError(err)
|
||||
require.IsType(&ecdsa.PublicKey{}, cert.PublicKey)
|
||||
assert.Equal(&key.PublicKey, cert.PublicKey.(*ecdsa.PublicKey))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func (s *Server) IssueJoinTicket(ctx context.Context, req *joinproto.IssueJoinTi
|
||||
}
|
||||
|
||||
log.Infof("Creating signed kubelet certificate")
|
||||
kubeletCert, kubeletKey, err := s.ca.GetCertificate(req.NodeName)
|
||||
kubeletCert, err := s.ca.GetCertificate(req.CertificateRequest)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "unable to generate kubelet certificate: %s", err)
|
||||
}
|
||||
@ -124,7 +124,6 @@ func (s *Server) IssueJoinTicket(ctx context.Context, req *joinproto.IssueJoinTi
|
||||
Token: kubeArgs.Token,
|
||||
DiscoveryTokenCaCertHash: kubeArgs.CACertHashes[0],
|
||||
KubeletCert: kubeletCert,
|
||||
KubeletKey: kubeletKey,
|
||||
ControlPlaneFiles: controlPlaneFiles,
|
||||
}, nil
|
||||
}
|
||||
@ -144,5 +143,5 @@ type dataKeyGetter interface {
|
||||
|
||||
type certificateAuthority interface {
|
||||
// GetCertificate returns a certificate and private key, signed by the issuer.
|
||||
GetCertificate(nodeName string) (kubeletCert []byte, kubeletKey []byte, err error)
|
||||
GetCertificate(certificateRequest []byte) (kubeletCert []byte, err error)
|
||||
}
|
||||
|
@ -49,33 +49,33 @@ func TestIssueJoinTicket(t *testing.T) {
|
||||
"worker node": {
|
||||
kubeadm: stubTokenGetter{token: testJoinToken},
|
||||
kms: stubKeyGetter{dataKey: testKey},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
id: mustMarshalID(testID),
|
||||
},
|
||||
"GetDataKey fails": {
|
||||
kubeadm: stubTokenGetter{token: testJoinToken},
|
||||
kms: stubKeyGetter{getDataKeyErr: someErr},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
id: mustMarshalID(testID),
|
||||
wantErr: true,
|
||||
},
|
||||
"loading IDs fails": {
|
||||
kubeadm: stubTokenGetter{token: testJoinToken},
|
||||
kms: stubKeyGetter{dataKey: testKey},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
id: []byte{0x1, 0x2, 0x3},
|
||||
wantErr: true,
|
||||
},
|
||||
"no ID file": {
|
||||
kubeadm: stubTokenGetter{token: testJoinToken},
|
||||
kms: stubKeyGetter{dataKey: testKey},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
wantErr: true,
|
||||
},
|
||||
"GetJoinToken fails": {
|
||||
kubeadm: stubTokenGetter{getJoinTokenErr: someErr},
|
||||
kms: stubKeyGetter{dataKey: testKey},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
id: mustMarshalID(testID),
|
||||
wantErr: true,
|
||||
},
|
||||
@ -93,14 +93,14 @@ func TestIssueJoinTicket(t *testing.T) {
|
||||
files: map[string][]byte{"test": {0x1, 0x2, 0x3}},
|
||||
},
|
||||
kms: stubKeyGetter{dataKey: testKey},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
id: mustMarshalID(testID),
|
||||
},
|
||||
"GetControlPlaneCertificateKey fails": {
|
||||
isControlPlane: true,
|
||||
kubeadm: stubTokenGetter{token: testJoinToken, certificateKeyErr: someErr},
|
||||
kms: stubKeyGetter{dataKey: testKey},
|
||||
ca: stubCA{cert: testCert, key: testKey},
|
||||
ca: stubCA{cert: testCert},
|
||||
id: mustMarshalID(testID),
|
||||
wantErr: true,
|
||||
},
|
||||
@ -125,7 +125,6 @@ func TestIssueJoinTicket(t *testing.T) {
|
||||
|
||||
req := &joinproto.IssueJoinTicketRequest{
|
||||
DiskUuid: "uuid",
|
||||
NodeName: "test",
|
||||
IsControlPlane: tc.isControlPlane,
|
||||
}
|
||||
resp, err := api.IssueJoinTicket(context.Background(), req)
|
||||
@ -145,7 +144,6 @@ func TestIssueJoinTicket(t *testing.T) {
|
||||
assert.Equal(tc.kubeadm.token.CACertHashes[0], resp.DiscoveryTokenCaCertHash)
|
||||
assert.Equal(tc.kubeadm.token.Token, resp.Token)
|
||||
assert.Equal(tc.ca.cert, resp.KubeletCert)
|
||||
assert.Equal(tc.ca.key, resp.KubeletKey)
|
||||
|
||||
if tc.isControlPlane {
|
||||
assert.Len(resp.ControlPlaneFiles, len(tc.kubeadm.files))
|
||||
@ -188,10 +186,9 @@ func (f stubKeyGetter) GetDataKey(context.Context, string, int) ([]byte, error)
|
||||
|
||||
type stubCA struct {
|
||||
cert []byte
|
||||
key []byte
|
||||
getCertErr error
|
||||
}
|
||||
|
||||
func (f stubCA) GetCertificate(string) ([]byte, []byte, error) {
|
||||
return f.cert, f.key, f.getCertErr
|
||||
func (f stubCA) GetCertificate(csr []byte) ([]byte, error) {
|
||||
return f.cert, f.getCertErr
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ type IssueJoinTicketRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DiskUuid string `protobuf:"bytes,1,opt,name=disk_uuid,json=diskUuid,proto3" json:"disk_uuid,omitempty"`
|
||||
NodeName string `protobuf:"bytes,2,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
|
||||
IsControlPlane bool `protobuf:"varint,3,opt,name=is_control_plane,json=isControlPlane,proto3" json:"is_control_plane,omitempty"`
|
||||
DiskUuid string `protobuf:"bytes,1,opt,name=disk_uuid,json=diskUuid,proto3" json:"disk_uuid,omitempty"`
|
||||
CertificateRequest []byte `protobuf:"bytes,2,opt,name=certificate_request,json=certificateRequest,proto3" json:"certificate_request,omitempty"`
|
||||
IsControlPlane bool `protobuf:"varint,3,opt,name=is_control_plane,json=isControlPlane,proto3" json:"is_control_plane,omitempty"`
|
||||
}
|
||||
|
||||
func (x *IssueJoinTicketRequest) Reset() {
|
||||
@ -69,11 +69,11 @@ func (x *IssueJoinTicketRequest) GetDiskUuid() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *IssueJoinTicketRequest) GetNodeName() string {
|
||||
func (x *IssueJoinTicketRequest) GetCertificateRequest() []byte {
|
||||
if x != nil {
|
||||
return x.NodeName
|
||||
return x.CertificateRequest
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *IssueJoinTicketRequest) GetIsControlPlane() bool {
|
||||
@ -91,12 +91,11 @@ type IssueJoinTicketResponse struct {
|
||||
StateDiskKey []byte `protobuf:"bytes,1,opt,name=state_disk_key,json=stateDiskKey,proto3" json:"state_disk_key,omitempty"`
|
||||
OwnerId []byte `protobuf:"bytes,2,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"`
|
||||
ClusterId []byte `protobuf:"bytes,3,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"`
|
||||
KubeletKey []byte `protobuf:"bytes,4,opt,name=kubelet_key,json=kubeletKey,proto3" json:"kubelet_key,omitempty"`
|
||||
KubeletCert []byte `protobuf:"bytes,5,opt,name=kubelet_cert,json=kubeletCert,proto3" json:"kubelet_cert,omitempty"`
|
||||
ApiServerEndpoint string `protobuf:"bytes,6,opt,name=api_server_endpoint,json=apiServerEndpoint,proto3" json:"api_server_endpoint,omitempty"`
|
||||
Token string `protobuf:"bytes,7,opt,name=token,proto3" json:"token,omitempty"`
|
||||
DiscoveryTokenCaCertHash string `protobuf:"bytes,8,opt,name=discovery_token_ca_cert_hash,json=discoveryTokenCaCertHash,proto3" json:"discovery_token_ca_cert_hash,omitempty"`
|
||||
ControlPlaneFiles []*ControlPlaneCertOrKey `protobuf:"bytes,9,rep,name=control_plane_files,json=controlPlaneFiles,proto3" json:"control_plane_files,omitempty"`
|
||||
KubeletCert []byte `protobuf:"bytes,4,opt,name=kubelet_cert,json=kubeletCert,proto3" json:"kubelet_cert,omitempty"`
|
||||
ApiServerEndpoint string `protobuf:"bytes,5,opt,name=api_server_endpoint,json=apiServerEndpoint,proto3" json:"api_server_endpoint,omitempty"`
|
||||
Token string `protobuf:"bytes,6,opt,name=token,proto3" json:"token,omitempty"`
|
||||
DiscoveryTokenCaCertHash string `protobuf:"bytes,7,opt,name=discovery_token_ca_cert_hash,json=discoveryTokenCaCertHash,proto3" json:"discovery_token_ca_cert_hash,omitempty"`
|
||||
ControlPlaneFiles []*ControlPlaneCertOrKey `protobuf:"bytes,8,rep,name=control_plane_files,json=controlPlaneFiles,proto3" json:"control_plane_files,omitempty"`
|
||||
}
|
||||
|
||||
func (x *IssueJoinTicketResponse) Reset() {
|
||||
@ -152,13 +151,6 @@ func (x *IssueJoinTicketResponse) GetClusterId() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *IssueJoinTicketResponse) GetKubeletKey() []byte {
|
||||
if x != nil {
|
||||
return x.KubeletKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *IssueJoinTicketResponse) GetKubeletCert() []byte {
|
||||
if x != nil {
|
||||
return x.KubeletCert
|
||||
@ -253,54 +245,53 @@ var File_join_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_join_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6a, 0x6f,
|
||||
0x69, 0x6e, 0x22, 0x7c, 0x0a, 0x16, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x54,
|
||||
0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x75, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64,
|
||||
0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f,
|
||||
0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x0e, 0x69, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65,
|
||||
0x22, 0x94, 0x03, 0x0a, 0x17, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x69,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x0e,
|
||||
0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b,
|
||||
0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b,
|
||||
0x6b, 0x75, 0x62, 0x65, 0x6c, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x6c, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a,
|
||||
0x0c, 0x6b, 0x75, 0x62, 0x65, 0x6c, 0x65, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6b, 0x75, 0x62, 0x65, 0x6c, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74,
|
||||
0x12, 0x2e, 0x0a, 0x13, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x65,
|
||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61,
|
||||
0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x3e, 0x0a, 0x1c, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76,
|
||||
0x65, 0x72, 0x79, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x63, 0x61, 0x5f, 0x63, 0x65, 0x72,
|
||||
0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x64, 0x69,
|
||||
0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x43, 0x61, 0x43, 0x65,
|
||||
0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6f, 0x72,
|
||||
0x5f, 0x6b, 0x65, 0x79, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61,
|
||||
0x6e, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x43, 0x0a, 0x19, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6f, 0x72,
|
||||
0x5f, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x55, 0x0a, 0x03,
|
||||
0x41, 0x50, 0x49, 0x12, 0x4e, 0x0a, 0x0f, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e,
|
||||
0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1c, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x2e, 0x49, 0x73,
|
||||
0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x2e, 0x49, 0x73, 0x73, 0x75,
|
||||
0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x6f, 0x69, 0x6e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6a, 0x6f, 0x69, 0x6e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x6e, 0x22, 0x90, 0x01, 0x0a, 0x16, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e,
|
||||
0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a,
|
||||
0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x75, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x65,
|
||||
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x69,
|
||||
0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x50, 0x6c, 0x61, 0x6e, 0x65, 0x22, 0xf3, 0x02, 0x0a, 0x17, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4a,
|
||||
0x6f, 0x69, 0x6e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||
0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6b, 0x75, 0x62, 0x65, 0x6c, 0x65, 0x74, 0x5f, 0x63, 0x65, 0x72,
|
||||
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6b, 0x75, 0x62, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x43, 0x65, 0x72, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x11, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x3e, 0x0a, 0x1c, 0x64, 0x69,
|
||||
0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x63, 0x61,
|
||||
0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x18, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x43, 0x61, 0x43, 0x65, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4f, 0x0a, 0x13, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65,
|
||||
0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x63, 0x65, 0x72,
|
||||
0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x43, 0x0a, 0x19, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x63, 0x65, 0x72,
|
||||
0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
|
||||
0x32, 0x55, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x4e, 0x0a, 0x0f, 0x49, 0x73, 0x73, 0x75, 0x65,
|
||||
0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1c, 0x2e, 0x6a, 0x6f, 0x69,
|
||||
0x6e, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x63, 0x6b, 0x65,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x2e,
|
||||
0x49, 0x73, 0x73, 0x75, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73, 0x79,
|
||||
0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f,
|
||||
0x6a, 0x6f, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6a, 0x6f, 0x69, 0x6e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -11,7 +11,7 @@ service API {
|
||||
|
||||
message IssueJoinTicketRequest {
|
||||
string disk_uuid = 1;
|
||||
string node_name = 2;
|
||||
bytes certificate_request = 2;
|
||||
bool is_control_plane = 3;
|
||||
}
|
||||
|
||||
@ -19,12 +19,11 @@ message IssueJoinTicketResponse {
|
||||
bytes state_disk_key = 1;
|
||||
bytes owner_id = 2;
|
||||
bytes cluster_id = 3;
|
||||
bytes kubelet_key = 4;
|
||||
bytes kubelet_cert = 5;
|
||||
string api_server_endpoint = 6;
|
||||
string token = 7;
|
||||
string discovery_token_ca_cert_hash = 8;
|
||||
repeated control_plane_cert_or_key control_plane_files = 9;
|
||||
bytes kubelet_cert = 4;
|
||||
string api_server_endpoint = 5;
|
||||
string token = 6;
|
||||
string discovery_token_ca_cert_hash = 7;
|
||||
repeated control_plane_cert_or_key control_plane_files = 8;
|
||||
}
|
||||
|
||||
message control_plane_cert_or_key {
|
||||
|
Loading…
Reference in New Issue
Block a user