Is there a strategy for encrypting Kubernetes secr...
# general
e
Is there a strategy for encrypting Kubernetes secret resources? There is sensitive data in them being saved in state that I would like to protect. The output value can be encrypted, but the input is not encrypted.
s
What do you mean by "the input is not encrypted"? Do you think this would solve your issue: https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/pulumi/#secret
e
I don’t think so, but maybe I’m not implementing this correctly. I’m using Golang. This is what I wrote
Copy code
TestSecret := pulumi.ToSecret("something-secret")

TestSecret.ApplyT(func(secret string) (*core.Secret, error) {
	b64 := base64.StdEncoding.EncodeToString([]byte(secret))

	return core.NewSecret(ctx, "test-secret", &core.SecretArgs{
		ApiVersion: pulumi.StringPtr("v1"),
		Metadata: &meta.ObjectMetaArgs{
			Name:      pulumi.StringPtr("test"),
			Namespace: pulumi.StringPtr("harness-delegate"),
		},
		Type: pulumi.StringPtr("Opaque"),
		Data: pulumi.ToStringMap(map[string]string{
			"test": b64,
		}),
	})
})
and this is the state
Copy code
{
    "urn": "urn:pulumi:esus-k8s-play-5-a::r1-compute-infra::kubernetes:core/v1:Secret::test-secret",
    "custom": true,
    "id": "harness-delegate/test",
    "type": "kubernetes:core/v1:Secret",
    "inputs": {
        "apiVersion": "v1",
        "data": {
            "test": "c29tZXRoaW5nLXNlY3JldA=="
        },
        "kind": "Secret",
        "metadata": {
            "labels": {
                "<http://app.kubernetes.io/managed-by|app.kubernetes.io/managed-by>": "pulumi"
            },
            "name": "test",
            "namespace": "harness-delegate"
        },
        "type": "Opaque"
    },
    "outputs": {
        "__initialApiVersion": "v1",
        "__inputs": {
            "apiVersion": "v1",
            "data": {
                "test": "c29tZXRoaW5nLXNlY3JldA=="
            },
            "kind": "Secret",
            "metadata": {
                "labels": {
                    "<http://app.kubernetes.io/managed-by|app.kubernetes.io/managed-by>": "pulumi"
                },
                "name": "test",
                "namespace": "harness-delegate"
            },
            "type": "Opaque"
        },
        "apiVersion": "v1",
        "data": {
            "4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
            "ciphertext": "v1:yRpxGYFgl0f6ceE+:zOvx3ZrvJWKAYeu8N3A+1PN2K1VtA7vCwFXceVY1qJNnEHucxtuyZWAPWMG9vA9zbwZv"
        },
        "kind": "Secret",
        "metadata": {
            "annotations": {
                "<http://kubectl.kubernetes.io/last-applied-configuration|kubectl.kubernetes.io/last-applied-configuration>": "{\"apiVersion\":\"v1\",\"data\":{\"test\":\"c29tZXRoaW5nLXNlY3JldA==\"},\"kind\":\"Secret\",\"metadata\":{\"labels\":{\"<http://app.kubernetes.io/managed-by\|app.kubernetes.io/managed-by\>":\"pulumi\"},\"name\":\"test\",\"namespace\":\"harness-delegate\"},\"type\":\"Opaque\"}\n"
            },
            "creationTimestamp": "2021-05-14T15:30:31Z",
            "labels": {
                "<http://app.kubernetes.io/managed-by|app.kubernetes.io/managed-by>": "pulumi"
            },
            "managedFields": [
                {
                    "apiVersion": "v1",
                    "fieldsType": "FieldsV1",
                    "fieldsV1": {
                        "f:data": {
                            ".": {},
                            "f:test": {}
                        },
                        "f:metadata": {
                            "f:annotations": {
                                ".": {},
                                "f:<http://kubectl.kubernetes.io/last-applied-configuration|kubectl.kubernetes.io/last-applied-configuration>": {}
                            },
                            "f:labels": {
                                ".": {},
                                "f:<http://app.kubernetes.io/managed-by|app.kubernetes.io/managed-by>": {}
                            }
                        },
                        "f:type": {}
                    },
                    "manager": "pulumi-resource-kubernetes",
                    "operation": "Update",
                    "time": "2021-05-14T15:30:31Z"
                }
            ],
            "name": "test",
            "namespace": "harness-delegate",
            "resourceVersion": "52444093",
            "selfLink": "/api/v1/namespaces/harness-delegate/secrets/test",
            "uid": "7831e616-ec55-490c-a7df-62cf1c3a4192"
        },
        "type": "Opaque"
    },
    "parent": "urn:pulumi:esus-k8s-play-5-a::r1-compute-infra::pulumi:pulumi:Stack::r1-compute-infra-esus-k8s-play-5-a",
    "provider": "urn:pulumi:esus-k8s-play-5-a::r1-compute-infra::pulumi:providers:kubernetes::default::a5b90831-b0d4-4814-8c74-e2496b95e19f",
    "propertyDependencies": {
        "apiVersion": [],
        "data": [],
        "kind": [],
        "metadata": [],
        "type": []
    },
    "additionalSecretOutputs": [
        "data",
        "stringData"
    ]
}
You can see the secret is not encrypted. This a security problem. I think something like this is more ideal, but
Data
needs to accept a
map[string]pulumi.StringOutput
for it to work.
Copy code
core.NewSecret(ctx, "test-secret", &core.SecretArgs{
		ApiVersion: pulumi.StringPtr("v1"),
		Metadata: &meta.ObjectMetaArgs{
			Name:      pulumi.StringPtr("test"),
			Namespace: pulumi.StringPtr("test"),
		},
		Type: pulumi.StringPtr("Opaque"),
		Data: pulumi.ToStringMap(map[string]string{
			"test": TestSecret.ApplyT(func(secret string) string {
					b64 := base64.StdEncoding.EncodeToString([]byte(secret))
					return b64
				}).(pulumi.StringOutput),
			}),
		})
g
Copy code
_, err = corev1.NewSecret(ctx, "test", &corev1.SecretArgs{
			StringData: pulumi.StringMap{"mysecret": pulumi.ToSecret(pulumi.String("secret")).(pulumi.StringOutput)},
		})
This should do what you want.
ToSecret
returns an
Output
, but you can use a type assertion if you’re wrapping a
pulumi.String
value like this.
We automatically mark k8s Secret
data
and
stringData
outputs as secret, but your original example was just representing the inputs as raw string data, so Pulumi didn’t know to mark it as secret.
e
Thanks Levi! This is great! I also saw your PR improvement too.
🎉 1
Using map[string]string was a result of my autocomplete. I’ll be more careful to stay in the Pulumi work using your objects. Very happy to have this resolved now!