Files
Jérôme Petazzoni b56e54eaec ♻️ s/exercise/lab/
Now that we have a good number of longer exercises, it makes
sense to rename the shorter demos/labs into 'labs' to avoid
confusion between the two.
2021-12-29 17:18:07 +01:00

339 lines
7.2 KiB
Markdown

# Sealed Secrets
- Kubernetes provides the "Secret" resource to store credentials, keys, passwords ...
- Secrets can be protected with RBAC
(e.g. "you can write secrets, but only the app's service account can read them")
- [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) is an operator that lets us store secrets in code repositories
- It uses asymetric cryptography:
- anyone can *encrypt* a secret
- only the cluster can *decrypt* a secret
---
## Principle
- The Sealed Secrets operator uses a *public* and a *private* key
- The public key is available publicly (duh!)
- We use the public key to encrypt secrets into a SealedSecret resource
- the SealedSecret resource can be stored in a code repo (even a public one)
- The SealedSecret resource is `kubectl apply`'d to the cluster
- The Sealed Secrets controller decrypts the SealedSecret with the private key
(this creates a classic Secret resource)
- Nobody else can decrypt secrets, since only the controller has the private key
---
## In action
- We will install the Sealed Secrets operator
- We will generate a Secret
- We will "seal" that Secret (generate a SealedSecret)
- We will load that SealedSecret on the cluster
- We will check that we now have a Secret
---
## Installing the operator
- The official installation is done through a single YAML file
- There is also a Helm chart if you prefer that
(if you're using Kubernetes 1.22+, see next slide!)
<!-- #VERSION# -->
.lab[
- Install the operator:
.small[
```bash
kubectl apply -f \
https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.16.0/controller.yaml
```
]
]
Note: it installs into `kube-system` by default.
If you change that, you will also need to inform `kubeseal` later on.
---
class: extra-details
## Sealed Secrets on Kubernetes 1.22
- As of version 0.16, Sealed Secrets manifests uses RBAC v1beta1
- RBAC v1beta1 isn't supported anymore in Kubernetes 1.22
- Sealed Secerets Helm chart provides manifests using RBAC v1
- Conclusion: to install Sealed Secrets on Kubernetes 1.22, use the Helm chart:
```bash
helm install --repo https://bitnami-labs.github.io/sealed-secrets/ \
sealed-secrets-controller sealed-secrets --namespace kube-system
```
- Make sure to install in the `kube-system` Namespace
- Make sure that the release is named `sealed-secrets-controller`
(or pass a `--controller-name` option to `kubeseal` later)
---
## Creating a Secret
- Let's create a normal (unencrypted) secret
.lab[
- Create a Secret with a couple of API tokens:
```bash
kubectl create secret generic awskey \
--from-literal=AWS_ACCESS_KEY_ID=AKI... \
--from-literal=AWS_SECRET_ACCESS_KEY=abc123xyz... \
--dry-run=client -o yaml > secret-aws.yaml
```
]
- Note the `--dry-run` and `-o yaml`
(we're just generating YAML, not sending the secrets to our Kubernetes cluster)
- We could also write the YAML from scratch or generate it with other tools
---
## Creating a Sealed Secret
- This is done with the `kubeseal` tool
- It will obtain the public key from the cluster
.lab[
- Create the Sealed Secret:
```bash
kubeseal < secret-aws.yaml > sealed-secret-aws.json
```
]
- The file `sealed-secret-aws.json` can be committed to your public repo
(if you prefer YAML output, you can add `-o yaml`)
---
## Using a Sealed Secret
- Now let's `kubectl apply` that Sealed Secret to the cluster
- The Sealed Secret controller will "unseal" it for us
.lab[
- Check that our Secret doesn't exist (yet):
```bash
kubectl get secrets
```
- Load the Sealed Secret into the cluster:
```bash
kubectl create -f sealed-secret-aws.json
```
- Check that the secret is now available:
```bash
kubectl get secrets
```
]
---
## Tweaking secrets
- Let's see what happens if we try to rename the Secret
(or use it in a different namespace)
.lab[
- Delete both the Secret and the SealedSecret
- Edit `sealed-secret-aws.json`
- Change the name of the secret, or its namespace
(both in the SealedSecret metadata and in the Secret template)
- `kubectl apply -f` the new JSON file and observe the results 🤔
]
---
## Sealed Secrets are *scoped*
- A SealedSecret cannot be renamed or moved to another namespace
(at least, not by default!)
- Otherwise, it would allow to evade RBAC rules:
- if I can view Secrets in namespace `myapp` but not in namespace `yourapp`
- I could take a SealedSecret belonging to namespace `yourapp`
- ... and deploy it in `myapp`
- ... and view the resulting decrypted Secret!
- This can be changed with `--scope namespace-wide` or `--scope cluster-wide`
---
## Working offline
- We can obtain the public key from the server
(technically, as a PEM certificate)
- Then we can use that public key offline
(without contacting the server)
- Relevant commands:
`kubeseal --fetch-cert > seal.pem`
`kubeseal --cert seal.pem < secret.yaml > sealedsecret.json`
---
## Key rotation
- The controller generate new keys every month by default
- The keys are kept as TLS Secrets in the `kube-system` namespace
(named `sealed-secrets-keyXXXXX`)
- When keys are "rotated", old decryption keys are kept
(otherwise we can't decrypt previously-generated SealedSecrets)
---
## Key compromise
- If the *sealing* key (obtained with `--fetch-cert` is compromised):
*we don't need to do anything (it's a public key!)*
- However, if the *unsealing* key (the TLS secret in `kube-system`) is compromised ...
*we need to:*
- rotate the key
- rotate the SealedSecrets that were encrypted with that key
<br/>
(as they are compromised)
---
## Rotating the key
- By default, new keys are generated every 30 days
- To force the generation of a new key "right now":
- obtain an RFC1123 timestamp with `date -R`
- edit Deployment `sealed-secrets-controller` (in `kube-system`)
- add `--key-cutoff-time=TIMESTAMP` to the command-line
- *Then*, rotate the SealedSecrets that were encrypted with it
(generate new Secrets, then encrypt them with the new key)
---
## Discussion (the good)
- The footprint of the operator is rather small:
- only one CRD
- one Deployment, one Service
- a few RBAC-related objects
---
## Discussion (the less good)
- Events could be improved
- `no key to decrypt secret` when there is a name/namespace mismatch
- no event indicating that a SealedSecret was successfully unsealed
- Key rotation could be improved (how to find secrets corresponding to a key?)
- If the sealing keys are lost, it's impossible to unseal the SealedSecrets
(e.g. cluster reinstall)
- ... Which means that we need to back up the sealing keys
- ... Which means that we need to be super careful with these backups!
---
## Other approaches
- [Kamus](https://kamus.soluto.io/) ([git](https://github.com/Soluto/kamus)) offers "zero-trust" secrets
(the cluster cannot decrypt secrets; only the application can decrypt them)
- [Vault](https://learn.hashicorp.com/tutorials/vault/kubernetes-sidecar?in=vault/kubernetes) can do ... a lot
- dynamic secrets (generated on the fly for a consumer)
- certificate management
- integration outside of Kubernetes
- and much more!
???
:EN:- The Sealed Secrets Operator
:FR:- L'opérateur *Sealed Secrets*