Skip to content

Instantly share code, notes, and snippets.

@bradfordcp
Last active October 2, 2023 14:03
Show Gist options
  • Save bradfordcp/9d274c6a55bb7734735213669d83e54b to your computer and use it in GitHub Desktop.
Save bradfordcp/9d274c6a55bb7734735213669d83e54b to your computer and use it in GitHub Desktop.

Demo for running Apache Cassandra on OpenShift

This directory contains all Kubernetes resources required to run a Apache Cassandra cluster on OpenShift 4 with cass-operator. It optionally provides TLS encryption for client connections and inter-node communication with certificates managed by cert-manager.

Prerequisites

  1. OpenShift 4 cluster
  2. A storage class named gp2 with volumeBindingMode: WaitForFirstConsumer
  3. oc CLI configured to communicate with the cluster
  4. make

Deploying Cassandra

make setup
make deploy-cassandra-base

This will create a single DC, 3-node Cassandra cluster with 3 racks. Verify the cluster is up and healthy:

oc get pods
NAME                           READY   STATUS    RESTARTS   AGE
demo-cluster-dc1-rack1-sts-0   2/2     Running   0          7m12s
demo-cluster-dc1-rack2-sts-0   2/2     Running   0          7m12s
demo-cluster-dc1-rack3-sts-0   2/2     Running   0          7m12s

oc get cassdc dc1
...
Status:
  Cassandra Operator Progress:  Ready

Enabling TLS

Create the TLS infrastructure (issuers / CA certificate) with cert-manager

# Create the TLS infrastructure
make setup-issuers

First we must request a signed certificate from the issuer

# Request a TLS certificate for use with this DC
make create-cluster-certificate

Then we perform the following steps to deploy the certificate and enable TLS. Note we must deploy the certificate and keystore before enabling TLS this is handled within thetls-disabled version of the CassandraDatacenter spec. The following tls-optional version enables TLS, but doesn't require its usage. This allows for transitioning the cluster from unencrypted to encrypted communication. Finally we perform one more rolling restart on the cluster requiring TLS for all communication.

# Perform each step only after the rolling restart of the cluster is complete
make deploy-cassandra-tls-disabled
make deploy-cassandra-tls-optional
make deploy-cassandra-tls-enforced

Certificate Management

