Creating Kubernetes Secrets Using TLS/SSL as an Example
Creating Kubernetes secrets isn’t intuitive the first time you do it. A common reason to use a secret is to add a SSL/TLS certificate to a cluster. Kubernetes provides two ways to add a secret: directly on the command line, and from a YAML source file. First, let’s generate a test certificate to work with and select our cluster.
Prerequisites
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=foo.bar.com"This command produces two files: tls.key and tls.cert. In production, you’d generate a key file and use it to obtain a certificate from a certificate authority.
Make sure you’ve selected the right Kubernetes cluster to receive your secret. In Google Cloud Platform/Google Kubernetes Engine (GKE), the command to select a Kubernetes cluster is:
gcloud container clusters get-credentials your-cluster-name --zone=your-cluster-zone
kubectl config get-contexts
kubectl config use-context gke_your-project-name_your-gcp-zone_your-cluster-name
```---
## Are you implementing Kubernetes? [Rootwork can help!](https://rootwork.it/#contact)
---
### Using the Command Line
The easiest way to create a TLS secret in Kubernetes is with the command:
```text
[code language="bash"]kubectl create secret tls test-tls --key="tls.key" --cert="tls.crt"[/code]Verify that it was added:
[code language="bash"]kubeclt get secrets[/code]To view the YAML source of the secret:
[code language="bash"]kubectl get secret test-tls -o yaml[/code]Delete the secret so we can demonstrate the next method:
[code language="bash"]kubectl delete secrets test-tls[/code]Using a YAML Source File
The major disadvantage of managing infrastructure from the command line (including creating secrets) is that it’s hard to document and reproduce. I much prefer creating files that specify the state of the system, which can be committed to a Git repo. At a minimum, get the YAML file that corresponds to your secret and save it to a private Git repo. Encrypt the repo and back it up off-site.
We can also create a YAML source file by hand and use it to create the secret, but this is a little trickier. The skeleton of the YAML file is:
[code language="yaml"]
apiVersion: v1
data:
tls.crt:
tls.key:
kind: Secret
metadata:
name: test-tls
namespace: default
type: kubernetes.io/tls
[/code]The trick is that you have to base64 encode the key and certificate data. In Bash:
[code language="bash"]
cat tls.crt | base64
cat tls.key | base64
[/code]Paste each piece of base64 encoded data into the appropriate sections of the YAML file as one line. Make sure your text editor doesn’t add any carriage returns to wrap the lines.
[code language="yaml"]
apiVersion: v1
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKakNDQWc2Z0F3SUJBZ0lKQUw2Y3R2bk9zMzlUTUEwR0NTcUdTSWIzRFFFQkJRVUFNQll4RkRBU0JnTlYKQkFNVEMyWnZieTVpWVhJdVkyOXRNQjRYRFRFNE1USXhOREUxTWpJeU1Gb1hEVEU1TVRJeE5ERTFNakl5TUZvdwpGakVVTUJJR0ExVUVBeE1MWm05dkxtSmhjaTVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3CmdnRUtBb0lCQVFDbWVsQTNqVy9NZ2REejJNazMwbXZ4K2VOSHJkQlIwMEJ4ZUR1VjBjYWVFUGNFa2RmSnk5V28KaTFpSXV1V04vZGV6UEhyTWMxenBPNGtzbWU5NThRZVFCWjNmVThWeGpRYktmb1JzNnhQUlNKZVVSckVCcWE4SQpUSXpEVVdaUTAwQ2xsa1dOejE4dDYvVjJycWxJd1VvaTVZWHloOVJsaWR4MjZRaXJBcFFFaXZDY2QzdUExc3AwCkUxRXdIVGxVdzFqSE9Eb3BLZGxaRndmcWhFSHNmYjZvLzJFb1A1MXMwY2JuTld6MHNsUjhhejdzOExVYnhBWnkKQkNQdDY1Z2VhT3hYWWUxaWhLYzN4SE4wYSsxMXpBYUdDMnpTemdOcEVWeFFJQ3lZdVZld3dNb0FrcHNkdGEybwpnMnFTaDZQZzRHeFFabzRwejIwN0c2SkFUaFIyNENiTEFnTUJBQUdqZHpCMU1CMEdBMVVkRGdRV0JCU3NBcUZoCkpPS0xZaXNHTkNVRGU4N1VWRkp0UERCR0JnTlZIU01FUHpBOWdCU3NBcUZoSk9LTFlpc0dOQ1VEZTg3VVZGSnQKUEtFYXBCZ3dGakVVTUJJR0ExVUVBeE1MWm05dkxtSmhjaTVqYjIyQ0NRQytuTGI1enJOL1V6QU1CZ05WSFJNRQpCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQU1wcDRLSEtPM2k1NzR3dzZ3eU1pTExHanpKYXI4Cm8xbHBBa3BJR3FMOHVnQWg5d2ZNQWhsYnhJcWZJRHlqNWQ3QlZIQlc1UHZweHpKV3pWbmhPOXMrdzdWRTlNVHUKWlJHSXVRMjdEeExueS9DVjVQdmJUSTBrcjcwYU9FcGlvTWYyUVUvaTBiN1B2ajJoeEJEMVZTVkd0bHFTSVpqUAo0VXZQYk1yTWZUWmJka1pIbG1SUjJmbW4zK3NTVndrZTRhWXlENVVHNnpBVitjd3BBbkZWS25VR0d3TkpVMjA4CmQrd3J2UUZ5bi9kcVBKTEdlNTkvODY4WjFCcFIxRmJYMitUVW4yWTExZ0dkL0J4VmlzeGJ0b29GQkhlVDFLbnIKTTZCVUhEeFNvWVF0VnJWSDRJMWh5UGRkdmhPczgwQkQ2K01Dd203OXE2UExaclVKOURGbFl2VTAKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBcG5wUU40MXZ6SUhRODlqSk45SnI4Zm5qUjYzUVVkTkFjWGc3bGRIR25oRDNCSkhYCnljdlZxSXRZaUxybGpmM1hzeng2ekhOYzZUdUpMSm52ZWZFSGtBV2QzMVBGY1kwR3luNkViT3NUMFVpWGxFYXgKQWFtdkNFeU13MUZtVU5OQXBaWkZqYzlmTGV2MWRxNnBTTUZLSXVXRjhvZlVaWW5jZHVrSXF3S1VCSXJ3bkhkNwpnTmJLZEJOUk1CMDVWTU5ZeHpnNktTblpXUmNINm9SQjdIMitxUDloS0QrZGJOSEc1elZzOUxKVWZHcys3UEMxCkc4UUdjZ1FqN2V1WUhtanNWMkh0WW9Tbk44UnpkR3Z0ZGN3R2hndHMwczREYVJGY1VDQXNtTGxYc01ES0FKS2IKSGJXdHFJTnFrb2VqNE9Cc1VHYU9LYzl0T3h1aVFFNFVkdUFteXdJREFRQUJBb0lCQUMvSitzOEhwZWxCOXJhWgpLNkgvb0ljVTRiNkkwYjA3ZEV0ZVpWUnJwS1ZwWDArTGdqTm1kUTN0K2xzOXMzbmdQWlF4TDFzVFhyK0JISzZWCi9kMjJhQ0pheW1mNmh6cENib21nYWVsT1RpRU13cDZJOEhUMnZjMFhGRzFaSjVMYUlidW0rSTV0MGZlL3ZYWDEKUzVrY0Mya2JGQ2w3L21lcmZJTVNBQy8vREhpRTUyV1QydEIrQk01U2FMV3p4cDhFa3NwNkxWN3ZwYmR4dGtrTwpkZ1A4QjkwWlByck5SdUN5ekRwRUkvMnhBY24yVzNidlBqRGpoTjBXdlhTbTErVk9DcXNqOEkrRkxoUzZJemVuCm1MUkFZNnpWVGpZV05TU2J3dTRkbnNmNElIOEdiQkZJajcrdlN5YVNVTEZiVGJzY3ZzQ3I1MUszbWt2bEVMVjgKaWsvMlJoa0NnWUVBMFpmV2xUTjR2alh2T0FjU1RUU3MwMFhIRWh6QXFjOFpUTEw2S1d4YkxQVFJNaXBEYklEbQp6b3BiMGNTemxlTCtNMVJCY3dqMk5HcUNodXcyczBaNTQyQVhSZXdteG1EcWJaWkFQY0UzbERQNW5wNGRpTFRCClZaMFY4UExSYjMrd2tUdE83VThJZlY1alNNdmRDTWtnekI4dU1yQ1VMYnhxMXlVUGtLdGpJdThDZ1lFQXkxYWMKWjEyZC9HWWFpQjJDcWpuN0NXZE5YdGhFS2dOYUFob21nNlFMZmlKakVLajk3SExKalFabFZ0b3kra1RrdTJjZAp0Wm1zUi9IU042YmZLbEpxckpUWWkzY2E1TGY4a3NxR0Z5Y0x1MXo3cmN6K1lUaEVWSFIyOVkrVHVWYXRDTnkzCklCOGNUQW1ORWlVMlVHR2VKeUllME44Z1VZRXRCYzFaMEg2QWllVUNnWUFETDIrUGJPelUxelQvZ1B3Q09GNjQKQjBOelB3U2VrQXN1WXpueUR6ZURnMlQ2Z2pIc0lEbGh3akNMQzVZL0hPZ0lGNnUyOTlmbURBaFh6SmM0T2tYMwo4cW5uNGlMa3VPeFhKZ1ZyNnRmUlpNalNaRXpHbXhpbEdISVE2MS9MZGdGVTg3WExYWHdmaTZPdW80cUVhNm9YCjhCRmZxOWRVcXB4bEVLY2Y1N3JsK1FLQmdGbjVSaFc2NS9oU0diVlhFWVZQU0pSOW9FK3lkRjcrd3FvaGRoOVQKekQ0UTZ6THBCQXJITkFYeDZZK0gxM3pFVlUzVEwrTTJUM1E2UGFHZ2Rpa2M5TlRPdkE3aU1nVTRvRXMzMENPWQpoR2x3bUhEc1B6YzNsWXlsU0NvYVVPeDJ2UFFwN2VJSndoU25PVVBwTVdKWi80Z2pZZTFjZmNseTFrQTJBR0x3ClJ1STlBb0dCQU14aGFJSUdwTGdmcHk0K24rai9BSWhJUUhLZFRCNVBqaGx0WWhqZittK011UURwK21OeTVMbzEKT0FRc0Q0enZ1b3VxeHlmQlFQZlllYThvcm4vTDE3WlJyc3lSNHlhS1M3cDVQYmJKQlNlcTc5Z0g5ZUNIQkxMbQo0aThCUFh0K0NmWktMQzg3NTNHSHVpOG91V25scUZ0NGxMQUlWaGJZQmtUbURZSWo4Q0NaCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
kind: Secret
metadata:
name: test-tls
namespace: default
type: kubernetes.io/tls
[/code]Finally, use the YAML file to create the secret:
[code language="bash"]kubectl create -f tls.yaml[/code]Creating a TLS Secret with Terraform
resource "kubernetes_secret" "tls" {
metadata {
name = "tls"
namespace = "web"
}
type = "tls"
data = {
"tls.crt" = var.tlscrt
"tls.key" = var.tlskey
}
}Use local variables to keep sensitive data, like the secret contents, out of your Terraform repo. Variable definition:
variable "tlscrt" {
type = string
}
variable "tlskey" {
type = string
}I prefer to put the actual secrets in a .env file, and source the file prior to running terraform. I use the .gitignore file in my Terraform repo to ensure that the .env file is never added to the repo by mistake. Here’s a sample of a .env file:
export TF_VAR_tlscrt="-----BEGIN CERTIFICATE-----
site cert here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
intermediate cert here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
CA root cert here
-----END CERTIFICATE-----"
export TF_VAR_tlskey="-----BEGIN PRIVATE KEY-----
key here
-----END PRIVATE KEY-----"Troubleshooting
See this article if you are having problems with curl/libcurl and SSL/TLS Certificates in Kubernetes!
References
- https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/
- https://kubernetes.io/docs/concepts/configuration/secret/
Comments
Comment #1 by Hello
Hello - Apr 4, 2020
This page saves me from days of chaos!!
Comment #2 by Arjun
Arjun - Sep 3, 2020
Can we add the ca.crt also to this secret?
Comment #3 by shiva
shiva - Oct 3, 2020
same question I have?
Comment #4 by Guillermo
Guillermo - Dec 2, 2020
Hello, there is a typo at: kubeclt get secrets
Comment #5 by Stan Halen
Stan Halen - Feb 4, 2021
FYI: You can use base64 -w 0 to prevent word-wrap
Comment #6 by Promise
Promise - Mar 3, 2023
You can as well use the kubectl create secret command to generate the yaml file: kubectl create secret tls my-certificate-name \ –cert=my-cert-file.crt \ –key=my-private.key \ –namespace my-namespace \ –dry-run=client -o yaml > my-certificate.yaml Then run the kubectl apply command: kubectl apply -f my-certificate.yaml