What does key mean when creating a kubernetes configmap from a file - kubernetes

I see here a syntax like this:
kubectl create cm configmap4 --from-file=special=config4.txt
I did not find a description of what repetition of = and the special means here.
Kubernetes documentation here only denotes one time usage of = after --from-file while creating configmaps in kubectl.

It appears from generating the YAML that this middle key mean all the keys that are being loaded from the file to be nested inside the mentioned key (special keyword in the question example).
It appears like this:
apiVersion: v1
data:
special: |
var3=val3
var4=val4
kind: ConfigMap
metadata:
creationTimestamp: "2019-06-01T08:20:15Z"
name: configmap4
namespace: default
resourceVersion: "123320"
selfLink: /api/v1/namespaces/default/configmaps/configmap4
uid: 1582b155-8446-11e9-87b7-0800277f619d

kubectl create configmap my-config --from-file=path/to/bar
When creating a configmap based on a file, the key will default to the basename of the file, and the value will default to the file content. If the basename is an invalid key, you may specify an alternate key.
Create a new configmap named my-config with specified keys instead of file basenames on disk
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt

Related

Use Kubernetes Secret as Environment Variable when secret is create from a file

I have created a kubernetes secret from a file (secret.txt):
k1=v1
k2=v2
k3=v3
It looks like this secret-:
apiVersion: v1
metadata:
name: secret007
data:
secret.txt: bWFza1NhbHQ9InRlc3RzYWx0IgpzM1
I am using it as environment variable in the pod like this:
- name: KEY1
valueFrom:
secretKeyRef:
key: k1
name: secret007
optional: false
Problem
Problem since the data has a value as a single base64 value. I am not able to refer it in the pod and getting this error.
Warning Failed 6s (x2 over 6s) kubelet, Error: couldn't find key k1 in Secret kube-system/secret007
Please suggest how to do this without changing the secret format i.e Secret would be a single key value of filename and all secret.txt values as a single base64 value. Is it possible?
You can create secret entries from environment file
kubectl create secret generic test --from-env-file=secret.txt
and the output will have distinct values in your secret
apiVersion: v1
data:
k1: djE=
k2: djI=
k3: djM=
kind: Secret
metadata:
creationTimestamp: null
name: test
This is a community wiki answer posted for better visibility. Feel free to expand it.
As already mentioned by #DavidMaze, Kubernetes will not to look "inside" a Secret or a ConfigMap values:
You can refer to the entire Secret value as you've shown in the
question, but there's no way to tell it (a) that the value is actually
newline-separated key=value pairs (as opposed to TOML, YAML, JSON,
XML, ...) and (b) that you want to pick some specific value out of
there.

kubectl apply with stringData in secret does not remove fields

