`vault login -method=cert` not working

Hi,

I am trying to enable TLS authentication in a Vault that is deployed within a Kubernetes cluster. My goal is to be able to login to the vault using cert method as follows:

vault login \
    -method=cert \
    -ca-cert=vault-ca.pem \
    -client-cert=cert.pem \
    -client-key=key.pem \
    name=web

I first deployed the vault following this page against a minikube cluster. This page creates the vault server’s public key, private key and certificate. With these three files, I assume any connection to the server will be secure. The steps I followed were as follows:

Creating a standalone TLS vault server

1. Create env variables

# SERVICE is the name of the Vault service in Kubernetes.
# It does not have to match the actual running service, though it may help for consistency.
SERVICE=vault-server-tls

# NAMESPACE where the Vault service is running.
NAMESPACE=vault-namespace

# SECRET_NAME to create in the Kubernetes secrets store.
SECRET_NAME=vault-server-tls

# TMPDIR is a temporary working directory.
TMPDIR=/tmp

2. Create a private key for the vault server

openssl genrsa -out ${TMPDIR}/vault.key 2048

3. Create and deploy Certificate Signing Request

  • 3.1) Create a file csr.conf
$ cat <<EOF >${TMPDIR}/csr.conf
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${SERVICE}
DNS.2 = ${SERVICE}.${NAMESPACE}
DNS.3 = ${SERVICE}.${NAMESPACE}.svc
DNS.4 = ${SERVICE}.${NAMESPACE}.svc.cluster.local
IP.1 = 127.0.0.1
EOF
  • 3.2) Create the Certificate Signing request using the configuration in csr.conf
openssl req -new -key ${TMPDIR}/vault.key -subj "/CN=${SERVICE}.${NAMESPACE}.svc" -out ${TMPDIR}/server.csr -config ${TMPDIR}/csr.conf
  • 3.3) Put the Certificate Signing Request in a CertificateSigningRequest yaml for Kubernetes
$ export CSR_NAME=vault-csr
$ cat <<EOF >${TMPDIR}/csr.yaml
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: ${CSR_NAME}
spec:
  groups:
  - system:authenticated
  request: $(cat ${TMPDIR}/server.csr | base64 | tr -d '\n')
  usages:
  - digital signature
  - key encipherment
  - server auth
EOF

and apply it in Kubernetes

kubectl create -f ${TMPDIR}/csr.yaml
  • 3.4) Approve the Certificate Signing Request
kubectl certificate approve ${CSR_NAME}

4. Get the Vault server’s Certificate

serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')

and put it in a file

echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt

5. Get Certificate Authority’s certificate

kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 -d > ${TMPDIR}/vault.ca

 

At this stage, I have the vault server’s private key vault.key, its certificate vault.crt and the CA certificate vault.ca

 

6. I can put these files into a Kubernetes secret to be used by the vault server deployment.

kubectl create secret generic ${SECRET_NAME} \
     --namespace ${NAMESPACE} \
     --from-file=vault.key=${TMPDIR}/vault.key \
     --from-file=vault.crt=${TMPDIR}/vault.crt \
     --from-file=vault.ca=${TMPDIR}/vault.ca

7. Finally deploy the vault server with a Helm chart and the following custom values

global:
  enabled: true
  tlsDisable: false

server:
  extraEnvironmentVars:
    VAULT_CACERT: /vault/userconfig/vault-server-tls/vault.ca

  extraVolumes:
    - type: secret
      name: vault-server-tls # Matches the ${SECRET_NAME} from above

  standalone:
    enabled: true
    config: |
      listener "tcp" {
        address = "[::]:8200"
        cluster_address = "[::]:8201"
        tls_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"
        tls_key_file  = "/vault/userconfig/vault-server-tls/vault.key"
        tls_client_ca_file = "/vault/userconfig/vault-server-tls/vault.ca"
      }

      storage "file" {
        path = "/vault/data"
      }
$ helm repo add hashicorp https://helm.releases.hashicorp.com
$ helm install vault hashicorp/vault --values values.yml

Authenticate with Cert

I kubectl exec into the pod vault-0 and I init and unseal the vault.

Then I try to login using the files I created. I know that they are the same as the server’s files. However, since they are paired and signed, I would expecte them to work. Also, I did go into the Vault’s UI and added vault.ca as the certificate to be used in TLS Acess.

$ vault login -method=cert -ca-cert=/vault/userconfig/vault-server-tls/vault.ca -client-cert=/vault/userconfig/vault-server-tls/vault.cr
t -client-key=/vault/userconfig/vault-server-tls/vault.key  

However, I get this error:

Error authenticating: Error making API request.

URL: PUT https://127.0.0.1:8200/v1/auth/cert/login
Code: 500. Errors:

* failed to verify client's certificate: x509: certificate specifies an incompatible key usage

My TLS understanding is limited. Could anyone point me into the right direction?

Hi Ana,

The problem is that you’re trying to authenticate with the vault server using a server certificate, not a client certificate. The key usages you show at the end of 3.3 include “server auth”, a client certificate would have “client auth” instead, for a start.

The certificate you’ve created is being used by the Vault server to authenticate itself to clients connecting to it; you need a separate client certificate to authenticate the client to the Vault server.

Hope that helps (at least a little).

Brendan