Spring Cloud Vault mutual TLS authentication issue - spring-boot

I am trying to set up a spring boot application to talk to my Vault server over TLS. I want to use mutual certificate authentication. I could set up the Vault server with TLS and I am able to use the CLI to login to it using client certificates. However, the spring boot application is unable to present its client certificate to the Vault server - each time I run my app, the Vault server prints:
http: TLS handshake error from 127.0.0.1:33288: tls: client didn't provide a certificate
The client (my spring boot app) prints:
org.springframework.vault.authentication.VaultLoginException:
Cannot login using org.springframework.web.client.ResourceAccessException:
I/O error on POST request for "https://localhost:8200/v1/auth/cert/login":
Received fatal alert: bad_certificate;
nested exception is javax.net.ssl.SSLHandshakeException:
Received fatal alert: bad_certificate
... (a stack trace for VaultLoginException)
Here is my bootstrap.yml:
spring:
application.name: vault-demo
cloud.vault:
host: localhost
port: 8200
scheme: https
uri: https://localhost:8200
connection-timeout: 5000
read-timeout: 15000
config.order: -10
authentication: CERT
ssl:
trust-store: classpath:keystore.jks
trust-store-password: changeit
key-store: classpath:client-cert.jks
key-store-password: changeit
cert-auth-path: cert
I can't find any documentation around the various properties that needs to be configured under spring.cloud.vault.*.
My client-cert.jks store has the client certificate and key. Enabling SSL verbose logs, I can see this:
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
which indicates that the client found the server's certificate in its trust store, but it's not sending the client's certificate to the server.
Further, if I use curl to send a login request, it is successful:
curl -k --request POST \
--cert work/ca/certs/client.cert.pem \
--key work/ca/private/client.decrypted.key.pem \
--data #payload.json \
https://localhost:8200/v1/auth/cert/login
# gives me back a JSON with newly issued token.
I also tried using a config class and passed the javax.net.ssl.keyStore and related properties as JAVA_OPTS, but there is absolutely no difference - vault keeps on saying that the client didn't send a certificate:
#Configuration
public class AppConfig extends AbstractVaultConfiguration {
#Value("${vault.uri}")
URI vaultUri;
#Override
public VaultEndpoint vaultEndpoint() {
return VaultEndpoint.from(vaultUri);
}
#Override
public ClientAuthentication clientAuthentication() {
try {
RestTemplate restTemplate = new RestTemplate();
HttpClientBuilder httpClientBuilder = HttpClients.custom()
.setSSLContext(SSLContext.getDefault())
.useSystemProperties();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(
httpClientBuilder.build()));
return new ClientCertificateAuthentication(restTemplate);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
Anyone can point out what I am missing / have done wrongly?

The issue was that my Vault configuration did not specify the tls_client_ca_file property correctly. Set it to the root CA certificate and everything worked. There was no need to add an AppConfig class either.

Related

How to disable authentication while testing email service using greenmail

I have written an email service using Spring Email and then used Greenmail to test the email service. But while running the test case it gives an error Authentication failed as below:
javax.mail.AuthenticationFailedException: 535 5.7.0 Authentication credentials invalid at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:965)
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:876)
How can this error be resolved without giving my username/password in the code. Note that I have also tried giving username/password but it failed with the same exception. Thanks for any help.
greenMail = new GreenMail(new ServerSetup(2525, "127.0.0.1", "smtp"));
greenMail.setUser("username", "secret");
When Setting up your greenmail instance for testing you need to use the setUser and enter
username and password above and then add the properties specified in the #One Guy post above this. has worked for me after I received the Authentication credentials invalid Exception.
Hope this helps anyone facing a the issue
See AuthenticationDisabledTest.java how to configure a GreenMail junit test using disabled authentication.
Looks like you don't added the mock credentials i.e. a a resource file called application-test.yml file which is located in the src/test/resources folder.
application.yml
spring:
mail:
default-encoding: UTF-8
host: localhost
jndi-name:
username: username
password: secret
port: 2525
properties:
mail:
debug: false
smtp:
debug: false
auth: true
starttls: true
protocol: smtp
test-connection: false
You can take a look an example by following link:
https://memorynotfound.com/spring-mail-integration-testing-junit-greenmail-example/

traefik's tls: client didn't provide a certificate when accessing https endpoint

Here's my configuration
[entryPoints]
[entryPoints.http]
address = ":801"
[entryPoints.https]
address = ":802"
[entryPoints.https.tls]
[entryPoints.https.tls.ClientCA]
files = ["/etc/ssl/comodo/bundle.crt"]
[[entryPoints.https.tls.certificates]]
certFile = "/etc/ssl/comodo/www.crt"
keyFile = "/etc/ssl/comodo/www.key"
[frontends]
[frontends.http] # default
entryPoints = ["http", "https"]
backend = "fallback"
passHostHeader = true
Now I'm trying to access https://mydomain:802 and I get following error in traefik debug output
http: TLS handshake error from 111.111.111.111:64463: tls: client didn't provide a certificate
curl error message
error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate
I can't figure out what I'm doing wrong.
Why would you want to use Mutual authentication (two-way handshake)? For normal SSL connections your server certificates are enough.
In your traefik.toml you're configuring Mutual authentication. If you really want so, you have to provide the certificate within your curl request:
curl --cert client.pem:<password> --key key.pem --cacert ca.pem
If you only want to provide "normal" SSL, you should delete following lines:
[entryPoints.https.tls.ClientCA]
files = ["/etc/ssl/comodo/bundle.crt"]

