feat(initramfs): rewrite user data (#121)

This commit is contained in:
Andrew Rynhard 2018-07-17 18:26:56 -07:00 committed by GitHub
parent dc9e2fe51a
commit 0036bd1555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 280 additions and 253 deletions

View File

@ -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{})

View File

@ -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
}

View File

@ -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:

View File

@ -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")
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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(
&reg.Registrator{Data: data.OS.Security},
&reg.Registrator{Data: data.Security.OS},
factory.Port(*port),
factory.ServerOptions(
grpc.Creds(

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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.