veyron/lib/modules: Use the agent for managing credentials in modules.Shell.

Change-Id: I17737af8d4fe2281d2f0e5a267cbff268758f788
diff --git a/lib/filelocker/locker_test.go b/lib/filelocker/locker_test.go
index 4e96ef9..b58bfe2 100644
--- a/lib/filelocker/locker_test.go
+++ b/lib/filelocker/locker_test.go
@@ -63,7 +63,7 @@
 	filepath := newFile()
 	defer os.Remove(filepath)
 
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -136,7 +136,7 @@
 	filepath := newFile()
 	defer os.Remove(filepath)
 
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/lib/modules/core/core_test.go b/lib/modules/core/core_test.go
index b314ad3..64eeabb 100644
--- a/lib/modules/core/core_test.go
+++ b/lib/modules/core/core_test.go
@@ -18,6 +18,7 @@
 	"v.io/core/veyron/lib/modules/core"
 	"v.io/core/veyron/lib/testutil"
 	_ "v.io/core/veyron/profiles"
+	"v.io/core/veyron2/rt"
 )
 
 func TestCommands(t *testing.T) {
@@ -37,7 +38,11 @@
 // TODO(cnicolaou): add test for proxyd
 
 func newShell(t *testing.T) (*modules.Shell, func()) {
-	sh, err := modules.NewShell(nil)
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -48,6 +53,7 @@
 		} else {
 			sh.Cleanup(nil, nil)
 		}
+		runtime.Cleanup()
 	}
 }
 
@@ -193,7 +199,6 @@
 	}
 	cltSession := expect.NewSession(t, clt.Stdout(), time.Minute)
 	cltSession.Expect("test: a message")
-	srv.Shutdown(nil, nil)
 }
 
 func TestExec(t *testing.T) {
diff --git a/lib/modules/examples_test.go b/lib/modules/examples_test.go
index 2154214..ee78224 100644
--- a/lib/modules/examples_test.go
+++ b/lib/modules/examples_test.go
@@ -28,7 +28,7 @@
 		return
 	}
 	// Parent process.
-	sh, _ := modules.NewShell(nil)
+	sh, _ := modules.NewShell(runtime.NewContext(), nil)
 	defer sh.Cleanup(nil, nil)
 	h, _ := sh.Start("echo", nil, "a", "b")
 	h.Shutdown(os.Stdout, os.Stderr)
@@ -41,7 +41,7 @@
 func ExampleDispatchAndExit() {
 	// DispatchAndExit will call os.Exit(0) when executed within the child.
 	modules.DispatchAndExit()
-	sh, _ := modules.NewShell(nil)
+	sh, _ := modules.NewShell(runtime.NewContext(), nil)
 	defer sh.Cleanup(nil, nil)
 	h, _ := sh.Start("echo", nil, "c", "d")
 	h.Shutdown(os.Stdout, os.Stderr)
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index 351af5f..b7e77c0 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -5,11 +5,13 @@
 	"io"
 	"os"
 	"os/exec"
+	"strconv"
 	"strings"
 	"sync"
 	"time"
 
 	vexec "v.io/core/veyron/lib/exec"
+	"v.io/core/veyron2/mgmt"
 	"v.io/core/veyron2/vlog"
 )
 
@@ -108,7 +110,7 @@
 	return newargs, append(cleaned, eh.entryPoint)
 }
 
-func (eh *execHandle) start(sh *Shell, env []string, args ...string) (Handle, error) {
+func (eh *execHandle) start(sh *Shell, agentfd *os.File, env []string, args ...string) (Handle, error) {
 	eh.mu.Lock()
 	defer eh.mu.Unlock()
 	eh.sh = sh
@@ -132,8 +134,20 @@
 	if err != nil {
 		return nil, err
 	}
+	config := vexec.NewConfig()
+	serialized, err := sh.config.Serialize()
+	if err != nil {
+		return nil, err
+	}
+	config.MergeFrom(serialized)
+	if agentfd != nil {
+		childfd := len(cmd.ExtraFiles) + vexec.FileOffset
+		config.Set(mgmt.SecurityAgentFDConfigKey, strconv.Itoa(childfd))
+		cmd.ExtraFiles = append(cmd.ExtraFiles, agentfd)
+		defer agentfd.Close()
+	}
 
-	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{Config: sh.config})
+	handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{Config: config})
 	eh.stdout = stdout
 	eh.stderr = stderr
 	eh.stdin = stdin
diff --git a/lib/modules/func.go b/lib/modules/func.go
index 4103fae..e7372e6 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -55,9 +55,13 @@
 	return args, env
 }
 
