Skip to content

Kubernetes mutating webhook decrypting configmaps and secrets encrypted with Spring Cloud Config asymmetric key

License

Notifications You must be signed in to change notification settings

grepplabs/spring-config-decryptor-webhook

Repository files navigation

spring-config-decryptor-webhook

WARNING: DO NOT USE IN PRODUCTION

Kubernetes mutating webhook decrypting configmaps and secrets encrypted with Spring Cloud Config asymmetric key.

Do not use in production as webhook http endpoint is unprotected and allows decryption of arbitrary secrets

Usage example

Prerequisites:

1.Generate RSA key pair

$ openssl genrsa -out rsa-private-key.pem 4096
$ openssl rsa -in rsa-private-key.pem -outform PEM -pubout -out rsa-public-key.pem

2.Create kubernetes secret with RSA private key

$ kubectl create namespace webhook
$ kubectl create secret generic spring-encrypt-key -n  webhook --from-file=rsa-private-key=rsa-private-key.pem

3.Deploy mutating webhook to kubernetes

Depending on your kubernetes installation change helm values and invoke make accordingly.

$ make HELM_VALUES=values-eks.yaml KUBE_CONTEXT=test-cluster helm-install

4.Check the deployment

$ kubectl get all -n webhook
NAME                                                   READY   STATUS    RESTARTS   AGE
pod/spring-config-decryptor-webhook-7c8bfc8d54-dw8dc   1/1     Running   0          5m50s

NAME                                      TYPE           CLUSTER-IP      EXTERNAL-IP                                                                           PORT(S)         AGE
service/spring-config-decryptor-webhook   LoadBalancer   172.20.30.252   internal-a785e316153b849e7bbee4001035c7ba-1452171545.eu-central-1.elb.amazonaws.com   443:32458/TCP   5m50s

NAME                                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/spring-config-decryptor-webhook   1/1     1            1           5m50s

NAME                                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/spring-config-decryptor-webhook-7c8bfc8d54   1         1         1       5m50s

$ kubectl get secrets -n webhook
NAME                                                    TYPE                                  DATA   AGE
default-token-vw4bg                                     kubernetes.io/service-account-token   3      3d2h
sh.helm.release.v1.spring-config-decryptor-webhook.v1   helm.sh/release.v1                    1      6m42s
spring-config-decryptor-webhook-certificate             kubernetes.io/tls                     3      6m42s
spring-config-decryptor-webhook-token-wlshn             kubernetes.io/service-account-token   3      6m42s
spring-encrypt-key                                      Opaque

5.Check cert-manager injected caBundle into mutatingwebhookconfigurations

$ kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io spring-config-decryptor-webhook -o json | jq -r '.webhooks[].clientConfig'
{
  "caBundle": "LS0tLS1CRUdJTiBDRVJUSUZ....",
}
{
  "caBundle": "LS0tLS1CRUdJTiBDRVJUSUZ....",
}

6.Create RSA encrypted test-secret secret with spring-config-decrypt=true label. Prefix the encrypted password value with{cipher}

ENCRYPTED_PASSWORD=$(spring encrypt --key @./rsa-public-key.pem my-password)
kubectl create secret generic test-secret --from-literal="username=my-app" --from-literal="password={cipher}${ENCRYPTED_PASSWORD}" -o yaml --dry-run | kubectl label -f- --dry-run -o yaml --local spring-config-decrypt="true" | kubectl apply -n webhook -f -

Check the mutating webhook decrypted the secret, and it is store in the plain text.

$ kubectl get secrets -n webhook test-secret -o json | jq -r '.data.password' | base64 -d
my-password

7.Create RSA encrypted test-cm configmap. Prefix secret property value with{cipher}

ENCRYPTED_VALUE=$(spring encrypt --key @./rsa-public-key.pem value2)
kubectl create configmap test-cm -n webhook --from-literal key1=value1 --from-literal "key2={cipher}${ENCRYPTED_VALUE}"

Check key2 is still encrypted

$ kubectl get configmaps -n webhook test-cm -o json | jq '.data'
{
  "key1": "value1",
  "key2": "{cipher}AgBBmob53tmsrm8ufAyVeSjLa3WDvRxa6OTLa5gDpG7wp5qoHZ90W78Fn117LOQ6QgrQ+N4TgoIZsS2dbNeYK+UrPr2hXgw+aHqUFxflifnA4KwfVNIHVQ2Z+XafJw2eaMh7ARUhxnWw2LPWM6M9LNCPJe9oExp/tW/6UOZLCfApVLVyEursRNMfGCeUDQB/2QfFKfgIExMbwkdPhUpjSokwgYjZy9fgNFNMY0Ovq4XNPISEwaNmKs5OskhMAdvfmUZnQ89ipDFK3pD+N//EHm0b6Bax2pNcIVMYe3296YQrvJ6Uh/bfdblVii6PLgyjAiEpxzYN4Q+sbq338C2IZoSZiAqLJzSWel5bwrzbUPKGJmiYRbIyhHVtuupw8L/oiRVxzx3iQcfXqvXE2k6gNNQ4JwqlUmrQq0eH5v9/GE/BMuIhLi13oTia1DGjSMxgzO/zdtG0By0c374fmH07O+Yxspg8rf4PDZWhprCrEvgXI7XTHjr8yk1rmZSZ/Cg4+E1Wp+yf89hSKQurjQC8ycIvljTF8ng5HaLl+Xzq3jber/Wzsu1zddunb06uzM3KeZgxvGFo3ZIuk+JZfskDCDa+MqCO81lIMe3oFT6u0ywciA3Vems5O36eitv5UOT569n6mY3pLwGQNVv+0M4QxR0XINM/WnJ8UPr2uzlAa6ckMlkwBxABTMK2C5bj8IAUUuEtPXLI/FLnDxywju7un7sV"
}

Label the config map with spring-config-decrypt=true and check the decrypted secret

$ kubectl label configmap -n webhook test-cm spring-config-decrypt=true
$ kubectl get configmaps -n webhook test-cm -o json | jq '.data'
{
  "key1": "value1",
  "key2": "value2"
}