Example #1
0
// Create a public domain with a CachedGuard.
// TODO(cjpatton) create a net.Conn here. defer Close() somehow. Add new
// constructor from a net.Conn that doesn't save the domain to disk.
// Refactor Request's in ca.go to use already existing connection.
func (d *Domain) CreatePublicCachedDomain(network, addr string, ttl int64) (*Domain, error) {
	newDomain := &Domain{
		Config: d.Config,
	}
	configDir, configName := path.Split(d.ConfigPath) // '/path/to/', 'file'

	// Load public key from domain.
	keyPath := path.Join(configDir, d.Config.DomainInfo.GetPolicyKeysPath())
	keys, err := NewOnDiskPBEKeys(Signing, PublicCachedDomainPassword, keyPath,
		NewX509Name(d.Config.X509Info))
	if err != nil {
		return nil, err
	}
	newDomain.Keys = keys

	// Set up a CachedGuard.
	newDomain.Guard = NewCachedGuard(newDomain.Keys.VerifyingKey,
		Datalog /*TODO(cjpatton) hardcoded*/, network, addr, ttl)
	newDomain.Config.DomainInfo.GuardNetwork = proto.String(network)
	newDomain.Config.DomainInfo.GuardAddress = proto.String(addr)
	newDomain.Config.DomainInfo.GuardTtl = proto.Int64(ttl)

	// Create domain directory ending with ".pub".
	configDir = strings.TrimRight(configDir, "/") + ".pub"
	err = util.MkdirAll(configDir, 0777)
	if err != nil {
		return nil, err
	}
	newDomain.ConfigPath = path.Join(configDir, configName)
	newDomain.Keys.dir = path.Join(configDir, d.Config.DomainInfo.GetPolicyKeysPath())

	// Save public key. Copy certificate from the old to new directory.
	// TODO(tmroeder) this is a bit hacky, but the best we can do short
	// of refactoring the NewOnDiskPBEKey() code. In particular, there is
	// currently no way to *just* save the keys.
	err = util.MkdirAll(newDomain.Keys.dir, 0777)
	if err != nil {
		return nil, err
	}
	for name, _ := range d.Keys.X509Paths() {
		inFile, err := os.Open(d.Keys.X509Path(name))
		if err != nil {
			return nil, err
		}
		defer inFile.Close()
		outFile, err := os.Create(newDomain.Keys.X509Path(name))
		if err != nil {
			return nil, err
		}
		defer outFile.Close()
		_, err = io.Copy(outFile, inFile)
		if err != nil {
			return nil, err
		}
	}

	// Save domain.
	err = newDomain.Save()
	return newDomain, err
}
Example #2
0
// CreateDomain initializes a new Domain, writing its configuration files to
// a directory. This creates the directory if needed, creates a policy key pair
// (encrypted with the given password when stored on disk), and initializes a
// default guard of the appropriate type if needed. Any parameters left empty in
// cfg will be set to reasonable default values.
func CreateDomain(cfg DomainConfig, configPath string, password []byte) (*Domain, error) {
	cfg.SetDefaults()

	configDir := path.Dir(configPath)
	err := util.MkdirAll(configDir, 0777)
	if err != nil {
		return nil, err
	}

	keypath := path.Join(configDir, cfg.DomainInfo.GetPolicyKeysPath())
	// This creates a keyset if it doesn't exist, and it reads the keyset
	// otherwise.
	keys, err := NewOnDiskPBEKeys(Signing, password, keypath, NewX509Name(cfg.X509Info))
	if err != nil {
		return nil, err
	}

	var guard Guard
	switch cfg.DomainInfo.GetGuardType() {
	case "ACLs":
		if cfg.AclGuardInfo == nil {
			return nil, fmt.Errorf("must supply ACL info for the ACL guard")
		}
		aclsPath := cfg.AclGuardInfo.GetSignedAclsPath()
		agi := ACLGuardDetails{
			SignedAclsPath: proto.String(path.Join(configDir, aclsPath)),
		}
		guard = NewSignedACLGuard(keys.VerifyingKey, agi)
	case "Datalog":
		if cfg.DatalogGuardInfo == nil {
			return nil, fmt.Errorf("must supply Datalog info for the Datalog guard")
		}
		rulesPath := cfg.DatalogGuardInfo.GetSignedRulesPath()
		dgi := DatalogGuardDetails{
			SignedRulesPath: proto.String(path.Join(configDir, rulesPath)),
		}
		guard, err = NewDatalogGuardFromConfig(keys.VerifyingKey, dgi)
		if err != nil {
			return nil, err
		}
	case "AllowAll":
		guard = LiberalGuard
	case "DenyAll":
		guard = ConservativeGuard
	default:
		return nil, newError("unrecognized guard type: %s", cfg.DomainInfo.GetGuardType())
	}

	d := &Domain{cfg, configPath, keys, guard}
	err = d.Save()
	if err != nil {
		return nil, err
	}
	return d, nil
}
Example #3
0
// NewSecret creates and encrypts a new secret value of the given length, or it
// reads and decrypts the value and checks that it's the right length. It
// creates the file and its parent directories if these directories do not
// exist.
func (k *Keys) NewSecret(file string, length int) ([]byte, error) {
	if _, err := os.Stat(file); err != nil {
		// Create the parent directories and the file.
		if err := util.MkdirAll(path.Dir(file), 0700); err != nil {
			return nil, err
		}

		secret := make([]byte, length)
		if _, err := rand.Read(secret); err != nil {
			return nil, err
		}

		enc, err := k.CryptingKey.Encrypt(secret)
		if err != nil {
			return nil, err
		}

		if err := ioutil.WriteFile(file, enc, 0700); err != nil {
			return nil, err
		}

		return secret, nil
	}

	enc, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}

	dec, err := k.CryptingKey.Decrypt(enc)
	if err != nil {
		return nil, err
	}

	if len(dec) != length {
		ZeroBytes(dec)
		return nil, newError("The decrypted value had length %d, but it should have had length %d", len(dec), length)
	}

	return dec, nil
}
Example #4
0
func main() {
	// tao -help ==> show main help
	// tao ==> show main help
	// tao [commonopts] cmd [otheropts] ==> some_cmd [commonopts] [otheropts]

	boolopts := []string{"quiet", "verbose", "help"}
	valopts := []string{"tao_domain"}

	flag.VisitAll(func(f *flag.Flag) {
		type BoolFlag interface {
			IsBoolFlag() bool
		}
		if b, ok := f.Value.(BoolFlag); ok && b.IsBoolFlag() {
			boolopts = append(boolopts, f.Name)
		} else {
			valopts = append(valopts, f.Name)
		}
	})

	var args []string
	cmd := "help"
	for i := 1; i < len(os.Args); i++ {
		arg := os.Args[i]
		if arg == "help" || arg == "-?" {
			args = append(args, "-help")
			continue
		}
		if arg == "--" {
			args = append(args, os.Args[i:]...)
			break
		}
		if arg == "" || arg[0] != '-' {
			cmd = arg
			args = append(args, os.Args[i+1:]...)
			break
		}
		if e := strings.Index(arg, "="); e != -1 { // -name=val
			name := flagName(arg[0:e])
			if !match(name, boolopts...) && !match(name, valopts...) {
				options.Usage("Unrecognized option: %s", arg)
			}
			args = append(args, arg)
		} else if match(flagName(arg), boolopts...) { // -bool
			args = append(args, arg)
		} else if match(flagName(arg), valopts...) { // -name val
			if i+1 >= len(os.Args) {
				options.Usage("flag needs an argument: %s", arg)
			}
			args = append(args, arg, os.Args[i+1])
			i++
		} else {
			options.Usage("Unrecognized option: %s", arg)
		}
	}

	// Add a default --tao_domain
	// config := os.Getenv("TAO_DOMAIN")
	// if config != "" {
	// 	arg := fmt.Sprintf("--tao_domain='%s'", config)
	// 	args = append([]string{arg}, args...)
	// }

	// Add a default --log_dir
	logdir := os.TempDir() + "/tao_log"
	if err := util.MkdirAll(logdir, 0777); err != nil {
		options.FailIf(err, "Can't create log directory: %s", logdir)
	}
	arg := fmt.Sprintf("--log_dir=%s", logdir)
	args = append([]string{arg}, args...)

	// Maybe add --alsologtostderr=true too?

	switch cmd {
	case "help":
		help()
	case "domain":
		subcmd(cmd, "tao_admin", args)
	case "host":
		subcmd(cmd, "linux_host", args)
	case "run", "list", "stop", "kill":
		subcmd(cmd, "tao_launch", args)
	default:
		options.Usage("Unrecognized tao command: %s", cmd)
	}
}
// Start starts a QEMU/KVM CoreOS container using the command line.
func (kcc *KvmCoreOSHostContainer) startVM() error {
	// Create a temporary directory for the config drive.
	td, err := ioutil.TempDir("", "coreos")
	kcc.Tempdir = td
	if err != nil {
		return err
	}

	// Create a temporary directory for the linux_host image. Note that the
	// args were validated in Start before this call.
	kcc.LHPath = kcc.spec.Args[1]

	// Expand the host file into the directory.
	linuxHostFile, err := os.Open(kcc.spec.Path)
	if err != nil {
		return err
	}

	zipReader, err := gzip.NewReader(linuxHostFile)
	if err != nil {
		return err
	}
	defer zipReader.Close()

	unzippedImage, err := ioutil.ReadAll(zipReader)
	if err != nil {
		return err
	}
	unzippedReader := bytes.NewReader(unzippedImage)
	tarReader := tar.NewReader(unzippedReader)
	for {
		hdr, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		fi := hdr.FileInfo()
		outputName := path.Join(kcc.LHPath, hdr.Name)
		if fi.IsDir() {
			if err := os.Mkdir(outputName, fi.Mode()); err != nil {
				return err
			}
		} else {

			outputFile, err := os.OpenFile(outputName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, fi.Mode())
			if err != nil {
				return err
			}

			if _, err := io.Copy(outputFile, tarReader); err != nil {
				outputFile.Close()
				return err
			}
			outputFile.Close()
		}
	}

	latestDir := path.Join(td, "openstack/latest")
	if err := util.MkdirAll(latestDir, 0700); err != nil {
		return err
	}

	cfg := kcc.Cfg
	userData := path.Join(latestDir, "user_data")
	if err := ioutil.WriteFile(userData, []byte(cfg.SSHKeysCfg), 0700); err != nil {
		return err
	}

	// Copy the rules into the mirrored filesystem for use by the Linux host
	// on CoreOS.
	if cfg.RulesPath != "" {
		rules, err := ioutil.ReadFile(cfg.RulesPath)
		if err != nil {
			return err
		}
		rulesFile := path.Join(kcc.LHPath, path.Base(cfg.RulesPath))
		if err := ioutil.WriteFile(rulesFile, []byte(rules), 0700); err != nil {
			return err
		}
	}

	qemuProg := "qemu-system-x86_64"
	qemuArgs := []string{"-name", cfg.Name,
		"-m", strconv.Itoa(cfg.Memory),
		"-machine", "accel=kvm:tcg",
		// Networking.
		"-net", "nic,vlan=0,model=virtio",
		"-net", "user,vlan=0,hostfwd=tcp::" + kcc.spec.Args[2] + "-:22,hostname=" + cfg.Name,
		// Tao communications through virtio-serial. With this
		// configuration, QEMU waits for a server on cfg.SocketPath,
		// then connects to it.
		"-chardev", "socket,path=" + cfg.SocketPath + ",id=port0-char",
		"-device", "virtio-serial",
		"-device", "virtserialport,id=port1,name=tao,chardev=port0-char",
		// The CoreOS image to boot from.
		"-drive", "if=virtio,file=" + cfg.ImageFile,
		// A Plan9P filesystem for SSH configuration (and our rules).
		"-fsdev", "local,id=conf,security_model=none,readonly,path=" + td,
		"-device", "virtio-9p-pci,fsdev=conf,mount_tag=config-2",
		// Another Plan9P filesystem for the linux_host files.
		"-fsdev", "local,id=tao,security_model=none,path=" + kcc.LHPath,
		"-device", "virtio-9p-pci,fsdev=tao,mount_tag=tao",
		// Machine config.
		"-cpu", "host",
		"-smp", "4",
		"-nographic"} // for now, we add -nographic explicitly.
	// TODO(tmroeder): append args later.
	//qemuArgs = append(qemuArgs, kcc.spec.Args...)

	glog.Info("Launching qemu/coreos")
	kcc.QCmd = exec.Command(qemuProg, qemuArgs...)
	// Don't connect QEMU/KVM to any of the current input/output channels,
	// since we'll connect over SSH.
	//kcc.QCmd.Stdin = os.Stdin
	//kcc.QCmd.Stdout = os.Stdout
	//kcc.QCmd.Stderr = os.Stderr
	// TODO(kwalsh) set up env, dir, and uid/gid.
	return kcc.QCmd.Start()
}