mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-28 13:48:49 +08:00
NOISSSUE - Vault integration as an addon. (#1266)
Integrates Vault PKI service as a service addon. Also adds some helper scripts to help setup the CA in Vault, as well as some docs to explain how to use them. Originally based from https://github.com/mteodor/vault. Signed-off-by: Joao Matos <joao@tritao.eu> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
parent
02db4066b1
commit
46c675cd5f
16
.env
16
.env
@ -153,8 +153,22 @@ MF_CERTS_SIGN_RSA_BITS=2048
|
||||
MF_CERTS_VAULT_HOST=
|
||||
MF_CERTS_VAULT_PKI_PATH=pki_int
|
||||
MF_CERTS_VAULT_ROLE=agent
|
||||
MF_CERTS_VAULT_TOKEN=s.nArgw6xn3uIOfA7nfKk8LFaW
|
||||
MF_CERTS_VAULT_TOKEN=
|
||||
|
||||
### Vault
|
||||
MF_VAULT_HOST=vault
|
||||
MF_VAULT_PORT=8200
|
||||
MF_VAULT_UNSEAL_KEY_1=
|
||||
MF_VAULT_UNSEAL_KEY_2=
|
||||
MF_VAULT_UNSEAL_KEY_3=
|
||||
MF_VAULT_TOKEN=
|
||||
MF_VAULT_CA_NAME=mainflux
|
||||
MF_VAULT_CA_ROLE_NAME=mainflux
|
||||
MF_VAULT_CA_DOMAIN_NAME=mainflux.com
|
||||
MF_VAULT_CA_OU='Mainflux Cloud'
|
||||
MF_VAULT_CA_ORG='Mainflux Company'
|
||||
MF_VAULT_CA_COUNTRY=Serbia
|
||||
MF_VAULT_CA_LOC=BG
|
||||
|
||||
### LoRa
|
||||
MF_LORA_ADAPTER_LOG_LEVEL=debug
|
||||
|
1
docker/addons/vault/.gitignore
vendored
Normal file
1
docker/addons/vault/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
data
|
100
docker/addons/vault/README.md
Normal file
100
docker/addons/vault/README.md
Normal file
@ -0,0 +1,100 @@
|
||||
This is Vault service deployment to be used with Mainflux.
|
||||
|
||||
When the Vault service is started, some initialization steps need to be done to set things up.
|
||||
|
||||
## Setup
|
||||
|
||||
The following scripts are provided, which work on the running Vault service in Docker.
|
||||
|
||||
1. `vault-init.sh`
|
||||
|
||||
Calls `vault operator init` to perform the initial vault initialization and generates
|
||||
a `data/secrets` file which contains the Vault unseal keys and root tokens.
|
||||
|
||||
After this step, the corresponding Vault environment variables (`MF_VAULT_TOKEN`, `MF_VAULT_UNSEAL_KEY_1`,
|
||||
`MF_VAULT_UNSEAL_KEY_2`, `MF_VAULT_UNSEAL_KEY_3`) should be updated in `.env` file.
|
||||
|
||||
Example contents for `data/secrets`:
|
||||
|
||||
```
|
||||
Unseal Key 1: Ay0YZecYJ2HVtNtXfPootXK5LtF+JZoDmBb7IbbYdLBI
|
||||
Unseal Key 2: P6hb7x2cglv0p61jdLyNE3+d44cJUOFaDt9jHFDfr8Df
|
||||
Unseal Key 3: zSBfDHzUiWoOzXKY1pnnBqKO8UD2MDLuy8DNTxNtEBFy
|
||||
Unseal Key 4: 5oJuDDuMI0I8snaw/n4VLNpvndvvKi6JlkgOxuWXqMSz
|
||||
Unseal Key 5: ZhsUkk2tXBYEcWgz4WUCHH9rocoW6qZoiARWlkE5Epi5
|
||||
|
||||
Initial Root Token: s.V2hdd00P4bHtUQnoWZK2hSaS
|
||||
|
||||
Vault initialized with 5 key shares and a key threshold of 3. Please securely
|
||||
distribute the key shares printed above. When the Vault is re-sealed,
|
||||
restarted, or stopped, you must supply at least 3 of these keys to unseal it
|
||||
before it can start servicing requests.
|
||||
|
||||
Vault does not store the generated master key. Without at least 3 key to
|
||||
reconstruct the master key, Vault will remain permanently sealed!
|
||||
|
||||
It is possible to generate new unseal keys, provided you have a quorum of
|
||||
existing unseal keys shares. See "vault operator rekey" for more information.
|
||||
bash-4.4
|
||||
|
||||
Use 3 out of five keys presented and put it into .env file and than start the composition again Vault should be in unsealed state ( take a note that this is not recommended in terms of security, this is deployment for development) A real production deployment can use Vault auto unseal mode where vault gets unseal keys from some 3rd party KMS ( on AWS for example)
|
||||
```
|
||||
|
||||
2. `vault-unseal.sh`
|
||||
|
||||
This can be run after the initialization to unseal Vault, which is necessary for it to be used to store and/or get
|
||||
secrets.
|
||||
|
||||
The unseal environment variables need to be set in `.env` for the script to work.
|
||||
|
||||
This script should not be necessary to run after the initial setup, since the Vault service unseals itself when
|
||||
starting the container.
|
||||
|
||||
3. `vault-set-pki.sh`
|
||||
|
||||
This script is used to generate the root certificate, intermediate certificate and HTTPS server certificate.
|
||||
After it runs, it copes the necessary certificates and keys to the `docker/ssl/certs` folder.
|
||||
|
||||
The CA parameters are obtained from the environment variables starting with `MF_VAULT_CA` in `.env` file.
|
||||
|
||||
## Vault CLI
|
||||
|
||||
It can also be useful to run the Vault CLI for inspection and administration work.
|
||||
|
||||
This can be done directly using the Vault image in Docker: `docker run -it mainflux/vault:latest vault`
|
||||
|
||||
```
|
||||
Usage: vault <command> [args]
|
||||
|
||||
Common commands:
|
||||
read Read data and retrieves secrets
|
||||
write Write data, configuration, and secrets
|
||||
delete Delete secrets and configuration
|
||||
list List data or secrets
|
||||
login Authenticate locally
|
||||
agent Start a Vault agent
|
||||
server Start a Vault server
|
||||
status Print seal and HA status
|
||||
unwrap Unwrap a wrapped secret
|
||||
|
||||
Other commands:
|
||||
audit Interact with audit devices
|
||||
auth Interact with auth methods
|
||||
debug Runs the debug command
|
||||
kv Interact with Vault's Key-Value storage
|
||||
lease Interact with leases
|
||||
monitor Stream log messages from a Vault server
|
||||
namespace Interact with namespaces
|
||||
operator Perform operator-specific tasks
|
||||
path-help Retrieve API help for paths
|
||||
plugin Interact with Vault plugins and catalog
|
||||
policy Interact with policies
|
||||
print Prints runtime configurations
|
||||
secrets Interact with secrets engines
|
||||
ssh Initiate an SSH session
|
||||
token Interact with tokens
|
||||
```
|
||||
|
||||
### Vault Web UI
|
||||
|
||||
The Vault Web UI is accessible by default on `http://localhost:8200/ui`.
|
10
docker/addons/vault/config.hcl
Normal file
10
docker/addons/vault/config.hcl
Normal file
@ -0,0 +1,10 @@
|
||||
storage "file" {
|
||||
path = "/vault/file"
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
address = "0.0.0.0:8200"
|
||||
tls_disable = 1
|
||||
}
|
||||
|
||||
ui = true
|
42
docker/addons/vault/docker-compose.yml
Normal file
42
docker/addons/vault/docker-compose.yml
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright (c) Mainflux
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# This docker-compose file contains optional Vault service for Mainflux platform.
|
||||
# Since this is optional, this file is dependent of docker-compose file
|
||||
# from <project_root>/docker. In order to run these services, execute command:
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/vault/docker-compose.yml up
|
||||
# from project root. Vault default port (8200) is exposed, so you can use Vault CLI tool for
|
||||
# vault inspection and administration, as well as access the UI.
|
||||
|
||||
version: '3.7'
|
||||
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
mainflux-vault-volume:
|
||||
|
||||
services:
|
||||
vault:
|
||||
image: vault:latest
|
||||
container_name: mainflux-vault
|
||||
ports:
|
||||
- ${MF_VAULT_PORT}:8200
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
volumes:
|
||||
- mainflux-vault-volume:/vault/file
|
||||
- mainflux-vault-volume:/vault/logs
|
||||
- ./config.hcl:/vault/config/config.hcl
|
||||
- ./entrypoint.sh:/entrypoint.sh
|
||||
environment:
|
||||
VAULT_ADDR: http://127.0.0.1:${MF_VAULT_PORT}
|
||||
MF_VAULT_PORT: ${MF_VAULT_PORT}
|
||||
MF_VAULT_UNSEAL_KEY_1: ${MF_VAULT_UNSEAL_KEY_1}
|
||||
MF_VAULT_UNSEAL_KEY_2: ${MF_VAULT_UNSEAL_KEY_2}
|
||||
MF_VAULT_UNSEAL_KEY_3: ${MF_VAULT_UNSEAL_KEY_3}
|
||||
entrypoint: /bin/sh
|
||||
command: /entrypoint.sh
|
||||
cap_add:
|
||||
- IPC_LOCK
|
23
docker/addons/vault/entrypoint.sh
Normal file
23
docker/addons/vault/entrypoint.sh
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/dumb-init /bin/sh
|
||||
|
||||
VAULT_CONFIG_DIR=/vault/config
|
||||
|
||||
docker-entrypoint.sh server &
|
||||
VAULT_PID=$!
|
||||
|
||||
sleep 2
|
||||
|
||||
echo $MF_VAULT_UNSEAL_KEY_1
|
||||
echo $MF_VAULT_UNSEAL_KEY_2
|
||||
echo $MF_VAULT_UNSEAL_KEY_3
|
||||
|
||||
if [[ ! -z "${MF_VAULT_UNSEAL_KEY_1}" ]] &&
|
||||
[[ ! -z "${MF_VAULT_UNSEAL_KEY_2}" ]] &&
|
||||
[[ ! -z "${MF_VAULT_UNSEAL_KEY_3}" ]]; then
|
||||
echo "Unsealing Vault"
|
||||
vault operator unseal ${MF_VAULT_UNSEAL_KEY_1}
|
||||
vault operator unseal ${MF_VAULT_UNSEAL_KEY_2}
|
||||
vault operator unseal ${MF_VAULT_UNSEAL_KEY_3}
|
||||
fi
|
||||
|
||||
wait $VAULT_PID
|
10
docker/addons/vault/vault-init.sh
Executable file
10
docker/addons/vault/vault-init.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
vault() {
|
||||
docker exec -it mainflux-vault vault "$@"
|
||||
}
|
||||
|
||||
mkdir -p data
|
||||
|
||||
vault operator init 2>&1 | tee >(sed -r 's/\x1b\[[0-9;]*m//g' > data/secrets)
|
142
docker/addons/vault/vault-set-pki.sh
Executable file
142
docker/addons/vault/vault-set-pki.sh
Executable file
@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
export MAINFLUX_DIR=$scriptdir/../../../
|
||||
|
||||
cd $scriptdir
|
||||
|
||||
readDotEnv() {
|
||||
set -o allexport
|
||||
source $MAINFLUX_DIR/.env
|
||||
set +o allexport
|
||||
}
|
||||
|
||||
vault() {
|
||||
docker exec -it mainflux-vault vault "$@"
|
||||
}
|
||||
|
||||
vaultEnablePKI() {
|
||||
vault secrets enable -path pki_${MF_VAULT_CA_NAME} pki
|
||||
vault secrets tune -max-lease-ttl=87600h pki_${MF_VAULT_CA_NAME}
|
||||
}
|
||||
|
||||
vaultAddRoleToSecret() {
|
||||
vault write pki_${MF_VAULT_CA_NAME}/roles/${MF_VAULT_CA_NAME} \
|
||||
allow_any_name=true \
|
||||
max_ttl="4300h" \
|
||||
default_ttl="4300h" \
|
||||
generate_lease=true
|
||||
}
|
||||
|
||||
vaultGenerateRootCACertificate() {
|
||||
echo "Generate root CA certificate"
|
||||
vault write -format=json pki_${MF_VAULT_CA_NAME}/root/generate/exported \
|
||||
common_name="\"$MF_VAULT_CA_DOMAIN_NAME CA Root\"" \
|
||||
ou="\"$MF_VAULT_CA_OU\""\
|
||||
organization="\"$MF_VAULT_CA_ORG\"" \
|
||||
country="\"$MF_VAULT_CA_COUNTRY\"" \
|
||||
locality="\"$MF_VAULT_CA_LOC\"" \
|
||||
ttl=87600h | tee >(jq -r .data.certificate >data/${MF_VAULT_CA_NAME}_ca.crt) \
|
||||
>(jq -r .data.issuing_ca >data/${MF_VAULT_CA_NAME}_issuing_ca.crt) \
|
||||
>(jq -r .data.private_key >data/${MF_VAULT_CA_NAME}_ca.key)
|
||||
}
|
||||
|
||||
vaultGenerateIntermediateCAPKI() {
|
||||
echo "Generate Intermediate CA PKI"
|
||||
export NAME_PKI_INT_PATH="pki_int_$MF_VAULT_CA_NAME"
|
||||
vault secrets enable -path=${NAME_PKI_INT_PATH} pki
|
||||
vault secrets tune -max-lease-ttl=43800h ${NAME_PKI_INT_PATH}
|
||||
}
|
||||
|
||||
vaultGenerateIntermediateCSR() {
|
||||
echo "Generate intermediate CSR"
|
||||
vault write -format=json ${NAME_PKI_INT_PATH}/intermediate/generate/exported \
|
||||
common_name="$MF_VAULT_CA_DOMAIN_NAME Intermediate Authority" \
|
||||
| tee >(jq -r .data.csr >data/${MF_VAULT_CA_NAME}_int.csr) \
|
||||
>(jq -r .data.private_key >data/${MF_VAULT_CA_NAME}_int.key)
|
||||
}
|
||||
|
||||
vaultSignIntermediateCSR() {
|
||||
echo "Sign intermediate CSR"
|
||||
docker cp data/${MF_VAULT_CA_NAME}_int.csr mainflux-vault:/vault/${MF_VAULT_CA_NAME}_int.csr
|
||||
vault write -format=json pki_${MF_VAULT_CA_NAME}/root/sign-intermediate \
|
||||
csr=@/vault/${MF_VAULT_CA_NAME}_int.csr \
|
||||
| tee >(jq -r .data.certificate >data/${MF_VAULT_CA_NAME}_int.crt) \
|
||||
>(jq -r .data.issuing_ca >data/${MF_VAULT_CA_NAME}_int_issuing_ca.crt)
|
||||
}
|
||||
|
||||
vaultInjectIntermediateCertificate() {
|
||||
echo "Inject Intermediate Certificate"
|
||||
docker cp data/${MF_VAULT_CA_NAME}_int.crt mainflux-vault:/vault/${MF_VAULT_CA_NAME}_int.crt
|
||||
vault write ${NAME_PKI_INT_PATH}/intermediate/set-signed certificate=@/vault/${MF_VAULT_CA_NAME}_int.crt
|
||||
}
|
||||
|
||||
vaultGenerateIntermediateCertificateBundle() {
|
||||
echo "Generate intermediate certificate bundle"
|
||||
cat data/${MF_VAULT_CA_NAME}_int.crt data/${MF_VAULT_CA_NAME}_ca.crt \
|
||||
> data/${MF_VAULT_CA_NAME}_int_bundle.crt
|
||||
}
|
||||
|
||||
vaultSetupIssuingURLs() {
|
||||
echo "Setup URLs for CRL and issuing"
|
||||
VAULT_ADDR=http://$MF_VAULT_HOST:$MF_VAULT_PORT
|
||||
vault write ${NAME_PKI_INT_PATH}/config/urls \
|
||||
issuing_certificates="$VAULT_ADDR/v1/${NAME_PKI_INT_PATH}/ca" \
|
||||
crl_distribution_points="$VAULT_ADDR/v1/${NAME_PKI_INT_PATH}/crl"
|
||||
}
|
||||
|
||||
vaultSetupCARole() {
|
||||
echo "Setup CA role"
|
||||
vault write ${NAME_PKI_INT_PATH}/roles/${MF_VAULT_CA_ROLE_NAME} \
|
||||
allow_subdomains=true \
|
||||
allow_any_name=true \
|
||||
max_ttl="720h"
|
||||
}
|
||||
|
||||
vaultGenerateServerCertificate() {
|
||||
echo "Generate server certificate"
|
||||
vault write -format=json ${NAME_PKI_INT_PATH}/issue/${MF_VAULT_CA_ROLE_NAME} \
|
||||
common_name="$MF_VAULT_CA_DOMAIN_NAME" ttl="8670h" \
|
||||
| tee >(jq -r .data.certificate >data/${MF_VAULT_CA_DOMAIN_NAME}.crt) \
|
||||
>(jq -r .data.private_key >data/${MF_VAULT_CA_DOMAIN_NAME}.key)
|
||||
}
|
||||
|
||||
vaultCleanupFiles() {
|
||||
docker exec mainflux-vault sh -c 'rm -rf /vault/*.{crt,csr}'
|
||||
}
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq command could not be found, please install it and try again."
|
||||
exit
|
||||
fi
|
||||
|
||||
readDotEnv
|
||||
|
||||
mkdir -p data
|
||||
|
||||
vault login ${MF_VAULT_TOKEN}
|
||||
|
||||
vaultEnablePKI
|
||||
vaultAddRoleToSecret
|
||||
vaultGenerateRootCACertificate
|
||||
vaultGenerateIntermediateCAPKI
|
||||
vaultGenerateIntermediateCSR
|
||||
vaultSignIntermediateCSR
|
||||
vaultInjectIntermediateCertificate
|
||||
vaultGenerateIntermediateCertificateBundle
|
||||
vaultSetupIssuingURLs
|
||||
vaultSetupCARole
|
||||
vaultGenerateServerCertificate
|
||||
vaultCleanupFiles
|
||||
|
||||
echo "Copying certificate files"
|
||||
|
||||
cp -v data/${MF_VAULT_CA_DOMAIN_NAME}.crt ${MAINFLUX_DIR}/docker/ssl/certs/mainflux-server.crt
|
||||
cp -v data/${MF_VAULT_CA_DOMAIN_NAME}.key ${MAINFLUX_DIR}/docker/ssl/certs/mainflux-server.key
|
||||
cp -v data/${MF_VAULT_CA_NAME}_int.key ${MAINFLUX_DIR}/docker/ssl/certs/ca.key
|
||||
cp -v data/${MF_VAULT_CA_NAME}_int.crt ${MAINFLUX_DIR}/docker/ssl/certs/ca.crt
|
||||
cp -v data/${MF_VAULT_CA_NAME}_int_bundle.crt ${MAINFLUX_DIR}/docker/ssl/bundle.pem
|
||||
|
||||
exit 0
|
22
docker/addons/vault/vault-unseal.sh
Executable file
22
docker/addons/vault/vault-unseal.sh
Executable file
@ -0,0 +1,22 @@
|
||||
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
export MAINFLUX_DIR=$scriptdir/../../../
|
||||
|
||||
readDotEnv() {
|
||||
set -o allexport
|
||||
source $MAINFLUX_DIR/.env
|
||||
set +o allexport
|
||||
}
|
||||
|
||||
vault() {
|
||||
docker exec -it mainflux-vault vault "$@"
|
||||
}
|
||||
|
||||
readDotEnv
|
||||
|
||||
vault operator unseal ${MF_VAULT_UNSEAL_KEY_1}
|
||||
vault operator unseal ${MF_VAULT_UNSEAL_KEY_2}
|
||||
vault operator unseal ${MF_VAULT_UNSEAL_KEY_3}
|
Loading…
x
Reference in New Issue
Block a user