mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-29 13:49:28 +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_HOST=
|
||||||
MF_CERTS_VAULT_PKI_PATH=pki_int
|
MF_CERTS_VAULT_PKI_PATH=pki_int
|
||||||
MF_CERTS_VAULT_ROLE=agent
|
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
|
### LoRa
|
||||||
MF_LORA_ADAPTER_LOG_LEVEL=debug
|
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