This bug report is a consolidation of multiple bug reports about Secret data encoding. The intention is to share a potential approach/solution to these issues and get feedback from the community prior to implementing it.
Terraform v0.12.28
provider.kubernetes v1.11.3
kubernetes_secret
Users have expressed interest having both plaintext strings and base64 encoded data passed as arguments to the Secret resource. One proposed solution:
resource "kubernetes_secret" "example" {
 metadata {
 name = "jvm-keystore"
 }

# 'data' will be automatically encoded into base64 before reaching the kubernetes API.
 data = {
 password = "P4ssw0rd"
 }
 # base64_data can contain byte sequences that are not in the UTF-8 range. Must be base64-encoded.
 base64_data = {
 keystore = filebase64("${path.module}/client.keystore.p12")
 }

 type = "kubernetes.io/basic-auth"
}
Alternatively, we could change the name of the arg to binary_data, to be similar to config_map resource, which might be a more intuitive user experience to someone using both secrets and config maps in Terraform Kubernetes Provider.
resource "kubernetes_config_map" "example" {
metadata {
name = "example-cm"
}
data = {
api_host = "myhost:443"
}
binary_data = {
"my_payload.bin" = filebase64("${path.module}/my_payload.bin")
}
}
resource "kubernetes_secret" "example" {
 metadata {
 name = "example-secret"
 }
data = {
password = "myhost:443"
}
 binary_data = {
 keystore = filebase64("${path.module}/client.keystore.p12")
 }
Similar to the way config_map works, the keys/values of data and binary_data are merged by the Kubernetes API into a single map, which overwrites the values of any duplicate keys.
To get the desired behavior on the Kubernetes side, we would need to send data from our existing data resource argument into the stringData field of the Kubernetes API. That would handle the plaintext string values.
For the base64-encoded values, we would send those directly to the data field of the Secret resource in the Kubernetes API.
To summarize:
Our data field would correspond with Kubernetes Secret field stringData, preserving the current behavior and retaining backwards compatibility. (Thanks, @alexsomesan for this idea!)
And our binary_data field would correspond with Kubernetes data field, providing a mechanism for sending base64-encoded data directly to Kubernetes (without Terraform modifying it).
See reproducer below.
We should be able to pass a string or a base64-encoded string to the Secret resource, since the Kubernetes API supports both.
Passing a base64-encoded file or string to the provider double-encodes it, making it difficult/impossible to use. And the built-in Terraform function base64decode cannot decode non-UTF8 data. Which means we need to handle this in the provider.
I found this file useful for testing. https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
Basically, if you can find a way to get this file into a Kubernetes Secret managed by Terraform, you will have accomplished the goal of this issue. Just be sure it's not double base64-encoded, as seen below. This is the current behavior.
Reproducer:
$ cat main.tf
resource "kubernetes_secret" "example" {
metadata {
name = "example"
}
data = {
bindata = filebase64("UTF-8-test.txt")
}
}
resource "kubernetes_pod" "main" {
metadata {
name = "test-pod"
}
spec {
container {
name = "default"
image = "alpine:latest"
command = ["cat", "/etc/test/bindata"]
volume_mount {
mount_path = "/etc/test"
name = "secretvol"
}
}
volume {
name = "secretvol"
secret {
secret_name = kubernetes_secret.example.metadata[0].name
}
}
}
}
$ head -n1 UTF-8-test.txt
UTF-8 decoder capability and stress test
$ kubectl logs test-pod |base64 -d |head -n1
UTF-8 decoder capability and stress test
$ kubectl logs test-pod |base64 -d |md5sum
7e4eb1871146e5fa31063937814fd1d7 -
$ md5sum UTF-8-test.txt
7e4eb1871146e5fa31063937814fd1d7 UTF-8-test.txt
This issue has a lot of community support, so we decided to go forward with this solution (supporting both base64 data and string data in the Secret resource). Also we want to add some validation to let users know when they accidentally pass base64 encoded data to a field that doesn't support it (instead of double-encoding the data).
If anyone in the community happens to pick up this task before we do, contributions are welcome. Otherwise we'll post an update here when the issue is picked up by someone on the providers team.
(@dak1n1
Also we want to add some validation to let users know when they accidentally pass base64 encoded data to a field that doesn't support it (instead of double-encoding the data).
This sometimes could be the expected behavior: the secret string data could well be itself a base64 encoding.)
@dak1n1 Any update on this? Is this on your roadmap?
This was solved in #1228.
I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks!
Most helpful comment
This issue has a lot of community support, so we decided to go forward with this solution (supporting both base64 data and string data in the Secret resource). Also we want to add some validation to let users know when they accidentally pass base64 encoded data to a field that doesn't support it (instead of double-encoding the data).
If anyone in the community happens to pick up this task before we do, contributions are welcome. Otherwise we'll post an update here when the issue is picked up by someone on the providers team.