What is the best way to secure spring cloud config?

I have a spring cloud config server running with spring bus. I want to make the calls to that server secure:
When a client is asking for configurations.
When calling /monitor - used by the webhook.
What is the best practice to do that? basic? encryption?
Can someone provide a working example?
Thanks!
You can secure it by adding encrypting and decrypting properties
You need to provide jks for securely encrypting and decrypting them
Spring cloud config server supports symmetric and asymmetric keys
To configure a symmetric key, you need to set encrypt.key to a secret String (or use the ENCRYPT_KEY environment variable to keep it out of plain-text configuration files).
For asymmetric you need to provide in bootsrap.yml such properties:
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: your git url or your local repository on file system
username: username for git or bitbucket if needed
password: password
clone-on-start: true this property will clone all repo localy on starttup
force-pull: true
application:
name: config-server
encrypt:
key-store:
location: jks location
password: letmein
alias: mytestkey
secret: changeme
For generating jks you need to execute this command
keytool -genkeypair -alias mytestkey -keyalg RSA \
-dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US" \
-keypass changeme -keystore server.jks -storepass letmein
Actually java by default has a limitation on certain key length parameters.
Its 128 bit by default.
To use key more key length you just need replace existing local_policy.jar and US_export_policy.jar in <java-home>/lib/security
Here is link for download :
https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
And also you can encrypt and decrypt your properties by such endpoints :
curl config_server_host:port/encrypt-d your data to be encrypted
curl config_server_host:port/decrypt -d your data to be decrypted // this will automatically use this endpoint to decrypt values
//Both are http post requests
To use encryption by config server you need to provide such prefix in your configuration for your application which will get configs from config server:
'{cipher}your_encrypted_data'
Also, you can control access to secrets in the config by the using of Spring Cloud Vault.
This solution simpler than encrypt all communication between your application and config server, but maybe this is not what you want.
I hope it helps.

golang autocert acme/autocert: missing server name

i use Library autocert in my application for generate ssl certificate, problem is 30% of users have problem with my application, my current code is :
fmt.Println("Starting server on " + this.Params.Bind)
if this.Params.SSL {
fmt.Println("SSL Enabled")
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(this.Params.HostsWhitelist...),
Cache: autocert.DirCache(this.Params.CertCache),
}
log.Fatal(autotls.RunWithManager(r, &m))
} else {
r.Run(this.Params.Bind)
}
the errors is :
2018/12/03 12:37:33 http: TLS handshake error from 68.71.48.249:55885: acme/autocert: missing server name
2018/12/03 12:37:33 http: TLS handshake error from 209.213.121.223:38284: acme/autocert: missing server name
2018/12/03 12:37:33 http: TLS handshake error from 209.213.121.223:38283: acme/autocert: missing server name
2018/12/03 12:37:33 http: TLS handshake error from 68.71.48.249:55887: acme/autocert: missing server name
2018/12/03 12:37:33 http: TLS handshake error from 68.71.48.249:55888: acme/autocert: missing server name
2018/12/03 12:37:33 http: TLS handshake error from 209.237.150.145:56842: acme/autocert: missing server name
how i can fix error missing server name ?
Maybe my blog will help you find a difference in your code vs the code I show in my blog.
https://marcofranssen.nl/build-a-go-webserver-on-http-2-using-letsencrypt/
Furthermore I figured out there is a much better library available to manage certificates via Letsencrypt.
https://marcofranssen.nl/use-the-acme-dns-challenge-to-get-a-tls-certificate/
In this second blog I utilize https://go-acme.github.io/lego/ which is supporting more of the ACME challenges. It ships with a cli, but can also be used as a lib in your webserver. In fact it is used in Traefik as well the Caddy webserver project.
You also should NOT use the SNI challenge anymore as it is considered insecure. Instead use the ALPN challenge.

Spring Boot project with SSL / HTTPS not working on AWS Elastic Beanstalk

My Spring Boot project works fine on https / ssl, when serving locally, using a p12 cert, but fails when uploading to AWS Elastic Beanstalk.
The following is the application.properties configuration:
security.require-ssl=true
server.use-forward-headers=true
server.port=8443
server.ssl.key-store: classpath:keystore.p12
server.ssl.key-store-password: jonathan
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat
The WebSecurityConfigurerAdapter subclass, configure(HttpSecurity http) method, contains the following line, to enable HTTPS / SSL:
http.requiresChannel().antMatchers("/**").requiresSecure();
Attached is classic load configurer configuration, inside AWS elastic beanstalk console:
Here is the SSL Certificate issued with the grasshapper.net domain, under AWS Certificate Manager:
I also have settings for under .ebextensions, the file with path is, src/main/resources/.ebextensions/.config (not sure if even needed):
option_settings:
aws:elb:listener:8443:
SSLCertificateId: [keeping private]
ListenerProtocol: HTTPS
InstancePort: 80
InstanceProtocol: HTTP
aws:elb:listener:80:
ListenerEnabled: false
Note (SSLCertifcateId): the ID is taken from the ARN, my AWS Certifcate manager SSL Certificate (if you expand the SSL Certificate you will see the ARN).
Does the proxy have a trusted IP address?
By default, IP addresses in 10/8, 192.168/16, 169.254/16 and 127/8 are
trusted. You can customize the valveā€™s configuration by adding an
entry to application.properties, as shown in the following example:
server.tomcat.internal-proxies=192\.168\.\d{1,3}\.\d{1,3}
Reference: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto-embedded-web-servers.html#howto-customize-tomcat-behind-a-proxy-server

Resources