Browse code

Use deployer service account for deployments

Jordan Liggitt authored on 2015/06/04 02:56:57
Showing 18 changed files
... ...
@@ -318,7 +318,7 @@ docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/cache/ruby-20-
318 318
 docker push ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest
319 319
 echo "[INFO] Pushed ruby-20-centos7"
320 320
 
321
-echo "[INFO] Back to 'master' context with 'admin' user..."
321
+echo "[INFO] Back to 'default' project with 'admin' user..."
322 322
 osc project ${CLUSTER_ADMIN_CONTEXT}
323 323
 
324 324
 # The build requires a dockercfg secret in the builder service account in order
... ...
@@ -338,12 +338,7 @@ osc project test
338 338
 echo "[INFO] Applying STI application config"
339 339
 osc create -f "${STI_CONFIG_FILE}"
340 340
 
341
-
342
-# this needs to be done before waiting for the build because right now only cluster-admins can see build logs, because that uses proxy
343
-echo "[INFO] Back to 'master' context with 'admin' user..."
344
-osc project default
345
-
346
-# Trigger build
341
+# Wait for build which should have triggered automatically
347 342
 echo "[INFO] Starting build from ${STI_CONFIG_FILE} and streaming its logs..."
348 343
 #osc start-build -n test ruby-sample-build --follow
349 344
 wait_for_build "test"
... ...
@@ -363,6 +358,9 @@ wait_for_app "test"
363 363
 #wait_for_build "custom"
364 364
 #wait_for_app "custom"
365 365
 
366
+echo "[INFO] Back to 'default' project with 'admin' user..."
367
+osc project ${CLUSTER_ADMIN_CONTEXT}
368
+
366 369
 # ensure the router is started
367 370
 # TODO: simplify when #4702 is fixed upstream
368 371
 wait_for_command '[[ "$(osc get endpoints router --output-version=v1beta3 -t "{{ if .subsets }}{{ len .subsets }}{{ else }}0{{ end }}" || echo "0")" != "0" ]]' $((5*TIME_MIN))
... ...
@@ -36,7 +36,7 @@ func TestSubjects(t *testing.T) {
36 36
 			Verb:     "get",
37 37
 			Resource: "pods",
38 38
 		},
39
-		expectedUsers:  util.NewStringSet("Anna", "ClusterAdmin", "Ellen", "Valerie", "system:openshift-client", "system:openshift-deployer"),
39
+		expectedUsers:  util.NewStringSet("Anna", "ClusterAdmin", "Ellen", "Valerie", "system:openshift-client"),
40 40
 		expectedGroups: util.NewStringSet("RootUsers", "system:cluster-admins", "system:cluster-readers", "system:nodes"),
41 41
 	}
42 42
 	test.clusterPolicies = newDefaultClusterPolicies()
