Skip to content

Round-tripping secrets can leak cleartext in last-applied-configuration #227

@nicorikken

Description

@nicorikken

We're using kubeseal v0.8.1 now, with support for metadata annotations, which is nice for secrets like jenkins-credentials. But due to this change the kubectl.kubernetes.io/last-applied-configuration annotation also gets added. And in my way of using kubeseal the stringData will leak into the sealed secret this way.

Reproduce issue (my workflow)

I typically first create a secret with stringData which is convenient. I apply it, so I can test it. Then I finally read it out from the cluster, feed it through kubeseal and commit it to git. This ensures me that the stringData has been converted to data and the secret actually works. And this workflow produces this issue. Describe in more detail below:

  1. Create a secret with stringData property rather than data property for convenience in a file.

    mysecret.yaml

    stringData:
      password: secretpassword
      username: username
    kind: Secret
    metadata:
      name: "mysecret"
      namespace: default
      labels:
        "jenkins.io/credentials-type": "usernamePassword"
      annotations:
        "jenkins.io/credentials-description" : "mysecret"
    type: Opaque
    
  2. Apply the secret to the cluster.

    kubectl apply -f mysecret.yaml

  3. The secret in the cluster now has the stringData property in the spec:template:metadata:annotations:kubectl.kubernetes.io/last-applied-configuration.

  4. Checkout the secret and seal with kubeseal

    kubectl get secret mysecret -o json | kubeseal --cert cert.pem > sealed-secret.json

  5. Now the sealed-secret.json contains the secret in plaintex in the metadata:

      "kind": "SealedSecret",
      "apiVersion": "bitnami.com/v1alpha1",
      "metadata": {
        "name": "mysecret",
        "namespace": "default",
        "creationTimestamp": null
      },
      "spec": {
        "template": {
          "metadata": {
            "name": "mysecret",
            "namespace": "default",
            "creationTimestamp": null,
            "labels": {
              "jenkins.io/credentials-type": "usernamePassword"
            },
            "annotations": {
              "jenkins.io/credentials-description": "mysecret",
              "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"jenkins.io/credentials-description\":\"mysecret\"},\"labels\":{\"jenkins.io/credentials-type\":\"usernamePassword\"},\"name\":\"mysecret\",\"namespace\":\"default\"},\"stringData\":{\"password\":\"secretpassword\",\"username\":\"username\"},\"type\":\"Opaque\"}\n"
            }
          },
          "type": "Opaque"
        },
        "encryptedData": {
          "password": "...",
          "username": "..."
        }
      },
      "status": {
    
      }
    }
    
  6. The resulting secret is not safe to share or check into git.

Probably the same will happen for the data property, which is just the base64 encoded version of the stringData

What should happen

I think the best way of dealing with this issue is by stripping the last-applied-configuration when ingesting a secret.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions