diff --git a/cmd/common.go b/cmd/common.go
index b3df7b954eba2a91261129e641bd4762bd50772e..51ffda221394e653088a771193a0b5653f4154bf 100644
--- a/cmd/common.go
+++ b/cmd/common.go
@@ -52,30 +52,25 @@ var (
 func runChecks(t check.NodeType) {
 	var summary check.Summary
 	var file string
+	var err error
+	var typeConf *viper.Viper
 
-	// Master variables
-	apiserverBin = viper.GetString("installation." + installation + ".master.bin.apiserver")
-	apiserverConf = viper.GetString("installation." + installation + ".master.conf.apiserver")
-	schedulerBin = viper.GetString("installation." + installation + ".master.bin.scheduler")
-	schedulerConf = viper.GetString("installation." + installation + ".master.conf.scheduler")
-	controllerManagerBin = viper.GetString("installation." + installation + ".master.bin.controller-manager")
-	controllerManagerConf = viper.GetString("installation." + installation + ".master.conf.controller-manager")
-	config = viper.GetString("installation." + installation + ".config")
-
-	etcdBin = viper.GetString("etcd.bin")
-	etcdConf = viper.GetString("etcd.conf")
-	flanneldBin = viper.GetString("flanneld.bin")
-	flanneldConf = viper.GetString("flanneld.conf")
-
-	// Node variables
-	kubeletBin = viper.GetString("installation." + installation + ".node.bin.kubelet")
-	kubeletConf = viper.GetString("installation." + installation + ".node.conf.kubelet")
-	proxyBin = viper.GetString("installation." + installation + ".node.bin.proxy")
-	proxyConf = viper.GetString("installation." + installation + ".node.conf.proxy")
-
-	// Federated
-	fedApiserverBin = viper.GetString("installation." + installation + ".federated.bin.apiserver")
-	fedControllerManagerBin = viper.GetString("installation." + installation + ".federated.bin.controller-manager")
+	switch t {
+	case check.MASTER:
+		file = masterFile
+		typeConf = viper.Sub("master")
+	case check.NODE:
+		file = nodeFile
+		typeConf = viper.Sub("node")
+	case check.FEDERATED:
+		file = federatedFile
+		typeConf = viper.Sub("federated")
+	}
+
+	// Get the set of exectuables we care about on this type of node
+	binmap := getBinaries(typeConf.Sub("bins"), false)
+	extrasmap := getBinaries(viper.Sub("optional"), true)
+	confmap := getConfigFiles(typeConf.Sub("confs"))
 
 	// Run kubernetes installation validation checks.
 	verifyKubeVersion(kubeMajorVersion, kubeMinorVersion)
@@ -96,26 +91,10 @@ func runChecks(t check.NodeType) {
 	}
 
 	// Variable substitutions. Replace all occurrences of variables in controls files.
-	s := multiWordReplace(string(in), "$apiserverbin", apiserverBin)
-	s = multiWordReplace(s, "$apiserverconf", apiserverConf)
-	s = multiWordReplace(s, "$schedulerbin", schedulerBin)
-	s = multiWordReplace(s, "$schedulerconf", schedulerConf)
-	s = multiWordReplace(s, "$controllermanagerbin", controllerManagerBin)
-	s = multiWordReplace(s, "$controllermanagerconf", controllerManagerConf)
-	s = multiWordReplace(s, "$config", config)
-
-	s = multiWordReplace(s, "$etcdbin", etcdBin)
-	s = multiWordReplace(s, "$etcdconf", etcdConf)
-	s = multiWordReplace(s, "$flanneldbin", flanneldBin)
-	s = multiWordReplace(s, "$flanneldconf", flanneldConf)
-
-	s = multiWordReplace(s, "$kubeletbin", kubeletBin)
-	s = multiWordReplace(s, "$kubeletconf", kubeletConf)
-	s = multiWordReplace(s, "$proxybin", proxyBin)
-	s = multiWordReplace(s, "$proxyconf", proxyConf)
-
-	s = multiWordReplace(s, "$fedapiserverbin", fedApiserverBin)
-	s = multiWordReplace(s, "$fedcontrollermanagerbin", fedControllerManagerBin)
+	s := string(in)
+	s = makeSubstitutions(s, "bin", binmap)
+	s = makeSubstitutions(s, "bin", extrasmap)
+	s = makeSubstitutions(s, "conf", confmap)
 
 	controls, err := check.NewControls(t, []byte(s))
 	if err != nil {
diff --git a/cmd/util.go b/cmd/util.go
index 0bc40beb5e734b4a6d45ddad8cb141c14990192d..686fb520b0ba09a83b796037d338a9e0c3b8a562 100644
--- a/cmd/util.go
+++ b/cmd/util.go
@@ -52,7 +52,7 @@ func exitWithError(err error) {
 
 func continueWithError(err error, msg string) string {
 	if err != nil {
-		glog.V(1).Info(err)
+		glog.V(2).Info(err)
 	}
 
 	if msg != "" {
@@ -85,12 +85,12 @@ func ps(proc string) string {
 }
 
 // getBinaries finds which of the set of candidate executables are running
-func getBinaries(v *viper.Viper) map[string]string {
+func getBinaries(v *viper.Viper, optional bool) map[string]string {
 	binmap := make(map[string]string)
 
 	for _, exeType := range v.AllKeys() {
 		bin, err := findExecutable(v.GetStringSlice(exeType))
-		if err != nil {
+		if err != nil && !optional {
 			exitWithError(fmt.Errorf("looking for %s executable but none of the candidates are running", exeType))
 		}
 
@@ -162,6 +162,8 @@ func findExecutable(candidates []string) (string, error) {
 	for _, c := range candidates {
 		if verifyBin(c) {
 			return c, nil
+		} else {
+			glog.V(1).Info(fmt.Sprintf("executable '%s' not running", c))
 		}
 	}
 
@@ -237,3 +239,13 @@ func multiWordReplace(s string, subname string, sub string) string {
 
 	return strings.Replace(s, subname, sub, -1)
 }
+
+func makeSubstitutions(s string, ext string, m map[string]string) string {
+	for k, v := range m {
+		subst := "$" + k + ext
+		glog.V(1).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
+		s = multiWordReplace(s, subst, v)
+	}
+
+	return s
+}
diff --git a/cmd/util_test.go b/cmd/util_test.go
index d5192a6f10045208ee8a8609e61c58ce3e8fa58f..35b08d5f8fbb43962659fbafbbdd5c08bcf5d25a 100644
--- a/cmd/util_test.go
+++ b/cmd/util_test.go
@@ -185,7 +185,7 @@ func TestGetBinaries(t *testing.T) {
 			for k, val := range c.config {
 				v.Set(k, val)
 			}
-			m := getBinaries(v)
+			m := getBinaries(v, false)
 			if !reflect.DeepEqual(m, c.exp) {
 				t.Fatalf("Got %v\nExpected %v", m, c.exp)
 			}
@@ -275,3 +275,23 @@ func TestGetConfigFiles(t *testing.T) {
 		})
 	}
 }
+
+func TestMakeSubsitutions(t *testing.T) {
+	cases := []struct {
+		input string
+		subst map[string]string
+		exp   string
+	}{
+		{input: "Replace $thisbin", subst: map[string]string{"this": "that"}, exp: "Replace that"},
+		{input: "Replace $thisbin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that"},
+		{input: "Replace $thisbin and $herebin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that and there"},
+	}
+	for _, c := range cases {
+		t.Run(c.input, func(t *testing.T) {
+			s := makeSubstitutions(c.input, "bin", c.subst)
+			if s != c.exp {
+				t.Fatalf("Got %s expected %s", s, c.exp)
+			}
+		})
+	}
+}