Reputation: 953
I'm trying to setup certificate-based authentication in Vault. For tests I've just created a clean Vault setup. Vault configuration below:
listener "tcp" {
address = "192.168.33.10:8200"
tls_cert_file = "/etc/vault/vault_cert.pem"
tls_key_file = "/etc/vault/vault_key.pem"
tls_disable_client_certs = false
tls_disable = false
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_disable = true
}
storage "file" {
path = "/etc/vault/data"
}
I've started and unsealed Vault and enabled cert authentication:
[vagrant@localhost ~]$ ./vault status
Key Value
--- -----
Seal Type shamir
Sealed false
Total Shares 5
Threshold 3
Version 0.9.3
Cluster Name vault-cluster-37dffb3b
Cluster ID 1ddd4712-99f6-3691-a066-d476fbc6d7c6
HA Enabled false
[vagrant@localhost ~]$ ./vault auth list
Path Type Description
---- ---- -----------
cert/ cert n/a
token/ token token based credentials
Now I've generated ssl key/certificate pair which is not added yet to Vault, so I expect Vault to tell me that certificate is invalid (at least that's my understanding from reading sources here. Though the answer I'm getting says that the certificate was not supplied at all:
[vagrant@localhost ~]$ VAULT_ADDR='https://192.168.33.10:8200' ./vault login -method cert -tls-skip-verify -client-cert=./client_cert.pem -client-key=./client_key.pem
Error authenticating: Error making API request.
URL: PUT https://192.168.33.10:8200/v1/auth/cert/login
Code: 400. Errors:
* client certificate must be supplied
From what I was able to find in sources, this error message is only returned when there is no certificate supplied to Vault at all. Just to make sure that's not a problem in Vault cli client, I've tried to do the same with curl, but got the same result:
[vagrant@localhost ~]$ curl -iv -k -X POST --cert ./client_cert.pem --key ./client_key.pem https://192.168.33.10:8200/v1/auth/cert/login
* About to connect() to 192.168.33.10 port 8200 (#0)
* Trying 192.168.33.10...
* Connected to 192.168.33.10 (192.168.33.10) port 8200 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* subject: CN=Vault,[email protected],O=Exmaple,L=Berlin,ST=BERLIN,C=DE
* start date: Feb 14 15:59:37 2018 GMT
* expire date: Feb 12 15:59:37 2028 GMT
* common name: Vault
* issuer: CN=Vault,[email protected],O=Exmaple,L=Berlin,ST=BERLIN,C=DE
> POST /v1/auth/cert/login HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.33.10:8200
> Accept: */*
>
< HTTP/1.1 400 Bad Request
HTTP/1.1 400 Bad Request
< Cache-Control: no-store
Cache-Control: no-store
< Content-Type: application/json
Content-Type: application/json
< Date: Wed, 14 Feb 2018 16:20:57 GMT
Date: Wed, 14 Feb 2018 16:20:57 GMT
< Content-Length: 51
Content-Length: 51
<
{"errors":["client certificate must be supplied"]}
* Connection #0 to host 192.168.33.10 left intact
Vault server running in trace mode doesn't provide any logs during this interaction. Though, if I will use a key from the different certificate trying to deliberately break TLS, I see an error message in Vault indicating that.
Any idea what could be wrong with this setup?
Upvotes: 3
Views: 23742
Reputation: 2150
Although I am answering late. But I was able to configure spring cloud config server to use Vault as backend with CERT authentication via certificates.
Here is my tutorial : https://medium.com/@java.developer.raman/enable-spring-config-server-to-use-cert-authentication-with-vault-as-back-end-ff84e1ef2de7?sk=45a26d7f1277437d91a5cff3d5997287
And GitHub repository: https://github.com/java-developer-raman/config-server-vault-backend
Upvotes: 0
Reputation: 5324
After digging through commits regarding the TLS client verification for Vault, I finally have a working Vault instance.
For setting up client certificate verification for any request to the Vault TCP listener, you have to configure two values:
tls_client_ca_file = "/my/intermediate/ca/intermediate.cert.pem
tls_require_and_verify_client_cert = true
When these two settings are configured, all requests to the backend without a valid client certificate are blocked, all valid client requests are then forwarded to the Vault instance.
In my understanding this simply is a "filter" for unauthorised access.
So let's begin with the TLS cert authentication setup:
First of all, we have to set up the Vault CLI to provide a Client Certificate for each request it executes:
export VAULT_CLIENT_CERT="/my/cert/path/vault-client.cert.pem"
export VAULT_CLIENT_KEY="/my/cert/path/vault-client.key.pem"
export VAULT_ADDR="https://my.vault.app.com:8200"
With this command, we can get through the TCP listener's "filter".
And finally execute the command that enables the Client Certificate authentication
vault auth enable cert
For granting access to specific clients, the certificate has to be linked to a policy which itself describes access to a specific Secrets Engine:
Let's create a simple KV secrets engine for myorganization/dev
:
vault secrets enable -path=myorganization/dev kv
Then we have to create a policy file (HCL syntax) for the Secrets Engine:
path "myorganization/dev/myapp" {
capabilities = ["read"]
}
After creating the policy file, we can upload it to the vault's policy store:
vault policy write myapp-read-access myapp-read-access.hcl
And finally we have to assign an app or client certificate* to this policy by uploading the .cert.pem file to the certificate store and mapping it to this policy:
vault write auth/cert/certs/myapp display_name="My Vault Test App" policies=myapp-read-access certificate=myapp.cert.pem ttl=3600
* This can be the same as in the export
directives or some other cert (same CA of course)
After this is configured, you can then use the CLI client:
vault login -method=cert
Alternatively, you can specify another certificate for the login by using:
vault login -method=cert -client-cert=myapp.cert.pem -client-key=myapp.key.pem
In my case I used a Java client, with the following Maven POM for dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-vault-dependencies</artifactId>
<version>2.0.2.BUILD-SNAPSHOT</version>
<scope>import</scope>
<type>pom</type>
</dependency>
And the following Vault client configuration (bootstrap.yml):
spring.application.name: myapp
spring.cloud.vault:
host: my.vault.app.com
port: 8200
scheme: https
generic.backend: myorganization/dev
authentication: CERT
ssl:
key-store: classpath:myapp.jks
key-store-password: <MYKEYSTOREPW>
cert-auth-path: cert
Et voilà:
2018-09-19 14:02:18.114 INFO 51832 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='vault', propertySources=[LeaseAwareVaultPropertySource {name='myorganization/dev/myapp'}, LeaseAwareVaultPropertySource {name='myorganization/dev/application'}]}
Or in case a invalid certificate is provided:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my.vault.app.com:8200/v1/auth/cert/login": Received fatal alert: bad_certificate; nested exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
Upvotes: 6
Reputation: 11
I had same exact issue today .. spent half day trying to figure out what's wrong ... turned out that in vault config "tls_disable_client_certs = false" in listener section, actually disables cert authentication ..
so hope anyone else might stumble upon this issue get some clue ... remove that line and cert auth should work.
here is document link , not sure how I interpreted this as enabling this means browser and other clients will ignore self-sign cert, which is not the case..
https://www.vaultproject.io/docs/configuration/listener/tcp.html#tls_disable_client_certs
tls_disable_client_certs (string: "false") – Turns off client authentication for this listener. The default behavior (when this is false) is for Vault to request client certificates when available.
Upvotes: 1