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:
parent
27adda4d9d
commit
4ff8824182
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
@ -28,6 +28,7 @@ func controlPlaneUd(in *Input) (string, error) {
|
||||
IPs: in.MasterIPs,
|
||||
Index: in.Index,
|
||||
},
|
||||
AESCBCEncryptionSecret: in.KubeadmTokens.AESCBCEncryptionSecret,
|
||||
}
|
||||
|
||||
ud := v1alpha1.NodeConfig{
|
||||
|
@ -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{
|
||||
|
@ -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{
|
||||
|
Loading…
x
Reference in New Issue
Block a user