blob: 75717175d646894a2e4a0c3e37b67f2ddbe5459e [file] [log] [blame]
package certs
import (
"net"
"time"
)
// Certificates is the set of certificates required to run our Kubernetes
// production.
type Certificates struct {
CAs CAs
ProdviderIntermediateCA *Certificate
Global Global
PerNode map[string]PerNode
}
type ensurer interface {
Ensure() error
}
// Ensure checks that all the Kubernetes production certificates and keys are
// present on disk, generating them as necessary.
//
// If the user has not decrypted cluster/secrets, an error will be returned.
// However, deeper sync checks are not currently performed.
func (c *Certificates) Ensure() error {
sub := []ensurer{
&c.CAs,
c.ProdviderIntermediateCA,
&c.Global,
}
for _, pn := range c.PerNode {
sub = append(sub, &pn)
}
for _, s := range sub {
if err := s.Ensure(); err != nil {
return err
}
}
return nil
}
// CAs are the root certificate authorities we use.
type CAs struct {
// EtcdPeer is used by etcd member nodes to authenticate peers.
EtcdPeer *Certificate
// Etcd is used by etcd membrer nodes to authenticate clients (ie.
// kube-apiservers).
Etcd *Certificate
// Kube is the main Kubernetes 'identity' CA, used to identify components
// and users.
Kube *Certificate
// KubeFront is the proxy/aggregation CA used by external apiservices to
// authenticate incoming apiserver connections.
KubeFront *Certificate
// Admitomatic is the CA used by the admitomatic webhook to authenticate
// incoming apiserver connections.
Admitomatic *Certificate
}
func (c *CAs) Ensure() error {
sub := []ensurer{
c.EtcdPeer,
c.Etcd,
c.Kube,
c.KubeFront,
c.Admitomatic,
}
for _, s := range sub {
if err := s.Ensure(); err != nil {
return err
}
}
return nil
}
// Global are all the non-per-node certificates we use.
type Global struct {
// EtcdKube is used by kubernetes apiservers to authenticate to etcd
// members.
EtcdKube *Certificate
// KubeApiserver is used by kubernetes apiservers to authenticate to other
// kubernetes components/users.
KubeApiserver *Certificate
// KubeControllerManager is used by kubernetes controller managers to
// authenticate to the kubernetes apiservers.
KubeControllerManager *Certificate
// KubeScheduler is used by the kubernetes schedulers to authenticate to
// the kubernetes apiservers.
KubeScheduler *Certificate
// KubefrontApiserver is used by the kubernetes apiserver to authenticate
// to external apiservices.
KubefrontApiserver *Certificate
// AdmitomaticWebhook is used by the admitomatic webhook to authenticate to
// the Kubernetes apiservers.
AdmitomaticWebhook *Certificate
}
func (g *Global) Ensure() error {
sub := []ensurer{
g.EtcdKube,
g.KubeApiserver,
g.KubeControllerManager,
g.KubeScheduler,
g.KubefrontApiserver,
g.AdmitomaticWebhook,
}
for _, s := range sub {
if err := s.Ensure(); err != nil {
return err
}
}
return nil
}
func (c *Certificates) MakeKubeEmergencyCreds(root, breadcrumb string) *Certificate {
return &Certificate{
name: "emergency",
duration: 7 * 24 * time.Hour,
root: root,
kind: kindClient,
cn: "admin",
san: []string{"admin", breadcrumb},
o: "system:masters",
issuer: c.CAs.Kube,
}
}
// Per node are all the per-node certificates we use.
type PerNode struct {
// EtcdPeer is used by etcd members to authenticate to other etcd members.
EtcdPeer *Certificate
// EtcdClient is used by etcd members to authenticate to their clients.
EtcdClient *Certificate
// Kubelet is used by kubelets to authenticate to other kubernetes
// components.
Kubelet *Certificate
}
func (p *PerNode) Ensure() error {
sub := []ensurer{
p.EtcdPeer,
p.EtcdClient,
p.Kubelet,
}
for _, s := range sub {
if err := s.Ensure(); err != nil {
return err
}
}
return nil
}
func mkCA(root, name, cn string) *Certificate {
return &Certificate{
name: name,
root: root,
kind: kindCA,
cn: cn,
}
}
// Prepare builds our Certificates structure at a given location on the
// filesystem, for the given nodes.
//
// Calling Ensure() on the returned Certificates will actually engage
// generation logic. Before that, no disk accesses are performed.
func Prepare(root string, fqdns []string) Certificates {
certs := Certificates{
CAs: CAs{
EtcdPeer: mkCA(root, "ca-etcdpeer", "etcd peer ca"),
Etcd: mkCA(root, "ca-etcd", "etcd ca"),
Kube: mkCA(root, "ca-kube", "kubernetes main CA"),
KubeFront: mkCA(root, "ca-kubefront", "kubernetes frontend CA"),
Admitomatic: mkCA(root, "ca-admitomatic", "admitomatic webhook CA"),
},
PerNode: make(map[string]PerNode),
}
certs.ProdviderIntermediateCA = &Certificate{
name: "ca-kube-prodvider",
root: root,
kind: kindProdvider,
cn: "kubernetes prodvider intermediate",
issuer: certs.CAs.Kube,
}
certs.Global = Global{
EtcdKube: &Certificate{
name: "etcd-kube",
root: root,
kind: kindClient,
cn: "kube etcd client certificate",
san: []string{"kube"},
issuer: certs.CAs.Etcd,
},
KubeApiserver: &Certificate{
name: "kube-apiserver",
root: root,
kind: kindClientServer,
cn: "k0.hswaw.net",
san: []string{
"k0.hswaw.net",
"kubernetes.default.svc.k0.hswaw.net",
},
ips: []net.IP{
{10, 10, 12, 1},
},
issuer: certs.CAs.Kube,
},
KubeControllerManager: &Certificate{
name: "kube-controllermanager",
root: root,
kind: kindClientServer,
cn: "system:kube-controller-manager",
san: []string{"system:kube-controller-manager"},
o: "system:kube-controller-manager",
issuer: certs.CAs.Kube,
},
KubeScheduler: &Certificate{
name: "kube-scheduler",
root: root,
kind: kindClientServer,
cn: "system:kube-scheduler",
san: []string{"system:kube-scheduler"},
o: "system:kube-scheduler",
issuer: certs.CAs.Kube,
},
KubefrontApiserver: &Certificate{
name: "kubefront-apiserver",
root: root,
kind: kindClientServer,
cn: "Kubernetes Frontend",
san: []string{"apiserver"},
issuer: certs.CAs.KubeFront,
},
AdmitomaticWebhook: &Certificate{
name: "admitomatic-webhook",
root: root,
kind: kindServer,
cn: "Admitomatic Webhook",
san: []string{"admitomatic.admitomatic.svc"},
issuer: certs.CAs.Admitomatic,
},
}
for _, fqdn := range fqdns {
certs.PerNode[fqdn] = PerNode{
EtcdPeer: &Certificate{
name: "etcdpeer-" + fqdn,
root: root,
kind: kindClientServer,
cn: "node etcd peer certificate",
san: []string{fqdn},
issuer: certs.CAs.EtcdPeer,
},
EtcdClient: &Certificate{
name: "etcd-" + fqdn,
root: root,
// etcd seems to need client too, as it's connecting to itself
// for... some reason?
// https://github.com/etcd-io/etcd/issues/9785
kind: kindClientServer,
cn: "node etcd server certificate",
san: []string{fqdn},
issuer: certs.CAs.Etcd,
},
Kubelet: &Certificate{
name: "kube-kubelet-" + fqdn,
root: root,
kind: kindClientServer,
cn: "system:node:" + fqdn,
o: "system:nodes",
san: []string{
"system:node:" + fqdn,
fqdn,
},
issuer: certs.CAs.Kube,
},
}
}
return certs
}