Base64 decode the K8 secrets on volume mount - kubernetes

My k8.yaml looks like this.
apiVersion: apps/v1
kind: Deployment
metadata:
name: <...>
namespace: <...>
spec:
template:
spec:
containers:
- name: <...>
image: <...>
volumeMounts:
- name: decoded
mountPath: /usr/src/app/decoded
volumes:
- name: decoded
secret:
secretName: base64-secret
defaultMode: 0755
Variables in base64-secret k8 secrets are base64 encoded. Is there anyway to decode the content when they are mounted to a path using the k8 yaml configuration?
So far, the only way I could think of is using a script to decode when the container starts.
FYI: the secret type is Generic

It can be done using base64 -d command (-d : decode)
Example :
#secret name samplesecret
kubectl get secret samplesecret
NAME TYPE DATA AGE
samplesecret Opaque 3 4m20s
#get all the keys in the secrets (keys wont be encoded but values will be encoded):
kubectl get secret samplesecret -o jsonpath='{.data}'
{"key1":"dmFsdWU=","key2":"dmFsdWUy","key3":"dmFsdWUz"}
#now decode the desired key's value by piping it to base64 -d:
kubectl get secret samplesecret -o jsonpath='{.data.key1}' | base64 -d
value
kubectl get secret samplesecret -o jsonpath='{.data.key2}' | base64 -d
value2
kubectl get secret samplesecret -o jsonpath='{.data.key3}' | base64 -d
value3
# if you want to iterate through all the keys & display their values decoded :
kubectl get secret <secretname> -o go-template='{{range $k,$v := .data}}{{"### "}}{{$k}}{{"\n"}}{{$v|base64decode}}{{"\n\n"}}{{end}}'
kubectl get secret samplesecret -o go-template='{{range $k,$v := .data}}{{"### "}}{{$k}}{{"\n"}}{{$v|base64decode}}{{"\n\n"}}{{end}}'
### key1
value
### key2
value2
### key3
value3

Related

How to edit a sealed secret in kubernetes?

I've a kubernetes sealed secret with encrypted data in it. How can I edit the sealed secret like editing a deployment using command "kubectl edit deployment".
I know kubectl edit secret works on normal secrets not on sealed secrets.
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
creationTimestamp: null
name: my-secret
namespace: test-ns
spec:
encryptedData:
password: AgCEP9MHaeVGelL3jSbnfUF47m+eR0Vv4ufzPyPXBvEjYcJluI0peLgilSqWUMnDLjp00UJq186nRYufEf7Bi1Jxm39t3nDbW13+wTSbblVzb9A2iKJI2VbxgTG/IDodNFxFWdKefZdZgVct2hTsuwlivIxpdxDZtcND4h+Cx8YFQMUpT5oO26oqISzRTh5Ewa6ehWtv6krfeFmbMQCF70eg0yioe6Op0YaQKloiFVInc1JK5KTR5iQYCeKb2R0ovKVa/lipbqjHCYSRhLR/3q5wz/ZuWz7g7ng6G9Q7o1pVv3udQYUvp2B6XvK1Nezc85wbhGgmuz5kcZUa36uF+eKMes6UdPcD7q58ndaj/0KWozdTAuk1OblV7mrUaK8Q45GIf+JqaBfzVt52INMT07P4MId/KB31sZDeE+OwEXhCDVTBAlxSRM0U9NjxDDb+mwUzxHNZHL1sY8M1YCoX+rr6n1+yW1HG42VHLCRzeBa2V31OFuQTNjoNxDEfUq+CSTRNDCmt8UvercSkgyM3mBa6JpHdkySllpqyEJDYKM1YvVRrjVvg1qGTF5dOCx6x3ROXnZtA3NBIafTu0+pHovVo+X7nUkl7hyupd0KKzBG+afgNpYQOxeuei5A+o++o92G5lexxk2v4bQt6ANYBxMlvT0LdBUW9e/L2y+TuNAHL23Xa/aTq1lagNBi9JTowX0lx0br2CqDbKg==
username: AgArwZm3qh83Fpzles1r/PjTDKQ2/SZ482IKC84T72/kI4M29aG2VT4SCXcqbmtVDYuVUN0wTbsFYsnwY1DSRrL4oup2xRg6N34IxHjj0ZtF1q0YtBKIM/DPcF2bBVAYc9/vOI0L3+VVSF9r93XYEMUWX6hY9eHa8VUHBM/Y65Sj3Il7Pmx/qoEcZ+e9UJhqWEJPotz6W5OMh/Al/QPJZknwUulM4coZ3C0J4TmrBVexPturcRCimDEQnd9UitotnGDoNAp2O28ovhXoImNsJBhNK5LykesRxEfIp4UJOb3I0CpLdoz9khEcb2r31j+KTtxifLez7Rg3Pg7BGpR3EKC3INZWrR8S/aUm5u/dP12ELgW3nq4WbafRitrZcHhLFZkHma/Er8miFbuTXvpFcXE1g+BnG2vIs4kHSl2QcP32HPGKHJJt0KEd1dUJrXXTjS9eXHJ2KsA5DZk4TcFA5dPAG76ZdKo0GCIQwvNeT0Ao4ntqmeOiijAQgmhXdCtD2WVavXi54h0f8F2ue6b0mBFCgTGKZyypjbXznzB/MPAZxgIu+UWQzV1CczwKlitPy638s/9iSan2/u2rhKu2SP0JFMZ6pPnfO51nMpDHtCDGFc1unjsjM4ZpnNXtaQJJmXo7Hw0L4dW2/N3uxCfxNtmYuBxE1t4GCefSUCTIleDgmAbB00nKkja+ml9bidcxawlIgHnoq/XNCqy2R3PkEw==
template:
data: null
metadata:
creationTimestamp: null
name: my-secret
namespace: test-ns
You can update the existing SealedSecret by using --merge-into option in SealedSecret service. You can simply copy & paste the encrypted data into a json and merge this to the existing SealedSecret like this
$ echo -n bar | kubectl create secret generic mysecret --dry-run=client --from-file=foo=/dev/stdin -o json \
| kubeseal > mysealedsecret.json
$ echo -n baz | kubectl create secret generic mysecret --dry-run=client --from-file=bar=/dev/stdin -o json \
| kubeseal --merge-into mysealedsecret.json
When the sealedsecret needs to decrypt and work the same as normal secrets in kubernetes then both sealedsecrets and secrets need to be in the same namespace.
For more detailed information refer this official sealedsecrets github page
To know more about the usage of SealedSecret refer to this document

