This commit is contained in:
parent
4417b9a0ec
commit
f4b9c8000f
11 changed files with 191 additions and 0 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -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
|
||||
|
|
124
example/README.md
Normal file
124
example/README.md
Normal file
|
@ -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"]
|
||||
|
||||
```
|
13
example/client/Dockerfile
Normal file
13
example/client/Dockerfile
Normal file
|
@ -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"]
|
BIN
example/client/client.cert
(Stored with Git LFS)
Normal file
BIN
example/client/client.cert
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
example/client/coffer-client
(Stored with Git LFS)
Executable file
BIN
example/client/coffer-client
(Stored with Git LFS)
Executable file
Binary file not shown.
3
example/config.toml
Normal file
3
example/config.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[client]
|
||||
id = "452B0788D966059B21DB04FF37BC6161072B15EA2CDF88A5040FEEAB89D1143A"
|
||||
CLIENT_SECRET = "SECRETKEY"
|
21
example/docker-compose.yml
Normal file
21
example/docker-compose.yml
Normal file
|
@ -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:
|
13
example/server/Dockerfile
Normal file
13
example/server/Dockerfile
Normal file
|
@ -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"]
|
BIN
example/server/coffer-server
(Stored with Git LFS)
Executable file
BIN
example/server/coffer-server
(Stored with Git LFS)
Executable file
Binary file not shown.
BIN
example/server/config.enc
(Stored with Git LFS)
Normal file
BIN
example/server/config.enc
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
example/server/server.cert
(Stored with Git LFS)
Normal file
BIN
example/server/server.cert
(Stored with Git LFS)
Normal file
Binary file not shown.
Loading…
Reference in a new issue