Add ability to consume secrets in env vars

This commit is contained in:
Paul Morie 2016-01-18 12:20:51 -05:00
parent dc83a11758
commit c548054560
6 changed files with 120 additions and 8 deletions

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: MY_SECRET_DATA
valueFrom:
secretKeyRef:
name: test-secret
key: data-1
restartPolicy: Never

View File

@ -354,8 +354,9 @@ func TestExampleObjectSchemas(t *testing.T) {
"rc": &api.ReplicationController{},
},
"../docs/user-guide/secrets": {
"secret-pod": &api.Pod{},
"secret": &api.Secret{},
"secret-pod": &api.Pod{},
"secret": &api.Secret{},
"secret-env-pod": &api.Pod{},
},
"../examples/spark": {
"spark-master-controller": &api.ReplicationController{},

View File

@ -560,8 +560,8 @@ type GitRepoVolumeSource struct {
// as files using the keys in the Data field as the file names.
// Secret volumes support ownership management and SELinux relabeling.
type SecretVolumeSource struct {
// Name of the secret in the pod's namespace to use
SecretName string `json:"secretName"`
// Name of the secret in the pod's namespace to use.
SecretName string `json:"secretName,omitempty"`
}
// Represents an NFS mount that lasts the lifetime of a pod.
@ -721,6 +721,8 @@ type EnvVarSource struct {
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
// Selects a key of a ConfigMap.
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
// Selects a key of a secret in the pod's namespace.
SecretKeyRef *SecretKeySelector `json:"secretKeyRef,omitempty"`
}
// ObjectFieldSelector selects an APIVersioned field of an object.
@ -741,6 +743,14 @@ type ConfigMapKeySelector struct {
Key string `json:"key"`
}
// SecretKeySelector selects a key of a Secret.
type SecretKeySelector struct {
// The name of the secret in the pod's namespace to select from.
LocalObjectReference `json:",inline"`
// The key of the secret to select from. Must be a valid secret key.
Key string `json:"key"`
}
// HTTPGetAction describes an action based on HTTP Get requests.
type HTTPGetAction struct {
// Optional: Path to access on the HTTP server.

View File

@ -724,9 +724,9 @@ type GitRepoVolumeSource struct {
// as files using the keys in the Data field as the file names.
// Secret volumes support ownership management and SELinux relabeling.
type SecretVolumeSource struct {
// SecretName is the name of a secret in the pod's namespace.
// Name of the secret in the pod's namespace to use.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#secrets
SecretName string `json:"secretName"`
SecretName string `json:"secretName,omitempty"`
}
// Represents an NFS mount that lasts the lifetime of a pod.
@ -847,6 +847,8 @@ type EnvVarSource struct {
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
// Selects a key of a ConfigMap.
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
// Selects a key of a secret in the pod's namespace
SecretKeyRef *SecretKeySelector `json:"secretKeyRef,omitempty"`
}
// ObjectFieldSelector selects an APIVersioned field of an object.
@ -865,6 +867,14 @@ type ConfigMapKeySelector struct {
Key string `json:"key"`
}
// SecretKeySelector selects a key of a Secret.
type SecretKeySelector struct {
// The name of the secret in the pod's namespace to select from.
LocalObjectReference `json:",inline"`
// The key of the secret to select from. Must be a valid secret key.
Key string `json:"key"`
}
// HTTPGetAction describes an action based on HTTP Get requests.
type HTTPGetAction struct {
// Path to access on the HTTP server.

View File

@ -1369,6 +1369,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
var (
tmpEnv = make(map[string]string)
configMaps = make(map[string]*apiextensions.ConfigMap)
secrets = make(map[string]*api.Secret)
mappingFunc = expansion.MappingFuncFor(tmpEnv, serviceEnv)
)
for _, envVar := range container.Env {
@ -1405,6 +1406,21 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
if !ok {
return result, fmt.Errorf("Couldn't find key %v in ConfigMap %v/%v", key, pod.Namespace, name)
}
case envVar.ValueFrom.SecretKeyRef != nil:
name := envVar.ValueFrom.SecretKeyRef.Name
key := envVar.ValueFrom.SecretKeyRef.Key
secret, ok := secrets[name]
if !ok {
secret, err = kl.kubeClient.Secrets(pod.Namespace).Get(name)
if err != nil {
return result, err
}
}
runtimeValBytes, ok := secret.Data[key]
if !ok {
return result, fmt.Errorf("Couldn't find key %v in Secret %v/%v", key, pod.Namespace, name)
}
runtimeVal = string(runtimeValBytes)
}
}

View File

@ -28,7 +28,7 @@ import (
var _ = Describe("Secrets", func() {
f := NewFramework("secrets")
It("should be consumable from pods [Conformance]", func() {
It("should be consumable from pods in volume [Conformance]", func() {
name := "secret-test-" + string(util.NewUUID())
volumeName := "secret-volume"
volumeMountPath := "/etc/secret-volume"
@ -74,7 +74,7 @@ var _ = Describe("Secrets", func() {
},
Containers: []api.Container{
{
Name: "secret-test",
Name: "secret-volume-test",
Image: "gcr.io/google_containers/mounttest:0.2",
Args: []string{
"--file_content=/etc/secret-volume/data-1",
@ -97,4 +97,63 @@ var _ = Describe("Secrets", func() {
"mode of file \"/etc/secret-volume/data-1\": -r--r--r--",
}, f.Namespace.Name)
})
It("should be consumable from pods in env vars [Conformance]", func() {
name := "secret-test-" + string(util.NewUUID())
secret := &api.Secret{
ObjectMeta: api.ObjectMeta{
Namespace: f.Namespace.Name,
Name: name,
},
Data: map[string][]byte{
"data-1": []byte("value-1"),
},
}
By(fmt.Sprintf("Creating secret with name %s", secret.Name))
defer func() {
By("Cleaning up the secret")
if err := f.Client.Secrets(f.Namespace.Name).Delete(secret.Name); err != nil {
Failf("unable to delete secret %v: %v", secret.Name, err)
}
}()
var err error
if secret, err = f.Client.Secrets(f.Namespace.Name).Create(secret); err != nil {
Failf("unable to create test secret %s: %v", secret.Name, err)
}
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod-secrets-" + string(util.NewUUID()),
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "secret-env-test",
Image: "gcr.io/google_containers/busybox",
Command: []string{"sh", "-c", "env"},
Env: []api.EnvVar{
{
Name: "SECRET_DATA",
ValueFrom: &api.EnvVarSource{
SecretKeyRef: &api.SecretKeySelector{
LocalObjectReference: api.LocalObjectReference{
Name: name,
},
Key: "data-1",
},
},
},
},
},
},
RestartPolicy: api.RestartPolicyNever,
},
}
testContainerOutput("consume secrets", f.Client, pod, 0, []string{
"SECRET_DATA=value-1",
}, f.Namespace.Name)
})
})