feat: add aescbcEncryptionSecret field to machine config

This change allows us to generate the EncryptionConfig on each
controlplane node. The benefit is that we no longer need to distibute
the EncryptionConfig via trustd.

Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
Andrew Rynhard 2019-09-25 08:48:06 -07:00
parent 27adda4d9d
commit 4ff8824182
12 changed files with 84 additions and 63 deletions

View File

@ -27,12 +27,12 @@ security:
ca:
crt: "{{ .Certs.K8sCert }}"
key: "{{ .Certs.K8sKey }}"
aescbcEncryptionSecret: "{{ .KubeadmTokens.AESCBCEncryptionSecret }}"
services:
init:
cni: flannel
kubeadm:
initToken: {{ .InitToken }}
certificateKey: '{{ .KubeadmTokens.CertKey }}'
configuration: |
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration

View File

@ -117,9 +117,10 @@ func editClusterConfig(data *userdata.UserData) (err error) {
clusterConfiguration.UseHyperKubeImage = true
// Apply CIS hardening recommendations; only generate encryption token only if we're the bootstrap node
if err = cis.EnforceMasterRequirements(clusterConfiguration, data.Services.Kubeadm.IsBootstrap()); err != nil {
if err = cis.EnforceBootstrapMasterRequirements(clusterConfiguration); err != nil {
return err
}
return nil
}
@ -141,6 +142,12 @@ func WriteConfig(data *userdata.UserData) (err error) {
return err
}
if data.Services.Kubeadm.IsControlPlane() {
if err = cis.EnforceCommonMasterRequirements(data.Security.Kubernetes.AESCBCEncryptionSecret); err != nil {
return err
}
}
// Marshal up config string
if _, err = data.Services.Kubeadm.MarshalYAML(); err != nil {
return err
@ -225,7 +232,6 @@ func WritePKIFiles(data *userdata.UserData) (err error) {
func RequiredFiles() []string {
return []string{
constants.AuditPolicyPathInitramfs,
constants.EncryptionConfigInitramfsPath,
constants.KubeadmCACert,
constants.KubeadmCAKey,
constants.KubeadmSACert,

View File

@ -55,35 +55,39 @@ func EnforceAuditingRequirements(cfg *kubeadmapi.ClusterConfiguration) error {
return nil
}
// CreateEncryptionToken generates an encryption token to be used for secrets
func CreateEncryptionToken() error {
if _, err := os.Stat(constants.EncryptionConfigInitramfsPath); !os.IsNotExist(err) {
return nil
}
// CreateEncryptionToken generates an encryption token to be used for secrets.
func CreateEncryptionToken() (string, error) {
encryptionKey := make([]byte, 32)
if _, err := rand.Read(encryptionKey); err != nil {
return err
return "", err
}
str := base64.StdEncoding.EncodeToString(encryptionKey)
aux := struct {
AESCBCEncryptionSecret string
}{
AESCBCEncryptionSecret: str,
}
t, err := template.New("encryptionconfig").Parse(encryptionConfig)
if err != nil {
return err
}
encBytes := []byte{}
buf := bytes.NewBuffer(encBytes)
if err := t.Execute(buf, aux); err != nil {
return err
}
if err := ioutil.WriteFile(constants.EncryptionConfigInitramfsPath, buf.Bytes(), 0400); err != nil {
return err
return str, nil
}
// WriteEncryptionConfigToDisk writes an EncryptionConfig to disk.
func WriteEncryptionConfigToDisk(aescbcEncryptionSecret string) error {
if _, err := os.Stat(constants.EncryptionConfigInitramfsPath); os.IsNotExist(err) {
aux := struct {
AESCBCEncryptionSecret string
}{
AESCBCEncryptionSecret: aescbcEncryptionSecret,
}
t, err := template.New("encryptionconfig").Parse(encryptionConfig)
if err != nil {
return err
}
encBytes := []byte{}
buf := bytes.NewBuffer(encBytes)
if err := t.Execute(buf, aux); err != nil {
return err
}
if err := ioutil.WriteFile(constants.EncryptionConfigInitramfsPath, buf.Bytes(), 0400); err != nil {
return err
}
}
return nil
@ -136,27 +140,26 @@ func EnforceExtraRequirements(cfg *kubeadmapi.ClusterConfiguration) error {
return nil
}
// EnforceMasterRequirements enforces the CIS requirements for master nodes.
func EnforceMasterRequirements(cfg *kubeadmapi.ClusterConfiguration, generateSecret bool) error {
// EnforceBootstrapMasterRequirements enforces the CIS requirements for master nodes.
func EnforceBootstrapMasterRequirements(cfg *kubeadmapi.ClusterConfiguration) error {
ensureFieldsAreNotNil(cfg)
if err := EnforceAuditingRequirements(cfg); err != nil {
return err
}
if generateSecret {
if err := CreateEncryptionToken(); err != nil {
return err
}
}
if err := EnforceSecretRequirements(cfg); err != nil {
return err
}
if err := EnforceTLSRequirements(cfg); err != nil {
return err
}
if err := EnforceAdmissionPluginsRequirements(cfg); err != nil {
return err
}
if err := EnforceExtraRequirements(cfg); err != nil {
return err
}
@ -164,6 +167,11 @@ func EnforceMasterRequirements(cfg *kubeadmapi.ClusterConfiguration, generateSec
return nil
}
// EnforceCommonMasterRequirements enforces the CIS requirements for master nodes.
func EnforceCommonMasterRequirements(aescbcEncryptionSecret string) error {
return WriteEncryptionConfigToDisk(aescbcEncryptionSecret)
}
// EnforceWorkerRequirements enforces the CIS requirements for master nodes.
func EnforceWorkerRequirements(cfg *kubeadmapi.JoinConfiguration) error {
return nil

View File

@ -15,11 +15,11 @@ security:
ca:
crt: "{{ .Certs.K8sCert }}"
key: "{{ .Certs.K8sKey }}"
aescbcEncryptionSecret: "{{ .KubeadmTokens.AESCBCEncryptionSecret }}"
services:
init:
cni: flannel
kubeadm:
certificateKey: '{{ .KubeadmTokens.CertKey }}'
configuration: |
apiVersion: kubeadm.k8s.io/v1beta2
kind: JoinConfiguration

View File

@ -17,6 +17,7 @@ import (
"text/template"
"time"
"github.com/talos-systems/talos/internal/pkg/cis"
"github.com/talos-systems/talos/pkg/constants"
"github.com/talos-systems/talos/pkg/crypto/x509"
tnet "github.com/talos-systems/talos/pkg/net"
@ -124,8 +125,8 @@ type Certs struct {
// KubeadmTokens holds the senesitve kubeadm data.
type KubeadmTokens struct {
BootstrapToken string
CertKey string
BootstrapToken string
AESCBCEncryptionSecret string
}
// TrustdInfo holds the trustd credentials.
@ -217,9 +218,7 @@ func NewInput(clustername string, masterIPs []string) (input *Input, err error)
return nil, err
}
// TODO: Can be dropped
// Gen kubeadm cert key
kubeadmCertKey, err := randBytes(26)
aescbcEncryptionSecret, err := cis.CreateEncryptionToken()
if err != nil {
return nil, err
}
@ -231,8 +230,8 @@ func NewInput(clustername string, masterIPs []string) (input *Input, err error)
}
kubeadmTokens := &KubeadmTokens{
BootstrapToken: kubeadmBootstrapToken,
CertKey: kubeadmCertKey,
BootstrapToken: kubeadmBootstrapToken,
AESCBCEncryptionSecret: aescbcEncryptionSecret,
}
trustdInfo := &TrustdInfo{

View File

@ -15,11 +15,11 @@ security:
ca:
crt: "{{ .Certs.K8sCert }}"
key: "{{ .Certs.K8sKey }}"
aescbcEncryptionSecret: {{ .KubeadmTokens.AESCBCEncryptionSecret }}
services:
init:
cni: flannel
kubeadm:
certificateKey: '{{ .KubeadmTokens.CertKey }}'
configuration: |
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration

View File

@ -13,10 +13,11 @@ import (
// KubernetesSecurity represents the set of security options specific to
// Kubernetes.
type KubernetesSecurity struct {
CA *x509.PEMEncodedCertificateAndKey `yaml:"ca"`
SA *x509.PEMEncodedCertificateAndKey `yaml:"sa"`
FrontProxy *x509.PEMEncodedCertificateAndKey `yaml:"frontproxy"`
Etcd *x509.PEMEncodedCertificateAndKey `yaml:"etcd"`
CA *x509.PEMEncodedCertificateAndKey `yaml:"ca"`
SA *x509.PEMEncodedCertificateAndKey `yaml:"sa"`
FrontProxy *x509.PEMEncodedCertificateAndKey `yaml:"frontproxy"`
Etcd *x509.PEMEncodedCertificateAndKey `yaml:"etcd"`
AESCBCEncryptionSecret string `yaml:"aescbcEncryptionSecret"`
}
// KubernetesSecurityCheck defines the function type for checks

View File

@ -180,6 +180,7 @@ func translateV1Alpha1Init(nc *v1alpha1.NodeConfig, ud *userdata.UserData) error
Crt: kubeCert,
Key: kubeKey,
},
AESCBCEncryptionSecret: nc.Cluster.AESCBCEncryptionSecret,
}
ud.Services.Trustd.CertSANs = []string{nc.Cluster.ControlPlane.IPs[nc.Cluster.ControlPlane.Index], "127.0.0.1", "::1"}
@ -288,6 +289,10 @@ func translateV1Alpha1ControlPlane(nc *v1alpha1.NodeConfig, ud *userdata.UserDat
ud.Services.Trustd.CertSANs = []string{nc.Cluster.ControlPlane.IPs[nc.Cluster.ControlPlane.Index], "127.0.0.1", "::1"}
ud.Services.Kubeadm.ControlPlane = true
ud.Security.Kubernetes = &userdata.KubernetesSecurity{
AESCBCEncryptionSecret: nc.Cluster.AESCBCEncryptionSecret,
}
// Craft a control plane kubeadm config
controlPlaneConfig := &kubeadm.JoinConfiguration{
TypeMeta: metav1.TypeMeta{

View File

@ -6,15 +6,16 @@ package v1alpha1
// ClusterConfig reperesents the cluster-wide config values
type ClusterConfig struct {
ControlPlane *ControlPlaneConfig `yaml:"controlPlane"`
ClusterName string `yaml:"clusterName,omitempty"`
Network *ClusterNetworkConfig `yaml:"network,omitempty"`
Token string `yaml:"token,omitempty"`
CA *ClusterCAConfig `yaml:"ca,omitempty"`
APIServer *APIServerConfig `yaml:"apiServer,omitempty"`
ControllerManager *ControllerManagerConfig `yaml:"controllerManager,omitempty"`
Scheduler *SchedulerConfig `yaml:"scheduler,omitempty"`
Etcd *EtcdConfig `yaml:"etcd,omitempty"`
ControlPlane *ControlPlaneConfig `yaml:"controlPlane"`
ClusterName string `yaml:"clusterName,omitempty"`
Network *ClusterNetworkConfig `yaml:"network,omitempty"`
Token string `yaml:"token,omitempty"`
AESCBCEncryptionSecret string `yaml:"aescbcEncryptionSecret"`
CA *ClusterCAConfig `yaml:"ca,omitempty"`
APIServer *APIServerConfig `yaml:"apiServer,omitempty"`
ControllerManager *ControllerManagerConfig `yaml:"controllerManager,omitempty"`
Scheduler *SchedulerConfig `yaml:"scheduler,omitempty"`
Etcd *EtcdConfig `yaml:"etcd,omitempty"`
}
// ControlPlaneConfig represents control plane config vals

View File

@ -28,6 +28,7 @@ func controlPlaneUd(in *Input) (string, error) {
IPs: in.MasterIPs,
Index: in.Index,
},
AESCBCEncryptionSecret: in.KubeadmTokens.AESCBCEncryptionSecret,
}
ud := v1alpha1.NodeConfig{

View File

@ -15,6 +15,7 @@ import (
"net"
"time"
"github.com/talos-systems/talos/internal/pkg/cis"
"github.com/talos-systems/talos/pkg/constants"
"github.com/talos-systems/talos/pkg/crypto/x509"
tnet "github.com/talos-systems/talos/pkg/net"
@ -137,8 +138,8 @@ type Certs struct {
// KubeadmTokens holds the senesitve kubeadm data.
type KubeadmTokens struct {
BootstrapToken string
CertKey string
BootstrapToken string
AESCBCEncryptionSecret string
}
// TrustdInfo holds the trustd credentials.
@ -230,9 +231,7 @@ func NewInput(clustername string, masterIPs []string) (input *Input, err error)
return nil, err
}
// TODO: Can be dropped
// Gen kubeadm cert key
kubeadmCertKey, err := randBytes(26)
aescbcEncryptionSecret, err := cis.CreateEncryptionToken()
if err != nil {
return nil, err
}
@ -244,8 +243,8 @@ func NewInput(clustername string, masterIPs []string) (input *Input, err error)
}
kubeadmTokens := &KubeadmTokens{
BootstrapToken: kubeadmBootstrapToken,
CertKey: kubeadmCertKey,
BootstrapToken: kubeadmBootstrapToken,
AESCBCEncryptionSecret: aescbcEncryptionSecret,
}
trustdInfo := &TrustdInfo{

View File

@ -46,7 +46,8 @@ func initUd(in *Input) (string, error) {
Crt: in.Certs.K8sCert,
Key: in.Certs.K8sKey,
},
Token: in.KubeadmTokens.BootstrapToken,
Token: in.KubeadmTokens.BootstrapToken,
AESCBCEncryptionSecret: in.KubeadmTokens.AESCBCEncryptionSecret,
}
ud := v1alpha1.NodeConfig{