mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 03:57:41 +00:00
Add ability to consume secrets in env vars
This commit is contained in:
parent
dc83a11758
commit
c548054560
16
docs/user-guide/secrets/secret-env-pod.yaml
Normal file
16
docs/user-guide/secrets/secret-env-pod.yaml
Normal 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
|
@ -356,6 +356,7 @@ func TestExampleObjectSchemas(t *testing.T) {
|
|||||||
"../docs/user-guide/secrets": {
|
"../docs/user-guide/secrets": {
|
||||||
"secret-pod": &api.Pod{},
|
"secret-pod": &api.Pod{},
|
||||||
"secret": &api.Secret{},
|
"secret": &api.Secret{},
|
||||||
|
"secret-env-pod": &api.Pod{},
|
||||||
},
|
},
|
||||||
"../examples/spark": {
|
"../examples/spark": {
|
||||||
"spark-master-controller": &api.ReplicationController{},
|
"spark-master-controller": &api.ReplicationController{},
|
||||||
|
@ -560,8 +560,8 @@ type GitRepoVolumeSource struct {
|
|||||||
// as files using the keys in the Data field as the file names.
|
// as files using the keys in the Data field as the file names.
|
||||||
// Secret volumes support ownership management and SELinux relabeling.
|
// Secret volumes support ownership management and SELinux relabeling.
|
||||||
type SecretVolumeSource struct {
|
type SecretVolumeSource struct {
|
||||||
// Name of the secret in the pod's namespace to use
|
// Name of the secret in the pod's namespace to use.
|
||||||
SecretName string `json:"secretName"`
|
SecretName string `json:"secretName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents an NFS mount that lasts the lifetime of a pod.
|
// Represents an NFS mount that lasts the lifetime of a pod.
|
||||||
@ -721,6 +721,8 @@ type EnvVarSource struct {
|
|||||||
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
|
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
|
||||||
// Selects a key of a ConfigMap.
|
// Selects a key of a ConfigMap.
|
||||||
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
|
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.
|
// ObjectFieldSelector selects an APIVersioned field of an object.
|
||||||
@ -741,6 +743,14 @@ type ConfigMapKeySelector struct {
|
|||||||
Key string `json:"key"`
|
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.
|
// HTTPGetAction describes an action based on HTTP Get requests.
|
||||||
type HTTPGetAction struct {
|
type HTTPGetAction struct {
|
||||||
// Optional: Path to access on the HTTP server.
|
// Optional: Path to access on the HTTP server.
|
||||||
|
@ -724,9 +724,9 @@ type GitRepoVolumeSource struct {
|
|||||||
// as files using the keys in the Data field as the file names.
|
// as files using the keys in the Data field as the file names.
|
||||||
// Secret volumes support ownership management and SELinux relabeling.
|
// Secret volumes support ownership management and SELinux relabeling.
|
||||||
type SecretVolumeSource struct {
|
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
|
// 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.
|
// Represents an NFS mount that lasts the lifetime of a pod.
|
||||||
@ -847,6 +847,8 @@ type EnvVarSource struct {
|
|||||||
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
|
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
|
||||||
// Selects a key of a ConfigMap.
|
// Selects a key of a ConfigMap.
|
||||||
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
|
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.
|
// ObjectFieldSelector selects an APIVersioned field of an object.
|
||||||
@ -865,6 +867,14 @@ type ConfigMapKeySelector struct {
|
|||||||
Key string `json:"key"`
|
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.
|
// HTTPGetAction describes an action based on HTTP Get requests.
|
||||||
type HTTPGetAction struct {
|
type HTTPGetAction struct {
|
||||||
// Path to access on the HTTP server.
|
// Path to access on the HTTP server.
|
||||||
|
@ -1369,6 +1369,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
|
|||||||
var (
|
var (
|
||||||
tmpEnv = make(map[string]string)
|
tmpEnv = make(map[string]string)
|
||||||
configMaps = make(map[string]*apiextensions.ConfigMap)
|
configMaps = make(map[string]*apiextensions.ConfigMap)
|
||||||
|
secrets = make(map[string]*api.Secret)
|
||||||
mappingFunc = expansion.MappingFuncFor(tmpEnv, serviceEnv)
|
mappingFunc = expansion.MappingFuncFor(tmpEnv, serviceEnv)
|
||||||
)
|
)
|
||||||
for _, envVar := range container.Env {
|
for _, envVar := range container.Env {
|
||||||
@ -1405,6 +1406,21 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
|
|||||||
if !ok {
|
if !ok {
|
||||||
return result, fmt.Errorf("Couldn't find key %v in ConfigMap %v/%v", key, pod.Namespace, name)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
var _ = Describe("Secrets", func() {
|
var _ = Describe("Secrets", func() {
|
||||||
f := NewFramework("secrets")
|
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())
|
name := "secret-test-" + string(util.NewUUID())
|
||||||
volumeName := "secret-volume"
|
volumeName := "secret-volume"
|
||||||
volumeMountPath := "/etc/secret-volume"
|
volumeMountPath := "/etc/secret-volume"
|
||||||
@ -74,7 +74,7 @@ var _ = Describe("Secrets", func() {
|
|||||||
},
|
},
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{
|
{
|
||||||
Name: "secret-test",
|
Name: "secret-volume-test",
|
||||||
Image: "gcr.io/google_containers/mounttest:0.2",
|
Image: "gcr.io/google_containers/mounttest:0.2",
|
||||||
Args: []string{
|
Args: []string{
|
||||||
"--file_content=/etc/secret-volume/data-1",
|
"--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--",
|
"mode of file \"/etc/secret-volume/data-1\": -r--r--r--",
|
||||||
}, f.Namespace.Name)
|
}, 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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user