(using kubernetes v1.15.7 in minikube and matching client version and minikube 1.9.0)
If I kubectl apply a secret like this:
apiVersion: v1
data:
MY_KEY: dmFsdWUK
MY_SECRET: c3VwZXJzZWNyZXQK
kind: Secret
metadata:
name: my-secret
type: Opaque
then subsequently kubectl apply a secret removing the MY_SECRET field, like this:
apiVersion: v1
data:
MY_KEY: dmFsdWUK
kind: Secret
metadata:
name: my-secret
type: Opaque
The data field in the result is what I expect when I kubectl get the secret:
data:
MY_KEY: dmFsdWUK
However, if I do the same thing using stringData instead for the first kubectl apply, it does not remove the missing key on the second one:
First kubectl apply:
apiVersion: v1
stringData:
MY_KEY: value
MY_SECRET: supersecret
kind: Secret
metadata:
name: my-secret
type: Opaque
Second kubectl apply (stays the same, except replacing MY_KEY's value with b2hubyEK to show the configuration DID change)
apiVersion: v1
data:
MY_KEY: b2hubyEK
kind: Secret
metadata:
name: my-secret
type: Opaque
kubectl get result after applying the second case:
data:
MY_KEY: b2hubyEK
MY_SECRET: c3VwZXJzZWNyZXQ=
The field also does not get removed if the second case uses stringData instead. So it seems that once stringData is used once, it's impossible to remove a field without deleting the secret. Is this a bug? Or should I be doing something differently when using stringData?
kubectl apply need to merge / patch the changes here. How this works is described in How apply calculates differences and merges changes
I would recommend to use kustomize with kubectl apply -k and use the secretGenerator to create a unique secret name, for every change. Then you are practicing Immutable Infrastructure and does not get this kind of problems.
A brand new tool for config manangement is kpt, and kpt live apply may also be an interesting solution for this.
The problem is that stringData is a write only field. It doesn’t have convergent behavior so it breaks the merge patch generator system. Most high level tools fix this by converting to normal data before dealing with the patch.

Using sensitive environment variables in Kubernetes configMaps

I know you can use ConfigMap properties as environment variables in the pod spec, but can you use environment variables declared in the pods spec inside the configmap?
For example:
I have a secret password which I wish to access in my configmap application.properties. The secret looks like so:
apiVersion: v1
data:
pw: THV3OE9vcXVpYTll==
kind: Secret
metadata:
name: foo
namespace: foo-bar
type: Opaque
so inside the pod spec I reference the secret as an env var. The configMap will be mounted as a volume from within the spec:
env:
- name: PASSWORD
valueFrom:
secretKeyRef:
name: foo
key: pw
...
and inside my configMap I can then reference the secret value like so:
apiVersion: v1
kind: ConfigMap
metadata:
name: application.properties
namespace: foo-bar
data:
application.properties: /
secret.password=$(PASSWORD)
Anything I've found online is just about consuming configMap values as env vars and doesn't mention consuming env vars in configMap values.
Currently it's not a Kubernetes Feature.
There is a closed issue requesting this feature and it's kind of controversial topic because the discussion is ongoing many months after being closed:
Reference Secrets from ConfigMap #79224
Referencing the closing comment:
Best practice is to not use secret values in envvars, only as mounted files. if you want to keep all config values in a single object, you can place all the values in a secret object and reference them that way.
Referencing secrets via configmaps is a non-goal... it confuses whether things mounting or injecting the config map are mounting confidential values.
I suggest you to read the entire thread to understand his reasons and maybe find another approach for your environment to get this variables.
"OK, but this is Real Life, I need to make this work"
Then I recommend you this workaround:
Import Data to Config Map from Kubernetes Secret
It makes the substitution with a shell in the entrypoint of the container.

Terraform kubernetes_config_map --from-env-file

I am creating a kubernetes configMap using '--from-env-file' option to store the file contents as environment variables.
kubectl create configmap env --from-env-file=env.properties -n namespace
When I create a terraform resource as below, the created configMap contains a file, not environment variables.
resource "kubernetes_config_map" "env" {
metadata {
name = "env-config"
namespace = var.namespace
}
data = {
"env.properties" = "${file("${path.module}/env.properties")}"
}
}
How to create configMap with file content as environment variables using terraform-kubernetes-provider resource ?
If env.properties looks like this:
$ cat env.properties
enemies=aliens
lives=3
allowed="true"
Then kubectl create configmap env --from-env-file=env.properties -n namespace would result in something like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: env
namespace: namespace
data:
allowed: '"true"'
enemies: aliens
lives: "3"
But what you're doing with Terraform would result in something more like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: env
namespace: namespace
data:
env.properties: |
enemies=aliens
lives=3
allowed="true"
Based on the Terraform docs it appears that what you're looking for, i.e. some native support for --from-env-file behaviour within the Terraform provider, is not possible.
The ConfigMap format that you get doing it the Terraform way could still be useful, you might just have to change how you're pulling the data from the ConfigMap into your pods/deployments. If you can share more details, and even a simplified/sanitized example of your pods/deployments where you're consuming the config map, it may be possible to describe how to change those to make use of the different style of ConfigMap. See more here.

How to use values from a ConfigMap with key/value separated by equal symbol (=)?

Given I have created a ConfigMap with a file like that :
VARIABLE1=foo
VARIABLE2=bar
Is there a way to access those values in Kubernetes or does it have to be in the YAML format?
Let's say you have a file called z with the contents above. You have two options to make that into a ConfigMap.
Option 1 (--from-file)
$ kubectl create cm cm1 --from-file=z
This will result in an object like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm1
data:
z: |
VARIABLE1=foo
VARIABLE2=bar
There is no direct way to project a single value from this ConfigMap as it contains just one blob. However you can, from a shell used in command of a container source that blob (if you project it as a file) and then use the resulting environment variables.
Option 2 (--from-env-file)
$ kubectl create cm cm2 --from-env-file=z
This will result in an object like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm2
data:
VARIABLE1: foo
VARIABLE2: bar
As you can see the different variables became separate key-value pairs in this case.
There are many more examples in the reference documentation