From f4b9c8000fbd6581ab013030d766267d2d96211d Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 2 Aug 2020 23:34:19 +0200 Subject: [PATCH] Add example --- .gitattributes | 2 + example/README.md | 124 +++++++++++++++++++++++++++++++++++ example/client/Dockerfile | 13 ++++ example/client/client.cert | 3 + example/client/coffer-client | 3 + example/config.toml | 3 + example/docker-compose.yml | 21 ++++++ example/server/Dockerfile | 13 ++++ example/server/coffer-server | 3 + example/server/config.enc | 3 + example/server/server.cert | 3 + 11 files changed, 191 insertions(+) create mode 100644 example/README.md create mode 100644 example/client/Dockerfile create mode 100644 example/client/client.cert create mode 100755 example/client/coffer-client create mode 100644 example/config.toml create mode 100644 example/docker-compose.yml create mode 100644 example/server/Dockerfile create mode 100755 example/server/coffer-server create mode 100644 example/server/config.enc create mode 100644 example/server/server.cert diff --git a/.gitattributes b/.gitattributes index 70e065a..5a6e95a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,5 @@ *.cert filter=lfs diff=lfs merge=lfs -text overview.png filter=lfs diff=lfs merge=lfs -text overview.svg filter=lfs diff=lfs merge=lfs -text +coffer-client filter=lfs diff=lfs merge=lfs -text +coffer-server filter=lfs diff=lfs merge=lfs -text diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..ec4cfcc --- /dev/null +++ b/example/README.md @@ -0,0 +1,124 @@ +Here you can find a simple example on how to run coffer. + +# Run the example + +To run the example, simply execute: + +```shell +docker-compose up +``` + +This should print out: + +```shell + @@@@@@@ @@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@ +@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ +!@@ @@! @@@ @@! @@! @@! @@! @@@ +!@! !@! @!@ !@! !@! !@! !@! @!@ +!@! @!@ !@! @!!!:! @!!!:! @!!!:! @!@!!@! +!!! !@! !!! !!!!!: !!!!!: !!!!!: !!@!@! +:!! !!: !!! !!: !!: !!: !!: :!! +:!: :!: !:! :!: :!: :!: :!: !:! + ::: ::: ::::: :: :: :: :: :::: :: ::: + :: :: : : : : : : : :: :: : : : + +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +TERM=xterm +container=podman +HOSTNAME=f7a1614d8752 +HOME=/root +CLIENT_SECRET=SECRETKEY +client +0 +``` + +Where `CLIENT_SECRET` is the secret set into the environment of `printenv` in +the client. `printenv` is the coffer'ed process. + +Note that if you connect to a shell in the client container you are not able to +retrieve the secret. The secret _only_ exists in the environment of the +coffer'ed process. It does not even exist in some parent process of the +coffer'ed process, as coffer reaps itself while starting the sub-process. This +is quite different from other alternatives that either set the secrets into the +environment of the container, or into a volume on the container. Both of which +are accessible (with more or less effort) from anyone that has access to the +container. + +Also note how the whole server container, despite being able to service hundreds +of clients in parallel, uses less than 3 MB in total. + +# Setup and Configuration +In this example we create a [coffer server](server/Dockerfile) with some [client secrets](config.toml) +and a simple [client container](client/Dockerfile). The container are built, run and connected a shared +network via [docker-compose](docker-compose.yml). + +Both, the client and the server, need a certificate. The client for +authenticating with the server, and the server for decrypting the client +secrets. + +Certificates can be generated with: +```shell +coffer-companion certificate certificate.cert +``` + +Furthermore, the secrets need to be authorized. Even though a coffer server can +handle secrets for multiple clients, a client can only request its own secrets. +Secrets retrieval is authorized by the public key of the client. You can get the +public key by +```shell +coffer-companion info certificate.cert +``` + +The public key must be put into the `id` section of a secret. For +example, our [secrets](config.toml) contain a section like this: +```toml +[client] +id = "452B0788D966059B21DB04FF37BC6161072B15EA2CDF88A5040FEEAB89D1143A" +CLIENT_SECRET = "SECRETKEY" +``` + +Finally, the promise of coffer is that certificates are the fundamental trust +anchor. This also means they are the _only_ thing you have to care about for +security of your secrets. Consequently, [secrets themselves are encrypted](server/config.enc) +with the server certificate: +```shell +coffer-companion encrypt --certificate certificate.cert --out config.enc --yaml config.toml +``` + +# Encoffering the client +You may have noticed that the actual client program (`printenv`) is not run +directly. Instead the [Dockerfile](client/Dockerfile) contains an entrypoint like this: +```Dockerfile +ENTRYPOINT ["coffer-client"] + +CMD ["--certificate", "client.cert", \ + "--server-address", "server:9187", \ + "--", \ + "printenv"] +``` + +The coffer client will connect to the server and retrieve its secrets. +Afterwards it sets the secrets into the process environment and replaces its own +process image with the coffer'ed command. + +The major drawback of this approach is that you have to build your own images. +If you want to coffer your own software this is probably only a minor +inconvenience. For pre-build images like e.g. the official +[postgres](https://hub.docker.com/_/postgres) image this means you have to +derive your own image for and coffer the entrypoint. For postgres this might +look like: +```Dockerfile +FROM postgres:12-alpine + +COPY ./coffer-client /usr/local/bin +COPY ./postgres.cert . + +ENTRYPOINT ["coffer-client", \ + "--certificate", "postgres.cert", + "--server-address", "server:9187", + "--", + "docker-entrypoint.sh"] + +CMD ["postgres"] + +``` diff --git a/example/client/Dockerfile b/example/client/Dockerfile new file mode 100644 index 0000000..9da8427 --- /dev/null +++ b/example/client/Dockerfile @@ -0,0 +1,13 @@ +FROM busybox + +RUN mkdir -p /usr/local/bin + +COPY ./coffer-client /usr/local/bin +COPY ./client.cert . + +ENTRYPOINT ["coffer-client"] + +CMD ["--certificate", "client.cert", \ + "--server-address", "server:9187", \ + "--", \ + "printenv"] diff --git a/example/client/client.cert b/example/client/client.cert new file mode 100644 index 0000000..075fe23 --- /dev/null +++ b/example/client/client.cert @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd30cde22ff081c15729db6c1413dd52ed5e01be12c90610ed7cf3eff19677f4 +size 92 diff --git a/example/client/coffer-client b/example/client/coffer-client new file mode 100755 index 0000000..7a7dec8 --- /dev/null +++ b/example/client/coffer-client @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e65f3ede48aebf13ac062932dcbf3c880fe3871decfc070615a6846cccd6d037 +size 1956064 diff --git a/example/config.toml b/example/config.toml new file mode 100644 index 0000000..56ea4a6 --- /dev/null +++ b/example/config.toml @@ -0,0 +1,3 @@ +[client] +id = "452B0788D966059B21DB04FF37BC6161072B15EA2CDF88A5040FEEAB89D1143A" +CLIENT_SECRET = "SECRETKEY" diff --git a/example/docker-compose.yml b/example/docker-compose.yml new file mode 100644 index 0000000..f4226e2 --- /dev/null +++ b/example/docker-compose.yml @@ -0,0 +1,21 @@ +version: "3" + +services: + server: + container_name: server + build: + context: ./server/ + networks: + - coffer + + client: + container_name: client + build: + context: ./client/ + networks: + - coffer + depends_on: + - server + +networks: + coffer: diff --git a/example/server/Dockerfile b/example/server/Dockerfile new file mode 100644 index 0000000..e36d0a6 --- /dev/null +++ b/example/server/Dockerfile @@ -0,0 +1,13 @@ +FROM gcr.io/distroless/static + +COPY ./coffer-server . +COPY ./server.cert . +COPY ./config.enc . + + +EXPOSE 9187 +ENTRYPOINT ["./coffer-server"] + +CMD ["--certificate", "server.cert", \ + "--secrets", "config.enc", \ + "--address", "0.0.0.0:9187"] diff --git a/example/server/coffer-server b/example/server/coffer-server new file mode 100755 index 0000000..20f49f6 --- /dev/null +++ b/example/server/coffer-server @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:723f0e9bae709df909dd1f9412669c49bfbfbde254a871d812700d01b56c3d96 +size 2361680 diff --git a/example/server/config.enc b/example/server/config.enc new file mode 100644 index 0000000..7c2d299 --- /dev/null +++ b/example/server/config.enc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9745332c86735794edf48929a250ec5f931fe9cf6c6f7b68d15b47c6e2c98a1 +size 157 diff --git a/example/server/server.cert b/example/server/server.cert new file mode 100644 index 0000000..8e630b1 --- /dev/null +++ b/example/server/server.cert @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbb96c640f871a7d0f2306eabc6e81b3a7d9e737ddf9f208dc130b433f79cd38 +size 92