github.com/coreos/mantle@v0.13.0/kola/tests/ignition/security.go (about)

     1  // Copyright 2018 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ignition
    16  
    17  import (
    18  	"crypto/tls"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"net"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"strings"
    25  
    26  	"github.com/vincent-petithory/dataurl"
    27  
    28  	"github.com/coreos/mantle/kola/cluster"
    29  	"github.com/coreos/mantle/kola/register"
    30  	"github.com/coreos/mantle/platform/conf"
    31  	"github.com/coreos/mantle/platform/machine/packet"
    32  )
    33  
    34  var (
    35  	localSecurityClient = conf.Ignition(`{
    36          "ignition": {
    37              "version": "2.2.0",
    38              "config": {
    39                  "append": [{
    40                      "source": "https://$IP"
    41                  }]
    42              },
    43              "security": {
    44                  "tls": {
    45                      "certificateAuthorities": [{
    46                          "source": "$KEY"
    47                      }]
    48                  }
    49              }
    50          }
    51      }`)
    52  	localSecurityClientV3 = conf.Ignition(`{
    53          "ignition": {
    54              "version": "3.0.0",
    55              "config": {
    56                  "merge": [{
    57                      "source": "https://$IP"
    58                  }]
    59              },
    60              "security": {
    61                  "tls": {
    62                      "certificateAuthorities": [{
    63                          "source": "$KEY"
    64                      }]
    65                  }
    66              }
    67          }
    68      }`)
    69  )
    70  
    71  func init() {
    72  	register.Register(&register.Test{
    73  		Name:        "coreos.ignition.security.tls",
    74  		Run:         securityTLS,
    75  		ClusterSize: 1,
    76  		NativeFuncs: map[string]func() error{
    77  			"TLSServe":   TLSServe,
    78  			"TLSServeV3": TLSServeV3,
    79  		},
    80  		// DO: https://github.com/coreos/bugs/issues/2205
    81  		// Packet & QEMU: https://github.com/coreos/ignition/issues/645
    82  		ExcludePlatforms: []string{"do", "packet", "qemu"},
    83  		Distros:          []string{"cl", "fcos", "rhcos"},
    84  	})
    85  }
    86  
    87  func securityTLS(c cluster.TestCluster) {
    88  	server := c.Machines()[0]
    89  
    90  	ip := server.PrivateIP()
    91  	if c.Platform() == packet.Platform {
    92  		// private IP not configured in the initramfs
    93  		ip = server.IP()
    94  	}
    95  
    96  	c.MustSSH(server, "sudo mkdir /var/tls")
    97  	c.MustSSH(server, "sudo openssl ecparam -genkey -name secp384r1 -out /var/tls/server.key")
    98  	c.MustSSH(server, strings.Replace(`sudo bash -c 'openssl req -new -x509 -sha256 -key /var/tls/server.key -out /var/tls/server.crt -days 3650 -subj "/CN=$IP" -config <(cat <<-EOF
    99  [req]
   100  default_bits = 2048
   101  default_md = sha256
   102  distinguished_name = dn
   103  
   104  [ dn ]
   105  CN = $IP
   106  
   107  [ SAN ]
   108  subjectAltName = IP:$IP
   109  EOF
   110  ) -extensions SAN'`, "$IP", ip, -1))
   111  	publicKey := c.MustSSH(server, "sudo cat /var/tls/server.crt")
   112  
   113  	var serveFunc string
   114  	var conf *conf.UserData
   115  	switch c.IgnitionVersion() {
   116  	case "v2":
   117  		serveFunc = "TLSServe"
   118  		conf = localSecurityClient
   119  	case "v3":
   120  		serveFunc = "TLSServeV3"
   121  		conf = localSecurityClientV3
   122  	default:
   123  		c.Fatal("unknown ignition version")
   124  	}
   125  
   126  	c.MustSSH(server, fmt.Sprintf("sudo systemd-run --quiet ./kolet run %s %s", c.H.Name(), serveFunc))
   127  
   128  	client, err := c.NewMachine(conf.Subst("$IP", ip).Subst("$KEY", dataurl.EncodeBytes(publicKey)))
   129  	if err != nil {
   130  		c.Fatalf("starting client: %v", err)
   131  	}
   132  
   133  	checkResources(c, client, map[string]string{
   134  		"data": "kola-data",
   135  	})
   136  }
   137  
   138  func ServeTLS(customFile []byte) error {
   139  	publicKey, err := ioutil.ReadFile("/var/tls/server.crt")
   140  	if err != nil {
   141  		return fmt.Errorf("reading public key: %v", err)
   142  	}
   143  
   144  	privateKey, err := ioutil.ReadFile("/var/tls/server.key")
   145  	if err != nil {
   146  		return fmt.Errorf("reading private key: %v", err)
   147  	}
   148  
   149  	cer, err := tls.X509KeyPair(publicKey, privateKey)
   150  	if err != nil {
   151  		return fmt.Errorf("error loading x509 keypair: %v", err)
   152  	}
   153  
   154  	config := &tls.Config{
   155  		Certificates: []tls.Certificate{cer},
   156  	}
   157  
   158  	caserver := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   159  		w.Write(customFile)
   160  	}))
   161  	l, err := net.Listen("tcp", ":443")
   162  	if err != nil {
   163  		return err
   164  	}
   165  	caserver.Listener.Close()
   166  	caserver.Listener = l
   167  	caserver.TLS = config
   168  	caserver.StartTLS()
   169  
   170  	select {}
   171  }
   172  
   173  func TLSServe() error {
   174  	customFile := []byte(`{
   175          "ignition": { "version": "2.1.0" },
   176          "storage": {
   177              "files": [{
   178                  "filesystem": "root",
   179                  "path": "/var/resource/data",
   180                  "contents": { "source": "data:,kola-data" }
   181              }]
   182          }
   183      }`)
   184  	return ServeTLS(customFile)
   185  }
   186  
   187  func TLSServeV3() error {
   188  	customFileV3 := []byte(`{
   189          "ignition": { "version": "3.0.0" },
   190          "storage": {
   191              "files": [{
   192                  "path": "/var/resource/data",
   193                  "contents": { "source": "data:,kola-data" }
   194              }]
   195          }
   196      }`)
   197  	return ServeTLS(customFileV3)
   198  }