/keyvault

Practice Project: key vault to store your secrets, provide RESTFul API, build with Gin

Primary LanguageGoMIT LicenseMIT

keyvault

Go codecov

Practice Project: key vault to store your secrets, provide RESTFul API, build with Gin

Just a practice project, it works in internal network. It's not a production-ready application.

Structure

+------------------+
|        API       |
+------------------+
|      Services    |
+------------------+
|  CertIO |   pkg  |
+---------+--------+
|       Models     |
+------------------+

Features

  • client and server use certificate to validate each other
  • server perform as a CA, and able to issue certificate to client
  • only authorized clients can communicate with keyvault
  • the certificate must have OU property, server will use it as the namespace of secret to query database
  • server has a master key to encrypt/decrypt the secrets using AES
  • the master key is randomly generated and stored in a file that only visible to the user who start the service
  • the master key is also encrypted in the database and only visible during runtime
  • server has RESTFul API to store the secrets, get secrets, issue certificates
  • communication is protected by TLS

The secret still visible as a plain text to authorized client. If the client choose to print it out or log it, there is nothing we can do. The sensitive data should never been seen anywhere.

Usage

API doc can be found in /docs

Test

Start the server

$ cd <the_path_of_project>
$ export DB_PATH=/tmp/vault.db
$ cd keyvault
## Start keyvault server
$ go run keyvault.go

Prepare certificates

Server side

CA certificate and privatekey, keyvault service certificate and private key are automatically generated when starting the server.

If you want to re-generate all certificates, just remove keyvault/etc/ca.crt and start the server again. You can use keyvault/etc/ca.key to sign client certificate request. The keyvault service will provide API to sign the request later.

Client side

Client need to generate private key manually. The following command will generate private key with RSA algorithm and key length is 4096.

$ openssl genrsa -out client.key 4096

Then client should create a CSR(Certificate Signing Request) file with OU specified, keyvault service will use OU to determine if client is authorized to access specific secret. For example, we set OU to KUBERNETES, and set other field to fit your need.

$ openssl req -new -nodes -key client.key -out client.csr -subj /C=CN/ST=SC/L=CD/O="KeyVault Client"/OU=KUBERNETES/CN=K8S.keyvault.org

Then use the CA key pairs to sign this request. (TODO: keyvault will provide API to do this, and this section should be updated)

$ openssl x509 -req -in client.csr -CA keyvault/etc/ca.crt  -CAkey keyvault/etc/ca_priv.key  -CAcreateserial -out client.crt

Access API

Create a new namespace. The namespace value must be exactly the same with OU in client.crt

curl -L --key certs/client.key --cert certs/client.crt --cacert certs/ca.crt https://keyvault.org/v1/vault/ -X POST -d '{"name": "KUBERNETES"}'

Create a new secret under the namespace

curl --key certs/client.key --cert certs/client.crt --cacert certs/ca.crt https://keyvault.org/v1/vault/KUBERNETES -X POST -d '{"key": "admin_user", "value": "some-password"}'

Get the secret

curl --key certs/client.key --cert certs/client.crt --cacert certs/ca.crt https://keyvault.org/v1/vault/KUBERNETES\?q\=admin_user

Development

go 1.15.5

Build the Docker Image

$ git clone 
$ cd keyvault
$ docker build -t keyvault:latest .
# or
$ docker-compose build

Start the service

First look

Start the service and listen on local port 443 in foreground. Ctl+c will terminate the service, and remove the container.

docker run --rm -p 443:443 --name keyvault keyvault:latest

Data persistance

Persist certificate and database file.

$ export HOST_DATA_DIR=/some/where/on/host
$ docker-compose up -d

Build binary with Docker

$ docker run --rm \
    -v "$PWD/keyvault":/usr/src/keyvault \
    -w /usr/src/keyvault \
    -e GOOS=linux \
    -e GOARCH=amd64 \
    -e CGO_ENABLED=1 \
    keyvault:debug \
    go build -v -o keyvault-linux-amd64

Note, build with GOOS=darwin and CGO_ENABLED=1 will fail on my macOS.

Other usage

This tool can be also used for generate CA and web certificate files.

Write your customized configuration file, update the certificates part with certificates details.

$ mkdir psonocdc
# specify the configuration file path
$ export KV_CONFIG_FILE=$PWD/psono.json
# specify the dir path to store generated certificates
$ export KV_CERT_DIR=$PWD/psonocdc
# start the service then certificates will be generated automatically
$ go run keyvaultd.go
...
# checkout the generated certificates
$ ls psonocdc
ca.crt        ca_priv.key   cert.pem      cert_priv.key