While this demo uses cert-manager to manage the certificate process it is not required. You may optionally create a Kubernetes Secret which contains a keystore and truststore.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ca
namespace: tls-demo
spec:
isCA: true
commonName: ca
secretName: ca-root-secret
privateKey:
algorithm: ECDSA
size: 256
issuerRef:
name: selfsigned
kind: Issuer
group: cert-manager.io
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ca
namespace: tls-demo
spec:
ca:
secretName: ca-root-secret
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
name: dc1
namespace: tls-demo
spec:
clusterName: demo-cluster
serverType: cassandra
serverVersion: 4.0.9
size: 3
resources:
requests:
cpu: '1'
memory: 16Gi
racks:
- name: rack1
- name: rack2
- name: rack3
storageConfig:
cassandraDataVolumeClaimSpec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 128Gi
storageClassName: gp2
config:
cassandra-yaml:
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
num_tokens: 16
role_manager: CassandraRoleManager
jvm-server-options:
initial_heap_size: 4G
max_heap_size: 4G
managementApiAuth:
insecure: {}
podTemplateSpec:
spec:
containers: []
securityContext: {}
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
name: dc1
namespace: tls-demo
spec:
clusterName: demo-cluster
serverType: cassandra
serverVersion: 4.0.9
size: 3
resources:
requests:
cpu: '1'
memory: 16Gi
racks:
- name: rack1
- name: rack2
- name: rack3
storageConfig:
cassandraDataVolumeClaimSpec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 128Gi
storageClassName: gp2
config:
cassandra-yaml:
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
num_tokens: 16
role_manager: CassandraRoleManager
client_encryption_options:
enabled: true
# If enabled and optional is set to true encrypted and unencrypted connections are handled.
optional: true
keystore: /crypto/keystore.jks
keystore_password: changeit
require_client_auth: true
# Set trustore and truststore_password if require_client_auth is true
truststore: /crypto/truststore.jks
truststore_password: changeit
protocol: TLS
# cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA] # An earlier version of this manifest configured cipher suites but the proposed config was less secure. This section does not need to be modified.
server_encryption_options:
internode_encryption: none
optional: true
keystore: /crypto/keystore.jks
keystore_password: changeit
truststore: /crypto/truststore.jks
truststore_password: changeit
jvm-server-options:
initial_heap_size: 4G
max_heap_size: 4G
managementApiAuth:
insecure: {}
podTemplateSpec:
spec:
containers:
- name: cassandra
volumeMounts:
- name: certs
mountPath: /crypto
volumes:
- name: certs
secret:
secretName: demo-cluster-tls
securityContext: {}
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
name: dc1
namespace: tls-demo
spec:
clusterName: demo-cluster
serverType: cassandra
serverVersion: 4.0.9
size: 3
resources:
requests:
cpu: '1'
memory: 16Gi
racks:
- name: rack1
- name: rack2
- name: rack3
storageConfig:
cassandraDataVolumeClaimSpec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 128Gi
storageClassName: gp2
config:
cassandra-yaml:
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
num_tokens: 16
role_manager: CassandraRoleManager
client_encryption_options:
enabled: true
# If enabled and optional is set to true encrypted and unencrypted connections are handled.
optional: true
keystore: /crypto/keystore.jks
keystore_password: changeit
require_client_auth: true
# Set trustore and truststore_password if require_client_auth is true
truststore: /crypto/truststore.jks
truststore_password: changeit
protocol: TLS
# cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA] # An earlier version of this manifest configured cipher suites but the proposed config was less secure. This section does not need to be modified.
server_encryption_options:
internode_encryption: all
optional: true
keystore: /crypto/keystore.jks
keystore_password: changeit
truststore: /crypto/truststore.jks
truststore_password: changeit
jvm-server-options:
initial_heap_size: 4G
max_heap_size: 4G
managementApiAuth:
insecure: {}
podTemplateSpec:
spec:
containers:
- name: cassandra
volumeMounts:
- name: certs
mountPath: /crypto
volumes:
- name: certs
secret:
secretName: demo-cluster-tls
securityContext: {}
apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
name: dc1
namespace: tls-demo
spec:
clusterName: demo-cluster
serverType: cassandra
serverVersion: 4.0.9
size: 3
resources:
requests:
cpu: '1'
memory: 16Gi
racks:
- name: rack1
- name: rack2
- name: rack3
storageConfig:
cassandraDataVolumeClaimSpec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 128Gi
storageClassName: gp2
config:
cassandra-yaml:
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
num_tokens: 16
role_manager: CassandraRoleManager
client_encryption_options:
enabled: true
# If enabled and optional is set to true encrypted and unencrypted connections are handled.
optional: true
keystore: /crypto/keystore.jks
keystore_password: changeit
require_client_auth: true
# Set trustore and truststore_password if require_client_auth is true
truststore: /crypto/truststore.jks
truststore_password: changeit
protocol: TLS
# cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA] # An earlier version of this manifest configured cipher suites but the proposed config was less secure. This section does not need to be modified.
server_encryption_options:
internode_encryption: all
optional: false
keystore: /crypto/keystore.jks
keystore_password: changeit
truststore: /crypto/truststore.jks
truststore_password: changeit
jvm-server-options:
initial_heap_size: 4G
max_heap_size: 4G
managementApiAuth:
insecure: {}
podTemplateSpec:
spec:
containers:
- name: cassandra
volumeMounts:
- name: certs
mountPath: /crypto
volumes:
- name: certs
secret:
secretName: demo-cluster-tls
securityContext: {}
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: demo-cluster
namespace: tls-demo
spec:
secretName: demo-cluster-tls
keystores:
jks:
create: true
passwordSecretRef: # Password used to encrypt the keystore
key: keystore-pass
name: jks-password
duration: 2160h # 90d
renewBefore: 360h # 15d
subject:
organizations:
- DataStax
isCA: false
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
usages:
- server auth
- client auth
dnsNames:
- demo-cluster-dc1-service.tls-demo.svc.cluster.local
issuerRef:
name: ca
kind: Issuer
group: cert-manager.io
.PHONY: setup
setup:
oc project tls-demo
echo "Login to the OpenShift console and install cass-operator and cert-manager operators either globally or within the tls-demo namespace"
.PHONY: setup-issuers
setup-issuers:
echo "Provisioning self signed certificate issuer and CA with cert-manager"
oc apply -f selfsigned.issuer.yaml
oc apply -f ca.certificate.yaml
oc apply -f ca.issuer.yaml
.PHONY: clean
clean:
oc delete -f ./demo.0.cassdc.yaml
oc delete -f ./demo.certificate.yaml
oc delete secret jks-password
oc delete secret demo-cluster-tls
oc delete secret demo-cluster-superuser
.PHONY: deploy-cassandra-base
deploy-cassandra-base:
echo "Deploying basic cluster with no TLS configured"
oc apply -f demo.0.cassdc.yaml
.PHONY: create-cluster-certificate
create-cluster-certificate:
echo "Deploying JKS password Secret and requesting a certificate for the cluster"
oc create secret generic jks-password --from-file=keystore-pass
oc apply -f demo.certificate.yaml
.PHONY: deploy-cassandra-tls-disabled
deploy-cassandra-tls-disabled:
echo "Deploying signed certificate to Cassandra cluster with TLS set to disabled"
oc apply -f demo.1.cassdc.yaml
.PHONY: deploy-cassandra-tls-optional
deploy-cassandra-tls-optional:
echo "Deploying signed certificate to Cassandra cluster with TLS set to optional"
oc apply -f demo.2.cassdc.yaml
.PHONY: deploy-cassandra-tls-enforced
deploy-cassandra-tls-enforced:
echo "Deploying cassandra.yaml change requiring TLS for all communication"
oc apply -f demo.3.cassdc.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned
namespace: tls-demo
spec:
selfSigned: {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment