Vault Install
Environment Variables
Let's set up some env.vars
# OpenShift Cluster Base Domain
export BASE_DOMAIN=$(oc get dns cluster -o jsonpath='{.spec.baseDomain}')
# Internal k8s service in-cluster
export KUBERNETES_HOST=https://kubernetes.default.svc:443
# Vault Service and Route base name
export VAULT_HELM_RELEASE=vault
# Vault Route FQDN
export VAULT_ROUTE=${VAULT_HELM_RELEASE}.apps.$BASE_DOMAIN
export VAULT_ADDR=https://${VAULT_ROUTE}
# Vault service in-cluster
export VAULT_SERVICE=${VAULT_HELM_RELEASE}-active.hashicorp.svc
# This makes it easier to use the CLI, else need to trust the CA
export VAULT_SKIP_VERIFY=true
Login to OpenShift
Login to OpenShift from the CLI using a cluster-admin
user.
oc login --server=https://api.${BASE_DOMAIN}:6443 -u <admin>
Install Cert Manager
We need to make use of Cert Manager Operator to help us setup PKI for vault in the next step. Install the Operator as follows.
Create a namespace.
cat <<EOF | oc apply -f-
kind: Namespace
apiVersion: v1
metadata:
name: cert-manager-operator
EOF
Create an Operator Group.
cat <<EOF | oc create -f-
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
annotations:
olm.providedAPIs: CertManager.v1alpha1.operator.openshift.io,Certificate.v1.cert-manager.io,CertificateRequest.v1.cert-manager.io,Challenge.v1.acme.cert-manager.io,ClusterIssuer.v1.cert-manager.io,Issuer.v1.cert-manager.io,Order.v1.acme.cert-manager.io
generateName: cert-manager-operator-
namespace: cert-manager-operator
spec:
targetNamespaces:
- cert-manager-operator
EOF
Create the Subscription.
cat <<EOF | oc apply -f-
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
labels:
operators.coreos.com/openshift-cert-manager-operator.openshift-cert-manager-operator: ''
name: openshift-cert-manager-operator
namespace: cert-manager-operator
spec:
channel: stable-v1
installPlanApproval: Automatic
name: openshift-cert-manager-operator
source: redhat-operators
sourceNamespace: openshift-marketplace
EOF
When OK, you should see.
oc get pods -n cert-manager-operator
NAME READY STATUS RESTARTS AGE cert-manager-operator-controller-manager-86bc8d6df-f7wzn 2/2 Running 0 2m22s
Setup PKI
We need to initialize vault with a CA certificate. We are going to create a root CA and an intermediate code signing cert. Change the cert details to suit your setup.
mkdir ~/tmp/vault-certs && cd ~/tmp/vault-certs
export CERT_ROOT=$(pwd)
mkdir -p ${CERT_ROOT}/{root,intermediate}
cd ${CERT_ROOT}/root/
openssl genrsa -out ca.key 2048
touch index.txt
echo 1000 > serial
mkdir -p newcerts
cat <<EOF > openssl.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = ${CERT_ROOT}/root
certs = \$dir/certs
crl_dir = \$dir/crl
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
# The root key and root certificate.
private_key = \$dir/ca.key
certificate = \$dir/ca.crt
# For certificate revocation lists.
crlnumber = \$dir/crlnumber
crl = \$dir/crl/ca.crl
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_strict
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
countryName = match
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA.
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:1
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[req_distinguished_name]
countryName = AU
countryName = Country Name
countryName_default = AU
stateOrProvinceName = State or Province Name
stateOrProvinceName_default = QLD
localityName= Locality Name
localityName_default = Brisbane
organizationName= Organization Name
organizationName_default = Acme Corp
commonName= Company Name
commonName_default = acme.corp
commonName_max = 64
[req]
distinguished_name = req_distinguished_name
[ v3_ca ]
basicConstraints = critical,CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
EOF
openssl req -x509 -new -nodes -key ca.key -sha256 -days 1024 -out ca.crt -extensions v3_ca -config openssl.cnf
cd ../intermediate
openssl genrsa -out ca.key 2048
openssl req -new -sha256 -key ca.key -out ca.csr -subj "/C=AU/ST=QLD/L=Brisbane/O=Acme Corp/OU=AC/CN=int.acme.corp"
openssl ca -config ../root/openssl.cnf -extensions v3_intermediate_ca -days 365 -notext -md sha256 -in ca.csr -out ca.crt
Load the intermediate cert as a secret into the OpenShift hashicorp
project (we will install vault here in the proceeding steps).
oc new-project hashicorp
oc create secret tls intermediate --cert=${CERT_ROOT}/intermediate/ca.crt --key=${CERT_ROOT}/intermediate/ca.key -n hashicorp
Create a Cert Manager Issuer
and Certificate
.
cat <<EOF | oc apply -f-
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: int-ca-issuer
spec:
ca:
secretName: intermediate
EOF
cat <<EOF | oc apply -f-
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: vault-certs
spec:
secretName: vault-certs
issuerRef:
name: int-ca-issuer
kind: Issuer
dnsNames:
- ${VAULT_ROUTE}
# Service Active FQDN
- ${VAULT_SERVICE}
organization:
- acme.corp
EOF
You can inspect the data:
section of the cert secret which contains the generated certificate details (ca.crt
, tls.crt
, tls.key
).
oc get secret vault-certs -o jsonpath='{.data}' | jq .
Install Vault
Install Vault using helm. Add the helm repo:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
Create a default values file:
- HA 3 node vault cluster
- Uses the Hashicorp UBI images (you can get enterprise support from Hashicorp - use vault-enterprise
) - check here for latest versions
- audit storage configured (adjust the disk size accordingly)
mkdir -p ${CERT_ROOT}/vault && cd ${CERT_ROOT}/vault
cat <<EOF > values.yaml
enabled: true
global:
tlsDisable: false
openshift: true
injector:
enabled: false
image:
repository: "registry.connect.redhat.com/hashicorp/vault-k8s"
tag: "1.1.0-ubi"
agentImage:
repository: "registry.connect.redhat.com/hashicorp/vault"
tag: "1.12.1-ubi"
ui:
enabled: true
server:
image:
repository: "registry.connect.redhat.com/hashicorp/vault"
tag: "1.12.1-ubi"
route:
enabled: true
host:
extraEnvironmentVars:
VAULT_CACERT: "/etc/vault-tls/vault-certs/ca.crt"
VAULT_TLS_SERVER_NAME:
standalone:
enabled: true
config: |
ui = true
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_cert_file = "/etc/vault-tls/vault-certs/tls.crt"
tls_key_file = "/etc/vault-tls/vault-certs/tls.key"
tls_client_ca_file = "/etc/vault-tls/vault-certs/ca.crt"
}
storage "file" {
path = "/vault/data"
}
auditStorage:
enabled: true
size: 5Gi
extraVolumes:
- type: "secret"
name: "vault-certs"
path: "/etc/vault-tls"
ha:
enabled: false
raft:
enabled: true
setNodeId: true
config: |
ui = true
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_cert_file = "/etc/vault-tls/vault-certs/tls.crt"
tls_key_file = "/etc/vault-tls/vault-certs/tls.key"
tls_client_ca_file = "/etc/vault-tls/vault-certs/ca.crt"
}
storage "raft" {
path = "/vault/data"
retry_join {
leader_api_addr = "https://vault-active.hashicorp.svc:8200"
leader_ca_cert_file = "/etc/vault-tls/vault-certs/ca.crt"
}
}
log_level = "debug"
service_registration "kubernetes" {}
service:
enabled: true
tolerations[0]:
operator: Exists
effect: NoSchedule
EOF
OK, lets install into hashicorp
namespace.
Run the installer.
helm install vault hashicorp/vault -f values.yaml \
--set server.route.host=$VAULT_ROUTE \
--set server.extraEnvironmentVars.VAULT_TLS_SERVER_NAME=$VAULT_ROUTE \
--namespace hashicorp \
--wait
When successful you should get.
NAME: vault LAST DEPLOYED: Wed May 25 16:44:35 2022 NAMESPACE: hashicorp STATUS: deployed REVISION: 1 NOTES: Thank you for installing HashiCorp Vault!
And all pods are running but not ready (this is ok).
oc get pods
NAME READY STATUS RESTARTS AGE vault-0 0/1 Running 0 20s
Unseal the vault
On first install, we need to initialize and unseal the vault. First step is to initialize and get the root
token.
oc -n hashicorp exec -ti vault-0 -- vault operator init -key-threshold=1 -key-shares=1
You should see the root
token and unseal key printed out. Save these.
# use the root token to unseal Unseal Key 1: this-is-not-my-key Initial Root Token: this-is-not-my-token
Export these in our environment for now for ease of use.
export ROOT_TOKEN=this-is-not-my-token
export UNSEAL_KEY=this-is-not-my-key
Unseal the node in the cluster.
oc -n hashicorp exec -ti vault-0 -- vault operator unseal $UNSEAL_KEY
And all pods are running and now ready once you have unsealed all the vault nodes.
oc get pods
NAME READY STATUS RESTARTS AGE vault-0 1/1 Running 0 5m40s
Vault CLI
Grab the vault cli
wget https://releases.hashicorp.com/vault/1.14.1/vault_1.14.1_linux_amd64.zip
unzip vault_1.14.1_linux_amd64.zip
sudo mv vault /usr/local/bin/vault && sudo chmod 755 /usr/local/bin/vault