Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support user configs, user secrets and separate environments for cassandra and sidecar #218

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ spec:
type: object
spec:
properties:
backupSecretVolume:
backupSecretVolumeSource:
type: object
cassandraEnv:
items:
type: object
type: array
cassandraImage:
type: string
cluster:
Expand All @@ -37,10 +41,6 @@ spec:
type: string
dataVolumeClaimSpec:
type: object
env:
items:
type: object
type: array
imagePullPolicy:
type: string
imagePullSecrets:
Expand All @@ -56,11 +56,15 @@ spec:
type: boolean
resources:
type: object
sidecarEnv:
items:
type: object
type: array
sidecarImage:
type: string
userConfigMapVolumeSource:
type: object
userSecretVolume:
userSecretVolumeSource:
type: object
required:
- nodes
Expand Down
13 changes: 8 additions & 5 deletions doc/backup_restore.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ You can inspect the secret created via `kubectl describe secrets/awsbackuptest`
Create a `CassandraDataCenter` CRD that injects the secret as environment variables that matches the AWS client libraries expected env variables:

```yaml
env:
sidecarEnv:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
Expand Down Expand Up @@ -65,7 +65,7 @@ spec:
resources:
requests:
storage: 100Mi
env:
sidecarEnv:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
Expand All @@ -85,6 +85,9 @@ spec:
To create a cluster using this yaml file use `kubectl apply -f myBackupCluster.yaml`

## Configuring GCP Object Storage via environment variables
The backup credentials will be added to the sidecar container at the `/tmp/backup-creds` location.
Use this location to set GOOGLE_APPLICATION_CREDENTIALS environment variable to the key json file stored in the secret.

First create a secret in kubernetes to hold a Google service account token/file (assuming they are stored in files named access and secret respectively).

`kubectl create secret generic gcp-auth-reference --from-file=my_service_key.json`
Expand Down Expand Up @@ -118,14 +121,14 @@ spec:
resources:
requests:
storage: 100Mi
userSecretSource:
backupSecretVolumeSource:
name: gcp-auth-reference
items:
- key: my_service_key.json
path: my_service_key.json
env:
sidecarEnv:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: "/tmp/user-secret/my_service_key.json"
value: "/tmp/backup-creds/my_service_key.json"
- name: GOOGLE_CLOUD_PROJECT
value: "cassandra-operator"
- name: BUCKET_NAME
Expand Down
120 changes: 120 additions & 0 deletions doc/tls-encryption.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
### SSL encryption

This is an example for running cassandra with ssl encryption using the operator.
Assuming you already have [generated keys](https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLCertWithCA.html) :
* keystore.jks
* trustore.jks
* cacert.pem (containing the root certificate)

Create a secret with those files :
```bash
kubectl create secret generic dc1-user-secret \
--from-file=keystore.jks \
--from-file=truststore.jks \
--from-file=cacert.pem
```

Create a config map with 2 entries:
* a cassandra yaml fragment for configuring node-to-node and client-to-node encryption
* `cqlshrc` to make cqlsh work with ssl

For instance :
```bash
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: dc1-user-config
data:
cassandra_ssl: |
server_encryption_options:
internode_encryption: all
keystore: /tmp/user-secret-config/keystore.jks
# keystore_password: myKeyPass
truststore: /tmp/user-secret-config/truststore.jks
#truststore_password: truststorePass
# More advanced defaults below:
protocol: TLSv1.2
algorithm: SunX509
store_type: JKS
cipher_suites: [TLS_RSA_WITH_AES_256_CBC_SHA]
require_client_auth: true
client_encryption_options:
enabled: true
keystore: /tmp/user-secret-config/keystore.jks ## Path to your .keystore file
# keystore_password: keystore password ## Password that you used to generate the keystore
truststore: /tmp/user-secret-config/truststore.jks ## Path to your .truststore
#truststore_password: truststore password ## Password that you used to generate the truststore
protocol: TLSv1.2
store_type: JKS
algorithm: SunX509
require_client_auth: false
cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA]
cqlshrc: |
[connection]
factory = cqlshlib.ssl.ssl_transport_factory
ssl = true

[ssl]
certfile = /tmp/user-secret-config/cacert.pem
validate = true