-func (fh *functionHandle) start(sh *Shell, env []string, args ...string) (Handle, error) {
+func (fh *functionHandle) start(sh *Shell, agent *os.File, env []string, args ...string) (Handle, error) {
 	fh.mu.Lock()
 	defer fh.mu.Unlock()
+	// In process commands need their own reference to a principal.
+	if agent != nil {
+		agent.Close()
+	}
 	fh.sh = sh
 	for _, p := range []*pipe{&fh.stdin, &fh.stdout} {
 		var err error
diff --git a/lib/modules/modules_internal_test.go b/lib/modules/modules_internal_test.go
index b8229e3..3c26937 100644
--- a/lib/modules/modules_internal_test.go
+++ b/lib/modules/modules_internal_test.go
@@ -6,6 +6,10 @@
 	"path/filepath"
 	"runtime"
 	"testing"
+
+	_ "v.io/core/veyron/profiles"
+
+	"v.io/core/veyron2/rt"
 )
 
 func Echo(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
@@ -26,7 +30,12 @@
 }
 
 func TestState(t *testing.T) {
-	sh, err := NewShell(nil)
+	r, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer r.Cleanup()
+	sh, err := NewShell(r.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/lib/modules/modules_test.go b/lib/modules/modules_test.go
index 6915d68..1f4e311 100644
--- a/lib/modules/modules_test.go
+++ b/lib/modules/modules_test.go
@@ -3,7 +3,6 @@
 import (
 	"bufio"
 	"bytes"
-	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -18,19 +17,22 @@
 	"v.io/core/veyron/lib/flags/consts"
 	"v.io/core/veyron/lib/modules"
 	"v.io/core/veyron/lib/testutil"
-	tsecurity "v.io/core/veyron/lib/testutil/security"
+	"v.io/core/veyron/lib/testutil/security"
 	_ "v.io/core/veyron/profiles"
-	vsecurity "v.io/core/veyron/security"
 
-	"v.io/core/veyron2/security"
+	"v.io/core/veyron2"
+	"v.io/core/veyron2/rt"
 )
 
 const credentialsEnvPrefix = "\"" + consts.VeyronCredentials + "="
 
+var runtime veyron2.Runtime
+
 func init() {
 	testutil.Init()
 	modules.RegisterChild("envtest", "envtest: <variables to print>...", PrintFromEnv)
 	modules.RegisterChild("printenv", "printenv", PrintEnv)
+	modules.RegisterChild("printblessing", "printblessing", PrintBlessing)
 	modules.RegisterChild("echos", "[args]*", Echo)
 	modules.RegisterChild("errortestChild", "", ErrorMain)
 	modules.RegisterChild("ignores_stdin", "", ignoresStdin)
@@ -38,6 +40,11 @@
 	modules.RegisterFunction("envtestf", "envtest: <variables to print>...", PrintFromEnv)
 	modules.RegisterFunction("echof", "[args]*", Echo)
 	modules.RegisterFunction("errortestFunc", "", ErrorMain)
+	var err error
+	runtime, err = rt.New()
+	if err != nil {
+		panic(err)
+	}
 }
 
 func ignoresStdin(io.Reader, io.Writer, io.Writer, map[string]string, ...string) error {
@@ -53,6 +60,12 @@
 	return nil
 }
 
+func PrintBlessing(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	blessing := veyron2.GetPrincipal(runtime.NewContext()).BlessingStore().Default()
+	fmt.Fprintf(stdout, "%s", blessing)
+	return nil
+}
+
 func PrintFromEnv(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
 	for _, a := range args[1:] {
 		if v := env[a]; len(v) > 0 {
@@ -132,8 +145,21 @@
 	}
 }
 
+func getBlessing(t *testing.T, sh *modules.Shell, env ...string) string {
+	h, err := sh.Start("printblessing", env)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	scanner := bufio.NewScanner(h.Stdout())
+	if !waitForInput(scanner) {
+		t.Errorf("timeout")
+		return ""
+	}
+	return scanner.Text()
+}
+
 func TestChild(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -143,8 +169,62 @@
 	testCommand(t, sh, "envtest", key, val)
 }
 
+func TestAgent(t *testing.T) {
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	defer sh.Cleanup(os.Stdout, os.Stderr)
+	a := getBlessing(t, sh)
+	b := getBlessing(t, sh)
+	if a != b {
+		t.Errorf("Expected same blessing for children, got %s and %s", a, b)
+	}
+	sh2, err := modules.NewShell(runtime.NewContext(), nil)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	defer sh2.Cleanup(os.Stdout, os.Stderr)
+	c := getBlessing(t, sh2)
+	if a == c {
+		t.Errorf("Expected different blessing for each shell, got %s and %s", a, c)
+	}
+}
+
+func TestCustomPrincipal(t *testing.T) {
+	p := security.NewPrincipal("myshell")
+	cleanDebug := p.BlessingStore().DebugString()
+	sh, err := modules.NewShell(runtime.NewContext(), p)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	defer sh.Cleanup(os.Stdout, os.Stderr)
+	blessing := getBlessing(t, sh)
+	if blessing != "myshell/child" {
+		t.Errorf("Bad blessing. Expected myshell/child, go %q", blessing)
+	}
+	newDebug := p.BlessingStore().DebugString()
+	if cleanDebug != newDebug {
+		t.Errorf("Shell modified custom principal. Was:\n%q\nNow:\n%q", cleanDebug, newDebug)
+	}
+}
+
+func TestNoAgent(t *testing.T) {
+	creds, _ := security.NewCredentials("noagent")
+	defer os.RemoveAll(creds)
+	sh, err := modules.NewShell(nil, nil)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	defer sh.Cleanup(os.Stdout, os.Stderr)
+	blessing := getBlessing(t, sh, fmt.Sprintf("VEYRON_CREDENTIALS=%s", creds))
+	if blessing != "noagent" {
+		t.Errorf("Bad blessing. Expected noagent, go %q", blessing)
+	}
+}
+
 func TestChildNoRegistration(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -159,7 +239,7 @@
 }
 
 func TestFunction(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -170,7 +250,7 @@
 }
 
 func TestErrorChild(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -210,7 +290,7 @@
 }
 
 func TestShutdownSubprocess(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -222,7 +302,7 @@
 // forever if a child does not die upon closing stdin; but instead times out and
 // returns an appropriate error.
 func TestShutdownSubprocessIgnoresStdin(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -247,7 +327,7 @@
 // implementation inappropriately sets stdout to the file that is to be closed
 // in Wait.
 func TestStdoutRace(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -279,7 +359,7 @@
 }
 
 func TestShutdownFunction(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -288,7 +368,7 @@
 }
 
 func TestErrorFunc(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -312,7 +392,7 @@
 }
 
 func TestEnvelope(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -347,146 +427,24 @@
 		}
 	}
 
-	foundVeyronCredentials := false
 	for _, want := range shEnv {
-		if strings.HasPrefix(want, credentialsEnvPrefix) {
-			foundVeyronCredentials = true
-			continue
-		}
 		if !find(want, childEnv) {
 			t.Errorf("failed to find %s in %#v", want, childEnv)
 		}
 	}
-	if !foundVeyronCredentials {
-		t.Errorf("%v environment variable not set in command envelope", consts.VeyronCredentials)
-	}
 
-	foundVeyronCredentials = false
 	for _, want := range childEnv {
 		if want == "\""+exec.VersionVariable+"=\"" {
 			continue
 		}
-		if strings.HasPrefix(want, credentialsEnvPrefix) {
-			foundVeyronCredentials = true
-			continue
-		}
 		if !find(want, shEnv) {
 			t.Errorf("failed to find %s in %#v", want, shEnv)
 		}
 	}
-	if !foundVeyronCredentials {
-		t.Errorf("%v environment variable not set for command", consts.VeyronCredentials)
-	}
-}
-
-func TestEnvCredentials(t *testing.T) {
-	startChildAndGetCredentials := func(sh *modules.Shell, env []string) string {
-		h, err := sh.Start("printenv", env)
-		if err != nil {
-			t.Fatalf("unexpected error: %s", err)
-		}
-		defer h.Shutdown(os.Stderr, os.Stderr)
-		scanner := bufio.NewScanner(h.Stdout())
-		for scanner.Scan() {
-			o := scanner.Text()
-			if strings.HasPrefix(o, credentialsEnvPrefix) {
-				return strings.TrimSuffix(strings.TrimPrefix(o, credentialsEnvPrefix), "\"")
-			}
-		}
-		return ""
-	}
-	validateCredentials := func(dir string, wantBlessing string) error {
-		if len(dir) == 0 {
-			return errors.New("credentials directory not found")
-		}
-		p, err := vsecurity.LoadPersistentPrincipal(dir, nil)
-		if err != nil {
-			return err
-		}
-		def := p.BlessingStore().Default()
-		if blessingsSharedWithAll := p.BlessingStore().ForPeer("random_peer"); !reflect.DeepEqual(blessingsSharedWithAll, def) {
-			return fmt.Errorf("Blessing shared with all peers: %v is different from default Blessings: %v", blessingsSharedWithAll, def)
-		}
-		if got := def.ForContext(security.NewContext(&security.ContextParams{LocalPrincipal: p})); len(got) != 1 || got[0] != wantBlessing {
-			return fmt.Errorf("got blessings: %v, want exactly one blessing: %v", got, wantBlessing)
-		}
-		return nil
-	}
-
-	// Test child credentials when runtime is not initialized and VeyronCredentials
-	// is not set.
-	sh, err := modules.NewShell(nil)
-	if err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "test-shell/child"); err != nil {
-		t.Fatal(err)
-	}
-
-	// Test that no two children have the same credentials directory.
-	if cred1, cred2 := startChildAndGetCredentials(sh, nil), startChildAndGetCredentials(sh, nil); cred1 == cred2 {
-		t.Fatalf("The same credentials directory %v was set for two children", cred1)
-	}
-	sh.Cleanup(nil, nil)
-
-	// Test child credentials when VeyronCredentials are set.
-	old := os.Getenv(consts.VeyronCredentials)
-	defer os.Setenv(consts.VeyronCredentials, old)
-	dir, _ := tsecurity.NewCredentials("os")
-	defer os.RemoveAll(dir)
-	if err := os.Setenv(consts.VeyronCredentials, dir); err != nil {
-		t.Fatal(err)
-	}
-	sh, err = modules.NewShell(nil)
-	if err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "os/child"); err != nil {
-		t.Fatal(err)
-	}
-	sh.Cleanup(nil, nil)
-
-	// Test that os VeyronCredentials are not deleted by the Cleanup.
-	if finfo, err := os.Stat(dir); err != nil || !finfo.IsDir() {
-		t.Fatalf("%q is not a directory", dir)
-	}
-
-	// Test that VeyronCredentials specified on the shell override the OS ones.
-	dir, _ = tsecurity.NewCredentials("shell")
-	defer os.RemoveAll(dir)
-	sh, err = modules.NewShell(nil)
-	if err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-	sh.SetVar(consts.VeyronCredentials, dir)
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "shell/child"); err != nil {
-		t.Fatal(err)
-	}
-	sh.ClearVar(consts.VeyronCredentials)
-	if credentials := startChildAndGetCredentials(sh, nil); len(credentials) != 0 {
-		t.Fatalf("found credentials %v set for child even when shell credentials were cleared", credentials)
-	}
-	anotherDir, _ := tsecurity.NewCredentials("anotherShell")
-	defer os.RemoveAll(anotherDir)
-	sh.SetVar(consts.VeyronCredentials, anotherDir)
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "anotherShell/child"); err != nil {
-		t.Fatal(err)
-	}
-	sh.Cleanup(nil, nil)
-
-	// Test that VeyronCredentials specified as a parameter overrides the OS and
-	// shell ones.
-	dir, _ = tsecurity.NewCredentials("param")
-	defer os.RemoveAll(dir)
-	env := []string{consts.VeyronCredentials + "=" + dir}
-	if err := validateCredentials(startChildAndGetCredentials(sh, env), "param"); err != nil {
-		t.Fatal(err)
-	}
-
 }
 
 func TestEnvMerge(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index 0c6a5eb..ecaefde 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -29,20 +29,10 @@
 // In particular stdin, stdout and stderr are provided as parameters, as is
 // a map representation of the shell's environment.
 //
-// Every Shell created by NewShell is initialized with its VeyronCredentials
-// environment variable set. The variable is set to the os's VeyronCredentials
-// if that is set, otherwise to a freshly created credentials directory. The
-// shell's VeyronCredentials can be set and cleared using the SetVar and
-// ClearVar methods respectively.
-//
-// By default, the VeyronCredentials for each command Start-ed by the shell are
-// set to a freshly created credentials directory that is blessed by the shell's
-// credentials (i.e., if shell's credentials have not been cleared). Thus, each
-// child of the shell gets its own credentials directory with a blessing from the
-// shell of the form
-//   <shell's default blessing>/child
-// These default credentials provided by the shell to each command can be
-// overridden by specifying VeyronCredentials in the environment provided as a
+// By default, every Shell created by NewShell starts a security agent
+// to manage principals for child processes.  These default
+// credentials can be overridden by passing a nil context to NewShell
+// then specifying VeyronCredentials in the environment provided as a
 // parameter to the Start method.
 package modules
 
@@ -53,13 +43,17 @@
 	"math/rand"
 	"os"
 	"sync"
+	"syscall"
 	"time"
 
 	"v.io/core/veyron2/security"
 
 	"v.io/core/veyron/lib/exec"
 	"v.io/core/veyron/lib/flags/consts"
-	vsecurity "v.io/core/veyron/security"
+	"v.io/core/veyron/security/agent"
+	"v.io/core/veyron/security/agent/keymgr"
+	"v.io/core/veyron2"
+	"v.io/core/veyron2/context"
 )
 
 const (
@@ -72,38 +66,55 @@
 	mu      sync.Mutex
 	env     map[string]string
 	handles map[Handle]struct{}
-	// tmpCredDirs are the temporary directories created by this
-	// shell. These must be removed when the shell is cleaned up.
-	tempCredDirs              []string
+	// tmpCredDir is the temporary directory created by this
+	// shell. This must be removed when the shell is cleaned up.
+	tempCredDir               string
 	startTimeout, waitTimeout time.Duration
 	config                    exec.Config
 	principal                 security.Principal
 	blessing                  security.Blessings
+	agent                     *keymgr.Agent
+	ctx                       *context.T
+	cancelCtx                 func()
 }
 
-// NewShell creates a new instance of Shell. It will also add a blessing
-// to the supplied principal and ensure that any child processes are
-// created with principals that are in turn blessed with it. A typical
-// use case is to pass in the runtime's principal and hence allow the
-// process hosting the shell to interact with its children and vice
-// versa. If a nil principal is passed in then NewShell will create a new
-// principal that shares a blessing with all of its children, in this mode,
-// any child processes can interact with each other but not with the parent.
-func NewShell(p security.Principal) (*Shell, error) {
+// NewShell creates a new instance of Shell.
+// If ctx is non-nil, the shell will manage Principals for child processes.
+// By default it adds a blessing to ctx's principal to ensure isolation. Any child processes
+// are created with principals derived from this new blessing.
+// However, if p is non-nil the shell will skip the new blessing and child processes
+// will have their principals derived from p's default blessing(s).
+func NewShell(ctx *context.T, p security.Principal) (*Shell, error) {
 	sh := &Shell{
 		env:          make(map[string]string),
 		handles:      make(map[Handle]struct{}),
 		startTimeout: time.Minute,
 		waitTimeout:  10 * time.Second,
 		config:       exec.NewConfig(),
-		principal:    p,
 	}
-	if p == nil {
-		if err := sh.initShellCredentials(); err != nil {
-			return nil, err
-		}
+	if ctx == nil {
 		return sh, nil
 	}
+	var err error
+	ctx, sh.cancelCtx = context.WithCancel(ctx)
+	if ctx, _, err = veyron2.SetNewStreamManager(ctx); err != nil {
+		return nil, err
+	}
+	sh.ctx = ctx
+
+	if sh.tempCredDir, err = ioutil.TempDir("", "shell_credentials"); err != nil {
+		return nil, err
+	}
+	if sh.agent, err = keymgr.NewLocalAgent(ctx, sh.tempCredDir, nil); err != nil {
+		return nil, err
+	}
+	if p != nil {
+		sh.principal = p
+		sh.blessing = p.BlessingStore().Default()
+		return sh, nil
+	}
+	p = veyron2.GetPrincipal(ctx)
+	sh.principal = p
 	gen := rand.New(rand.NewSource(time.Now().UnixNano()))
 	// Use a unique blessing tree per shell.
 	blessingName := fmt.Sprintf("%s-%d", shellBlessingExtension, gen.Int63())
@@ -124,60 +135,42 @@
 	return sh, nil
 }
 
-func (sh *Shell) initShellCredentials() error {
-	sh.mu.Lock()
-	defer sh.mu.Unlock()
-	if dir := os.Getenv(consts.VeyronCredentials); len(dir) != 0 {
-		sh.env[consts.VeyronCredentials] = dir
-		return nil
+func (sh *Shell) getChildCredentials() (*os.File, error) {
+	if sh.ctx == nil {
+		return nil, nil
 	}
-
-	dir, err := ioutil.TempDir("", "shell_credentials")
-	if err != nil {
-		return err
-	}
-	sh.env[consts.VeyronCredentials] = dir
-	sh.tempCredDirs = append(sh.tempCredDirs, dir)
-	return nil
-}
-
-func (sh *Shell) getChildCredentials(shellCredDir string) (string, error) {
 	root := sh.principal
 	rootBlessing := sh.blessing
-	if root == nil {
-		r, err := principalFromDir(shellCredDir)
-		if err != nil {
-			return "", err
-		}
-		root = r
-		rootBlessing = root.BlessingStore().Default()
-	}
-
-	dir, err := ioutil.TempDir("", "shell_child_credentials")
+	_, conn, err := sh.agent.NewPrincipal(sh.ctx, true)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
-	sh.tempCredDirs = append(sh.tempCredDirs, dir)
-	// Create a principal and default blessing for the child that is
-	// derived from the blessing created for this shell. This can
-	// be used by the parent to invoke RPCs on any children and for the
-	// children to invoke RPCs on each other.
-	p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
+	ctx, cancel := context.WithCancel(sh.ctx)
+	if ctx, _, err = veyron2.SetNewStreamManager(ctx); err != nil {
+		return nil, err
+	}
+	defer cancel()
+	fd, err := syscall.Dup(int(conn.Fd()))
 	if err != nil {
-		return "", err
+		return nil, err
+	}
+	syscall.CloseOnExec(fd)
+	p, err := agent.NewAgentPrincipal(ctx, fd)
+	if err != nil {
+		return nil, err
 	}
 	blessingForChild, err := root.Bless(p.PublicKey(), rootBlessing, childBlessingExtension, security.UnconstrainedUse())
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 	if err := p.BlessingStore().SetDefault(blessingForChild); err != nil {
-		return "", err
+		return nil, err
 	}
 	if _, err := p.BlessingStore().Set(blessingForChild, security.AllPrincipals); err != nil {
-		return "", err
+		return nil, err
 	}
 	if err := p.AddToRoots(blessingForChild); err != nil {
-		return "", err
+		return nil, err
 	}
 
 	if sh.blessing != nil {
@@ -185,7 +178,7 @@
 		// by the parent, should the child choose to invoke RPCs on the parent.
 		blessingFromChild, err := root.Bless(p.PublicKey(), root.BlessingStore().Default(), childBlessingExtension, security.UnconstrainedUse())
 		if err != nil {
-			return "", err
+			return nil, err
 		}
 		// We store this blessing as the one to use with a pattern that matches
 		// the root's name.
@@ -194,14 +187,14 @@
 		ctx := security.NewContext(&security.ContextParams{LocalPrincipal: root})
 		rootName := root.BlessingStore().Default().ForContext(ctx)[0]
 		if _, err := p.BlessingStore().Set(blessingFromChild, security.BlessingPattern(rootName)); err != nil {
-			return "", err
+			return nil, err
 		}
 
 		if err := p.AddToRoots(blessingFromChild); err != nil {
-			return "", err
+			return nil, err
 		}
 	}
-	return dir, nil
+	return conn, nil
 }
 
 type Main func(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error
@@ -244,12 +237,16 @@
 	if err != nil {
 		return nil, err
 	}
+	p, err := sh.getChildCredentials()
+	if err != nil {
+		return nil, err
+	}
 	cmd := registry.getCommand(name)
 	if cmd == nil {
 		return nil, fmt.Errorf("%s: not registered", name)
 	}
 	expanded := append([]string{name}, sh.expand(args...)...)
-	h, err := cmd.factory().start(sh, cenv, expanded...)
+	h, err := cmd.factory().start(sh, p, cenv, expanded...)
 	if err != nil {
 		// If the error is a timeout, then h can be used to recover
 		// any output from the process.
@@ -399,18 +396,14 @@
 		}
 	}
 
-	// TODO(ataly, ashankar, caprita): The following code may lead to
-	// removing the credential directories for child processes that are
-	// still alive (this can happen e.g. if the Wait on the child timed
-	// out). While we can hope that some error will reach the caller of
-	// Cleanup (because we harvest the error codes from Shutdown), it may
-	// lead to failures that are harder to debug because the original issue
-	// will get masked by the credentials going away. One possibility is
-	// to only remove the credentials dir when Shutdown returns no timeout
-	// error.
-	for _, dir := range sh.tempCredDirs {
-		os.RemoveAll(dir)
+	if sh.cancelCtx != nil {
+		// Note(ribrdb, caprita): This will shutdown the agents.  If there
+		// were errors shutting down it is possible there could be child
+		// processes still running, and stopping the agent may cause
+		// additional failures.
+		sh.cancelCtx()
 	}
+	os.RemoveAll(sh.tempCredDir)
 	return err
 }
 
@@ -425,15 +418,7 @@
 	// want the child to directly use the directory specified
 	// by the shell's VeyronCredentials.
 	delete(m1, consts.VeyronCredentials)
-
-	// Set the VeyronCredentials environment variable for the child
-	// if it is not already set and the shell's VeyronCredentials are set.
-	if len(evmap[consts.VeyronCredentials]) == 0 && (len(sh.env[consts.VeyronCredentials]) != 0 || sh.principal != nil) {
-		var err error
-		if evmap[consts.VeyronCredentials], err = sh.getChildCredentials(sh.env[consts.VeyronCredentials]); err != nil {
-			return nil, err
-		}
-	}
+	delete(m1, agent.FdVarName)
 
 	m2 := mergeMaps(m1, evmap)
 	r := []string{}
@@ -477,5 +462,5 @@
 // commands.
 type command interface {
 	envelope(sh *Shell, env []string, args ...string) ([]string, []string)
-	start(sh *Shell, env []string, args ...string) (Handle, error)
+	start(sh *Shell, agent *os.File, env []string, args ...string) (Handle, error)
 }
diff --git a/lib/signals/signals_test.go b/lib/signals/signals_test.go
index b5ea0bc..21d3430 100644
--- a/lib/signals/signals_test.go
+++ b/lib/signals/signals_test.go
@@ -20,10 +20,8 @@
 	"v.io/core/veyron2/services/mgmt/appcycle"
 
 	"v.io/core/veyron/lib/expect"
-	"v.io/core/veyron/lib/flags/consts"
 	"v.io/core/veyron/lib/modules"
 	"v.io/core/veyron/lib/testutil"
-	"v.io/core/veyron/lib/testutil/security"
 	"v.io/core/veyron/profiles"
 	vflag "v.io/core/veyron/security/flag"
 	"v.io/core/veyron/services/mgmt/device"
@@ -125,8 +123,8 @@
 	}
 }
 
-func newShell(t *testing.T, command string) (*modules.Shell, modules.Handle, *expect.Session) {
-	sh, err := modules.NewShell(nil)
+func newShell(t *testing.T, r veyron2.Runtime, command string) (*modules.Shell, modules.Handle, *expect.Session) {
+	sh, err := modules.NewShell(r.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -143,7 +141,12 @@
 // TestCleanShutdownSignal verifies that sending a signal to a child that
 // handles it by default causes the child to shut down cleanly.
 func TestCleanShutdownSignal(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaults")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaults")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	checkSignalIsDefault(t, syscall.SIGINT)
@@ -156,7 +159,12 @@
 // TestCleanShutdownStop verifies that sending a stop comamnd to a child that
 // handles stop commands by default causes the child to shut down cleanly.
 func TestCleanShutdownStop(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaults")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaults")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	fmt.Fprintf(h.Stdin(), "stop\n")
@@ -170,7 +178,12 @@
 // that handles stop command as part of a custom set of signals handled, causes
 // the child to shut down cleanly.
 func TestCleanShutdownStopCustom(t *testing.T) {
-	sh, h, s := newShell(t, "handleCustomWithStop")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleCustomWithStop")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	fmt.Fprintf(h.Stdin(), "stop\n")
@@ -191,7 +204,12 @@
 // TestStopNoHandler verifies that sending a stop command to a child that does
 // not handle stop commands causes the child to exit immediately.
 func TestStopNoHandler(t *testing.T) {
-	sh, h, s := newShell(t, "handleCustom")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleCustom")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	fmt.Fprintf(h.Stdin(), "stop\n")
@@ -202,7 +220,12 @@
 // that handles these signals by default causes the child to exit immediately
 // upon receiving the second signal.
 func TestDoubleSignal(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaults")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaults")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	checkSignalIsDefault(t, syscall.SIGTERM)
@@ -217,7 +240,12 @@
 // to a child that handles these by default causes the child to exit immediately
 // upon receiving the stop command.
 func TestSignalAndStop(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaults")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaults")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	checkSignalIsDefault(t, syscall.SIGTERM)
@@ -231,7 +259,12 @@
 // that handles stop commands by default causes the child to exit immediately
 // upon receiving the second stop command.
 func TestDoubleStop(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaults")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaults")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	fmt.Fprintf(h.Stdin(), "stop\n")
@@ -243,7 +276,12 @@
 // TestSendUnhandledSignal verifies that sending a signal that the child does
 // not handle causes the child to exit as per the signal being sent.
 func TestSendUnhandledSignal(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaults")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaults")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	checkSignalIsNotDefault(t, syscall.SIGABRT)
@@ -256,7 +294,12 @@
 // process to exit (ensures that there is no dependency in ShutdownOnSignals
 // on having a goroutine read from the returned channel).
 func TestDoubleSignalIgnoreChan(t *testing.T) {
-	sh, h, s := newShell(t, "handleDefaultsIgnoreChan")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleDefaultsIgnoreChan")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	// Even if we ignore the channel that ShutdownOnSignals returns,
@@ -271,7 +314,12 @@
 // TestHandlerCustomSignal verifies that sending a non-default signal to a
 // server that listens for that signal causes the server to shut down cleanly.
 func TestHandlerCustomSignal(t *testing.T) {
-	sh, h, s := newShell(t, "handleCustom")
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
+	sh, h, s := newShell(t, runtime, "handleCustom")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 	s.Expect("ready")
 	checkSignalIsNotDefault(t, syscall.SIGABRT)
@@ -285,8 +333,13 @@
 // to a server that listens for that signal causes the server to shut down
 // cleanly, even when a STOP signal is also among the handled signals.
 func TestHandlerCustomSignalWithStop(t *testing.T) {
+	runtime, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	defer runtime.Cleanup()
 	for _, signal := range []syscall.Signal{syscall.SIGABRT, syscall.SIGHUP} {
-		sh, h, s := newShell(t, "handleCustomWithStop")
+		sh, h, s := newShell(t, runtime, "handleCustomWithStop")
 		s.Expect("ready")
 		checkSignalIsNotDefault(t, signal)
 		syscall.Kill(h.Pid(), signal)
@@ -349,20 +402,14 @@
 	defer runtime.Cleanup()
 	ctx := runtime.NewContext()
 
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(runtime.NewContext(), nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 
-	// Set the child process up with a blessing from the parent so that
-	// the default authorization works for RPCs between the two.
-	principal := veyron2.GetPrincipal(ctx)
-	childcreds, _ := security.ForkCredentials(principal, "child")
-	defer os.RemoveAll(childcreds)
 	configServer, configServiceName, ch := createConfigServer(t, ctx)
 	defer configServer.Stop()
-	sh.SetVar(consts.VeyronCredentials, childcreds)
 	sh.SetConfigKey(mgmt.ParentNameConfigKey, configServiceName)
 	sh.SetConfigKey(mgmt.ProtocolConfigKey, "tcp")
 	sh.SetConfigKey(mgmt.AddressConfigKey, "127.0.0.1:0")
diff --git a/lib/testutil/integration/util.go b/lib/testutil/integration/util.go
index 0255ab3..531cec3 100644
--- a/lib/testutil/integration/util.go
+++ b/lib/testutil/integration/util.go
@@ -20,6 +20,8 @@
 	"v.io/core/veyron/lib/modules"
 	"v.io/core/veyron/lib/modules/core"
 	tsecurity "v.io/core/veyron/lib/testutil/security"
+	"v.io/core/veyron2/options"
+	"v.io/core/veyron2/rt"
 	"v.io/core/veyron2/security"
 )
 
@@ -364,7 +366,11 @@
 func NewTestEnvironment(t *testing.T) TestEnvironment {
 	t.Log("creating root principal")
 	principal := tsecurity.NewPrincipal("root")
-	shell, err := modules.NewShell(principal)
+	runtime, err := rt.New(options.RuntimePrincipal{principal})
+	if err != nil {
+		t.Fatalf("rt.New() failed: %v", err)
+	}
+	shell, err := modules.NewShell(runtime.NewContext(), principal)
 	if err != nil {
 		t.Fatalf("NewShell() failed: %v", err)
 	}
diff --git a/runtimes/google/ipc/client_test.go b/runtimes/google/ipc/client_test.go
index ace8a6d..a124355 100644
--- a/runtimes/google/ipc/client_test.go
+++ b/runtimes/google/ipc/client_test.go
@@ -6,12 +6,14 @@
 	"os"
 	"path/filepath"
 	"runtime"
+	"strings"
 	"testing"
 	"time"
 
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/naming"
+	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/rt"
 	verror "v.io/core/veyron2/verror2"
 	"v.io/core/veyron2/vlog"
@@ -20,7 +22,9 @@
 	"v.io/core/veyron/lib/flags/consts"
 	"v.io/core/veyron/lib/modules"
 	"v.io/core/veyron/lib/modules/core"
+	tsecurity "v.io/core/veyron/lib/testutil/security"
 	"v.io/core/veyron/profiles"
+	inaming "v.io/core/veyron/runtimes/google/naming"
 )
 
 var r veyron2.Runtime
@@ -42,8 +46,7 @@
 }
 
 func runMountTable(t *testing.T, ctx *context.T) (*modules.Shell, func()) {
-	principal := veyron2.GetPrincipal(ctx)
-	sh, err := modules.NewShell(principal)
+	sh, err := modules.NewShell(ctx, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -56,13 +59,6 @@
 	rootSession := expect.NewSession(t, root.Stdout(), time.Minute)
 	rootSession.ExpectVar("PID")
 	rootName := rootSession.ExpectVar("MT_NAME")
-	if t.Failed() {
-		t.Fatalf("%s", rootSession.Error())
-	}
-	sh.SetVar(consts.NamespaceRootPrefix, rootName)
-	if err = veyron2.GetNamespace(ctx).SetRoots(rootName); err != nil {
-		t.Fatalf("unexpected error setting namespace roots: %s", err)
-	}
 
 	deferFn := func() {
 		if testing.Verbose() {
@@ -75,6 +71,16 @@
 			root.Shutdown(nil, nil)
 		}
 	}
+
+	if t.Failed() {
+		deferFn()
+		t.Fatalf("%s", rootSession.Error())
+	}
+	sh.SetVar(consts.NamespaceRootPrefix, rootName)
+	if err = veyron2.GetNamespace(ctx).SetRoots(rootName); err != nil {
+		t.Fatalf("unexpected error setting namespace roots: %s", err)
+	}
+
 	return sh, deferFn
 }
 
@@ -451,5 +457,71 @@
 	testForVerror(t, verr, verror.NoServers)
 }
 
+// TestReconnect verifies that the client transparently re-establishes the
+// connection to the server if the server dies and comes back (on the same
+// endpoint).
+func TestReconnect(t *testing.T) {
+	principal := tsecurity.NewPrincipal("client")
+	r, err := rt.New(options.RuntimePrincipal{principal})
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	sh, err := modules.NewShell(r.NewContext(), principal)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	defer sh.Cleanup(os.Stderr, os.Stderr)
+	server, err := sh.Start(core.EchoServerCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0", "mymessage", "")
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	session := expect.NewSession(t, server.Stdout(), time.Minute)
+	session.ReadLine()
+	serverName := session.ExpectVar("NAME")
+	serverEP, _ := naming.SplitAddressName(serverName)
+	ep, _ := inaming.NewEndpoint(serverEP)
+	makeCall := func() (string, error) {
+		ctx, _ := context.WithDeadline(r.NewContext(), time.Now().Add(10*time.Second))
+		call, err := veyron2.GetClient(ctx).StartCall(ctx, serverName, "Echo", []interface{}{"bratman"})
+		if err != nil {
+			return "", fmt.Errorf("START: %s", err)
+		}
+		var result string
+		var rerr error
+		if err = call.Finish(&result, &rerr); err != nil {
+			return "", err
+		}
+		return result, nil
+	}
+	expected := "mymessage: bratman\n"
+	if result, err := makeCall(); err != nil || result != expected {
+		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
+	}
+	// Kill the server, verify client can't talk to it anymore.
+	sh.SetWaitTimeout(time.Minute)
+	if err := server.Shutdown(os.Stderr, os.Stderr); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+
+	if _, err := makeCall(); err == nil || (!strings.HasPrefix(err.Error(), "START") && !strings.Contains(err.Error(), "EOF")) {
+		t.Fatalf(`Got (%v) want ("START: <err>" or "EOF") as server is down`, err)
+	}
+
+	// Resurrect the server with the same address, verify client
+	// re-establishes the connection. This is racy if another
+	// process grabs the port.
+	server, err = sh.Start(core.EchoServerCommand, nil, "--", "--veyron.tcp.address="+ep.Address, "mymessage again", "")
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	session = expect.NewSession(t, server.Stdout(), time.Minute)
+	defer server.Shutdown(os.Stderr, os.Stderr)
+	expected = "mymessage again: bratman\n"
+	if result, err := makeCall(); err != nil || result != expected {
+		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
+	}
+
+}
+
 // TODO(cnicolaou:) tests for:
 // -- Test for bad discharges error and correct invalidation, client.go:870..880
diff --git a/runtimes/google/ipc/resolve_test.go b/runtimes/google/ipc/resolve_test.go
index 3b3c2cd..ab64566 100644
--- a/runtimes/google/ipc/resolve_test.go
+++ b/runtimes/google/ipc/resolve_test.go
@@ -27,7 +27,7 @@
 }
 
 func TestResolveToEndpoint(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("modules.NewShell failed: %s", err)
 	}
diff --git a/runtimes/google/ipc/server_test.go b/runtimes/google/ipc/server_test.go
index 9a2975c..1f362be 100644
--- a/runtimes/google/ipc/server_test.go
+++ b/runtimes/google/ipc/server_test.go
@@ -83,70 +83,6 @@
 	}
 }
 
-// TestReconnect verifies that the client transparently re-establishes the
-// connection to the server if the server dies and comes back (on the same
-// endpoint).
-func TestReconnect(t *testing.T) {
-	principal := tsecurity.NewPrincipal("client")
-	b := createBundle(t, principal, nil, nil) // We only need the client from the bundle.
-	defer b.cleanup(t)
-	sh, err := modules.NewShell(principal)
-	if err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-	defer sh.Cleanup(os.Stderr, os.Stderr)
-	server, err := sh.Start(core.EchoServerCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0", "mymessage", "")
-	if err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-	session := expect.NewSession(t, server.Stdout(), time.Minute)
-	session.ReadLine()
-	serverName := session.ExpectVar("NAME")
-	serverEP, _ := naming.SplitAddressName(serverName)
-	ep, _ := inaming.NewEndpoint(serverEP)
-	makeCall := func() (string, error) {
-		ctx, _ := context.WithDeadline(testContext(), time.Now().Add(10*time.Second))
-		call, err := b.client.StartCall(ctx, serverName, "Echo", []interface{}{"bratman"})
-		if err != nil {
-			return "", fmt.Errorf("START: %s", err)
-		}
-		var result string
-		var rerr error
-		if err = call.Finish(&result, &rerr); err != nil {
-			return "", err
-		}
-		return result, nil
-	}
-	expected := "mymessage: bratman\n"
-	if result, err := makeCall(); err != nil || result != expected {
-		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
-	}
-	// Kill the server, verify client can't talk to it anymore.
-	sh.SetWaitTimeout(time.Minute)
-	if err := server.Shutdown(os.Stderr, os.Stderr); err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-
-	if _, err := makeCall(); err == nil || (!strings.HasPrefix(err.Error(), "START") && !strings.Contains(err.Error(), "EOF")) {
-		t.Fatalf(`Got (%v) want ("START: <err>" or "EOF") as server is down`, err)
-	}
-
-	// Resurrect the server with the same address, verify client
-	// re-establishes the connection. This is racy if another
-	// process grabs the port.
-	server, err = sh.Start(core.EchoServerCommand, nil, "--", "--veyron.tcp.address="+ep.Address, "mymessage again", "")
-	if err != nil {
-		t.Fatalf("unexpected error: %s", err)
-	}
-	session = expect.NewSession(t, server.Stdout(), time.Minute)
-	defer server.Shutdown(os.Stderr, os.Stderr)
-	expected = "mymessage again: bratman\n"
-	if result, err := makeCall(); err != nil || result != expected {
-		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
-	}
-
-}
-
 type proxyHandle struct {
 	ns    naming.Namespace
 	sh    *modules.Shell
@@ -155,7 +91,7 @@
 }
 
 func (h *proxyHandle) Start(t *testing.T, args ...string) error {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/runtimes/google/ipc/stream/manager/manager_test.go b/runtimes/google/ipc/stream/manager/manager_test.go
index ada68cf..e1fb7b4 100644
--- a/runtimes/google/ipc/stream/manager/manager_test.go
+++ b/runtimes/google/ipc/stream/manager/manager_test.go
@@ -508,7 +508,7 @@
 
 func testServerRestartDuringClientLifetime(t *testing.T, protocol string) {
 	client := InternalNew(naming.FixedRoutingID(0xcccccccc))
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index d735fe3..6062899 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -18,10 +18,8 @@
 	"v.io/core/veyron2/services/mgmt/appcycle"
 
 	"v.io/core/veyron/lib/expect"
-	"v.io/core/veyron/lib/flags/consts"
 	"v.io/core/veyron/lib/modules"
 	"v.io/core/veyron/lib/testutil"
-	"v.io/core/veyron/lib/testutil/security"
 	"v.io/core/veyron/profiles"
 	"v.io/core/veyron/runtimes/google/rt"
 	vflag "v.io/core/veyron/security/flag"
@@ -121,7 +119,7 @@
 // TestNoWaiters verifies that the child process exits in the absence of any
 // wait channel being registered with its runtime.
 func TestNoWaiters(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -152,7 +150,7 @@
 // TestForceStop verifies that ForceStop causes the child process to exit
 // immediately.
 func TestForceStop(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -305,14 +303,11 @@
 	r, _ := rt.New(profileOpt)
 	ctx := r.NewContext()
 
-	p := veyron2.GetPrincipal(ctx)
-	childcreds, _ := security.ForkCredentials(p, appCmd)
 	configServer, configServiceName, ch := createConfigServer(t, ctx)
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(ctx, veyron2.GetPrincipal(ctx))
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	sh.SetVar(consts.VeyronCredentials, childcreds)
 	sh.SetConfigKey(mgmt.ParentNameConfigKey, configServiceName)
 	sh.SetConfigKey(mgmt.ProtocolConfigKey, "tcp")
 	sh.SetConfigKey(mgmt.AddressConfigKey, "127.0.0.1:0")
@@ -330,7 +325,6 @@
 	return ctx, h, appCycle, func() {
 		configServer.Stop()
 		sh.Cleanup(os.Stderr, os.Stderr)
-		os.RemoveAll(childcreds)
 		// Don't do r.Cleanup() since the runtime needs to be used by
 		// more than one test case.
 	}
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index f6ae79d..0d1c7a0 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -70,7 +70,7 @@
 }
 
 func TestInitArgs(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -146,7 +146,7 @@
 		return err
 	}
 	fmt.Fprintf(stdout, "RUNNER_DEFAULT_BLESSING=%v\n", defaultBlessing(p))
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(ctx, p)
 	if err != nil {
 		return err
 	}
@@ -169,7 +169,7 @@
 }
 
 func TestPrincipalInheritance(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -232,7 +232,7 @@
 		t.Fatal(err)
 	}
 
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index f8df35c..5f6a14d 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -2,6 +2,7 @@
 
 import (
 	"os"
+	"syscall"
 
 	"v.io/core/veyron2/security"
 
@@ -60,5 +61,15 @@
 }
 
 func (rt *vrt) connectToAgent(fd int) (security.Principal, error) {
-	return agent.NewAgentPrincipal(rt.NewContext(), fd)
+	// Dup the fd, so we can create multiple runtimes.
+	syscall.ForkLock.Lock()
+	newfd, err := syscall.Dup(fd)
+	if err == nil {
+		syscall.CloseOnExec(newfd)
+	}
+	syscall.ForkLock.Unlock()
+	if err != nil {
+		return nil, err
+	}
+	return agent.NewAgentPrincipal(rt.NewContext(), newfd)
 }
diff --git a/runtimes/google/rt/securityx.go b/runtimes/google/rt/securityx.go
index 8ebb15d..0c8ca3f 100644
--- a/runtimes/google/rt/securityx.go
+++ b/runtimes/google/rt/securityx.go
@@ -5,6 +5,7 @@
 	"os"
 	"os/user"
 	"strconv"
+	"syscall"
 
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/mgmt"
@@ -75,7 +76,12 @@
 	if fd == "" {
 		return -1, nil
 	}
-	return strconv.Atoi(fd)
+	ifd, err := strconv.Atoi(fd)
+	if err == nil && handle != nil {
+		// If we're using a handle, children can't inherit the agent.
+		syscall.CloseOnExec(ifd)
+	}
+	return ifd, err
 }
 
 func defaultBlessingName() string {
diff --git a/runtimes/google/rt/shutdown_test.go b/runtimes/google/rt/shutdown_test.go
index b29baa6..8c7c20a 100644
--- a/runtimes/google/rt/shutdown_test.go
+++ b/runtimes/google/rt/shutdown_test.go
@@ -26,7 +26,7 @@
 }
 
 func newShell(t *testing.T) *modules.Shell {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/runtimes/google/rt/signal_test.go b/runtimes/google/rt/signal_test.go
index aeb249b..d9b296d 100644
--- a/runtimes/google/rt/signal_test.go
+++ b/runtimes/google/rt/signal_test.go
@@ -77,7 +77,7 @@
 }
 
 func TestWithRuntime(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -97,7 +97,7 @@
 }
 
 func TestWithoutRuntime(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/security/agent/client.go b/security/agent/client.go
index d2574dc..496c08d 100644
--- a/security/agent/client.go
+++ b/security/agent/client.go
@@ -77,7 +77,6 @@
 		name:   naming.JoinAddressName(naming.FormatEndpoint(addr.Network(), addr.String()), ""),
 		ctx:    ctx,
 	}
-
 	agent := &client{caller: caller}
 	if err := agent.fetchPublicKey(); err != nil {
 		return nil, err
diff --git a/security/agent/keymgr/client.go b/security/agent/keymgr/client.go
index 3d0641c..65f175e 100644
--- a/security/agent/keymgr/client.go
+++ b/security/agent/keymgr/client.go
@@ -7,6 +7,7 @@
 	"os"
 	"strconv"
 	"sync"
+	"syscall"
 
 	"v.io/core/veyron/lib/unixfd"
 	"v.io/core/veyron/security/agent/server"
@@ -36,6 +37,19 @@
 	return newAgent(defaultManagerSocket)
 }
 
+func NewLocalAgent(ctx *context.T, path string, passphrase []byte) (*Agent, error) {
+	file, err := server.RunKeyManager(ctx, path, passphrase)
+	if err != nil {
+		return nil, err
+	}
+	syscall.CloseOnExec(int(file.Fd()))
+	conn, err := net.FileConn(file)
+	if err != nil {
+		return nil, err
+	}
+	return &Agent{conn: conn.(*net.UnixConn)}, nil
+}
+
 func newAgent(fd int) (a *Agent, err error) {
 	file := os.NewFile(uintptr(fd), "fd")
 	defer file.Close()
diff --git a/security/agent/server/server.go b/security/agent/server/server.go
index 28569fa..808b5a5 100644
--- a/security/agent/server/server.go
+++ b/security/agent/server/server.go
@@ -192,6 +192,7 @@
 		for {
 			clientAddr, _, ack, err := unixfd.ReadConnection(conn, buf)
 			if err == io.EOF {
+				conn.Close()
 				return
 			}
 			if clientAddr != nil {
diff --git a/security/flag/flag_test.go b/security/flag/flag_test.go
index f2edf84..fbf46bc 100644
--- a/security/flag/flag_test.go
+++ b/security/flag/flag_test.go
@@ -67,7 +67,7 @@
 }
 
 func TestNewAuthorizerOrDie(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/services/mgmt/application/impl/acl_test.go b/services/mgmt/application/impl/acl_test.go
index 4f1a558..c603e34 100644
--- a/services/mgmt/application/impl/acl_test.go
+++ b/services/mgmt/application/impl/acl_test.go
@@ -92,7 +92,7 @@
 }
 
 func TestApplicationUpdateACL(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// setup mock up directory to put state in
@@ -221,7 +221,7 @@
 }
 
 func TestPerAppACL(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// setup mock up directory to put state in
@@ -357,7 +357,7 @@
 }
 
 func TestInitialACLSet(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Setup mock up directory to put state in.
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index 3abef07..d509be9 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -327,7 +327,7 @@
 // command. Further versions are started through the soft link that the device
 // manager itself updates.
 func TestDeviceManagerUpdateAndRevert(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, veyron2.GetPrincipal(globalCtx))
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
@@ -341,10 +341,8 @@
 	// convenient to put it there so we have everything in one place.
 	currLink := filepath.Join(root, "current_link")
 
-	crDir, crEnv := mgmttest.CredentialsForChild(globalCtx, "devicemanager")
-	defer os.RemoveAll(crDir)
 	dmArgs := []string{"factoryDM", root, "unused_helper", mockApplicationRepoName, currLink}
-	args, env := sh.CommandEnvelope(deviceManagerCmd, crEnv, dmArgs...)
+	args, env := sh.CommandEnvelope(deviceManagerCmd, nil, dmArgs...)
 
 	scriptPathFactory := generateDeviceManagerScript(t, root, args, env)
 
@@ -355,7 +353,7 @@
 	// We instruct the initial device manager that we run to pause before
 	// stopping its service, so that we get a chance to verify that
 	// attempting an update while another one is ongoing will fail.
-	dmPauseBeforeStopEnv := append(crEnv, "PAUSE_BEFORE_STOP=1")
+	dmPauseBeforeStopEnv := []string{"PAUSE_BEFORE_STOP=1"}
 
 	// Start the initial version of the device manager, the so-called
 	// "factory" version. We use the modules-generated command to start it.
@@ -380,7 +378,7 @@
 	// Set up a second version of the device manager. The information in the
 	// envelope will be used by the device manager to stage the next
 	// version.
-	crDir, crEnv = mgmttest.CredentialsForChild(globalCtx, "devicemanager")
+	crDir, crEnv := mgmttest.CredentialsForChild(globalCtx, "child")
 	defer os.RemoveAll(crDir)
 	*envelope = envelopeFromShell(sh, crEnv, deviceManagerCmd, application.DeviceManagerTitle, "v2DM")
 	updateDevice(t, "factoryDM")
@@ -423,7 +421,7 @@
 	}
 
 	// Create a third version of the device manager and issue an update.
-	crDir, crEnv = mgmttest.CredentialsForChild(globalCtx, "devicemanager")
+	crDir, crEnv = mgmttest.CredentialsForChild(globalCtx, "child")
 	defer os.RemoveAll(crDir)
 	*envelope = envelopeFromShell(sh, crEnv, deviceManagerCmd, application.DeviceManagerTitle, "v3DM")
 	updateDevice(t, "v2DM")
@@ -562,7 +560,7 @@
 // TestAppLifeCycle installs an app, starts it, suspends it, resumes it, and
 // then stops it.
 func TestAppLifeCycle(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
@@ -775,7 +773,7 @@
 // TestDeviceManagerClaim claims a devicemanager and tests ACL permissions on
 // its methods.
 func TestDeviceManagerClaim(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
@@ -841,7 +839,7 @@
 }
 
 func TestDeviceManagerUpdateACL(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
@@ -945,7 +943,7 @@
 // This should bring up a functioning device manager.  In the end it runs
 // Uninstall and verifies that the installation is gone.
 func TestDeviceManagerInstallation(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 	testDir, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
 	defer cleanup()
@@ -998,7 +996,7 @@
 }
 
 func TestDeviceManagerGlobAndDebug(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
@@ -1162,7 +1160,7 @@
 }
 
 func TestDeviceManagerPackages(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
@@ -1232,7 +1230,7 @@
 // TODO(rjkroege): Verify that associations persist across restarts once
 // permanent storage is added.
 func TestAccountAssociation(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
@@ -1331,7 +1329,7 @@
 }
 
 func TestAppWithSuidHelper(t *testing.T) {
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, globalCtx, nil)
 	defer deferFn()
 
 	// Set up mock application and binary repositories.
diff --git a/services/mgmt/lib/testutil/modules.go b/services/mgmt/lib/testutil/modules.go
index 307993c..b98460d 100644
--- a/services/mgmt/lib/testutil/modules.go
+++ b/services/mgmt/lib/testutil/modules.go
@@ -11,6 +11,7 @@
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/rt"
+	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/lib/expect"
@@ -18,7 +19,7 @@
 	"v.io/core/veyron/lib/modules"
 	"v.io/core/veyron/lib/modules/core"
 	"v.io/core/veyron/lib/testutil"
-	"v.io/core/veyron/lib/testutil/security"
+	tsecurity "v.io/core/veyron/lib/testutil/security"
 )
 
 const (
@@ -46,7 +47,7 @@
 
 // CredentialsForChild creates credentials for a child process.
 func CredentialsForChild(ctx *context.T, blessing string) (string, []string) {
-	creds, _ := security.ForkCredentials(veyron2.GetPrincipal(ctx), blessing)
+	creds, _ := tsecurity.ForkCredentials(veyron2.GetPrincipal(ctx), blessing)
 	return creds, []string{consts.VeyronCredentials + "=" + creds}
 }
 
@@ -60,8 +61,8 @@
 
 // CreateShellAndMountTable builds a new modules shell and its
 // associated mount table.
-func CreateShellAndMountTable(t *testing.T, ctx *context.T) (*modules.Shell, func()) {
-	sh, err := modules.NewShell(nil)
+func CreateShellAndMountTable(t *testing.T, ctx *context.T, p security.Principal) (*modules.Shell, func()) {
+	sh, err := modules.NewShell(ctx, p)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index 847d224..685f19a 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -119,7 +119,7 @@
 		return
 	}
 
-	shell, err := modules.NewShell(nil)
+	shell, err := modules.NewShell(ctx, nil)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "unexpected error: %s\n", err)
 		os.Exit(1)
diff --git a/tools/naming/simulator/driver_test.go b/tools/naming/simulator/driver_test.go
index 51bbeb7..657b46a 100644
--- a/tools/naming/simulator/driver_test.go
+++ b/tools/naming/simulator/driver_test.go
@@ -40,7 +40,7 @@
 }
 
 func TestVariables(t *testing.T) {
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(nil, nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/tools/servicerunner/main.go b/tools/servicerunner/main.go
index 25c47c9..09a8e37 100644
--- a/tools/servicerunner/main.go
+++ b/tools/servicerunner/main.go
@@ -68,16 +68,11 @@
 
 	vars := map[string]string{}
 
-	sh, err := modules.NewShell(nil)
+	sh, err := modules.NewShell(r.NewContext(), nil)
 	if err != nil {
 		panic(fmt.Sprintf("modules.NewShell: %s", err))
 	}
 	defer sh.Cleanup(os.Stderr, os.Stderr)
-	v, ok := sh.GetVar(consts.VeyronCredentials)
-	if !ok {
-		panic("modules.Shell: missing " + consts.VeyronCredentials)
-	}
-	vars[consts.VeyronCredentials] = v
 
 	h, err := sh.Start(core.RootMTCommand, nil, "--", "--veyron.tcp.protocol=ws", "--veyron.tcp.address=127.0.0.1:0")
 	panicOnError(err)
diff --git a/tools/servicerunner/servicerunner_test.go b/tools/servicerunner/servicerunner_test.go
index 9996af2..524f277 100644
--- a/tools/servicerunner/servicerunner_test.go
+++ b/tools/servicerunner/servicerunner_test.go
@@ -47,7 +47,6 @@
 	}
 	fmt.Println(vars)
 	expectedVars := []string{
-		"VEYRON_CREDENTIALS",
 		"MT_NAME",
 		"PROXY_NAME",
 		"WSPR_ADDR",