... ...
@@ -77,7 +77,6 @@ func DefaultAPIClientCAFile(certDir string) string {
77 77
 
78 78
 func DefaultAPIClientCerts(certDir string) []ClientCertInfo {
79 79
 	return []ClientCertInfo{
80
-		DefaultDeployerClientCertInfo(certDir),
81 80
 		DefaultOpenshiftLoopbackClientCertInfo(certDir),
82 81
 		DefaultClusterAdminClientCertInfo(certDir),
83 82
 		DefaultRouterClientCertInfo(certDir),
... ...
@@ -109,18 +108,6 @@ func DefaultRegistryClientCertInfo(certDir string) ClientCertInfo {
109 109
 	}
110 110
 }
111 111
 
112
-func DefaultDeployerClientCertInfo(certDir string) ClientCertInfo {
113
-	return ClientCertInfo{
114
-		CertLocation: configapi.CertInfo{
115
-			CertFile: DefaultCertFilename(certDir, "openshift-deployer"),
116
-			KeyFile:  DefaultKeyFilename(certDir, "openshift-deployer"),
117
-		},
118
-		UnqualifiedUser: "openshift-deployer",
119
-		User:            "system:openshift-deployer",
120
-		Groups:          util.NewStringSet("system:deployers"),
121
-	}
122
-}
123
-
124 112
 func DefaultOpenshiftLoopbackClientCertInfo(certDir string) ClientCertInfo {
125 113
 	return ClientCertInfo{
126 114
 		CertLocation: configapi.CertInfo{
... ...
@@ -108,7 +108,6 @@ func GetMasterFileReferences(config *MasterConfig) []*string {
108 108
 		refs = append(refs, &config.ServiceAccountConfig.PublicKeyFiles[i])
109 109
 	}
110 110
 
111
-	refs = append(refs, &config.MasterClients.DeployerKubeConfig)
112 111
 	refs = append(refs, &config.MasterClients.OpenShiftLoopbackKubeConfig)
113 112
 	refs = append(refs, &config.MasterClients.ExternalKubernetesKubeConfig)
114 113
 
... ...
@@ -224,8 +224,6 @@ type ServingInfo struct {
224 224
 }
225 225
 
226 226
 type MasterClients struct {
227
-	// DeployerKubeConfig is a .kubeconfig filename for depoyment pods to use
228
-	DeployerKubeConfig string
229 227
 	// OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master
230 228
 	OpenShiftLoopbackKubeConfig string
231 229
 	// ExternalKubernetesKubeConfig is a .kubeconfig filename for proxying to kubernetes
... ...
@@ -213,8 +213,6 @@ type ServingInfo struct {
213 213
 }
214 214
 
215 215
 type MasterClients struct {
216
-	// DeployerKubeConfig is a .kubeconfig filename for depoyment pods to use
217
-	DeployerKubeConfig string `json:"deployerKubeConfig"`
218 216
 	// OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master
219 217
 	OpenShiftLoopbackKubeConfig string `json:"openshiftLoopbackKubeConfig"`
220 218
 	// ExternalKubernetesKubeConfig is a .kubeconfig filename for proxying to kubernetes
... ...
@@ -100,7 +100,6 @@ kubernetesMasterConfig:
100 100
   servicesSubnet: ""
101 101
   staticNodeNames: null
102 102
 masterClients:
103
-  deployerKubeConfig: ""
104 103
   externalKubernetesKubeConfig: ""
105 104
   openshiftLoopbackKubeConfig: ""
106 105
 masterPublicURL: ""
... ...
@@ -113,7 +113,6 @@ func ValidateMasterConfig(config *api.MasterConfig) ValidationResults {
113 113
 		validationResults.AddErrors(fielderrors.NewFieldInvalid("kubernetesMasterConfig", config.KubernetesMasterConfig, "kubernetesMasterConfig and masterClients.externalKubernetesKubeConfig are mutually exclusive"))
114 114
 	}
115 115
 
116
-	validationResults.AddErrors(ValidateKubeConfig(config.MasterClients.DeployerKubeConfig, "deployerKubeConfig").Prefix("masterClients")...)
117 116
 	validationResults.AddErrors(ValidateKubeConfig(config.MasterClients.OpenShiftLoopbackKubeConfig, "openShiftLoopbackKubeConfig").Prefix("masterClients")...)
118 117
 
119 118
 	if len(config.MasterClients.ExternalKubernetesKubeConfig) > 0 {
... ...
@@ -125,7 +124,7 @@ func ValidateMasterConfig(config *api.MasterConfig) ValidationResults {
125 125
 		validationResults.AddErrors(ValidateOAuthConfig(config.OAuthConfig).Prefix("oauthConfig")...)
126 126
 	}
127 127
 
128
-	validationResults.AddErrors(ValidateServiceAccountConfig(config.ServiceAccountConfig, builtInKubernetes).Prefix("serviceAccountConfig")...)
128
+	validationResults.Append(ValidateServiceAccountConfig(config.ServiceAccountConfig, builtInKubernetes).Prefix("serviceAccountConfig"))
129 129
 
130 130
 	validationResults.AddErrors(ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)
131 131
 
... ...
@@ -177,47 +176,50 @@ func ValidateEtcdStorageConfig(config api.EtcdStorageConfig) fielderrors.Validat
177 177
 	return allErrs
178 178
 }
179 179
 
180
-func ValidateServiceAccountConfig(config api.ServiceAccountConfig, builtInKubernetes bool) fielderrors.ValidationErrorList {
181
-	allErrs := fielderrors.ValidationErrorList{}
180
+func ValidateServiceAccountConfig(config api.ServiceAccountConfig, builtInKubernetes bool) ValidationResults {
181
+	validationResults := ValidationResults{}
182 182
 
183 183
 	managedNames := util.NewStringSet(config.ManagedNames...)
184 184
 	if !managedNames.Has(bootstrappolicy.BuilderServiceAccountName) {
185
-		// TODO: warn that default builder service account won't be auto-created
185
+		validationResults.AddWarnings(fielderrors.NewFieldInvalid("managedNames", "", fmt.Sprintf("missing %q, which will require manual creation in each namespace before builds can run", bootstrappolicy.BuilderServiceAccountName)))
186
+	}
187
+	if !managedNames.Has(bootstrappolicy.DeployerServiceAccountName) {
188
+		validationResults.AddWarnings(fielderrors.NewFieldInvalid("managedNames", "", fmt.Sprintf("missing %q, which will require manual creation in each namespace before deployments can run", bootstrappolicy.DeployerServiceAccountName)))
186 189
 	}
187 190
 	if builtInKubernetes && !managedNames.Has(bootstrappolicy.DefaultServiceAccountName) {
188
-		// TODO: warn that default service account won't be auto-created
191
+		validationResults.AddWarnings(fielderrors.NewFieldInvalid("managedNames", "", fmt.Sprintf("missing %q, which will prevent creation of pods that do not specify a valid service account", bootstrappolicy.DefaultServiceAccountName)))
189 192
 	}
190 193
 
191 194
 	for i, name := range config.ManagedNames {
192 195
 		if ok, msg := kvalidation.ValidateServiceAccountName(name, false); !ok {
193
-			allErrs = append(allErrs, fielderrors.NewFieldInvalid(fmt.Sprintf("", i), name, msg))
196
+			validationResults.AddErrors(fielderrors.NewFieldInvalid(fmt.Sprintf("managedNames[%d]", i), name, msg))
194 197
 		}
195 198
 	}
196 199
 
197 200
 	if len(config.PrivateKeyFile) > 0 {
198 201
 		if fileErrs := ValidateFile(config.PrivateKeyFile, "privateKeyFile"); len(fileErrs) > 0 {
199
-			allErrs = append(allErrs, fileErrs...)
202
+			validationResults.AddErrors(fileErrs...)
200 203
 		} else if privateKey, err := serviceaccount.ReadPrivateKey(config.PrivateKeyFile); err != nil {
201
-			allErrs = append(allErrs, fielderrors.NewFieldInvalid("privateKeyFile", config.PrivateKeyFile, err.Error()))
204
+			validationResults.AddErrors(fielderrors.NewFieldInvalid("privateKeyFile", config.PrivateKeyFile, err.Error()))
202 205
 		} else if err := privateKey.Validate(); err != nil {
203
-			allErrs = append(allErrs, fielderrors.NewFieldInvalid("privateKeyFile", config.PrivateKeyFile, err.Error()))
206
+			validationResults.AddErrors(fielderrors.NewFieldInvalid("privateKeyFile", config.PrivateKeyFile, err.Error()))
204 207
 		}
205 208
 	} else if builtInKubernetes {
206
-		// TODO: warn that no service account tokens will be generated
209
+		validationResults.AddWarnings(fielderrors.NewFieldInvalid("privateKeyFile", "", "no service account tokens will be generated, which could prevent builds and deployments from working"))
207 210
 	}
208 211
 
209 212
 	if len(config.PublicKeyFiles) == 0 {
210
-		// TODO: warn that no service accounts will be able to authenticate
213
+		validationResults.AddWarnings(fielderrors.NewFieldInvalid("publicKeyFiles", "", "no service account tokens will be accepted by the API, which will prevent builds and deployments from working"))
211 214
 	}
212 215
 	for i, publicKeyFile := range config.PublicKeyFiles {
213 216
 		if fileErrs := ValidateFile(publicKeyFile, fmt.Sprintf("publicKeyFiles[%d]", i)); len(fileErrs) > 0 {
214
-			allErrs = append(allErrs, fileErrs...)
217
+			validationResults.AddErrors(fileErrs...)
215 218
 		} else if _, err := serviceaccount.ReadPublicKey(publicKeyFile); err != nil {
216
-			allErrs = append(allErrs, fielderrors.NewFieldInvalid(fmt.Sprintf("publicKeyFiles[%d]", i), publicKeyFile, err.Error()))
219
+			validationResults.AddErrors(fielderrors.NewFieldInvalid(fmt.Sprintf("publicKeyFiles[%d]", i), publicKeyFile, err.Error()))
217 220
 		}
218 221
 	}
219 222
 
220
-	return allErrs
223
+	return validationResults
221 224
 }
222 225
 
223 226
 func ValidateAssetConfig(config *api.AssetConfig) fielderrors.ValidationErrorList {
... ...
@@ -7,8 +7,9 @@ const (
7 7
 
8 8
 // users
9 9
 const (
10
-	DefaultServiceAccountName = "default"
11
-	BuilderServiceAccountName = "builder"
10
+	DefaultServiceAccountName  = "default"
11
+	BuilderServiceAccountName  = "builder"
12
+	DeployerServiceAccountName = "deployer"
12 13
 
13 14
 	RouterUnqualifiedUsername   = "openshift-router"
14 15
 	RegistryUnqualifiedUsername = "openshift-registry"
... ...
@@ -21,7 +22,6 @@ const (
21 21
 const (
22 22
 	UnauthenticatedUsername   = "system:anonymous"
23 23
 	InternalComponentUsername = "system:openshift-client"
24
-	DeployerUsername          = "system:openshift-deployer"
25 24
 
26 25
 	AuthenticatedGroup   = "system:authenticated"
27 26
 	UnauthenticatedGroup = "system:unauthenticated"
... ...
@@ -413,15 +413,6 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
413 413
 		},
414 414
 		{
415 415
 			ObjectMeta: kapi.ObjectMeta{
416
-				Name: DeployerRoleBindingName,
417
-			},
418
-			RoleRef: kapi.ObjectReference{
419
-				Name: DeployerRoleName,
420
-			},
421
-			Users: util.NewStringSet(DeployerUsername),
422
-		},
423
-		{
424
-			ObjectMeta: kapi.ObjectMeta{
425 416
 				Name: ClusterAdminRoleBindingName,
426 417
 			},
427 418
 			RoleRef: kapi.ObjectReference{
... ...
@@ -30,5 +30,15 @@ func GetBootstrapServiceAccountProjectRoleBindings(namespace string) []authoriza
30 30
 			},
31 31
 			Users: util.NewStringSet(serviceaccount.MakeUsername(namespace, BuilderServiceAccountName)),
32 32
 		},
33
+		{
34
+			ObjectMeta: kapi.ObjectMeta{
35
+				Name:      DeployerRoleBindingName,
36
+				Namespace: namespace,
37
+			},
38
+			RoleRef: kapi.ObjectReference{
39
+				Name: DeployerRoleName,
40
+			},
41
+			Users: util.NewStringSet(serviceaccount.MakeUsername(namespace, DeployerServiceAccountName)),
42
+		},
33 43
 	}
34 44
 }
... ...
@@ -59,7 +59,6 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
59 59
 
60 60
 	// in-order list of plug-ins that should intercept admission decisions
61 61
 	// TODO: Push node environment support to upstream in future
62
-	// TODO: JTL: update serviceaccount admission plugin to limit secrets to the ones held by the serviceaccount
63 62
 	admissionControlPluginNames := []string{"NamespaceExists", "NamespaceLifecycle", "OriginPodNodeEnvironment", "LimitRanger", "ServiceAccount", "ResourceQuota"}
64 63
 	admissionController := admission.NewFromPlugins(kubeClient, admissionControlPluginNames, "")
65 64
 
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"net"
11 11
 	"net/http"
12 12
 	"os"
13
+	"path"
13 14
 	"regexp"
14 15
 	"strings"
15 16
 	"time"
... ...
@@ -33,6 +34,7 @@ import (
33 33
 	etcdallocator "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service/allocator/etcd"
34 34
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/serviceaccount"
35 35
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
36
+	serviceaccountadmission "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/serviceaccount"
36 37
 
37 38
 	"github.com/openshift/origin/pkg/api/latest"
38 39
 	"github.com/openshift/origin/pkg/api/v1"
... ...
@@ -984,18 +986,20 @@ func (c *MasterConfig) RunDeploymentController() error {
984 984
 	if err != nil {
985 985
 		return err
986 986
 	}
987
-	// TODO eliminate these environment variables once we figure out what they do
988
-	env := []api.EnvVar{
989
-		{Name: "KUBERNETES_MASTER", Value: kclientConfig.Host},
990
-		{Name: "OPENSHIFT_MASTER", Value: kclientConfig.Host},
991
-	}
992
-	env = append(env, clientcmd.EnvVarsFromConfig(c.DeployerClientConfig())...)
987
+	// TODO eliminate these environment variables once service accounts provide a kubeconfig that includes all of this info
988
+	env := clientcmd.EnvVars(
989
+		kclientConfig.Host,
990
+		kclientConfig.CAData,
991
+		kclientConfig.Insecure,
992
+		path.Join(serviceaccountadmission.DefaultAPITokenMountPath, kapi.ServiceAccountTokenKey),
993
+	)
993 994
 
994 995
 	factory := deploycontroller.DeploymentControllerFactory{
995
-		KubeClient:    kclient,
996
-		Codec:         latest.Codec,
997
-		Environment:   env,
998
-		DeployerImage: c.ImageFor("deployer"),
996
+		KubeClient:     kclient,
997
+		Codec:          latest.Codec,
998
+		Environment:    env,
999
+		DeployerImage:  c.ImageFor("deployer"),
1000
+		ServiceAccount: bootstrappolicy.DeployerServiceAccountName,
999 1001
 	}
1000 1002
 
1001 1003
 	controller := factory.Create()
... ...
@@ -87,8 +87,6 @@ type MasterConfig struct {
87 87
 	// PrivilegedLoopbackClientConfig is the client configuration used to call OpenShift APIs from system components
88 88
 	// To apply different access control to a system component, create a client config specifically for that component.
89 89
 	PrivilegedLoopbackClientConfig kclient.Config
90
-	// DeployerPrivilegedLoopbackClientConfig is the client configuration used to call OpenShift APIs from launched deployer pods
91
-	DeployerOSClientConfig kclient.Config
92 90
 
93 91
 	// kubeClient is the client used to call Kubernetes APIs from system components, built from KubeClientConfig.
94 92
 	// It should only be accessed via the *Client() helper methods.
... ...
@@ -127,10 +125,6 @@ func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) {
127 127
 	if err != nil {
128 128
 		return nil, err
129 129
 	}
130
-	_, deployerOSClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.DeployerKubeConfig)
131
-	if err != nil {
132
-		return nil, err
133
-	}
134 130
 
135 131
 	imageTemplate := variable.NewDefaultImageTemplate()
136 132
 	imageTemplate.Format = options.ImageConfig.Format
... ...
@@ -173,7 +167,6 @@ func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) {
173 173
 		ClientCAs:    clientCAs,
174 174
 		APIClientCAs: apiClientCAs,
175 175
 
176
-		DeployerOSClientConfig:             *deployerOSClientConfig,
177 176
 		PrivilegedLoopbackClientConfig:     *privilegedLoopbackClientConfig,
178 177
 		PrivilegedLoopbackOpenShiftClient:  privilegedLoopbackOpenShiftClient,
179 178
 		PrivilegedLoopbackKubernetesClient: privilegedLoopbackKubeClient,
... ...
@@ -362,12 +355,6 @@ func (c *MasterConfig) DeploymentControllerClients() (*osclient.Client, *kclient
362 362
 	return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient
363 363
 }
364 364
 
365
-// DeployerClientConfig returns the client configuration a Deployer instance launched in a pod
366
-// should use when making API calls.
367
-func (c *MasterConfig) DeployerClientConfig() *kclient.Config {
368
-	return &c.DeployerOSClientConfig
369
-}
370
-
371 365
 func (c *MasterConfig) DeploymentConfigControllerClients() (*osclient.Client, *kclient.Client) {
372 366
 	return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient
373 367
 }
... ...
@@ -173,7 +173,6 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig
173 173
 		},
174 174
 
175 175
 		MasterClients: configapi.MasterClients{
176
-			DeployerKubeConfig:           admin.DefaultKubeConfigFilename(args.ConfigDir.Value(), "openshift-deployer"),
177 176
 			OpenShiftLoopbackKubeConfig:  admin.DefaultKubeConfigFilename(args.ConfigDir.Value(), "openshift-client"),
178 177
 			ExternalKubernetesKubeConfig: args.KubeConnectionArgs.ClientConfigLoadingRules.ExplicitPath,
179 178
 		},
... ...
@@ -229,10 +228,11 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig
229 229
 	}
230 230
 
231 231
 	if builtInKubernetes {
232
-		// When we start Kubernetes, we're responsible for generating the default account
232
+		// When we start Kubernetes, we're responsible for generating all the managed service accounts
233 233
 		config.ServiceAccountConfig.ManagedNames = []string{
234 234
 			bootstrappolicy.DefaultServiceAccountName,
235 235
 			bootstrappolicy.BuilderServiceAccountName,
236
+			bootstrappolicy.DeployerServiceAccountName,
236 237
 		}
237 238
 		// We also need the private key file to give to the token generator
238 239
 		config.ServiceAccountConfig.PrivateKeyFile = admin.DefaultServiceAccountPrivateKeyFile(args.ConfigDir.Value())
... ...
@@ -241,11 +241,12 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig
241 241
 			admin.DefaultServiceAccountPublicKeyFile(args.ConfigDir.Value()),
242 242
 		}
243 243
 	} else {
244
-		// When running against an external Kubernetes, we're only responsible for the builder account.
244
+		// When running against an external Kubernetes, we're only responsible for the builder and deployer accounts.
245 245
 		// We don't have the private key, but we need to get the public key to authenticate signed tokens.
246 246
 		// TODO: JTL: take arg for public key(s)?
247 247
 		config.ServiceAccountConfig.ManagedNames = []string{
248 248
 			bootstrappolicy.BuilderServiceAccountName,
249
+			bootstrappolicy.DeployerServiceAccountName,
249 250
 		}
250 251
 		config.ServiceAccountConfig.PublicKeyFiles = []string{}
251 252
 	}
... ...
@@ -48,17 +48,23 @@ func (cfg *Config) Bind(flags *pflag.FlagSet) {
48 48
 	BindClientConfigSecurityFlags(&cfg.CommonConfig, flags)
49 49
 }
50 50
 
51
-func EnvVarsFromConfig(config *kclient.Config) []api.EnvVar {
52
-	insecure := "false"
53
-	if config.Insecure {
54
-		insecure = "true"
51
+func EnvVars(host string, caData []byte, insecure bool, bearerTokenFile string) []api.EnvVar {
52
+	envvars := []api.EnvVar{
53
+		{Name: "KUBERNETES_MASTER", Value: host},
54
+		{Name: "OPENSHIFT_MASTER", Value: host},
55 55
 	}
56
-	return []api.EnvVar{
57
-		{Name: "OPENSHIFT_CA_DATA", Value: string(config.CAData)},
58
-		{Name: "OPENSHIFT_CERT_DATA", Value: string(config.CertData)},
59
-		{Name: "OPENSHIFT_KEY_DATA", Value: string(config.KeyData)},
60
-		{Name: "OPENSHIFT_INSECURE", Value: insecure},
56
+
57
+	if len(bearerTokenFile) > 0 {
58
+		envvars = append(envvars, api.EnvVar{Name: "BEARER_TOKEN_FILE", Value: bearerTokenFile})
59
+	}
60
+
61
+	if len(caData) > 0 {
62
+		envvars = append(envvars, api.EnvVar{Name: "OPENSHIFT_CA_DATA", Value: string(caData)})
63
+	} else if insecure {
64
+		envvars = append(envvars, api.EnvVar{Name: "OPENSHIFT_INSECURE", Value: "true"})
61 65
 	}
66
+
67
+	return envvars
62 68
 }
63 69
 
64 70
 func (cfg *Config) bindEnv() error {
... ...
@@ -25,6 +25,8 @@ import (
25 25
 //
26 26
 // Use the DeploymentControllerFactory to create this controller.
27 27
 type DeploymentController struct {
28
+	// serviceAccount to create deployment pods with
29
+	serviceAccount string
28 30
 	// deploymentClient provides access to deployments.
29 31
 	deploymentClient deploymentClient
30 32
 	// podClient provides access to pods.
... ...
@@ -210,6 +212,7 @@ func (c *DeploymentController) makeDeployerPod(deployment *kapi.ReplicationContr
210 210
 			},
211 211
 			ActiveDeadlineSeconds: &maxDeploymentDurationSeconds,
212 212
 			RestartPolicy:         kapi.RestartPolicyNever,
213
+			ServiceAccount:        c.serviceAccount,
213 214
 		},
214 215
 	}
215 216
 
... ...
@@ -26,6 +26,8 @@ type DeploymentControllerFactory struct {
26 26
 	KubeClient kclient.Interface
27 27
 	// Codec is used for encoding/decoding.
28 28
 	Codec runtime.Codec
29
+	// ServiceAccount is the service account name to run deployer pods as
30
+	ServiceAccount string
29 31
 	// Environment is a set of environment which should be injected into all deployer pod containers.
30 32
 	Environment []kapi.EnvVar
31 33
 	// DeployerImage specifies which Docker image can support the default strategies.
... ...
@@ -51,6 +53,7 @@ func (factory *DeploymentControllerFactory) Create() controller.RunnableControll
51 51
 	eventBroadcaster.StartRecordingToSink(factory.KubeClient.Events(""))
52 52
 
53 53
 	deployController := &DeploymentController{
54
+		serviceAccount: factory.ServiceAccount,
54 55
 		deploymentClient: &deploymentClientImpl{
55 56
 			getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
56 57
 				return factory.KubeClient.ReplicationControllers(namespace).Get(name)