Skip to content
Snippets Groups Projects
Commit ea1d39af authored by kaiyou's avatar kaiyou
Browse files

Move pki code to a dedicated package

parent 1698270e
No related branches found
No related tags found
No related merge requests found
package cluster
import (
"forge.tedomum.net/acides/hepto/hepto/pkg/pki"
"github.com/sirupsen/logrus"
)
func (c *Cluster) initCerts() {
// Prepare the cluster PKI
if c.node.Role == Master {
pki, err := NewClusterPKI("pki")
ca, err := pki.NewClusterPKI("pki")
if err != nil {
logrus.Fatal("could not initialize pki: ", err)
}
masterCerts, err := NewMasterCerts("master", c.networking.NodeAddress.IP)
masterCerts, err := pki.NewMasterCerts("master", c.networking.NodeAddress.IP)
if err != nil {
logrus.Fatal("could not initialize master certs: ", err)
}
c.pki = pki
c.pki = ca
c.masterCerts = masterCerts
}
c.ml.State.PKI = c.pki
// Initialize node certificates
certs, err := NewNodeCerts("certs", c.node.Name)
certs, err := pki.NewNodeCerts("certs", c.node.Name)
if err != nil {
logrus.Fatal("could not initialize node certificates: ", err)
}
c.certs = certs
c.ml.State.Certificates = make(map[string]*NodeCerts)
c.ml.State.Certificates = make(map[string]*pki.NodeCerts)
c.ml.State.Certificates[c.node.Name] = certs
}
......
......@@ -4,6 +4,7 @@ package cluster
import (
"forge.tedomum.net/acides/hepto/hepto/pkg/sml"
"forge.tedomum.net/acides/hepto/hepto/pkg/pki"
"forge.tedomum.net/acides/hepto/hepto/pkg/wg"
"github.com/sirupsen/logrus"
)
......@@ -14,9 +15,9 @@ type Cluster struct {
vpn *wg.Wireguard
networking *ClusterNetworking
node *NodeSettings
certs *NodeCerts
masterCerts *MasterCerts
pki *ClusterPKI
certs *pki.NodeCerts
masterCerts *pki.MasterCerts
pki *pki.ClusterPKI
services *ClusterServices
}
......@@ -26,7 +27,7 @@ func New(settings *ClusterSettings, node *NodeSettings) *Cluster {
node: node,
networking: NewClusterNetworking(settings.Name, node.Name),
ml: sml.New[HeptoMeta, HeptoState](node.Name, node.IP, node.Port, node.Anchors, settings.Key),
pki: &ClusterPKI{},
pki: &pki.ClusterPKI{},
services: NewClusterServices(),
}
}
......
......@@ -4,6 +4,8 @@ import (
"encoding/json"
"fmt"
"strings"
"forge.tedomum.net/acides/hepto/hepto/pkg/pki"
)
// Represents a node metadata
......@@ -17,10 +19,10 @@ type HeptoMeta struct {
// Represents the cluster state
type HeptoState struct {
// Cluster CAs public certificates
PKI *ClusterPKI `json:"ca"`
PKI *pki.ClusterPKI `json:"ca"`
// Certificate per node, this should only
// be updated by the node itself
Certificates map[string]*NodeCerts `json:"nodes"`
Certificates map[string]*pki.NodeCerts `json:"nodes"`
}
func (m *HeptoMeta) Encode() ([]byte, error) {
......
......@@ -5,6 +5,7 @@ import (
"fmt"
"net"
"forge.tedomum.net/acides/hepto/hepto/pkg/pki"
"forge.tedomum.net/acides/hepto/hepto/pkg/wrappers"
"github.com/sirupsen/logrus"
"go.etcd.io/etcd/server/v3/embed"
......@@ -67,14 +68,14 @@ func (s *ClusterServices) startEtcd() {
go s.watch(service)
}
func (s *ClusterServices) startK8sMaster(net *ClusterNetworking, pki *ClusterPKI, certs *MasterCerts) {
func (s *ClusterServices) startK8sMaster(net *ClusterNetworking, ca *pki.ClusterPKI, certs *pki.MasterCerts) {
api, err := wrappers.APIServer(s.ctx, []string{
"--bind-address", net.NodeAddress.IP.String(),
"--service-cluster-ip-range", net.ServiceNet.String(),
"--tls-cert-file", certs.Service.CertPath(),
"--tls-private-key-file", certs.Service.KeyPath(),
"--client-ca-file", pki.API.CertPath(),
"--kubelet-certificate-authority", pki.Kubelet.CertPath(),
"--client-ca-file", ca.API.CertPath(),
"--kubelet-certificate-authority", ca.Kubelet.CertPath(),
"--kubelet-client-certificate", certs.Kubelet.CertPath(),
"--kubelet-client-key", certs.Kubelet.KeyPath(),
"--etcd-servers", "http://localhost:2379",
......@@ -89,7 +90,7 @@ func (s *ClusterServices) startK8sMaster(net *ClusterNetworking, pki *ClusterPKI
}
cmConfig := KubeConfig{
URL: fmt.Sprintf("https://[%s]:6443", net.NodeAddress.IP.String()),
CACert: pki.Services.CertPath(),
CACert: ca.Services.CertPath(),
ClientCert: certs.ControllersClient.CertPath(),
ClientKey: certs.ControllersClient.KeyPath(),
}
......@@ -110,7 +111,7 @@ func (s *ClusterServices) startK8sMaster(net *ClusterNetworking, pki *ClusterPKI
}
schedulerConfig := KubeConfig{
URL: fmt.Sprintf("https://[%s]:6443", net.NodeAddress.IP.String()),
CACert: pki.Services.CertPath(),
CACert: ca.Services.CertPath(),
ClientCert: certs.SchedulerClient.CertPath(),
ClientKey: certs.SchedulerClient.KeyPath(),
}
......@@ -130,17 +131,17 @@ func (s *ClusterServices) startK8sMaster(net *ClusterNetworking, pki *ClusterPKI
go s.watch(scheduler)
}
func (s *ClusterServices) startK8sNode(master net.IP, pki *ClusterPKI, certs *NodeCerts) {
func (s *ClusterServices) startK8sNode(master net.IP, ca *pki.ClusterPKI, certs *pki.NodeCerts) {
kubeletKubeConfig := KubeConfig{
URL: fmt.Sprintf("https://[%s]:6443", master.String()),
CACert: pki.Services.CertPath(),
CACert: ca.Services.CertPath(),
ClientCert: certs.API.CertPath(),
ClientKey: certs.API.KeyPath(),
}
kubeletKubeConfigPath := "/kubelet-kubeconfig.yaml"
kubeletKubeConfig.Write(kubeletKubeConfigPath)
kubeletConfig := KubeletConfig{
CACert: pki.Kubelet.CertPath(),
CACert: ca.Kubelet.CertPath(),
TLSCert: certs.Service.CertPath(),
TLSKey: certs.Service.KeyPath(),
}
......
package pki
import (
"os"
"path/filepath"
"forge.tedomum.net/acides/hepto/hepto/pkg/pekahi"
)
// Cluster PKI is made of three different PKIs
type ClusterPKI struct {
// Signs services exposed over the cluster
Services *pekahi.PKI `json:"services"`
// Signs kubelet client certificates (master)
Kubelet *pekahi.PKI `json:"kubelet"`
// Signs apiserver client certificates (nodes and controller)
API *pekahi.PKI `json:"api"`
}
func NewClusterPKI(path string) (*ClusterPKI, error) {
err := os.MkdirAll(path, 0755)
if err != nil {
return nil, err
}
servicesCA, err := pekahi.GetPKI(filepath.Join(path, "services"))
if err != nil {
return nil, err
}
kubeletCA, err := pekahi.GetPKI(filepath.Join(path, "kubelet"))
if err != nil {
return nil, err
}
apiserverCA, err := pekahi.GetPKI(filepath.Join(path, "api"))
if err != nil {
return nil, err
}
return &ClusterPKI{servicesCA, kubeletCA, apiserverCA}, nil
}
// Merge PKI
func (n *ClusterPKI) Merge(other *ClusterPKI) bool {
change := false
if n.API == nil && other.API != nil {
n.API = other.API
change = true
}
if n.Services == nil && other.Services != nil {
n.Services = other.Services
change = true
}
if n.Kubelet == nil && other.Kubelet != nil {
n.Kubelet = other.Kubelet
change = true
}
return change
}
package cluster
package pki
import (
"crypto/x509"
"net"
"os"
"path/filepath"
"forge.tedomum.net/acides/hepto/hepto/pkg/pekahi"
"github.com/sirupsen/logrus"
)
// Cluster PKI is made of three different PKIs
type ClusterPKI struct {
// Signs services exposed over the cluster
Services *pekahi.PKI `json:"services"`
// Signs kubelet client certificates (master)
Kubelet *pekahi.PKI `json:"kubelet"`
// Signs apiserver client certificates (nodes and controller)
API *pekahi.PKI `json:"api"`
}
// Node certs
type NodeCerts struct {
// Certificate for exposing the kubelet service
Service *pekahi.Certificate `json:"service"`
// Node certificate for accessing the apiserver
API *pekahi.Certificate `json:"api"`
}
// Master certs
type MasterCerts struct {
// Certificate for exposing the apiserver
......@@ -44,97 +24,6 @@ type MasterCerts struct {
SchedulerClient *pekahi.Certificate
}
// Merge PKI
func (n *ClusterPKI) Merge(other *ClusterPKI) bool {
change := false
if n.API == nil && other.API != nil {
n.API = other.API
change = true
}
if n.Services == nil && other.Services != nil {
n.Services = other.Services
change = true
}
if n.Kubelet == nil && other.Kubelet != nil {
n.Kubelet = other.Kubelet
change = true
}
return change
}
// Merge a single node or master certificate
func mergeCert(local *pekahi.Certificate, remote *pekahi.Certificate) bool {
change := false
// Import CSR to master for signing
if local.CSR == nil && remote.CSR != nil {
local.CSR = remote.CSR
change = true
}
// Import and save cert back to node
if local.Cert == nil && remote.Cert != nil {
local.Cert = remote.Cert
local.Save()
change = true
}
return change
}
// Merge node certificates
func (n *NodeCerts) Merge(other *NodeCerts) bool {
change := mergeCert(n.Service, other.Service)
change = change || mergeCert(n.API, other.API)
return change
}
func NewClusterPKI(path string) (*ClusterPKI, error) {
err := os.MkdirAll(path, 0755)
if err != nil {
return nil, err
}
servicesCA, err := pekahi.GetPKI(filepath.Join(path, "services"))
if err != nil {
return nil, err
}
kubeletCA, err := pekahi.GetPKI(filepath.Join(path, "kubelet"))
if err != nil {
return nil, err
}
apiserverCA, err := pekahi.GetPKI(filepath.Join(path, "api"))
if err != nil {
return nil, err
}
return &ClusterPKI{servicesCA, kubeletCA, apiserverCA}, nil
}
func NewNodeCerts(path string, nodeName string) (*NodeCerts, error) {
err := os.MkdirAll(path, 0755)
if err != nil {
return nil, err
}
// Service certificate
serviceCert, err := pekahi.GetCertificate(filepath.Join(path, "service"))
if err != nil {
return nil, err
}
err = serviceCert.MakeCSR(pekahi.NewServerTemplate([]string{nodeName}, []net.IP{}))
if err != nil {
return nil, err
}
// API certificate
apiClientCert, err := pekahi.GetCertificate(filepath.Join(path, "api"))
if err != nil {
return nil, err
}
err = apiClientCert.MakeCSR(pekahi.NewClientTemplate("system:nodes:"+nodeName, "system:nodes"))
if err != nil {
return nil, err
}
return &NodeCerts{
Service: serviceCert,
API: apiClientCert,
}, nil
}
func NewMasterCerts(path string, ip net.IP) (*MasterCerts, error) {
err := os.MkdirAll(path, 0755)
if err != nil {
......@@ -200,21 +89,6 @@ func NewMasterCerts(path string, ip net.IP) (*MasterCerts, error) {
}, nil
}
func signCert(p *pekahi.PKI, c *pekahi.Certificate, template *x509.Certificate) {
if c.CSR != nil && c.Cert == nil {
logrus.Info("signing certificate ", c.CSR.Subject.String())
err := p.Sign(c, template)
if err != nil {
logrus.Warnf("cannot sign API certificate for %s: %s", c.CSR.Subject.String(), err)
}
}
}
func (p *ClusterPKI) SignNodeCerts(name string, n *NodeCerts) {
signCert(p.Services, n.Service, pekahi.NewServerTemplate([]string{name}, []net.IP{}))
signCert(p.API, n.API, pekahi.NewClientTemplate("system:node:"+name, "system:nodes"))
}
func (p *ClusterPKI) SignMasterCerts(m *MasterCerts) {
signCert(p.Services, m.Service, pekahi.NewServerTemplate(m.Service.CSR.DNSNames, m.Service.CSR.IPAddresses))
signCert(p.Kubelet, m.Kubelet, pekahi.NewClientTemplate(m.Kubelet.CSR.Subject.CommonName, ""))
......
package pki
import (
"net"
"os"
"path/filepath"
"forge.tedomum.net/acides/hepto/hepto/pkg/pekahi"
)
// Node certs
type NodeCerts struct {
// Certificate for exposing the kubelet service
Service *pekahi.Certificate `json:"service"`
// Node certificate for accessing the apiserver
API *pekahi.Certificate `json:"api"`
}
func NewNodeCerts(path string, nodeName string) (*NodeCerts, error) {
err := os.MkdirAll(path, 0755)
if err != nil {
return nil, err
}
// Service certificate
serviceCert, err := pekahi.GetCertificate(filepath.Join(path, "service"))
if err != nil {
return nil, err
}
err = serviceCert.MakeCSR(pekahi.NewServerTemplate([]string{nodeName}, []net.IP{}))
if err != nil {
return nil, err
}
// API certificate
apiClientCert, err := pekahi.GetCertificate(filepath.Join(path, "api"))
if err != nil {
return nil, err
}
err = apiClientCert.MakeCSR(pekahi.NewClientTemplate("system:nodes:"+nodeName, "system:nodes"))
if err != nil {
return nil, err
}
return &NodeCerts{
Service: serviceCert,
API: apiClientCert,
}, nil
}
// Merge node certificates
func (n *NodeCerts) Merge(other *NodeCerts) bool {
change := mergeCert(n.Service, other.Service)
change = change || mergeCert(n.API, other.API)
return change
}
func (p *ClusterPKI) SignNodeCerts(name string, n *NodeCerts) {
signCert(p.Services, n.Service, pekahi.NewServerTemplate([]string{name}, []net.IP{}))
signCert(p.API, n.API, pekahi.NewClientTemplate("system:node:"+name, "system:nodes"))
}
package pki
import (
"crypto/x509"
"forge.tedomum.net/acides/hepto/hepto/pkg/pekahi"
"github.com/sirupsen/logrus"
)
// Merge a single node or master certificate
func mergeCert(local *pekahi.Certificate, remote *pekahi.Certificate) bool {
change := false
// Import CSR to master for signing
if local.CSR == nil && remote.CSR != nil {
local.CSR = remote.CSR
change = true
}
// Import and save cert back to node
if local.Cert == nil && remote.Cert != nil {
local.Cert = remote.Cert
local.Save()
change = true
}
return change
}
func signCert(p *pekahi.PKI, c *pekahi.Certificate, template *x509.Certificate) {
if c.CSR != nil && c.Cert == nil {
logrus.Info("signing certificate ", c.CSR.Subject.String())
err := p.Sign(c, template)
if err != nil {
logrus.Warnf("cannot sign certificate for %s: %s", c.CSR.Subject.String(), err)
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment