feat(initramfs): rewrite user data (#121)
This commit is contained in:
parent
dc9e2fe51a
commit
0036bd1555
@ -6,6 +6,7 @@ import "C"
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
@ -95,20 +96,20 @@ func root() (err error) {
|
||||
// Start the services essential to managing the node.
|
||||
log.Println("starting OS services")
|
||||
services.Start(&service.OSD{})
|
||||
if data.Kubernetes.Init {
|
||||
if data.Services.Kubeadm.Init {
|
||||
services.Start(&service.ROTD{})
|
||||
services.Start(&service.ProxyD{})
|
||||
}
|
||||
|
||||
// Start the services essential to running Kubernetes.
|
||||
log.Println("starting Kubernetes services")
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
switch data.Services.Kubeadm.ContainerRuntime {
|
||||
case constants.ContainerRuntimeDocker:
|
||||
services.Start(&service.Docker{})
|
||||
case constants.ContainerRuntimeCRIO:
|
||||
fallthrough
|
||||
default:
|
||||
services.Start(&service.CRIO{})
|
||||
default:
|
||||
panic(fmt.Errorf("Unknown container runtime: %s", data.Services.Kubeadm.ContainerRuntime))
|
||||
}
|
||||
services.Start(&service.Kubelet{})
|
||||
services.Start(&service.Kubeadm{})
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/autonomy/dianemo/src/initramfs/cmd/init/pkg/constants"
|
||||
"github.com/autonomy/dianemo/src/initramfs/cmd/init/pkg/service/conditions"
|
||||
"github.com/autonomy/dianemo/src/initramfs/pkg/crypto/x509"
|
||||
"github.com/autonomy/dianemo/src/initramfs/pkg/userdata"
|
||||
)
|
||||
|
||||
@ -17,13 +18,13 @@ type Kubeadm struct{}
|
||||
|
||||
// Pre implements the Service interface.
|
||||
func (p *Kubeadm) Pre(data userdata.UserData) (err error) {
|
||||
if data.Kubernetes.Init {
|
||||
if err = writeKubeadmPKIFiles(data.Kubernetes.CA); err != nil {
|
||||
if data.Services.Kubeadm.Init {
|
||||
if err = writeKubeadmPKIFiles(data.Security.Kubernetes.CA); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = writeKubeadmManifest(data.Kubernetes.Configuration); err != nil {
|
||||
if err = writeKubeadmManifest(data.Services.Kubeadm.Configuration); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -33,7 +34,7 @@ func (p *Kubeadm) Pre(data userdata.UserData) (err error) {
|
||||
// Cmd implements the Service interface.
|
||||
func (p *Kubeadm) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
var cmd string
|
||||
if data.Kubernetes.Init {
|
||||
if data.Services.Kubeadm.Init {
|
||||
cmd = "init"
|
||||
} else {
|
||||
cmd = "join"
|
||||
@ -44,7 +45,7 @@ func (p *Kubeadm) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
"--config=/etc/kubernetes/kubeadm.yaml",
|
||||
"--ignore-preflight-errors=cri",
|
||||
}
|
||||
if data.Kubernetes.Init {
|
||||
if data.Services.Kubeadm.Init {
|
||||
args = append(args, "--skip-token-print")
|
||||
}
|
||||
|
||||
@ -53,7 +54,7 @@ func (p *Kubeadm) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
|
||||
// Condition implements the Service interface.
|
||||
func (p *Kubeadm) Condition(data userdata.UserData) func() (bool, error) {
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
switch data.Services.Kubeadm.ContainerRuntime {
|
||||
case constants.ContainerRuntimeDocker:
|
||||
return conditions.WaitForFileExists(constants.ContainerRuntimeDockerSocket)
|
||||
case constants.ContainerRuntimeCRIO:
|
||||
@ -77,7 +78,7 @@ func writeKubeadmManifest(data string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeKubeadmPKIFiles(data *userdata.PEMEncodedCertificateAndKey) (err error) {
|
||||
func writeKubeadmPKIFiles(data *x509.PEMEncodedCertificateAndKey) (err error) {
|
||||
if err = os.MkdirAll(path.Dir(constants.KubeadmCACert), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -51,28 +51,32 @@ func (p *Kubelet) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
"--v=2",
|
||||
}
|
||||
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
switch data.Services.Kubeadm.ContainerRuntime {
|
||||
case constants.ContainerRuntimeCRIO:
|
||||
args = append(args, "--container-runtime=remote", "--container-runtime-endpoint=unix:///var/run/crio/crio.sock")
|
||||
default:
|
||||
}
|
||||
|
||||
for k, v := range data.Kubernetes.Kubelet.ExtraArgs {
|
||||
if data.Services.Kubelet == nil {
|
||||
return name, args
|
||||
}
|
||||
|
||||
for k, v := range data.Services.Kubelet.ExtraArgs {
|
||||
arg := "--" + k + "=" + v
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
if len(data.Kubernetes.Kubelet.FeatureGates) != 0 {
|
||||
if len(data.Services.Kubelet.FeatureGates) != 0 {
|
||||
featureGates := "--feature-gates="
|
||||
for k, v := range data.Kubernetes.Kubelet.FeatureGates {
|
||||
for k, v := range data.Services.Kubelet.FeatureGates {
|
||||
featureGates += k + "=" + v + ","
|
||||
}
|
||||
args = append(args, featureGates)
|
||||
}
|
||||
|
||||
if len(data.Kubernetes.Kubelet.Labels) != 0 {
|
||||
if len(data.Services.Kubelet.Labels) != 0 {
|
||||
labels := "--node-labels="
|
||||
for k, v := range data.Kubernetes.Kubelet.Labels {
|
||||
for k, v := range data.Services.Kubelet.Labels {
|
||||
labels += k + "=" + v + ","
|
||||
}
|
||||
args = append(args, labels)
|
||||
@ -83,7 +87,7 @@ func (p *Kubelet) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
|
||||
// Condition implements the Service interface.
|
||||
func (p *Kubelet) Condition(data userdata.UserData) func() (bool, error) {
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
switch data.Services.Kubeadm.ContainerRuntime {
|
||||
case constants.ContainerRuntimeDocker:
|
||||
return conditions.None()
|
||||
case constants.ContainerRuntimeCRIO:
|
||||
|
@ -24,7 +24,7 @@ func (p *OSD) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
"--userdata=" + constants.UserDataPath,
|
||||
}
|
||||
|
||||
if data.OS.Security.RootsOfTrust.Generate {
|
||||
if !data.Services.Kubeadm.Init {
|
||||
args = append(args, "--generate=true")
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,9 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"time"
|
||||
@ -56,12 +58,13 @@ func (m *Manager) build(proc Service) (cmd *exec.Cmd, err error) {
|
||||
|
||||
// Setup logging.
|
||||
w, err := servicelog.New(path.Base(name))
|
||||
mw := io.MultiWriter(w, os.Stdout)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("service log handler: %v", err)
|
||||
return
|
||||
}
|
||||
cmd.Stdout = w
|
||||
cmd.Stderr = w
|
||||
cmd.Stdout = mw
|
||||
cmd.Stderr = mw
|
||||
|
||||
return cmd, nil
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/autonomy/dianemo/src/initramfs/pkg/crypto/x509"
|
||||
"github.com/autonomy/dianemo/src/initramfs/pkg/userdata"
|
||||
"github.com/spf13/cobra"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
@ -15,155 +14,143 @@ import (
|
||||
// injectCmd represents the inject command
|
||||
var injectCmd = &cobra.Command{
|
||||
Use: "inject",
|
||||
Short: "Inject data into fields in the user data.",
|
||||
Short: "inject data into fields in the user data.",
|
||||
Long: ``,
|
||||
}
|
||||
|
||||
// injectOSCmd represents the gen inject os command
|
||||
// injectOSCmd represents the inject command
|
||||
// nolint: dupl
|
||||
var injectOSCmd = &cobra.Command{
|
||||
Use: "os",
|
||||
Short: "Populates fields in the user data that are generated for the OS",
|
||||
Short: "inject OS data.",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
|
||||
if len(args) != 1 {
|
||||
os.Exit(1)
|
||||
}
|
||||
filename := args[0]
|
||||
fileBytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
data := &userdata.UserData{}
|
||||
if err = yaml.Unmarshal(fileBytes, data); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if data.OS.Security == nil {
|
||||
data.OS.Security = &userdata.Security{}
|
||||
data.OS.Security.Identity = &userdata.PEMEncodedCertificateAndKey{}
|
||||
data.OS.Security.CA = &userdata.PEMEncodedCertificateAndKey{}
|
||||
}
|
||||
|
||||
encoded := &bytes.Buffer{}
|
||||
encoder := base64.NewEncoder(base64.StdEncoding, encoded)
|
||||
// nolint: errcheck
|
||||
defer encoder.Close()
|
||||
if identity != "" {
|
||||
fileBytes, err = ioutil.ReadFile(identity + ".crt")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err = encoder.Write(fileBytes); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
data.OS.Security.Identity.Crt = encoded.Bytes()
|
||||
encoded.Reset()
|
||||
|
||||
fileBytes, err = ioutil.ReadFile(identity + ".key")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err = encoder.Write(fileBytes); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
data.OS.Security.Identity.Key = encoded.Bytes()
|
||||
encoded.Reset()
|
||||
}
|
||||
if ca != "" {
|
||||
fileBytes, err = ioutil.ReadFile(ca + ".crt")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err = encoder.Write(fileBytes); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
data.OS.Security.CA.Crt = encoded.Bytes()
|
||||
encoded.Reset()
|
||||
}
|
||||
|
||||
dataBytes, err := yaml.Marshal(data)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := ioutil.WriteFile(filename, dataBytes, 0700); err != nil {
|
||||
if err := inject(args, crt, key, injectOSData); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// injectKubernetesCmd represents the gen inject kubernetes command
|
||||
var injectKubernetesCmd = &cobra.Command{
|
||||
Use: "kubernetes",
|
||||
Short: "Populates fields in the user data that are generated for Kubernetes",
|
||||
// injectIdentityCmd represents the inject command
|
||||
// nolint: dupl
|
||||
var injectIdentityCmd = &cobra.Command{
|
||||
Use: "identity",
|
||||
Short: "inject identity data.",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
os.Exit(1)
|
||||
}
|
||||
filename := args[0]
|
||||
fileBytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
data := &userdata.UserData{}
|
||||
if err = yaml.Unmarshal(fileBytes, data); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if data.Kubernetes.CA == nil {
|
||||
data.Kubernetes.CA = &userdata.PEMEncodedCertificateAndKey{}
|
||||
}
|
||||
if ca != "" {
|
||||
encoded := &bytes.Buffer{}
|
||||
encoder := base64.NewEncoder(base64.StdEncoding, encoded)
|
||||
fileBytes, err = ioutil.ReadFile(ca + ".crt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err = encoder.Write(fileBytes); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
data.Kubernetes.CA.Crt = encoded.Bytes()
|
||||
encoded.Reset()
|
||||
|
||||
fileBytes, err = ioutil.ReadFile(ca + ".key")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err = encoder.Write(fileBytes); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
data.Kubernetes.CA.Key = encoded.Bytes()
|
||||
encoded.Reset()
|
||||
}
|
||||
|
||||
dataBytes, err := yaml.Marshal(data)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := ioutil.WriteFile(filename, dataBytes, 0700); err != nil {
|
||||
if err := inject(args, crt, key, injectIdentityData); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// injectKubernetesCmd represents the inject command
|
||||
// nolint: dupl
|
||||
var injectKubernetesCmd = &cobra.Command{
|
||||
Use: "kubernetes",
|
||||
Short: "inject Kubernetes data.",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := inject(args, crt, key, injectKubernetesData); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func injectOSData(u *userdata.UserData, crt, key string) (err error) {
|
||||
if u.Security == nil {
|
||||
u.Security = &userdata.Security{
|
||||
OS: &userdata.OSSecurity{},
|
||||
}
|
||||
}
|
||||
crtAndKey, err := x509.NewCertificateAndKeyFromFiles(crt, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
u.Security.OS.CA = crtAndKey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func injectIdentityData(u *userdata.UserData, crt, key string) (err error) {
|
||||
if u.Security == nil {
|
||||
u.Security = &userdata.Security{
|
||||
OS: &userdata.OSSecurity{},
|
||||
}
|
||||
}
|
||||
crtAndKey, err := x509.NewCertificateAndKeyFromFiles(crt, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
u.Security.OS.Identity = crtAndKey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func injectKubernetesData(u *userdata.UserData, crt, key string) (err error) {
|
||||
if u.Security == nil {
|
||||
u.Security = &userdata.Security{
|
||||
Kubernetes: &userdata.KubernetesSecurity{},
|
||||
}
|
||||
}
|
||||
crtAndKey, err := x509.NewCertificateAndKeyFromFiles(crt, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
u.Security.Kubernetes.CA = crtAndKey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func inject(args []string, crt, key string, f func(*userdata.UserData, string, string) error) (err error) {
|
||||
if len(args) != 1 {
|
||||
err = fmt.Errorf("expected 1 argument, got %d", len(args))
|
||||
return
|
||||
}
|
||||
|
||||
configBytes, err := ioutil.ReadFile(args[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := &userdata.UserData{}
|
||||
if err = yaml.Unmarshal(configBytes, data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = f(data, crt, key); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dataBytes, err := yaml.Marshal(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = ioutil.WriteFile(args[0], dataBytes, 0600); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Inject OS
|
||||
injectOSCmd.Flags().StringVar(&ca, "ca", "", "the basename of the key pair to use as the CA")
|
||||
injectOSCmd.Flags().StringVar(&identity, "identity", "", "the basename of the key pair to use as the identity")
|
||||
// Inject Kubernetes
|
||||
injectKubernetesCmd.Flags().StringVar(&ca, "ca", "", "the basename of the key pair to use as the CA")
|
||||
injectKubernetesCmd.Flags().StringVar(&hash, "hash", "", "the basename of the CA to use as the hash")
|
||||
injectCmd.PersistentFlags().StringVar(&crt, "crt", "", "the path to the PKI certificate")
|
||||
if err := injectCmd.MarkPersistentFlagRequired("crt"); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
injectCmd.PersistentFlags().StringVar(&key, "key", "", "the path to the PKI key")
|
||||
if err := injectCmd.MarkPersistentFlagRequired("key"); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
injectCmd.AddCommand(injectOSCmd, injectKubernetesCmd)
|
||||
injectCmd.AddCommand(injectOSCmd, injectIdentityCmd, injectKubernetesCmd)
|
||||
rootCmd.AddCommand(injectCmd)
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ var (
|
||||
ip string
|
||||
port int
|
||||
hours int
|
||||
identity string
|
||||
hash string
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
|
@ -39,30 +39,30 @@ func main() {
|
||||
}
|
||||
|
||||
if *generate {
|
||||
if len(data.OS.Security.RootsOfTrust.Endpoints) == 0 {
|
||||
if len(data.Services.ROTD.Endpoints) == 0 {
|
||||
log.Fatalf("at least one root of trust endpoint is required")
|
||||
}
|
||||
|
||||
creds := basic.NewCredentials(
|
||||
data.OS.Security.CA.Crt,
|
||||
data.OS.Security.RootsOfTrust.Username,
|
||||
data.OS.Security.RootsOfTrust.Password,
|
||||
data.Security.OS.CA.Crt,
|
||||
data.Services.ROTD.Username,
|
||||
data.Services.ROTD.Password,
|
||||
)
|
||||
|
||||
// TODO: In the case of failure, attempt to generate the identity from
|
||||
// another RoT.
|
||||
var conn *grpc.ClientConn
|
||||
conn, err = basic.NewConnection(data.OS.Security.RootsOfTrust.Endpoints[0], *rotPort, creds)
|
||||
conn, err = basic.NewConnection(data.Services.ROTD.Endpoints[0], *rotPort, creds)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
generator := gen.NewGenerator(conn)
|
||||
if err = generator.Identity(data.OS.Security); err != nil {
|
||||
if err = generator.Identity(data.Security); err != nil {
|
||||
log.Fatalf("generate identity: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
config, err := tls.NewConfig(tls.Mutual, data.OS.Security)
|
||||
config, err := tls.NewConfig(tls.Mutual, data.Security.OS)
|
||||
if err != nil {
|
||||
log.Fatalf("credentials: %v", err)
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ func (g *Generator) Identity(data *userdata.Security) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
data.Identity = &userdata.PEMEncodedCertificateAndKey{}
|
||||
data.Identity.Key = key.KeyPEM
|
||||
data.OS.Identity = &x509.PEMEncodedCertificateAndKey{}
|
||||
data.OS.Identity.Key = key.KeyPEM
|
||||
|
||||
pemBlock, _ := pem.Decode(key.KeyPEM)
|
||||
if pemBlock == nil {
|
||||
@ -76,10 +76,10 @@ func (g *Generator) Identity(data *userdata.Security) (err error) {
|
||||
Csr: csr.X509CertificateRequestPEM,
|
||||
}
|
||||
|
||||
return poll(g, req, data.Identity)
|
||||
return poll(g, req, data.OS.Identity)
|
||||
}
|
||||
|
||||
func poll(g *Generator, in *proto.CertificateRequest, data *userdata.PEMEncodedCertificateAndKey) (err error) {
|
||||
func poll(g *Generator, in *proto.CertificateRequest, data *x509.PEMEncodedCertificateAndKey) (err error) {
|
||||
timeout := time.NewTimer(time.Minute * 5).C
|
||||
tick := time.NewTicker(time.Second * 5).C
|
||||
|
||||
|
@ -33,19 +33,19 @@ func main() {
|
||||
log.Fatalf("credentials: %v", err)
|
||||
}
|
||||
|
||||
config, err := tls.NewConfig(tls.ServerOnly, data.OS.Security)
|
||||
config, err := tls.NewConfig(tls.ServerOnly, data.Security.OS)
|
||||
if err != nil {
|
||||
log.Fatalf("credentials: %v", err)
|
||||
}
|
||||
|
||||
creds := basic.NewCredentials(
|
||||
data.OS.Security.CA.Crt,
|
||||
data.OS.Security.RootsOfTrust.Username,
|
||||
data.OS.Security.RootsOfTrust.Password,
|
||||
data.Security.OS.CA.Crt,
|
||||
data.Services.ROTD.Username,
|
||||
data.Services.ROTD.Password,
|
||||
)
|
||||
|
||||
err = factory.Listen(
|
||||
®.Registrator{Data: data.OS.Security},
|
||||
®.Registrator{Data: data.Security.OS},
|
||||
factory.Port(*port),
|
||||
factory.ServerOptions(
|
||||
grpc.Creds(
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
// Registrator is the concrete type that implements the factory.Registrator and
|
||||
// proto.ROTDServer interfaces.
|
||||
type Registrator struct {
|
||||
Data *userdata.Security
|
||||
Data *userdata.OSSecurity
|
||||
}
|
||||
|
||||
// Register implements the factory.Registrator interface.
|
||||
|
@ -9,8 +9,10 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"strings"
|
||||
@ -48,6 +50,13 @@ type KeyPair struct {
|
||||
*tls.Certificate
|
||||
}
|
||||
|
||||
// PEMEncodedCertificateAndKey represents the PEM encoded certificate and
|
||||
// private key pair.
|
||||
type PEMEncodedCertificateAndKey struct {
|
||||
Crt []byte
|
||||
Key []byte
|
||||
}
|
||||
|
||||
// Options is the functional options struct.
|
||||
type Options struct {
|
||||
Organization string
|
||||
@ -303,6 +312,71 @@ func NewKeyPair(ca *x509.Certificate, key *ecdsa.PrivateKey, setters ...Option)
|
||||
return keypair, nil
|
||||
}
|
||||
|
||||
// NewCertificateAndKeyFromFiles initializes and returns a
|
||||
// PEMEncodedCertificateAndKey from the path to a crt and key.
|
||||
func NewCertificateAndKeyFromFiles(crt, key string) (p *PEMEncodedCertificateAndKey, err error) {
|
||||
p = &PEMEncodedCertificateAndKey{}
|
||||
|
||||
crtBytes, err := ioutil.ReadFile(crt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.Crt = crtBytes
|
||||
|
||||
keyBytes, err := ioutil.ReadFile(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.Key = keyBytes
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for
|
||||
// PEMEncodedCertificateAndKey. It is expected that the Crt and Key are a base64
|
||||
// encoded string in the YAML file. This function decodes the strings into byte
|
||||
// slices.
|
||||
func (p *PEMEncodedCertificateAndKey) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var aux struct {
|
||||
Crt string `yaml:"crt"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
if err := unmarshal(&aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decodedCrt, err := base64.StdEncoding.DecodeString(aux.Crt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decodedKey, err := base64.StdEncoding.DecodeString(aux.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Crt = decodedCrt
|
||||
p.Key = decodedKey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface for
|
||||
// PEMEncodedCertificateAndKey. It is expected that the Crt and Key are a base64
|
||||
// encoded string in the YAML file. This function encodes the byte slices into
|
||||
// strings
|
||||
func (p *PEMEncodedCertificateAndKey) MarshalYAML() (interface{}, error) {
|
||||
var aux struct {
|
||||
Crt string `yaml:"crt"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
aux.Crt = base64.StdEncoding.EncodeToString(p.Crt)
|
||||
aux.Key = base64.StdEncoding.EncodeToString(p.Key)
|
||||
|
||||
return aux, nil
|
||||
}
|
||||
|
||||
// Hash calculates the SHA-256 hash of the Subject Public Key Information (SPKI)
|
||||
// object in an x509 certificate (in DER encoding). It returns the full hash as
|
||||
// a hex encoded string (suitable for passing to Set.Allow). See
|
||||
|
@ -21,7 +21,7 @@ const (
|
||||
)
|
||||
|
||||
// NewConfig initializes a TLS config for the specified type.
|
||||
func NewConfig(t Type, data *userdata.Security) (config *tls.Config, err error) {
|
||||
func NewConfig(t Type, data *userdata.OSSecurity) (config *tls.Config, err error) {
|
||||
certPool := x509.NewCertPool()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read ca certificate: %s", err)
|
||||
|
@ -1,65 +1,51 @@
|
||||
package userdata
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/autonomy/dianemo/src/initramfs/pkg/crypto/x509"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// UserData represents the user data.
|
||||
type UserData struct {
|
||||
Version string `yaml:"version"`
|
||||
OS *OS `yaml:"os"`
|
||||
Kubernetes *Kubernetes `yaml:"kubernetes,omitempty"`
|
||||
Security *Security `yaml:"security"`
|
||||
Networking *Networking `yaml:"networking"`
|
||||
Services *Services `yaml:"services"`
|
||||
}
|
||||
|
||||
// OS represents the operating system specific configuration options.
|
||||
type OS struct {
|
||||
Network *Network `yaml:"network,omitempty"`
|
||||
Security *Security `yaml:"security"`
|
||||
}
|
||||
|
||||
// Network represents the operating system networking specific configuration
|
||||
// options.
|
||||
type Network struct{}
|
||||
|
||||
// Security represents the operating system security specific configuration
|
||||
// options.
|
||||
// Security represents the set of options available to configure security.
|
||||
type Security struct {
|
||||
CA *PEMEncodedCertificateAndKey `yaml:"ca"`
|
||||
Identity *PEMEncodedCertificateAndKey `yaml:"identity"`
|
||||
RootsOfTrust *RootsOfTrust `yaml:"rootsOfTrust"`
|
||||
OS *OSSecurity `yaml:"os"`
|
||||
Kubernetes *KubernetesSecurity `yaml:"kubernetes"`
|
||||
}
|
||||
|
||||
// RootsOfTrust describes the configuration of the Root of Trust (RoT) services.
|
||||
// The username and password are used by master nodes, and worker nodes. The
|
||||
// master nodes use them to authentication clients, while the workers use them
|
||||
// to authenticate as a client. The endpoints should only be specified in the
|
||||
// worker user data, and should include all master nodes participating as a RoT.
|
||||
type RootsOfTrust struct {
|
||||
Generate bool `yaml:"generate,omitempty"`
|
||||
Username string `yaml:"username,omitempty"`
|
||||
Password string `yaml:"password,omitempty"`
|
||||
Endpoints []string `yaml:"endpoints,omitempty"`
|
||||
// OSSecurity represents the set of security options specific to the OS.
|
||||
type OSSecurity struct {
|
||||
CA *x509.PEMEncodedCertificateAndKey `yaml:"ca"`
|
||||
Identity *x509.PEMEncodedCertificateAndKey `yaml:"identity"`
|
||||
}
|
||||
|
||||
// PEMEncodedCertificateAndKey represents the PEM encoded certificate and
|
||||
// private key pair.
|
||||
type PEMEncodedCertificateAndKey struct {
|
||||
Crt []byte
|
||||
Key []byte
|
||||
// KubernetesSecurity represents the set of security options specific to
|
||||
// Kubernetes.
|
||||
type KubernetesSecurity struct {
|
||||
CA *x509.PEMEncodedCertificateAndKey `yaml:"ca"`
|
||||
}
|
||||
|
||||
// Kubernetes represents the Kubernetes specific configuration options.
|
||||
type Kubernetes struct {
|
||||
CA *PEMEncodedCertificateAndKey `yaml:"ca,omitempty"`
|
||||
Init bool `yaml:"init,omitempty"`
|
||||
Kubelet Kubelet `yaml:"kubelet,omitempty"`
|
||||
ContainerRuntime string `yaml:"containerRuntime,omitempty"`
|
||||
Configuration string `yaml:"configuration,omitempty"`
|
||||
// Networking represents the set of options available to configure networking.
|
||||
type Networking struct {
|
||||
OS struct{} `yaml:"os"`
|
||||
Kubernetes struct{} `yaml:"kubernetes"`
|
||||
}
|
||||
|
||||
// Services represents the set of services available to configure.
|
||||
type Services struct {
|
||||
Kubeadm *Kubeadm `yaml:"kubeadm"`
|
||||
Kubelet *Kubelet `yaml:"kubelet"`
|
||||
ROTD *ROTD `yaml:"rotd"`
|
||||
}
|
||||
|
||||
// Kubelet describes the set of configuration options available for the kubelet.
|
||||
@ -69,49 +55,22 @@ type Kubelet struct {
|
||||
ExtraArgs map[string]string `yaml:"extraArgs,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for
|
||||
// PEMEncodedCertificateAndKey. It is expected that the Crt and Key are a base64
|
||||
// encoded string in the YAML file. This function decodes the strings into byte
|
||||
// slices.
|
||||
func (p *PEMEncodedCertificateAndKey) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var aux struct {
|
||||
Crt string `yaml:"crt"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
if err := unmarshal(&aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decodedCrt, err := base64.StdEncoding.DecodeString(aux.Crt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decodedKey, err := base64.StdEncoding.DecodeString(aux.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Crt = decodedCrt
|
||||
p.Key = decodedKey
|
||||
|
||||
return nil
|
||||
// Kubeadm describes the set of configuration options available for kubeadm.
|
||||
type Kubeadm struct {
|
||||
ContainerRuntime string `yaml:"containerRuntime,omitempty"`
|
||||
Configuration string `yaml:"configuration,omitempty"`
|
||||
Init bool `yaml:"init,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface for
|
||||
// PEMEncodedCertificateAndKey. It is expected that the Crt and Key are a base64
|
||||
// encoded string in the YAML file. This function encodes the byte slices into
|
||||
// strings
|
||||
func (p *PEMEncodedCertificateAndKey) MarshalYAML() (interface{}, error) {
|
||||
var aux struct {
|
||||
Crt string `yaml:"crt"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
aux.Crt = base64.StdEncoding.EncodeToString(p.Crt)
|
||||
aux.Key = base64.StdEncoding.EncodeToString(p.Key)
|
||||
|
||||
return aux, nil
|
||||
// ROTD describes the configuration of the Root of Trust (RoT) service. The
|
||||
// username and password are used by master nodes, and worker nodes. The master
|
||||
// nodes use them to authenticate clients, while the workers use them to
|
||||
// authenticate as a client. The endpoints should only be specified in the
|
||||
// worker user data, and should include all master nodes participating as a RoT.
|
||||
type ROTD struct {
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
Endpoints []string `yaml:"endpoints,omitempty"`
|
||||
}
|
||||
|
||||
// Download initializes a UserData struct from a remote URL.
|
||||
|
Loading…
x
Reference in New Issue
Block a user