My goal is to run a distributed NIFI cluster inside docker containers on a docker swarm. The configurations I made to the official NIFI docker image work in a way that I am able to run the cluster.
For the cluster I use a single service and each replica is a separate NIFI instance. Since this works I want to continue with security now. I started by applying a publically signed wildcard certificate to the java application using a secret (handing over the trust- and keystore). For my opinion this could be a feasable approach for most distributed java applications. But with NIFI I now got the issue that NIFI itself does not support wildcard certificates.
I am currently thinking about an approach how to run the cluster in a way that each container has its own certificate. My current idea is to run self signed certificates inside the container using a self managed internal CA which the NIFI JVMs can trust. Since I am not 100% sure if this would be the right approach to this issue I am thankful for hints and ideas.
NIFI uses some ports to do the communication and requests are issued using the HTTP/S protocol. NIFI itself runs as java application on the nodes/containers.
Apache NiFi provides a TLS Toolkit which automates much of this process for you. It can run an ephemeral or long-lived internal certificate authority (CA) which generates internal keys and uses them to create a self-signed CA certificate and sign incoming certificate signing requests (CSR). Each node that comes online can reach out to the CA service and install a properly-configured certificate in its keystore and truststore, and automatically populate the nifi.properties file with the locations and passwords for those files with a single command-line invocation. This can be configured to run at deployment time via Dockerfile, Ruby/Python/shell script, etc.
A HMAC/SHA-256 signature is calculated over the SPKI using a shared secret token value to ensure rogue/malicious services don't get issued certificates. All the certificates will be signed by the same CA cert, and this is already populated in the truststore, so each node in the cluster will trust the others. The requested CN is also populated in the SAN entries, and additional SAN entries are supported, so this is RFC 6125 compliant.
As noted above, wildcard certificates are not supported and not recommended, for a litany of reasons (some enumerated here) but also because a more secure deployment of unique certificates is made easy using the provided toolkit. There are ongoing efforts (NIFI-5443, NIFI-5398) to modify some internal cluster communications to be resilient in the face of wildcard certificates, but these are not currently available.
Related
I have a spring boot client application and a server application. I am implementing MTLS client authentication part. I have a client certificate that is self signed and this needs to be added to a custom truststore in the server. Basically I am looking for a mechanism to add my custom truststore at runtime.
I want the default truststore and the custom truststore to be picked up. I implemented this using TomcatServletWebServerFactory but I did not have any luck. Can someone please help. I am looking for a programmatic solution.
I do not want to change the default java truststore. I still need that.
Since you do not want to replace the existing truststore with your custom one (that could be done by running the JVM with a few system properties) you need to add code that trusts a peer if the builtin or a custom trusttore approve the client.
For this you need to create and install your own Trustmanager. See an example here: https://community.oracle.com/tech/developers/discussion/1535342/java-ssl-trustmanager
If the checkClientTrusted and checkServerTrusted methods do not raise an exception the certificate is approved. Leaving the methods empty would even turn off any certificate validation - not to be recommended.
In order to establish a SSL connection with client certificates between a Spring client application and a Spring server application, there are a few things to note:
Involved Trust Stores
There are two very different trust stores relevant in this context:
The trust store used by the client to determine whether it can trust the server's SSL certificate. When using the java.net package for client requests, the trust store is configured via the JVM property "javax.net.ssl.trustStore" - see e.g. https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html
The trust store used by Tomcat (the underlying servlet container used by Spring Boot in its default configuration) to determine whether it shall trust a client. This is configured via the spring application property "server.ssl.trust-store" - see https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.server.server.ssl.trust-store
In the context of a Spring server application the first one is relevant for connections which the server makes to a second server - so only when the server acts as client as well - e.g. when acting as a proxy server.
The second trust store is relevant for connections between the server and its clients. This is the one you need to deal with.
Certificates in the Tomcat Trust Store
The trust store which is used by Tomcat does NOT contain the client certificates. Instead, it must contain the certificate of the Certificate Authority who has signed the client certificate. So when using self-signed certificates, you need to install the CA certificate which you have generated on your own.
The big advantage of this is, that you do not need to change the server trust store, when you grant access to new clients.
The downside is, that you have to handle a certificate revocation. The CRL (certificate revocation list) is also stored in the trust store. See:
CRL Explained: What Is a Certificate Revocation List?
Merging the Default Trust Store and the Custom Trust Store
As now should be clear, this is not a good idea and would constitute a major security flaw, as it would allow any client which has a certificate signed by a CA in the default trust store (which can be easily obtained) to connect to the server. The server trust store must only contain those certificates which you use to sign your client certificates!
And there is no need to merge the two, as this are totally separate trust stores with totally different functions.
But, of course it is technically feasible to merge trust stores. This can all be done by keytool - see below.
Managing Trust Stores
Adding, deleting, exporting, listing, and printing certificates and CRLs can all be done via the Oracle command line tool "keytool", which is part of the OpenJDK. See
keytool Reference
How can I install certificates on pods or servers where Java code is deployed?
There's two ways:
(Perhaps not what you're looking for) Use AWS Application Load Balancer and AWS Certificate Manager to terminal TLS. This is done by creating Service of type LoadBalancer with annotation service.beta.kubernetes.io/aws-load-balancer-ssl-cert: ... (and some others). Note that you can't access the ACM private key, so this doesn't work if you want to terminate TLS in Java.
Use cert-mananager to generate a certificate with Let's Encrypt or another supported service. Create an Issuer and then create a Certificate and a Secret to store its private key in the appropriate namespace. Then you can reference the Secret in your pods and load them in Java.
If you go the second route but would like to have a single certificate that is reused across namespaces, then you have to use something like syncator to replicate the Secrets across namespaces.
Is it possible to use openssl to generate the necessary certs to provide self signed certs for ibm MQ broker (version 9) and client. Or can i only use ibm's internal mechanism to generate the certs (ie. runmqckm -cert ).
Please advise.
B.
The queue manager requires a CMS format keystore that must be managed using IBM's tools. I recommend runmqakm instead of runmqckm to manage the queue manager's keystore since runmqakm is compiled C and you can run through an entire script of commands before runmqckm is done firing up its JRE.
For anything that can use a JKS, feel free to use OpenSSL, Keytool, or anything that works with x.509 certificates. This includes Broker's Java nodes, MQ File Transfer Edition agents, MQ client apps using native Java or JEE, and so on.
I am having doubts about how to secure my microservices application with SSL.
A quik situation sketch :
I have a amazon ec2 instance with a loadbalancer in front.
On the ec2 instance I am running 5 microservices with a registry and a gateway application ( in a VPC ).
The loadbalancer uses a certificate from the Amazon certificate manager.
I also have a self signed certificate generated with the keytool.
Now the question I am having is :
Should I only configure the self signed certificate for my gateway application and register the self signed certificate with the loadbalancer as a trusted certificate or should I configure the self signed certificate for every microservice also ?
Regards,
You want to have microservices exposed to end user, and secured with https.
If you want security, please don't use self signed certificates. Let's Encrypt is much better option.
You can use API Gateway for that, it goes with https. It may be single endpoint for your all services - then directories can lead to different services. On the other hand, if all that goes on single machine, I would use single JVM... But that is different story.
Other option is more unclear. According to comments - not only for me. If your microservices are exposed to internet - you can terminate https on your load balancers. What I don't get is that >>my gateway application<<. It looks like there is something in between end user, and microservices... If that is true then https should be terminates somewhere there.
As a side note - I have no idea why you have load balancer in front of EC2 instance. Usually LB is used in front of auto scaling group to spread load among it's instances. If you want to automate that - Elastic Beanstalk is good option.
I overheard a conversation where 2 developers were talking about an authentication system they were building and they were talking about a Java "key store" and also mentioned a "CAS server" as well as SSL. I went to the JASIG CAS website and it seems that its used for authentication systems where you want to control user logins and sessions. It seems that the Java keystore is a file (an embedded DB perhaps?) that stores encrypted CA certificates.
I'm trying to figure out how these 3 technologies could be used together to create a secure, Java-based authentication system.
So would a web app use the CAS client (in my case Java) to communicate with a running instance of the CAS server? If so, where and how do the keystore and SSL cert snap into the architecture? Does CAS store the SSL cert in the keystore, and then use it with the backend directory (ActiveDirectory, etc.) somehow? Can someone just give me a high-level overview of how this would all come together?
CAS central authentication is largely orthogonal to SSL and its keystores and certificating authorities. CAS is a way to allow multiple services to share one authentication server, so users can sign on only once at a central authentication server. Connections to the services and the central authentication server can of course be encrypted using SSL, just like other network connections. Using SSL necessitates the use of keystores and trust stores to store the keys and trust certificates, including CA - certificating authority - certificates.