{"id":7695,"date":"2024-03-19T07:00:28","date_gmt":"2024-03-19T14:00:28","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cosmosdb\/?p=7695"},"modified":"2024-03-13T07:42:41","modified_gmt":"2024-03-13T14:42:41","slug":"how-to-use-self-signed-certificates-to-connect-to-azure-managed-instance-for-apache-cassandra","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cosmosdb\/how-to-use-self-signed-certificates-to-connect-to-azure-managed-instance-for-apache-cassandra\/","title":{"rendered":"How to use self-signed certificates to connect to Azure Managed Instance for Apache Cassandra"},"content":{"rendered":"<p>Azure Managed Instance for Apache Cassandra, a fully managed service, enables you to run Apache Cassandra workloads on Azure, freeing you from managing the infrastructure. In this blog post, I will show you how to use self-signed certificates to connect to your cluster and verify the identity of both the client and the server.<\/p>\n<h2>What is a self-signed certificate?<\/h2>\n<p>By default, all connections made by Azure Managed Instance for Apache Cassandra are secured using SSL certificates signed by a Certificate Authority (CA). Certificate authority signed certificates provide an extra layer of trust and security to all connections that use them. They are used in Cassandra\u2019s inter-node communication and the default for client-side authorization of the server. With a self-signed certificate, you act as your own CA, creating the root (private) and leaf (public) certificates. This certificate is only to verify your own client\u2019s connection to the database, so there is no need for a third party.<\/p>\n<h2>Why use self-signed certificates?<\/h2>\n<p>When you use this managed service, all communication is done through your own personal virtual network (VNet) into which resources are injected, so all traffic from client to node will be done on <a href=\"https:\/\/learn.microsoft.com\/security\/benchmark\/azure\/baselines\/virtual-network-security-baseline?toc=%2Fazure%2Fvirtual-network%2Ftoc.json%3Ftoc%3D%2Fazure%2Fvirtual-network%2Ftoc.json%3Ftoc%3D%2Fazure%2Fvirtual-network%2Ftoc.json\" target=\"_blank\" rel=\"noopener\">secure Microsoft channels<\/a>. This also allows fine tuning of the network security rules applied to the connection through network security groups (NSGs), except for certain rules needed for the operation of Cassandra.<\/p>\n<p>Self-signed certificates add an extra layer of security by enabling authentication of the client by the cluster. By default, the client verifies the cluster it is connecting to using <a href=\"https:\/\/learn.microsoft.com\/azure\/security\/fundamentals\/azure-ca-details?tabs=root-and-subordinate-cas-list\" target=\"_blank\" rel=\"noopener\">Azure\u2019s default certificates<\/a>. Those certificates are signed by a trusted certificate authority. However, in this default setup, the cluster does not verify the client, instead trusting that anyone able to access the VNet can access the database. Adding the self-signed certificates ensures that only clients who have access to the key can communicate with the cluster.<\/p>\n<p><img decoding=\"async\" class=\"wp-image-7697 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on.png\" alt=\"Is Windows Authentication Mode For Sql Server (on Premise) Supported ...\" width=\"580\" height=\"928\" srcset=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on.png 1452w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on-188x300.png 188w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on-640x1024.png 640w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on-768x1228.png 768w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on-960x1536.png 960w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2024\/03\/is-windows-authentication-mode-for-sql-server-on-1281x2048.png 1281w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/><\/p>\n<p>Figure 1: An example of the communication pattern for a mutual <a id=\"post-7695-_Int_srIUUMd7\"><\/a>TLS connection (one where the self-signed certificates are set up)<\/p>\n<h2>How to use self-signed certificates?<\/h2>\n<p>Generating a client certificate is a straightforward process. First you need a configuration file, for example: gen_rootCa_cert.conf from the <a href=\"https:\/\/docs.datastax.com\/en\/cassandra-oss\/3.x\/cassandra\/configuration\/secureSSLCertWithCA.html\" target=\"_blank\" rel=\"noopener\">DataStax documentation<\/a>:<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\"># gen_rootCa_cert.conf<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">[ <\/span><span style=\"font-family: terminal, monaco, monospace;\">req ]<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">distinguished_name = req_distinguished_name<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">prompt\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0= no<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">output_password\u00a0 \u00a0 = myPass<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">default_bits\u00a0 \u00a0 \u00a0 \u00a0= 2048<\/span>\r\n\r\n<span style=\"font-family: terminal, monaco, monospace;\">[ req_distinguished_name ]<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">C                  = US<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">O\u00a0\u00a0\u00a0\u00a0              = YourCompany<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">OU\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = TestCluster<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">CN\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = YourComputerName<\/span><\/pre>\n<p>This file contains information included in your certificate, such as the common name, country, and organization. You can edit this file to suit your needs.<\/p>\n<p>Then, if you have openssl installed on your machine, you can use the command:<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">openssl req \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -config gen_rootCa_cert.conf \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -new -x509 -nodes \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -subj \/CN=YourComputerName\/OU=TestCluster\/O=YourCompany\/C=US\/ \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -keyout rootCa.key \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -out rootCa.crt \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -days 365<\/span><\/pre>\n<p>To generate the key and the certificate in <a id=\"post-7695-_Int_o5StXvs3\"><\/a>PEM format. The client uses the key to verify the cert which the cluster provides.<\/p>\n<p>The rest of the steps described in the DataStax document are not necessary. Instead, simply run the following steps from the <a href=\"https:\/\/learn.microsoft.com\/azure\/managed-instance-apache-cassandra\/create-cluster-portal#configuring-client-certificates-optional\" target=\"_blank\" rel=\"noopener\">Quickstart Guide<\/a>:<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">resourceGroupName='&lt;Resource_Group_Name&gt;'<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">clusterName='&lt;Cluster Name&gt;'<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">az managed-cassandra cluster update \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  --resource-group $resourceGroupName \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  --cluster-name $clusterName \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  --client-certificates \/usr\/csuser\/clouddrive\/rootCert.pem<\/span><\/pre>\n<p>The reason that you do not have to follow all the steps laid out in the linked tutorial is because issuing the managed-cassandra update sets up the cassandra.yaml to use the client_encryption_options and adds the certificate you included in the command to the keystore of each node. The rolling restart applies those yaml changes to the Cassandra process.<\/p>\n<p>In the end, all nodes will expect a valid client certificate with every request.<\/p>\n<h2>How to connect to your cluster using cqlsh?<\/h2>\n<p>To connect to the cluster with cqlsh after you set up your self-signed certificates, use the following settings.<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">[authentication]<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">username = &lt;cluster-username&gt;<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">password = &lt;cluster-password&gt;<\/span>\r\n\r\n<span style=\"font-family: terminal, monaco, monospace;\">[connection]<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">hostname = &lt;node-ip OR node.managedcassandra.cosmos.azure.com&gt;<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">port = 9042<\/span>\r\n\r\n<span style=\"font-family: terminal, monaco, monospace;\">[ssl]<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">userkey = \/path\/to\/rootCa.key<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">usercert = \/path\/to\/rootCa.crt<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">certfile = \/etc\/ssl\/certs\/digicertroot.crt<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">validate = <\/span><span style=\"font-family: terminal, monaco, monospace;\">true ;; Optional, see below<\/span><\/pre>\n<p>In this file, you need to replace the following placeholders with the actual values:<\/p>\n<ul>\n<li><span style=\"font-family: terminal, monaco, monospace;\">&lt;cluster-username&gt;\/&lt;cluster-password&gt;<\/span> with your configured Cassandra login.<\/li>\n<li><span style=\"font-family: terminal, monaco, monospace;\">\/path\/to\/rootCa.key<\/span> with the path to your client certificate file.<\/li>\n<li><span style=\"font-family: terminal, monaco, monospace;\">\/path\/to\/rootCa.crt<\/span> with the path to your client key file.<\/li>\n<li><span style=\"font-family: terminal, monaco, monospace;\">\/etc\/ssl\/certs\/digicertroot.crt<\/span> with the path to your server certificate file.\n<ul>\n<li>NOTE: This is only needed when you set <span style=\"font-family: terminal, monaco, monospace;\">validate = true<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>To use validate=true, you need to enable hostname validation. The cluster uses *.managedcassandra.cosmos.azure.com for the internal node names, so you need to configure your hosts file like this, with &lt;dcname&gt; as the Cassandra datacenter name, and <a id=\"post-7695-_Int_57Oq6B89\"><\/a>IP addresses as their given values. You will need to do this for each node you want to connect to.<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">&lt;node 1 ip&gt; &lt;dcname&gt;000000.managedcassandra.cosmos.azure.com<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">&lt;node 2 ip&gt; &lt;dcname&gt;000001.managedcassandra.cosmos.azure.com<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">&lt;node 3 ip&gt; &lt;dcname&gt;000002.managedcassandra.cosmos.azure.com<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">\u2026<\/span><\/pre>\n<p>Finally, you can use the following command to launch cqlsh:<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">cqlsh --cqlshrc=\/path\/to\/cqlshrc<\/span><\/pre>\n<p>If you see any errors or warnings, you may need to check your cqlshrc file or your certificate files for any mistakes or inconsistencies. If you are using \u201cvaldate=true\u201d then check using openssl to see what certificate the cluster is providing. If it is not DigiCert, then change the certfile value in the cqlshrc to match whatever value is returned. To see that certificate, you can use the command:<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">openssl s_client -showcerts \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -connect &lt;nodename<\/span><span style=\"font-family: terminal, monaco, monospace;\">&gt;.managedcassandra.internal.cosmos.azure.com:9042 \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -cert \/path\/to\/rootCa.crt \\<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">  -key  \/path\/to\/rootCa.key<\/span><\/pre>\n<h2>How to connect to your cluster using python?<\/h2>\n<p>To connect to your cluster using python, you can use the cassandra-driver package, which provides a high-level <a id=\"post-7695-_Int_H0nnDMNt\"><\/a>API for interacting with Cassandra. You can install it using pip:<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">pip install cassandra-driver<\/span><\/pre>\n<p>Use the following configuration, adjusted for your environment, to connect with self-signed certificates through the python driver.<\/p>\n<pre><span style=\"font-family: terminal, monaco, monospace;\">import ssl<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">import cfg<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">from cassandra.auth import PlainTextAuthProvider<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">from cassandra.cluster import Cluster<\/span>\r\n\r\n<span style=\"font-family: terminal, monaco, monospace;\">ssl_context = ssl.SSLContext(<\/span><span style=\"font-family: terminal, monaco, monospace;\">ssl.PROTOCOL_TLSv1_2)<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">ssl_context.verify_mode = ssl.CERT_REQUIRED<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">ssl_context.load_verify_locations(capath=\"\/etc\/ssl\/certs\/\")<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">ssl_context.load_cert_chain(<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    \"\/path\/to\/rootCa.crt\"<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    keyfile=\"\/path\/to\/rootCa.key\")<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">auth_provider = PlainTextAuthProvider(<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    username=cfg.config['username'],<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    password=cfg.config['password'])<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">cluster = <\/span><span style=\"font-family: terminal, monaco, monospace;\">Cluster(<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    [cfg.config['contactPoint']],<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    port=cfg.config['port'],<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    auth_provider=auth_provider,<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    ssl_context=ssl_context,<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    protocol_version=4)<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">session = cluster.connect()<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">rows = session.execute('SELECT * FROM system.local')<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">for row in rows:<\/span>\r\n<span style=\"font-family: terminal, monaco, monospace;\">    print(row)<\/span><\/pre>\n<p>Note that you may need to adjust the contact points, the port, the certificates, the key file, and the queries according to your cluster configuration and schema.<\/p>\n<h2>SSL Validation<\/h2>\n<p>As seen in the examples above, when you want to validate there are extra steps you need to take. SSL hostname validation exists as an extra check the client makes to confirm that the server it is talking to is correct. At this point in the process, the client has verified that the server is authentic, confirmed by the CA signed certificates, but the extra step makes sure that the name is right. The cluster\u2019s nodes will present themselves as dcname000000.managedcassandra.cosmos.azure.com, so if you connect to them using the plain <a id=\"post-7695-_Int_YUzhbbRC\"><\/a>IP Address, this validation tells you that this is the wrong server, and the connection fails.<\/p>\n<p>It is not usually necessary, but those who need it must take those extra steps to have this final layer of protection.<\/p>\n<h2>Conclusion<\/h2>\n<p>When security is your highest priority this process to ensures that your client is validated with self-signed certificates. However, Azure Managed Instance for Apache Cassandra provides a very high level of security right out of the box and can be used in a safe way with minimal configuration.<\/p>\n<h2>About Azure Cosmos <a id=\"post-7695-_Int_OcRf8JBT\"><\/a>DB<\/h2>\n<p>Azure Cosmos DB is a fully managed and serverless distributed database for modern app development, with SLA-backed speed and availability, automatic and instant scalability, and support for open-source PostgreSQL, MongoDB, and Apache Cassandra. <a href=\"https:\/\/cosmos.azure.com\/try\/\" target=\"_blank\" rel=\"noopener\">Try Azure Cosmos DB for free here.<\/a> To stay in the loop on Azure Cosmos DB updates, follow us on <a href=\"https:\/\/twitter.com\/AzureCosmosDB\" target=\"_blank\" rel=\"noopener\">X<\/a>, <a href=\"https:\/\/aka.ms\/AzureCosmosDBYouTube\" target=\"_blank\" rel=\"noopener\">YouTube<\/a>, and <a href=\"https:\/\/www.linkedin.com\/company\/azure-cosmos-db\/\" target=\"_blank\" rel=\"noopener\">LinkedIn<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Azure Managed Instance for Apache Cassandra, a fully managed service, enables you to run Apache Cassandra workloads on Azure, freeing you from managing the infrastructure. In this blog post, I will show you how to use self-signed certificates to connect to your cluster and verify the identity of both the client and the server. What [&hellip;]<\/p>\n","protected":false},"author":150569,"featured_media":7704,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[16,14,1821],"tags":[],"class_list":["post-7695","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cassandra-api","category-core-sql-api","category-managed-instance-apache-cassandra"],"acf":[],"blog_post_summary":"<p>Azure Managed Instance for Apache Cassandra, a fully managed service, enables you to run Apache Cassandra workloads on Azure, freeing you from managing the infrastructure. In this blog post, I will show you how to use self-signed certificates to connect to your cluster and verify the identity of both the client and the server. What [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/7695","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/users\/150569"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/comments?post=7695"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/7695\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media\/7704"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media?parent=7695"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/categories?post=7695"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/tags?post=7695"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}