Set environment variable in kubernetes secret

When using Kubernetes .yml files, I can do the following:
$ cat configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-configmap
data:
foo: ${FOO}
bar: ${BAR}
static: doesNotChange
$ export FOO=myFooVal
$ export BAR=myBarVal
$ cat configmap.yml | envsubst | kubectl apply -f -
This would replace ${FOO} and ${BAR} in the configmap.yml file before actually applying the file to the cluster.
How could I achieve the very same behavior with a Kubernetes secret which has it's data values base64 encoded?
I would need to read all the keys in the data: field, decode the values, apply the environment variables and encode it again.
A tool to decode and encode the data: values inplace would be much appreciated.
It is actually possible, to store the secret.yml with stringData instead of data which allows to keep the files in plain text (SOPS encryption is still possible and encouraged)
$ cat secret.yml
apiVersion: v1
kind: Secret
metadata:
name: test-secret
namespace: default
type: Opaque
stringData:
dotenv: |
DATABASE_URL="postgresql://test:test#localhost:5432/test?schema=public"
API_PORT=${PORT}
FOO=${FOO}
BAR=${BAR}
$ export PORT=80
$ export FOO=myFooValue
$ export BAR=myBarValue
$ cat secret.yml | envsubst | kubectl apply -f -
A plus is for sure, that this not only allows for creation of the secret, but updating is also possible.
Just for documentation, here would be the full call with SOPS:
$ sops --decrypt secret.enc.yml | envsubst | kubectl apply -f -

How to make the kubernetes pods unable to decrypt the kubernetes secrets without a key?