[authentication]
# username = cassandra // use the one provided during certificate generation
# password = cassandra // use the one provided during certificate generation
EOF
```

## Deploying the cluster with TLS
The credentials will be added to the cassandra container at the `/tmp/user-secret-config` location, so we use that in the
`cqlshrc` configuration in the configMap example above.
The yaml fragment and the cqlshrc are going to be added to the `/etc/cassandra/` inside the container.

We also use an environment variable **CQLSHRC** to let operator move the `cqlshrc` file
to the default folder where cqlsh will expect to find it (~/.cassandra)

Create a `CassandraDataCenter` CRD that injects the secret, configuration and the environment variable
into the cassandra container:

```yaml
apiVersion: stable.instaclustr.com/v1
kind: CassandraDataCenter
metadata:
name: foo-cassandra
labels:
app: cassandra
chart: cassandra-0.1.0
release: foo
spec:
replicas: 3
cassandraImage: "gcr.io/cassandra-operator/cassandra:latest"
sidecarImage: "gcr.io/cassandra-operator/cassandra-sidecar:latest"
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 512Mi
requests:
memory: 512Mi
dataVolumeClaim:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
userSecretVolumeSource:
secretName: dc1-user-secret
userConfigMapVolumeSource:
name: dc1-user-config
# type is a workaround for https://github.com/kubernetes/kubernetes/issues/68466
type: array
items:
- key: cassandra_ssl
path: cassandra.yaml.d/003-ssl.yaml
- key: cqlshrc
path: cqlshrc
cassandraEnv:
- name: CQLSHRC
value: "/etc/cassandra/cqlshrc"
prometheusEnabled: false
```

8 changes: 8 additions & 0 deletions docker/cassandra/entry-point
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ do
done
)

# Copy over cqlshrc to a default location if defined as ENV
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can make this nicer. It IMO shouldn't be a requirement that users have to define an environment variable and add a file to a config map to get cqlsh to function.

Instead I suggest that we write our own wrapper for cqlsh that detects if SSL is enabled, and fetches the CA cert (or just disables trust checking). This will also be necessary once we support authn/authz, since we need to implement shared-secret support.

As a side question, should cqlsh be installed the C* container at all? If people want to connect to the cluster, should they instead start a new pod/container that just contains cqlsh?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zegelin we currently use cqlsh now in cql-readiness-probe, and this is easily replaceable with either python script or, say, a statically compiled gocql simple program. So we don't have an inherent requirement to have it in the container at all.

Also, if people want to use cqlsh to connect to the cluster, they can either spin a new container with all the certificates and custom configs as they need to, or have it installed locally if they have the network access to the cluster. So, if you think that's a good path to follow, I can replace the readiness script with something else pretty quickly and stop the dependency on cqlsh.

Copy link
Contributor Author

@alourie alourie Aug 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did rush it a bit. Clearly, any "script" we use will have to know about SSL configuration to be able to connect to the node. So having a wrapper around cqlsh might be a useful and simpler solution.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to get the PR closed, I think we should create a new issue/PR for the wrapper script and solve that one separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, I'm going to remove this part and deal with that in #241

if [[ ! -z "${CQLSHRC}" ]]; then
if [[ ! -e ~/.cassandra ]]; then
mkdir ~/.cassandra
fi
mv ${CQLSHRC} ~/.cassandra/
fi

exec /usr/sbin/cassandra
19 changes: 10 additions & 9 deletions examples/go/example-datacenter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ spec:
imagePullPolicy: IfNotPresent
imagePullSecrets:
- name: regcred
backupSecretVolume:
secretName: backup-secret
backupSecretVolumeSource:
secretName: gcp-auth-reference
# type is a workaround for https://github.com/kubernetes/kubernetes/issues/68466
type: array
items:
- key: creds.json
path: creds.json
env:
- key: my-service-key.json
path: my-service-key.json
sidecarEnv:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: "/etc/google/creds.json"
userSecretVolume:
value: "/tmp/backup-creds/my-service-key.json"
cassandraEnv:
- name: CQLSHRC
value: "/etc/cassandra/cqlshrc"
userSecretVolumeSource:
secretName: dc1-user-secret
userConfigMapVolumeSource:
name: dc1-user-config
alourie marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -33,8 +36,6 @@ spec:
path: cassandra.yaml.d/003-ssl.yaml
- key: cqlshrc
path: cqlshrc
- key: install_cqlshrc
path: cassandra-env.sh.d/003-install-cqlshrc.sh
resources:
limits:
memory: 1Gi
Expand Down
9 changes: 5 additions & 4 deletions pkg/apis/cassandraoperator/v1alpha1/cassandradatacenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ type CassandraDataCenterSpec struct {
SidecarImage string `json:"sidecarImage"`
ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy"`
ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
BackupSecretVolume v1.SecretVolumeSource `json:"backupSecretVolume,omitempty"`
UserSecretVolume v1.SecretVolumeSource `json:"userSecretVolume,omitempty"`
UserConfigMapVolumeSource v1.ConfigMapVolumeSource `json:"userConfigMapVolumeSource,omitempty"`
BackupSecretVolumeSource *v1.SecretVolumeSource `json:"backupSecretVolumeSource,omitempty"`
UserSecretVolumeSource *v1.SecretVolumeSource `json:"userSecretVolumeSource,omitempty"`
UserConfigMapVolumeSource *v1.ConfigMapVolumeSource `json:"userConfigMapVolumeSource,omitempty"`
Resources v1.ResourceRequirements `json:"resources"`
DataVolumeClaimSpec v1.PersistentVolumeClaimSpec `json:"dataVolumeClaimSpec"`
PrivilegedSupported bool `json:"privilegedSupported,omitempty"`
PrometheusSupport bool `json:"prometheusSupport"`
Env []v1.EnvVar `json:"env,omitempty"`
SidecarEnv []v1.EnvVar `json:"sidecarEnv,omitempty"`
CassandraEnv []v1.EnvVar `json:"cassandraEnv,omitempty"`
}

// CassandraDataCenterStatus defines the observed state of CassandraDataCenter
Expand Down
29 changes: 24 additions & 5 deletions pkg/apis/cassandraoperator/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions pkg/apis/cassandraoperator/v1alpha1/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading