In Kubernetes, Secrets are similar to ConfigMaps but specifically designed for storing and managing sensitive information such as passwords, API keys, tokens, or any other confidential data that should not be exposed in plaintext.
Like ConfigMaps, Secrets are created using YAML or JSON manifests and can be managed through the Kubernetes API or tools like kubectl. However, Secrets have an additional layer of security and are encoded in Base64 format when stored in the cluster.
Secrets are primarily used to provide sensitive data to applications running in containers, ensuring that the data remains secure and protected from unauthorized access. They can be mounted as volumes or exposed as environment variables in the application containers, allowing them to access the secret data during runtime.
Compared to ConfigMaps, Secrets have a few key differences:
It's crucial to follow security best practices when using Secrets, such as limiting access, rotating the secrets regularly, and using encryption mechanisms (like TLS) for transport-level security.
NOTE: I wouldn't recommend using Kubernetes secrets for real world applications due to the limitations such as lack of encryption. Instead I would research the best approach for your use-case. For example if you are already tied into a cloud providers ecosystem such as Azure or AWS then Microsoft Azure Key Vault or AWS Secrets Manager would be worth investigating.
To run the example I had the following tools/software installed:
I also setup a alias for kubectl using the following command:
Set-Alias -Name k -Value kubectl
Make sure minikube is up and running:
minikube start
> k create secret generic db-user-pass --from-literal=username=admin --from-literal=password='S!B\*d$zDsb='
secret/db-user-pass created
> k get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 2 115s
Create a deployment and service definition using the following content for a secret-deploy.yaml
file.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
name: my-app
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: matthewregis/public:dotnet-display-env-var
ports:
- containerPort: 80
env:
- name: username
valueFrom:
secretKeyRef:
key: username
name: db-user-pass
- name: password
valueFrom:
secretKeyRef:
key: password
name: db-user-pass
replicas: 1
---
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 80
type: NodePort
Apply deployment and service
> k apply -f .\secret-deploy.yaml
deployment.apps/my-app-deployment created
service/my-app-service created
> minikube service my-app-service
|-----------|----------------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|----------------|-------------|---------------------------|
| default | my-app-service | 80 | http://192.168.49.2:30244 |
|-----------|----------------|-------------|---------------------------|
🏃 Starting tunnel for service my-app-service.
|-----------|----------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|----------------|-------------|------------------------|
| default | my-app-service | | http://127.0.0.1:55096 |
|-----------|----------------|-------------|------------------------|
🎉 Opening service default/my-app-service in default browser...
❗ Because you are using a Docker driver on windows, the terminal needs to be open to run it.
✋ Stopping tunnel for service my-app-service.
This opened a web browser and I was able to verify the username and password as environment variables were set and they also have the value I had set originally in step 1.
> k delete service my-app-service
service "my-app-service" deleted
> k delete deployment my-app-deployment
deployment.apps "my-app-deployment" deleted
> k delete secret db-user-pass
secret "db-user-pass" deleted