Summary
This article will discuss how to set up and connect with the python driver to a DSE cluster with Kerberos.
Applies to
- DataStax Enterprise
Solution
My dse.yaml:
authentication_options:
other_schemes:
- internal
scheme_permissions: false
default_scheme: kerberos
enabled: true
kerberos_options:
keytab: /home/automaton/ctool_security/dse.keytab
service_principal: dse_automaton/_HOST@lacerda-kerberos
http_principal: HTTP/_HOST@lacerda-kerberos
qop: auth
My kerberos principals which I added with addprinc:
kadmin: listprincs
HTTP/ip-10-101-32-144.srv101.dsinternal.org@lacerda-kerberos
HTTP/ip-10-101-32-187.srv101.dsinternal.org@lacerda-kerberos
HTTP/ip-10-101-33-155.srv101.dsinternal.org@lacerda-kerberos
K/M@lacerda-kerberos
automaton@lacerda-kerberos
cassandra/admin@lacerda-kerberos
cassandra@lacerda-kerberos
dse_automaton/ip-10-101-32-144.srv101.dsinternal.org@lacerda-kerberos
dse_automaton/ip-10-101-32-187.srv101.dsinternal.org@lacerda-kerberos
dse_automaton/ip-10-101-33-155.srv101.dsinternal.org@lacerda-kerberos
kadmin/admin@lacerda-kerberos
kadmin/changepw@lacerda-kerberos
kadmin/ip-10-101-32-187.srv101.dsinternal.org@lacerda-kerberos
kiprop/ip-10-101-32-187.srv101.dsinternal.org@lacerda-kerberos
krbtgt/lacerda-kerberos@lacerda-kerberos
root/admin@lacerda-kerberos
As you can see from the above, I have a 3 node cluster and have added principals for HTTP and dse_automaton for all 3 nodes ([dse_automaton|HTTP]/{hostname}@{realm}).
This portion is optional, you can use kinit or setup a keytab, it's your preference. For me, after adding all of my principles, including the user principal that I will be connecting with, I set up a keytab named dse.keytab for my user service principal cassandra:
$ kadmin -kt dse.keytab -p cassandra
Authenticating as principal cassandra with keytab dse.keytab.
Password for cassandra@lacerda-kerberos:
kadmin: ktadd -k dse.keytab cassandra@lacerda-kerberos
Entry for principal cassandra@lacerda-kerberos with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:dse.keytab.
Entry for principal cassandra@lacerda-kerberos with kvno 2, encryption type des-hmac-sha1 added to keytab WRFILE:dse.keytab.
Entry for principal cassandra@lacerda-kerberos with kvno 2, encryption type des-cbc-md5 added to keytab WRFILE:dse.keytab.
kadmin: exit
My dse.keytab looked like the following:
$ klist -kt dse.keytab -e
Keytab name: FILE:dse.keytab
KVNO Timestamp Principal
---- ------------------- ------------------------------------------------------
2 01/20/2021 03:04:48 cassandra@lacerda-kerberos (arcfour-hmac)
2 01/20/2021 03:04:48 cassandra@lacerda-kerberos (des-hmac-sha1)
2 01/20/2021 03:04:48 cassandra@lacerda-kerberos (des-cbc-md5)
Here's my ~/.cassandra/cqlshrc file:
[kerberos]
hostname = ip-10-101-32-187.srv101.dsinternal.org
service = dse_automaton
[connection]
hostname = ip-10-101-32-187.srv101.dsinternal.org
And within cqlsh, I set up several roles for the user principals:
cqlsh> list roles;
role | super | login | options
-----------------------------------------------------------------------+-------+-------+---------
cassandra | True | True | {}
cassandra/admin@lacerda-kerberos | True | True | {}
cassandra@lacerda-kerberos | True | True | {}
From my remote client laptop, I ran kinit to get a ticket from the KDC:
$ kinit -p cassandra
Or, if you're using a keytab for your user principal like I did:
$ kinit -kt dse.keytab -p cassandra@lacerda-kerberos
And here's the ticket that was produced from the kinit:
$ klist
Ticket cache: KCM:501
Default principal: cassandra@lacerda-kerberos
Valid starting Expires Service principal
01/19/2021 07:13:18 01/19/2021 17:13:18 krbtgt/lacerda-kerberos@lacerda-kerberos
renew until 01/26/2021 07:13:13
And for complete transparency, my /etc/krb5.conf file looks like this (same on client and KDC server):
[libdefaults]
default_realm = lacerda-kerberos
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 72h
renew_lifetime = 7d
forwardable = true
# The following krb5.conf variables are only for MIT Kerberos.
krb4_config = /etc/krb.conf
krb4_realms = /etc/krb.realms
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
# The following encryption type specification will be used by MIT Kerberos
# if uncommented. In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.
#
# Thie only time when you might need to uncomment these lines and change
# the enctypes is if you have local software that will break on ticket
# caches containing ticket encryption types it doesn't know about (such as
# old versions of Sun Java).
# default_tgs_enctypes = des3-hmac-sha1
# default_tkt_enctypes = des3-hmac-sha1
# permitted_enctypes = des3-hmac-sha1
# The following libdefaults parameters are only for Heimdal Kerberos.
v4_instance_resolve = false
v4_name_convert = {
host = {
rcmd = host
ftp = ftp
}
plain = {
something = something-else
}
}
fcc-mit-ticketflags = true
[realms]
LACERDA-KERBEROS = {
kdc = 10.101.32.187
admin_server = 10.101.32.187
default_domain = lacerda-kerberos
}
lacerda-kerberos = {
kdc = 10.101.32.187
admin_server = 10.101.32.187
}
[domain_realm]
.mit.edu = ATHENA.MIT.EDU
mit.edu = ATHENA.MIT.EDU
.media.mit.edu = MEDIA-LAB.MIT.EDU
media.mit.edu = MEDIA-LAB.MIT.EDU
.csail.mit.edu = CSAIL.MIT.EDU
csail.mit.edu = CSAIL.MIT.EDU
.whoi.edu = ATHENA.MIT.EDU
whoi.edu = ATHENA.MIT.EDU
.stanford.edu = stanford.edu
.slac.stanford.edu = SLAC.STANFORD.EDU
.toronto.edu = UTORONTO.CA
.utoronto.ca = UTORONTO.CA
[login]
krb4_convert = true
krb4_get_tickets = false
I had to install some packages prior to running any code:
sudo pip install git+git://github.com/datastax/python-driver
sudo pip install pure_sasl
sudo pip install kerberos
With my ticket and the preparations complete, I was able to create the following python code to connect to my DSE cluster:
from dse.auth import DSEGSSAPIAuthProvider
from dse.cluster import Cluster
auth_provider = DSEGSSAPIAuthProvider(service='dse_automaton', qops=["auth"] )
cluster = Cluster(auth_provider=auth_provider, contact_points=("10.101.32.187",), port=9042)
session = cluster.connect()
print(session.execute("select * from keyspace1.names").one())