Skip to content

Commit

Permalink
Add an example of secret injection in legacy config file
Browse files Browse the repository at this point in the history
  • Loading branch information
Marko Mikulicic committed Oct 7, 2019
1 parent 466ed46 commit e3f771c
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 3 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,11 +445,11 @@ $ jb install --jsonnetpkg-home=vendor_jsonnet

## FAQ

- Will you still be able to decrypt if you no longer have access to your cluster?
### Will you still be able to decrypt if you no longer have access to your cluster?

No, the private key is only stored in the Secret managed by the controller (unless you have some other backup of your k8s objects). There are no backdoors - without that private key, then you can't decrypt the SealedSecrets. If you can't get to the Secret with the encryption key, and you also can't get to the decrypted versions of your Secrets live in the cluster, then you will need to regenerate new passwords for everything, seal them again with a new sealing key, etc.

- How can I do a backup of my SealedSecrets?
### How can I do a backup of my SealedSecrets?

If you do want to make a backup of the encryption private key, it's easy to do from an account with suitable access and:

Expand All @@ -466,10 +466,19 @@ $ kubectl replace -f master.key
$ kubectl delete pod -n kube-system -l name=sealed-secrets-controller
```

- What flags are available for kubeseal?
### What flags are available for kubeseal?

You can check the flags available using `kubeseal --help`.

### How do I update parts of JSON/YAML/TOML.. file encrypted with sealed secrets?

A kubernetes secret resource contains multiple items, basically a flat map of key/value pairs.
SealedSecrets operate at that level, and does not care what you put in the values. In other words
it cannot make sense of any structured configuration file you might have put in a secret and thus
cannot help you update individual fields in it.

Since this is a common problem, especially when dealing with legacy applications, we do offer an [example](docs/examples/config-template) of a possible workaround.

## Community

- [#sealed-secrets on Kubernetes Slack](https://kubernetes.slack.com/messages/sealed-secrets)
Expand Down
18 changes: 18 additions & 0 deletions docs/examples/config-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Injecting secrets in config file templates

Kubernetes Secrets are very flexible and can be consumed in many ways.
Secret values can be passed to containers as environment variables or appear as regular files when mounting secret volumes.

Often users end up using the latter method just to wrap full configuration files into k8s secrets, just
because one or more fields in the config file happen to be secrets (e.g. a database password, or a session cookie encryption key).

Ideally you should avoid configuring your software that way, instead split your configuration from your secrets somehow. Also make sure you know about [12 Factor](https://www.12factor.net/).

That said, there are circumstances where you just have to provide such a file to your application (perhaps because it's a legacy app) and encrypting the whole configuration file in a single SealedSecrets item is problematic:

* You cannot easily update individual secret values (e.g. rotate your DB password), without first decrypting the whole configuration file.
* Since the whole configuration file is encrypted, it's hard to view, change (and review) non-secret parts of the config.

This example shows a possible approach to split the non-secret part of the config into a ConfigMap, and rely on a simple "Init Container" to merge the actual secret values back into it.

The example here includes an example Secret resource, which since you're reading this as part of the sealed-secrets documentation, you'd probably pass through `kubeseal` before checking it in; that said this approach is not limited to sealed-secrets.
38 changes: 38 additions & 0 deletions docs/examples/config-template/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: example
data:
myconfig.json.tmpl: |
{
"Server": [{
"host": "foobar",
"ip": "10.10.10.12",
"port": "22",
"env": "SOME_ENV",
"user": "myuser",
"password": "{{ (ds "secrets").server1 }}",
"role": "foo"
},{
"host": "barfoo",
"ip": "10.10.10.11",
"port": "22",
"env": "SOME_OTHER_STUFF",
"user": "otheruser",
"password": "{{ (ds "secrets").server2 }}",
"role": "foo"
}
],
"Database": [{
"host": "somedb",
"ip": "10.10.10.10",
"port": "1521",
"sid": "FOO",
"env": "BAZ",
"user": "abcdefg123",
"password": "{{ (ds "secrets").database1 }}",
"role": "foo"
}
]
}
58 changes: 58 additions & 0 deletions docs/examples/config-template/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example
spec:
selector:
matchLabels:
app: example
template:
metadata:
labels:
app: example
spec:
initContainers:
- name: inject-secrets
image: hairyhenderson/gomplate:alpine
volumeMounts:
# The /secrets directory will contain one file per sercret item.
# The secret item's key will become the file name, while its value goes in the file contents.
- name: config-secrets-volume
mountPath: /secrets
# The config map containing the config file template will be available here.
- name: config-template-volume
mountPath: /input
# While the expanded template will be put in a volume shared with the application which will run
# in the main container when this init container is done.
- name: config-volume
mountPath: /output
# Now we can actually run the template expander and inject secrets into the template.
command: ["sh", "-c"]
args:
- gomplate -d secrets=/secrets/ </input/myconfig.json.tmpl >/output/myconfig.json
containers:
# This is an example application that assumes a complex configuration file in /config/myconfig.json.
# The JSON format here is just an example; any textual file format would work.
- name: app
image: bitnami/minideb:buster
volumeMounts:
- name: config-volume
mountPath: /config
command: ["sh", "-c"]
args:
- |
echo Your app will get this config file:
cat /config/myconfig.json
# dummy application
sleep 100000h
volumes:
- name: config-volume
emptyDir: {}
- name: config-template-volume
configMap:
name: example
- name: config-secrets-volume
secret:
secretName: example

9 changes: 9 additions & 0 deletions docs/examples/config-template/secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
apiVersion: v1
kind: Secret
metadata:
name: example
stringData:
server1: foo
server2: bar
database1: baz

0 comments on commit e3f771c

Please sign in to comment.