diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index a0ba735..4408068 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -68,6 +68,7 @@ jobs: - label: "remote-static" - label: "remote-https-pinned" - label: "remote-https-bad-cert" + - label: "discoverable-kms" steps: - name: Checkout code uses: actions/checkout@v3 diff --git a/Earthfile b/Earthfile index a9e26d8..c0807c6 100644 --- a/Earthfile +++ b/Earthfile @@ -1,5 +1,9 @@ VERSION 0.6 -ARG BASE_IMAGE=quay.io/kairos/core-ubuntu:latest + +# renovate: datasource=github-releases depName=kairos-io/kairos +ARG KAIROS_VERSION="v2.5.0" +ARG BASE_IMAGE=quay.io/kairos/ubuntu:23.10-core-amd64-generic-$KAIROS_VERSION + ARG OSBUILDER_IMAGE=quay.io/kairos/osbuilder-tools # renovate: datasource=docker depName=golang ARG GO_VERSION=1.20 diff --git a/cmd/discovery/client/client.go b/cmd/discovery/client/client.go index 964e09e..5bed811 100644 --- a/cmd/discovery/client/client.go +++ b/cmd/discovery/client/client.go @@ -16,6 +16,9 @@ import ( "github.com/mudler/yip/pkg/utils" ) +// Because of how go-pluggable works, we can't just print to stdout +const LOGFILE = "/tmp/kcrypt-challenger-client.log" + var errPartNotFound error = fmt.Errorf("pass for partition not found") var errBadCertificate error = fmt.Errorf("unknown certificate") @@ -30,6 +33,10 @@ func NewClient() (*Client, error) { // ❯ echo '{ "data": "{ \\"label\\": \\"LABEL\\" }"}' | sudo -E WSS_SERVER="http://localhost:8082/challenge" ./challenger "discovery.password" func (c *Client) Start() error { + if err := os.RemoveAll(LOGFILE); err != nil { // Start fresh + return fmt.Errorf("removing the logfile: %w", err) + } + factory := pluggable.NewPluginFactory() // Input: bus.EventInstallPayload @@ -59,7 +66,7 @@ func (c *Client) Start() error { return factory.Run(pluggable.EventType(os.Args[1]), os.Stdin, os.Stdout) } -func (c *Client) generatePass(postEndpoint string, p *block.Partition) error { +func (c *Client) generatePass(postEndpoint string, headers map[string]string, p *block.Partition) error { rand := utils.RandomString(32) pass, err := tpm.EncryptBlob([]byte(rand)) @@ -75,6 +82,10 @@ func (c *Client) generatePass(postEndpoint string, p *block.Partition) error { tpm.WithAdditionalHeader("name", p.Name), tpm.WithAdditionalHeader("uuid", p.UUID), } + for k, v := range headers { + opts = append(opts, tpm.WithAdditionalHeader(k, v)) + } + conn, err := tpm.Connection(postEndpoint, opts...) if err != nil { return err @@ -84,20 +95,27 @@ func (c *Client) generatePass(postEndpoint string, p *block.Partition) error { } func (c *Client) waitPass(p *block.Partition, attempts int) (pass string, err error) { - // IF we don't have any server configured, just do local - if c.Config.Kcrypt.Challenger.Server == "" { + additionalHeaders := map[string]string{} + serverURL := c.Config.Kcrypt.Challenger.Server + + // If we don't have any server configured, just do local + if serverURL == "" { return localPass(c.Config) } - challengeEndpoint := fmt.Sprintf("%s/getPass", c.Config.Kcrypt.Challenger.Server) - postEndpoint := fmt.Sprintf("%s/postPass", c.Config.Kcrypt.Challenger.Server) + if c.Config.Kcrypt.Challenger.MDNS { + serverURL, additionalHeaders, err = queryMDNS(serverURL) + } + + getEndpoint := fmt.Sprintf("%s/getPass", serverURL) + postEndpoint := fmt.Sprintf("%s/postPass", serverURL) for tries := 0; tries < attempts; tries++ { var generated bool - pass, generated, err = getPass(challengeEndpoint, c.Config.Kcrypt.Challenger.Certificate, p) + pass, generated, err = getPass(getEndpoint, additionalHeaders, c.Config.Kcrypt.Challenger.Certificate, p) if err == errPartNotFound { // IF server doesn't have a pass for us, then we generate one and we set it - err = c.generatePass(postEndpoint, p) + err = c.generatePass(postEndpoint, additionalHeaders, p) if err != nil { return } @@ -118,7 +136,7 @@ func (c *Client) waitPass(p *block.Partition, attempts int) (pass string, err er return } - fmt.Printf("Failed with error: %s . Will retry.\n", err.Error()) + logToFile("Failed with error: %s . Will retry.\n", err.Error()) time.Sleep(1 * time.Second) // network errors? retry } @@ -145,3 +163,14 @@ func (c *Client) decryptPassphrase(pass string) (string, error) { return string(passBytes), err } + +func logToFile(format string, a ...any) { + s := fmt.Sprintf(format, a...) + file, err := os.OpenFile(LOGFILE, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + panic(err) + } + defer file.Close() + + file.WriteString(s) +} diff --git a/cmd/discovery/client/config.go b/cmd/discovery/client/config.go index 0e54137..27fc290 100644 --- a/cmd/discovery/client/config.go +++ b/cmd/discovery/client/config.go @@ -13,11 +13,10 @@ type Client struct { type Config struct { Kcrypt struct { Challenger struct { - Server string `yaml:"challenger_server,omitempty"` - // Non-volatile index memory: where we store the encrypted passphrase (offline mode) - NVIndex string `yaml:"nv_index,omitempty"` - // Certificate index: this is where the rsa pair that decrypts the passphrase lives - CIndex string `yaml:"c_index,omitempty"` + MDNS bool `yaml:"mdns,omitempty"` + Server string `yaml:"challenger_server,omitempty"` + NVIndex string `yaml:"nv_index,omitempty"` // Non-volatile index memory: where we store the encrypted passphrase (offline mode) + CIndex string `yaml:"c_index,omitempty"` // Certificate index: this is where the rsa pair that decrypts the passphrase lives TPMDevice string `yaml:"tpm_device,omitempty"` Certificate string `yaml:"certificate,omitempty"` } diff --git a/cmd/discovery/client/enc.go b/cmd/discovery/client/enc.go index e60c68d..5d698e8 100644 --- a/cmd/discovery/client/enc.go +++ b/cmd/discovery/client/enc.go @@ -16,13 +16,19 @@ import ( const DefaultNVIndex = "0x1500000" -func getPass(server, certificate string, partition *block.Partition) (string, bool, error) { - msg, err := tpm.Get(server, +func getPass(server string, headers map[string]string, certificate string, partition *block.Partition) (string, bool, error) { + opts := []tpm.Option{ tpm.WithCAs([]byte(certificate)), tpm.AppendCustomCAToSystemCA, tpm.WithAdditionalHeader("label", partition.FilesystemLabel), tpm.WithAdditionalHeader("name", partition.Name), - tpm.WithAdditionalHeader("uuid", partition.UUID)) + tpm.WithAdditionalHeader("uuid", partition.UUID), + } + for k, v := range headers { + opts = append(opts, tpm.WithAdditionalHeader(k, v)) + } + + msg, err := tpm.Get(server, opts...) if err != nil { return "", false, err } diff --git a/cmd/discovery/client/mdns.go b/cmd/discovery/client/mdns.go new file mode 100644 index 0000000..7a6b329 --- /dev/null +++ b/cmd/discovery/client/mdns.go @@ -0,0 +1,85 @@ +package client + +import ( + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/hashicorp/mdns" +) + +const ( + MDNSServiceType = "_kcrypt._tcp" + MDNSTimeout = 15 * time.Second +) + +// queryMDNS will make an mdns query on local network to find a kcrypt challenger server +// instance. If none is found, the original URL is returned and no additional headers. +// If a response is received, the IP address and port from the response will be returned// and an additional "Host" header pointing to the original host. +func queryMDNS(originalURL string) (string, map[string]string, error) { + additionalHeaders := map[string]string{} + var err error + + parsedURL, err := url.Parse(originalURL) + if err != nil { + return originalURL, additionalHeaders, fmt.Errorf("parsing the original host: %w", err) + } + + host := parsedURL.Host + if !strings.HasSuffix(host, ".local") { // sanity check + return "", additionalHeaders, fmt.Errorf("domain should end in \".local\" when using mdns") + } + + mdnsIP, mdnsPort := discoverMDNSServer(host) + if mdnsIP == "" { // no reply + logToFile("no reply from mdns\n") + return originalURL, additionalHeaders, nil + } + + additionalHeaders["Host"] = parsedURL.Host + newURL := strings.ReplaceAll(originalURL, host, mdnsIP) + // Remove any port in the original url + if port := parsedURL.Port(); port != "" { + newURL = strings.ReplaceAll(newURL, port, "") + } + + // Add any possible port from the mdns response + if mdnsPort != "" { + newURL = strings.ReplaceAll(newURL, mdnsIP, fmt.Sprintf("%s:%s", mdnsIP, mdnsPort)) + } + + return newURL, additionalHeaders, nil +} + +// discoverMDNSServer performs an mDNS query to discover any running kcrypt challenger +// servers on the same network that matches the given hostname. +// If a response if received, the IP address and the Port from the response are returned. +func discoverMDNSServer(hostname string) (string, string) { + // Make a channel for results and start listening + entriesCh := make(chan *mdns.ServiceEntry, 4) + defer close(entriesCh) + + logToFile("Will now wait for some mdns server to respond\n") + // Start the lookup. It will block until we read from the chan. + mdns.Lookup(MDNSServiceType, entriesCh) + + expectedHost := hostname + "." // FQDN + // Wait until a matching server is found or we reach a timeout + for { + select { + case entry := <-entriesCh: + logToFile("mdns response received\n") + if entry.Host == expectedHost { + logToFile("%s matches %s\n", entry.Host, expectedHost) + return entry.AddrV4.String(), strconv.Itoa(entry.Port) // TODO: v6? + } else { + logToFile("%s didn't match %s\n", entry.Host, expectedHost) + } + case <-time.After(MDNSTimeout): + logToFile("timed out waiting for mdns\n") + return "", "" + } + } +} diff --git a/go.mod b/go.mod index b98d0e3..a03ba96 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,11 @@ require ( github.com/go-logr/logr v1.2.4 github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.5.0 + github.com/hashicorp/mdns v1.0.5 github.com/jaypipes/ghw v0.11.0 github.com/kairos-io/kairos-sdk v0.0.15 github.com/kairos-io/kcrypt v0.7.0 - github.com/kairos-io/tpm-helpers v0.0.0-20230119140150-3fa97128ef6b + github.com/kairos-io/tpm-helpers v0.0.0-20240123063624-f7a3fcc66199 github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5 github.com/mudler/go-processmanager v0.0.0-20220724164624-c45b5c61312d github.com/mudler/yip v1.3.0 @@ -100,6 +101,7 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/miekg/dns v1.1.41 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect diff --git a/go.sum b/go.sum index 8df1fa7..bb31000 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,4 @@ atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= -atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4= -atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/cursor v0.1.3 h1:w8GcylMdZRyFzvDiGm3wy3fhZYYT7BwaqNjUFHxo0NU= atomicgo.dev/cursor v0.1.3/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= @@ -69,8 +67,6 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek= -github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -124,12 +120,8 @@ github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaD github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.7.1 h1:k8DbDkSOwt5rgxQ3uCI4WMKIJxIndSCBUaGm5oRn+Go= -github.com/containerd/containerd v1.7.1/go.mod h1:gA+nJUADRBm98QS5j5RPROnt0POQSMK+r7P7EGMC/Qc= github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4= github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -373,6 +365,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE= +github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -392,8 +386,6 @@ github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JP github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/itchyny/gojq v0.12.12 h1:x+xGI9BXqKoJQZkr95ibpe3cdrTbY8D9lonrK433rcA= -github.com/itchyny/gojq v0.12.12/go.mod h1:j+3sVkjxwd7A7Z5jrbKibgOLn0ZfLWkV+Awxr/pyzJE= github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4= github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= @@ -419,14 +411,12 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kairos-io/kairos-sdk v0.0.8 h1:3yfxdmUuJoN7ePg+ogpH1PJvuMsLmLcxEXuWoiGdIrg= -github.com/kairos-io/kairos-sdk v0.0.8/go.mod h1:Z+1CLqMZq97bzwX2XSIArr8EoniMth3mMYkOOb8L3QY= github.com/kairos-io/kairos-sdk v0.0.15 h1:1hcnRfKlBzDWcZ8z7UrUqJ2v6GafCHZknPqm90iTZdU= github.com/kairos-io/kairos-sdk v0.0.15/go.mod h1:Ew3NKFuXByu3Y3yGu8Q92M3oMqsXrg2VilouubdhYqA= github.com/kairos-io/kcrypt v0.7.0 h1:ESmCBIFbBBv7mJf0/f6ugqwSvz63M5oP9sUIdHiDlLc= github.com/kairos-io/kcrypt v0.7.0/go.mod h1:a9eI+vPVIQHPRtqEV/O/yIfDOdMWd9epVrq1p94gccM= -github.com/kairos-io/tpm-helpers v0.0.0-20230119140150-3fa97128ef6b h1:pwe1AlcpEAFA937Yl81mmQwE80wtxUEvBaMLrvrAb9Y= -github.com/kairos-io/tpm-helpers v0.0.0-20230119140150-3fa97128ef6b/go.mod h1:6YGebKVrPoJGBd9QE+x4zyuo3vPw1y33iQkNChjlBo8= +github.com/kairos-io/tpm-helpers v0.0.0-20240123063624-f7a3fcc66199 h1:eXiZNiQfZDelYfTF733IxDOKGAKJqn0fF0kFY10QreU= +github.com/kairos-io/tpm-helpers v0.0.0-20240123063624-f7a3fcc66199/go.mod h1:6YGebKVrPoJGBd9QE+x4zyuo3vPw1y33iQkNChjlBo8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -451,8 +441,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lithammer/fuzzysearch v1.1.7 h1:q8rZNmBIUkqxsxb/IlwsXVbCoPIH/0juxjFHY0UIwhU= -github.com/lithammer/fuzzysearch v1.1.7/go.mod h1:ZhIlfRGxnD8qa9car/yplC6GmnM14CS07BYAKJJBK2I= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -466,8 +454,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -480,6 +466,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -515,8 +503,6 @@ github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5 h1:FaZD86+A9mV github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5/go.mod h1:WmKcT8ONmhDQIqQ+HxU+tkGWjzBEyY/KFO8LTGCu4AI= github.com/mudler/go-processmanager v0.0.0-20220724164624-c45b5c61312d h1:/lAg9vPAAU+s35cDMCx1IyeMn+4OYfCBPqi08Q8vXDg= github.com/mudler/go-processmanager v0.0.0-20220724164624-c45b5c61312d/go.mod h1:HGGAOJhipApckwNV8ZTliRJqxctUv3xRY+zbQEwuytc= -github.com/mudler/yip v1.2.0 h1:hs6x2HDUq+0mwxKzY0SLixnv+VKYc4n3tDY/nXPVejU= -github.com/mudler/yip v1.2.0/go.mod h1:7fAek4ZV9SS8anO6drK+tn5eXA6w1mXKpPxI0wZT5u8= github.com/mudler/yip v1.3.0 h1:MjVh4dDr/imwJ46qXGbftnLRKmDgzs0Y60WyVtXY4i4= github.com/mudler/yip v1.3.0/go.mod h1:3WeDh6tGX1yYPJom05E7xEjw8dNVlkH2WFxLi7Gflzk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -540,8 +526,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs= -github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -604,8 +588,6 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.61 h1:cZFweZ0C4zbBsusyThfgqg0KU0PTnq5xupnGN3Ytxzc= -github.com/pterm/pterm v0.12.61/go.mod h1:07yyGZKQr8BpKKBaOZI1qKzzngqUisHdSYR4fQ9Nb4g= github.com/pterm/pterm v0.12.63 h1:fHlrpFiI9qLtEU0TWDWMU+tAt4qKJ/s157BEAPtGm8w= github.com/pterm/pterm v0.12.63/go.mod h1:Bq1eoUJ6BhUzzXG8WxA4l7T3s7d3Ogwg7v9VXlsVat0= github.com/qeesung/image2ascii v1.0.1 h1:Fe5zTnX/v/qNC3OC4P/cfASOXS501Xyw2UUcgrLgtp4= @@ -633,7 +615,6 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -676,7 +657,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -752,8 +733,6 @@ golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -833,12 +812,11 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -912,6 +890,7 @@ golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316092937-0b90fd5c4c48/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -925,14 +904,11 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -941,8 +917,6 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -954,8 +928,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/mdns-notes.md b/mdns-notes.md new file mode 100644 index 0000000..d88204b --- /dev/null +++ b/mdns-notes.md @@ -0,0 +1,103 @@ +# Prerequisites + +Nodes and KMS should be on the same local network (mdns requirement) + +# Steps + +- Create a cluster with a port bound to the host: + +``` +k3d cluster create kcrypt -p '30000:30000@server:0' +``` + +(we are going to assign this port to the kcrypt challenger server and advertise it over mdns) + +- Follow [the instructions to setup the kcrypt challenger server](https://github.com/kairos-io/kcrypt-challenger#installation): + +``` +helm repo add kairos https://kairos-io.github.io/helm-charts +helm install kairos-crd kairos/kairos-crds +``` + +Create the following 'kcrypt-challenger-values.yaml` file: + + +```yaml +service: + challenger: + type: "NodePort" + port: 8082 + nodePort: 30000 +``` + +and deploy the challenger server with it: + +```bash +helm install -f kcrypt-challenger-values.yaml kairos-challenger kairos/kairos-challenger +``` + +- Add the sealedvolume and secret for the tpm chip: + +``` +apiVersion: v1 +kind: Secret +metadata: + name: example-host-tpm-secret + namespace: default +type: Opaque +stringData: + pass: "awesome-passphrase" +--- +apiVersion: keyserver.kairos.io/v1alpha1 +kind: SealedVolume +metadata: + name: example-host + namespace: default +spec: + TPMHash: "5640e37f4016da16b841a93880dcc44886904392fa3c86681087b77db5afedbe" + partitions: + - label: COS_PERSISTENT + secret: + name: example-host-tpm-secret + path: pass + quarantined: false +``` + +- Start the [simple-mdns-server](https://github.com/kairos-io/simple-mdns-server) + +``` +go run . --port 30000 --interfaceName enp121s0 --serviceType _kcrypt._tcp --hostName mychallenger.local +``` + + +- Start a node in manual install mode + +- Replace `/system/discovery/kcrypt-discovery-challenger` with a custom build (until we merge) + +- Create the following config: + +``` +#cloud-config + +users: + - name: kairos + passwd: kairos + +install: + grub_options: + extra_cmdline: "rd.neednet=1" + encrypted_partitions: + - COS_PERSISTENT + +# Kcrypt configuration block +kcrypt: + challenger: + mdns: true + challenger_server: "http://mychallenger.local" +``` + +- Install: + +``` +kairos-agent manual-install --device auto config.yaml +``` diff --git a/renovate.json b/renovate.json index f4249a5..a3956f0 100644 --- a/renovate.json +++ b/renovate.json @@ -11,8 +11,32 @@ "timezone": "Europe/Brussels", "packageRules": [ { - "matchUpdateTypes": ["patch"], + "matchUpdateTypes": [ + "patch" + ], "automerge": true } + ], + "regexManagers": [ + { + "fileMatch": [ + "^Earthfile$" + ], + "matchStrings": [ + "#\\s*renovate:\\s*datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\sARG\\s+.+_VERSION=(?.*?)\\s" + ], + "versioningTemplate": "{{#if versioning}}{{versioning}}{{else}}semver{{/if}}" + }, + { + "fileMatch": [ + "^earthly\\.(sh|ps1)$" + ], + "datasourceTemplate": "docker", + "depNameTemplate": "earthly/earthly", + "matchStrings": [ + "earthly\\/earthly:(?.*?)\\s" + ], + "versioningTemplate": "semver-coerced" + } ] } diff --git a/tests/assets/challenger-server-ingress.template.yaml b/tests/assets/challenger-server-ingress.template.yaml index 1571871..18ed92c 100644 --- a/tests/assets/challenger-server-ingress.template.yaml +++ b/tests/assets/challenger-server-ingress.template.yaml @@ -11,6 +11,7 @@ spec: - hosts: - 10.0.2.2.challenger.sslip.io - ${CLUSTER_IP}.challenger.sslip.io + - discoverable-kms.local secretName: kms-tls rules: - host: 10.0.2.2.challenger.sslip.io @@ -33,3 +34,13 @@ spec: name: kcrypt-controller-kcrypt-escrow-server port: number: 8082 + - host: discoverable-kms.local + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: kcrypt-controller-kcrypt-escrow-server + port: + number: 8082 diff --git a/tests/encryption_test.go b/tests/encryption_test.go index 0793d83..10a2d88 100644 --- a/tests/encryption_test.go +++ b/tests/encryption_test.go @@ -19,13 +19,19 @@ import ( var installationOutput string var vm VM +var mdnsVM VM var _ = Describe("kcrypt encryption", func() { var config string + var vmOpts VMOptions + var expectedInstallationSuccess bool BeforeEach(func() { + expectedInstallationSuccess = true + + vmOpts = DefaultVMOptions() RegisterFailHandler(printInstallationOutput) - _, vm = startVM() + _, vm = startVM(vmOpts) fmt.Printf("\nvm.StateDir = %+v\n", vm.StateDir) vm.EventuallyConnects(1200) @@ -43,7 +49,9 @@ var _ = Describe("kcrypt encryption", func() { Expect(err).ToNot(HaveOccurred()) installationOutput, err = vm.Sudo("/bin/bash -c 'set -o pipefail && kairos-agent manual-install --device auto config.yaml 2>&1 | tee manual-install.txt'") - Expect(err).ToNot(HaveOccurred(), installationOutput) + if expectedInstallationSuccess { + Expect(err).ToNot(HaveOccurred(), installationOutput) + } }) AfterEach(func() { @@ -63,6 +71,63 @@ var _ = Describe("kcrypt encryption", func() { Expect(err).ToNot(HaveOccurred()) }) + When("discovering KMS with mdns", Label("discoverable-kms"), func() { + var tpmHash string + var mdnsHostname string + + BeforeEach(func() { + By("creating the secret in kubernetes") + tpmHash = createTPMPassphraseSecret(vm) + + mdnsHostname = "discoverable-kms.local" + + By("deploying simple-mdns-server vm") + mdnsVM = deploySimpleMDNSServer(mdnsHostname) + + config = fmt.Sprintf(`#cloud-config + +hostname: metal-{{ trunc 4 .MachineID }} +users: +- name: kairos + passwd: kairos + +install: + encrypted_partitions: + - COS_PERSISTENT + grub_options: + extra_cmdline: "rd.neednet=1" + reboot: false # we will reboot manually + +kcrypt: + challenger: + mdns: true + challenger_server: "http://%[1]s" +`, mdnsHostname) + }) + + AfterEach(func() { + cmd := exec.Command("kubectl", "delete", "sealedvolume", tpmHash) + out, err := cmd.CombinedOutput() + Expect(err).ToNot(HaveOccurred(), out) + + err = mdnsVM.Destroy(func(vm VM) {}) + Expect(err).ToNot(HaveOccurred()) + }) + + It("discovers the KMS using mdns", func() { + Skip("TODO: make this test work") + + By("rebooting") + vm.Reboot() + By("checking that we can connect after installation") + vm.EventuallyConnects(1200) + By("checking if we got an encrypted partition") + out, err := vm.Sudo("blkid") + Expect(err).ToNot(HaveOccurred(), out) + Expect(out).To(MatchRegexp("TYPE=\"crypto_LUKS\" PARTLABEL=\"persistent\""), out) + }) + }) + // https://kairos.io/docs/advanced/partition_encryption/#offline-mode When("doing local encryption", Label("local-encryption"), func() { BeforeEach(func() { @@ -92,25 +157,9 @@ users: //https://kairos.io/docs/advanced/partition_encryption/#online-mode When("using a remote key management server (automated passphrase generation)", Label("remote-auto"), func() { var tpmHash string - var err error BeforeEach(func() { - tpmHash, err = vm.Sudo("/system/discovery/kcrypt-discovery-challenger") - Expect(err).ToNot(HaveOccurred(), tpmHash) - - kubectlApplyYaml(fmt.Sprintf(`--- -apiVersion: keyserver.kairos.io/v1alpha1 -kind: SealedVolume -metadata: - name: "%[1]s" - namespace: default -spec: - TPMHash: "%[1]s" - partitions: - - label: COS_PERSISTENT - quarantined: false -`, strings.TrimSpace(tpmHash))) - + tpmHash = createTPMPassphraseSecret(vm) config = fmt.Sprintf(`#cloud-config hostname: metal-{{ trunc 4 .MachineID }} @@ -213,10 +262,6 @@ install: kcrypt: challenger: challenger_server: "http://%s" - nv_index: "" - c_index: "" - tpm_device: "" - `, os.Getenv("KMS_ADDRESS")) }) @@ -243,24 +288,15 @@ kcrypt: When("the key management server is listening on https", func() { var tpmHash string - var err error BeforeEach(func() { - tpmHash, err = vm.Sudo("/system/discovery/kcrypt-discovery-challenger") - Expect(err).ToNot(HaveOccurred(), tpmHash) + tpmHash = createTPMPassphraseSecret(vm) + }) - kubectlApplyYaml(fmt.Sprintf(`--- -apiVersion: keyserver.kairos.io/v1alpha1 -kind: SealedVolume -metadata: - name: "%[1]s" - namespace: default -spec: - TPMHash: "%[1]s" - partitions: - - label: COS_PERSISTENT - quarantined: false -`, strings.TrimSpace(tpmHash))) + AfterEach(func() { + cmd := exec.Command("kubectl", "delete", "sealedvolume", tpmHash) + out, err := cmd.CombinedOutput() + Expect(err).ToNot(HaveOccurred(), out) }) When("the certificate is pinned on the configuration", Label("remote-https-pinned"), func() { @@ -300,6 +336,8 @@ install: When("the no certificate is set in the configuration", Label("remote-https-bad-cert"), func() { BeforeEach(func() { + expectedInstallationSuccess = false + config = fmt.Sprintf(`#cloud-config hostname: metal-{{ trunc 4 .MachineID }} @@ -317,16 +355,13 @@ install: kcrypt: challenger: challenger_server: "https://%s" - nv_index: "" - c_index: "" - tpm_device: "" `, os.Getenv("KMS_ADDRESS")) }) It("fails to talk to the server", func() { out, err := vm.Sudo("cat manual-install.txt") Expect(err).ToNot(HaveOccurred(), out) - Expect(out).To(MatchRegexp("could not encrypt partition.*x509: certificate signed by unknown authority")) + Expect(out).To(MatchRegexp("failed to verify certificate: x509: certificate signed by unknown authority")) }) }) }) @@ -363,29 +398,57 @@ func getChallengerServerCert() string { } func createConfigWithCert(server, cert string) client.Config { - return client.Config{ - Kcrypt: struct { - Challenger struct { - Server string "yaml:\"challenger_server,omitempty\"" - NVIndex string "yaml:\"nv_index,omitempty\"" - CIndex string "yaml:\"c_index,omitempty\"" - TPMDevice string "yaml:\"tpm_device,omitempty\"" - Certificate string "yaml:\"certificate,omitempty\"" - } - }{ - Challenger: struct { - Server string "yaml:\"challenger_server,omitempty\"" - NVIndex string "yaml:\"nv_index,omitempty\"" - CIndex string "yaml:\"c_index,omitempty\"" - TPMDevice string "yaml:\"tpm_device,omitempty\"" - Certificate string "yaml:\"certificate,omitempty\"" - }{ - Server: server, - NVIndex: "", - CIndex: "", - TPMDevice: "", - Certificate: cert, - }, - }, - } + c := client.Config{} + c.Kcrypt.Challenger.Server = server + c.Kcrypt.Challenger.Certificate = cert + + return c +} + +func createTPMPassphraseSecret(vm VM) string { + tpmHash, err := vm.Sudo("/system/discovery/kcrypt-discovery-challenger") + Expect(err).ToNot(HaveOccurred(), tpmHash) + + kubectlApplyYaml(fmt.Sprintf(`--- +apiVersion: keyserver.kairos.io/v1alpha1 +kind: SealedVolume +metadata: + name: "%[1]s" + namespace: default +spec: + TPMHash: "%[1]s" + partitions: + - label: COS_PERSISTENT + quarantined: false +`, strings.TrimSpace(tpmHash))) + + return tpmHash +} + +// We run the simple-mdns-server (https://github.com/kairos-io/simple-mdns-server/) +// inside a VM next to the one we test. The server advertises the KMS as running on 10.0.2.2 +// (the host machine). This is a "hack" and is needed because of how the default +// networking in qemu works. We need to be within the same network and that +// network is only available withing another VM. +// https://wiki.qemu.org/Documentation/Networking +func deploySimpleMDNSServer(hostname string) VM { + opts := DefaultVMOptions() + opts.Memory = "2000" + opts.CPUS = "1" + opts.EmulateTPM = false + _, vm := startVM(opts) + vm.EventuallyConnects(1200) + + out, err := vm.Sudo(`curl -s https://api.github.com/repos/kairos-io/simple-mdns-server/releases/latest | jq -r .assets[].browser_download_url | grep $(uname -m) | xargs curl -L -o sms.tar.gz`) + Expect(err).ToNot(HaveOccurred(), string(out)) + + out, err = vm.Sudo("tar xvf sms.tar.gz") + Expect(err).ToNot(HaveOccurred(), string(out)) + + // Start the simple-mdns-server in the background + out, err = vm.Sudo(fmt.Sprintf( + "/bin/bash -c './simple-mdns-server --port 80 --address 10.0.2.2 --serviceType _kcrypt._tcp --hostName %s &'", hostname)) + Expect(err).ToNot(HaveOccurred(), string(out)) + + return vm } diff --git a/tests/suite_test.go b/tests/suite_test.go index be2a716..ad79357 100644 --- a/tests/suite_test.go +++ b/tests/suite_test.go @@ -25,6 +25,53 @@ func TestE2e(t *testing.T) { RunSpecs(t, "kcrypt-challenger e2e test Suite") } +type VMOptions struct { + ISO string + User string + Password string + Memory string + CPUS string + RunSpicy bool + UseKVM bool + EmulateTPM bool +} + +func DefaultVMOptions() VMOptions { + var err error + + memory := os.Getenv("MEMORY") + if memory == "" { + memory = "2096" + } + cpus := os.Getenv("CPUS") + if cpus == "" { + cpus = "2" + } + + runSpicy := false + if s := os.Getenv("MACHINE_SPICY"); s != "" { + runSpicy, err = strconv.ParseBool(os.Getenv("MACHINE_SPICY")) + Expect(err).ToNot(HaveOccurred()) + } + + useKVM := false + if envKVM := os.Getenv("KVM"); envKVM != "" { + useKVM, err = strconv.ParseBool(os.Getenv("KVM")) + Expect(err).ToNot(HaveOccurred()) + } + + return VMOptions{ + ISO: os.Getenv("ISO"), + User: user(), + Password: pass(), + Memory: memory, + CPUS: cpus, + RunSpicy: runSpicy, + UseKVM: useKVM, + EmulateTPM: true, + } +} + func user() string { user := os.Getenv("SSH_USER") if user == "" { @@ -42,8 +89,8 @@ func pass() string { return pass } -func startVM() (context.Context, VM) { - if os.Getenv("ISO") == "" { +func startVM(vmOpts VMOptions) (context.Context, VM) { + if vmOpts.ISO == "" { fmt.Println("ISO missing") os.Exit(1) } @@ -53,29 +100,22 @@ func startVM() (context.Context, VM) { stateDir, err := os.MkdirTemp("", "") Expect(err).ToNot(HaveOccurred()) - emulateTPM(stateDir) + if vmOpts.EmulateTPM { + emulateTPM(stateDir) + } sshPort, err := getFreePort() Expect(err).ToNot(HaveOccurred()) - memory := os.Getenv("MEMORY") - if memory == "" { - memory = "2096" - } - cpus := os.Getenv("CPUS") - if cpus == "" { - cpus = "2" - } - opts := []types.MachineOption{ types.QEMUEngine, - types.WithISO(os.Getenv("ISO")), - types.WithMemory(memory), - types.WithCPU(cpus), + types.WithISO(vmOpts.ISO), + types.WithMemory(vmOpts.Memory), + types.WithCPU(vmOpts.CPUS), types.WithSSHPort(strconv.Itoa(sshPort)), types.WithID(vmName), - types.WithSSHUser(user()), - types.WithSSHPass(pass()), + types.WithSSHUser(vmOpts.User), + types.WithSSHPass(vmOpts.Password), types.OnFailure(func(p *process.Process) { defer GinkgoRecover() @@ -109,9 +149,12 @@ func startVM() (context.Context, VM) { types.WithStateDir(stateDir), // Serial output to file: https://superuser.com/a/1412150 func(m *types.MachineConfig) error { + if vmOpts.EmulateTPM { + m.Args = append(m.Args, + "-chardev", fmt.Sprintf("socket,id=chrtpm,path=%s/swtpm-sock", path.Join(stateDir, "tpm")), + "-tpmdev", "emulator,id=tpm0,chardev=chrtpm", "-device", "tpm-tis,tpmdev=tpm0") + } m.Args = append(m.Args, - "-chardev", fmt.Sprintf("socket,id=chrtpm,path=%s/swtpm-sock", path.Join(stateDir, "tpm")), - "-tpmdev", "emulator,id=tpm0,chardev=chrtpm", "-device", "tpm-tis,tpmdev=tpm0", "-chardev", fmt.Sprintf("stdio,mux=on,id=char0,logfile=%s,signal=off", path.Join(stateDir, "serial.log")), "-serial", "chardev:char0", "-mon", "chardev=char0", @@ -123,14 +166,14 @@ func startVM() (context.Context, VM) { // Set this to true to debug. // You can connect to it with "spicy" or other tool. var spicePort int - if os.Getenv("MACHINE_SPICY") != "" { + if vmOpts.RunSpicy { spicePort, err = getFreePort() Expect(err).ToNot(HaveOccurred()) fmt.Printf("Spice port = %d\n", spicePort) opts = append(opts, types.WithDisplay(fmt.Sprintf("-spice port=%d,addr=127.0.0.1,disable-ticketing", spicePort))) } - if os.Getenv("KVM") != "" { + if vmOpts.UseKVM { opts = append(opts, func(m *types.MachineConfig) error { m.Args = append(m.Args, "-enable-kvm", @@ -147,7 +190,7 @@ func startVM() (context.Context, VM) { ctx, err := vm.Start(context.Background()) Expect(err).ToNot(HaveOccurred()) - if os.Getenv("MACHINE_SPICY") != "" { + if vmOpts.RunSpicy { cmd := exec.Command("spicy", "-h", "127.0.0.1", "-p", strconv.Itoa(spicePort))