Does vault not verify the certificate of cluster members?

I’m having a very difficult time getting my test-cluster vault nodes to reject each other for unknown certificates. My expectation is that if I give 3 nodes 3 different self-signed certificates they will not communicate with each other. In practice “it just works” which seems not very secure.

are my expectations wrong? did I not configure something correctly?

Vault-a has a self-signed CA with CA-signed certificate, b and c have just self-signed certificates. After unsealing the cluster starts working like nothing is wrong. Non of the nodes reject the other.

configuration is as follows:

docker-compose.yml

version: '3.8'

services:
  vault-a:
    image: vault:1.12.2
    command: vault server -config /vault/config/vault.conf
    cap_add:
      - IPC_LOCK
    expose:
      - '8200'
      - '8201'
    ports:
      - '8101:443'
    volumes:
      - ./vault-a-file:/vault/file
      - ./vault-a.conf:/vault/config/vault.conf
  vault-b:
    image: vault:1.12.2
    command: vault server -config /vault/config/vault.conf
    cap_add:
      - IPC_LOCK
    expose:
      - '8200'
      - '8201'
    ports:
      - '8203:8200'
    volumes:
      - ./vault-b-file:/vault/file
      - ./vault-b.conf:/vault/config/vault.conf
  vault-c:
    image: vault:1.12.2
    command: vault server -config /vault/config/vault.conf
    cap_add:
      - IPC_LOCK
    expose:
      - '8200'
      - '8201'
    ports:
      - '8205:8200'
    volumes:
      - ./vault-c-file:/vault/file
      - ./vault-c.conf:/vault/config/vault.conf

vault-a.conf

ui = true
disable_mlock = true

storage "raft" {
    path = "/vault/file"
    
    retry_join {
        leader_api_addr = "https://vault-b:8200"
        leader_ca_cert_file = "/vault/file/ca-cert.pem"
    }
    retry_join {
        leader_api_addr = "https://vault-c:8200"
        leader_ca_cert_file = "/vault/file/ca-cert.pem"
        leader_client_cert_file = "/vault/file/cert.pem"
        leader_client_key_file = "/vault/file/cert-key.pem"
    }
}

api_addr = "https://vault-a:8200"
cluster_addr = "https://vault-a:8201"

listener "tcp" {
    address = "0.0.0.0:443"
    tls_cert_file = "/vault/file/cert.pem"
    tls_key_file = "/vault/file/cert-key.pem"
    tls_min_version = "tls13"
}

listener "tcp" {
    address = "0.0.0.0:8200"
    cluster_address = "0.0.0.0:8201"
    tls_cert_file = "/vault/file/cert.pem"
    tls_key_file = "/vault/file/cert-key.pem"
    tls_client_ca_file = "/vault/file/ca-cert.pem"
    tls_require_and_verify_client_cert = true
    tls_min_version = "tls13"
}

vault-b.conf

ui = true
disable_mlock = true

storage "raft" {
    path = "/vault/file"
}

api_addr = "https://vault-b:8200"
cluster_addr = "https://vault-b:8201"

listener "tcp" {
    address     = "0.0.0.0:8200"
    cluster_address = "0.0.0.0:8201"
    tls_cert_file = "/vault/file/cert.pem"
    tls_key_file = "/vault/file/key.pem"
    tls_disable_client_certs = true
    tls_min_version = "tls13"
}

vault-c.conf

ui = true
disable_mlock = true

storage "raft" {
    path = "/vault/file"
}

api_addr = "https://vault-c:8200"
cluster_addr = "https://vault-c:8201"

listener "tcp" {
    address     = "0.0.0.0:8200"
    cluster_address = "0.0.0.0:8201"
    tls_cert_file = "/vault/file/cert.pem"
    tls_key_file = "/vault/file/key.pem"
    tls_disable_client_certs = true
    tls_min_version = "tls13"
}

Vault does not use the port 8200 listeners at all for communication within an existing cluster.

They are only used briefly for nodes to join a Raft cluster during initial setup.

Once cluster membership is established, the internal cluster communication all happens over port 8201 using internally generated certificates and keys which are not user-configurable.

1 Like