The end goal I'm trying to achieve is to create a kubernetes secret (potentially with a key) and a pod which uses that. But the catch is, the pod created should not be able to decode/decrypt the secret value without a particular key.
I have tried the secrets with data encryption at rest but that's not sufficient for my requirement.
Edit: I am trying to making this as step by step solution. (as asked by #Dawid in comments)
Encrypt your data using your-key (your encryption-logic, probably, in a script).
./encrypt.sh --key your-key --data your-data
Create a secret of this encrypted data
kubectl create secret generic your-secret-name --from-literal=secretdata=your-encrypted-data
You could add decryption logic like this in your pod ( either as a sidecar or initContainer)
# decrypt.sh will decode base64 then your decryption logic using your-key
./decrypt.sh --key your-key --data /var/my-secrets
Also you need to mount this secret as volume to your container .
spec:
containers:
- image: "image"
name: app
...
volumeMounts:
- mountPath: "/var/my-secrets"
name: my-secret
volumes:
- name: my-secret
secret:
secretName: your-secret-name
As answered by #Kiran here are the steps I followed to obtain the solution.
Encrypt using the openssl
echo -n "preetham" | openssl enc -e -aes-256-cbc -a -salt -pass pass:<PASSWORD>
Created the secret from the YAML file. preetham-secrets-test.yaml
apiVersion: v1
kind: Secret
metadata:
name: preetham-secrets
type: Opaque
stringData: # Using stringData instead data
username: U2FsdGVkX18VsbQaVpeqrCCJCDEd3LCbefT6nupChvw= # output from the step 1
Create the secret
kubectl apply -f preetham-secrets-test.yaml -n <NAMESPACE>
Mount the secret to volume and exec into the pod. Kubernetes reference
Inside the pod assuming the secret is mounted to /opt/mnt/secrets/.
bash-4.2# cat /opt/mnt/secrets/username
U2FsdGVkX18VsbQaVpeqrCCJCDEd3LCbefT6nupChvw=bash-4.2#
Decrypt the same using the openssl.( you may have to install the openssl based on the image using
bash-4.2# echo "U2FsdGVkX18VsbQaVpeqrCCJCDEd3LCbefT6nupChvw=" | openssl enc -d -aes-256-cbc -a -salt -pass pass:<PASSWORD>
preethambash-4.2#

Return correct Key Value using go-template

I'm trying to retrieve the value for the key clientSecret, from my kubernetes response, but I am failing to find the correct go syntax.
I have tried commands like:
kubectl get secret client-secret -o yaml --namespace magic-test -o go-template --template="{{range .items}}{{range .data}}{{.clientSecret}} {{end}}{{end}}"
And other variations
This is the yaml output of what I am trying to retrieve from
kubectl get secret client-secret -n magic-test -o yaml
apiVersion: v1
data:
clientSecret: NmQQuCNFiOWItsdfOTAyMCb00MjEwLWFiNGQtNTI4NDdiNWM5ZjMx
kind: Secret
metadata:
creationTimestamp: 2019-05-31T14:03:44Z
name: client-secret
namespace: magic-test
resourceVersion: "11544532074"
selfLink: /api/v1/namespaces/magic-test/secrets/client-secret
uid: e72acdsfbcc-83fsdac-1sdf1e9-9sdffaf-0050dsf56b7c1fa
type: Opaque
How can I retrieve the value for clientSecret?
The output is not a list of items but an object or dictionary, so you can't iterate over the pipeline but you may simply index it by the keys you're interested in.
So simply use the template {{.data.clientSecret}}:
kubectl get secret client-secret -o yaml --namespace magic-test -o go-template
--template="{{.data.clientSecret}}"

Unable to read my newly created Kubernetes secret

I set my secret like this:
$ kubectl create secret generic aws-region VAL=eu-west-1 \
> -o yaml --dry-run | kubectl replace -f -
secret "aws-region" replaced
Seems to be set:
kubectl get secret | ack region
aws-region Opaque 0 20m
An I try to read it like this:
76 - name: AWS_REGION
77 valueFrom:
78 secretKeyRef:
79 name: aws-region
80 key: VAL
But that gives a CreateContainerConfigError when I run kubectl apply -f service.yml
What am I doing wrong?
Since you're only showing us a small part of service.yaml it's impossible to tell where the error comes from but I can confirm the following works (using a test pod I created here):
$ kubectl create secret generic aws-region --from-literal=VAL=eu-west-1
$ kubectl apply -f pod.yaml
$ kubectl describe po/envfromsecret
Name: envfromsecret
Namespace: default
...
Environment:
AWS_REGION: <set to the key 'VAL' in secret 'aws-region'> Optional: false
UPDATE: I now noticed that the DATA column in the output of your kubectl get secret command is actually 0, that is, it's empty. Consider using the form I used above (with --from-literal=) to create the secret.