diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b68f6a..ccea9ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,11 @@ ## New -Added example for enforcing GraphDB security (`examples/security-enforce`) demonstrating the +- Added example for enforcing GraphDB security (`examples/security-enforce`) demonstrating the `graphdb.auth.security.enabled` property, which prevents users from disabling security via the Workbench or REST API. +- Added encryption at rest configuration + ## Version 12.4.0 diff --git a/README.md b/README.md index c3ab0ba..e206e69 100644 --- a/README.md +++ b/README.md @@ -366,6 +366,13 @@ IMPORTANT: This is generated by helm-docs, do not attempt modifying it on hand a | cluster.token.secretKey | string | `""` | | | command | list | `[]` | | | configuration.defaultJavaArguments | string | `"-XX:+UseContainerSupport -XX:MaxRAMPercentage=70 -XX:-UseCompressedOops -Ddefault.min.distinct.threshold=100m"` | | +| configuration.encryption.alias | string | `"graphdb-master-key"` | | +| configuration.encryption.file | string | `""` | | +| configuration.encryption.keystorePasswordExistingSecret | string | `""` | | +| configuration.encryption.keystorePasswordSecretKey | string | `"keystorePassword"` | | +| configuration.encryption.masterKeyExistingSecret | string | `"graphdb-masterkey"` | | +| configuration.encryption.masterKeySecretKey | string | `"masterKey"` | | +| configuration.encryption.type | string | `""` | | | configuration.externalUrl | string | `"http://graphdb.127.0.0.1.nip.io/"` | | | configuration.extraProperties.configmapKey | string | `"graphdb.properties"` | | | configuration.extraProperties.existingConfigmap | string | `""` | | diff --git a/examples/encryption-at-rest/README.md b/examples/encryption-at-rest/README.md new file mode 100644 index 0000000..afbe5cf --- /dev/null +++ b/examples/encryption-at-rest/README.md @@ -0,0 +1,40 @@ +# Encryption at Rest examples for GraphDB + +This example shows how to configure the Helm chart with encryption at rest. Two alternatives are currently supported: +- Using a master key file +- Using a keystore that contains the master key + +## Requirements + +For PKCS12 configuration (i.e. keystore), you need `keytool` to create the `p12` keystore file. + +## Configuring Encryption at Rest with a master key file + +First, create the master key. The example below uses a SHA256-generated digest using `openssl` + +```bash +openssl dgst -sha256 -binary > master.key +``` + +Then, create the secret, and install the helm chart + +```bash +kubectl create secret generic graphdb-masterkey --from-file=masterKey=master.key +helm install --values enc-file-values.yaml graphdb ontotext/graphdb +``` + +## Configuring Encryption at Rest with a keystore (PKCS12) + +First, create the keystore. For this, you need `keytool` + +```bash +keytool -genseckey -alias masterkey -keyalg AES -keysize 256 -keystore master.p12 -storetype PKCS12 -storepass password -keypass password +``` + +Then, upload the keystore and the keystore password as kubectl secrets and install the helm chart + +```bash +kubectl create secret generic graphdb-masterkeystore --from-file=masterKeyStore=master.p12 +kubectl create secret generic graphdb-masterkeystorePassword --from-listeral=masterkeystorePassword=password +helm install --values enc-pkcs12-values.yaml graphdb ontotext/graphdb +``` diff --git a/examples/encryption-at-rest/enc-file-values.yaml b/examples/encryption-at-rest/enc-file-values.yaml new file mode 100644 index 0000000..1fdfe04 --- /dev/null +++ b/examples/encryption-at-rest/enc-file-values.yaml @@ -0,0 +1,6 @@ +configuration: + encryption: + type: file + file: /opt/graphdb/home/data/master.key + masterKeyExistingSecret: graphdb-masterkey + masterKeySecretKey: masterkey diff --git a/examples/encryption-at-rest/enc-pkcs12-values.yaml b/examples/encryption-at-rest/enc-pkcs12-values.yaml new file mode 100644 index 0000000..719a6d7 --- /dev/null +++ b/examples/encryption-at-rest/enc-pkcs12-values.yaml @@ -0,0 +1,10 @@ +configuration: + encryption: + type: pkcs12 + file: /opt/graphdb/home/data/master.p12 + masterKeyExistingSecret: graphdb-masterkeystore + masterKeySecretKey: masterKeyStore + keystorePasswordExistingSecret: graphdb-masterkeystorePassword + keystorePasswordSecretKey: masterkeystorePassword + alias: masterkey + diff --git a/templates/graphdb/configmap-environment.yaml b/templates/graphdb/configmap-environment.yaml index af4afbc..938ad7e 100644 --- a/templates/graphdb/configmap-environment.yaml +++ b/templates/graphdb/configmap-environment.yaml @@ -15,3 +15,10 @@ data: -Dhttp.socket.keepalive=true {{ tpl .Values.configuration.defaultJavaArguments . }} {{ tpl .Values.configuration.javaArguments . }} + {{- if .Values.configuration.encryption.type }} + GRAPHDB_DATA_ENCRYPTION_TYPE: {{ .Values.configuration.encryption.type }} + GRAPHDB_DATA_ENCRYPTION_FILE: {{ required "configuration.encryption.file is required" .Values.configuration.encryption.file }} + {{- if eq .Values.configuration.encryption.type "pkcs12" }} + GRAPHDB_DATA_ENCRYPTION_KEYSTORE_ALIAS: {{ required "configuration.encryption.alias is required " .Values.configuration.encryption.alias }} + {{- end }} + {{- end }} diff --git a/templates/graphdb/statefulset.yaml b/templates/graphdb/statefulset.yaml index fac01bb..14aa810 100644 --- a/templates/graphdb/statefulset.yaml +++ b/templates/graphdb/statefulset.yaml @@ -96,6 +96,11 @@ spec: - name: graphdb-secret-properties secret: secretName: {{ include "graphdb.fullname.secret.properties" . }} + {{- if .Values.configuration.encryption.type }} + - name: graphdb-encryption-master-key + secret: + secretName: {{ .Values.configuration.encryption.masterKeyExistingSecret }} + {{- end }} {{- if .Values.configuration.extraProperties.existingConfigmap }} - name: graphdb-extra-properties configMap: @@ -316,6 +321,9 @@ spec: name: {{ .Values.cluster.token.existingSecret }} key: {{ .Values.cluster.token.secretKey }} {{- end }} + envFrom: + - configMapRef: + name: {{ include "graphdb.fullname.configmap.environment" . }} volumeMounts: - name: {{ .Values.persistence.volumeClaimTemplate.name }} mountPath: /opt/graphdb/home @@ -345,6 +353,11 @@ spec: mountPath: /tmp/graphdb/users.js subPath: {{ .Values.security.initialUsers.secretKey }} {{- end }} + {{- if or (eq .Values.configuration.encryption.type "file" ) (eq .Values.configuration.encryption.type "pkcs12") }} + - name: graphdb-encryption-master-key + mountPath: /tmp/master.key + subPath: {{ .Values.configuration.encryption.masterKeySecretKey }} + {{- end }} {{- with .Values.initContainerSecurityContext }} securityContext: {{- toYaml . | nindent 12 }} {{- end }} @@ -407,7 +420,20 @@ spec: echo "Provisioning settings with settings.js file..." cp /tmp/graphdb/settings.js /opt/graphdb/home/data/settings.js fi - + ENC_TYPE=${GRAPHDB_DATA_ENCRYPTION_TYPE:-""} + if [[ $ENC_TYPE == @(file|pkcs12) && -f /tmp/master.key ]]; then + echo "Configuring up encryption at rest" + FILE=${GRAPHDB_DATA_ENCRYPTION_FILE:-"/opt/graphdb/home/data/master.key"} + if [[ -f ${FILE} ]]; then + echo "Master key already exists" + else + echo "Copying master key to ${FILE}" + mkdir -p $(dirname $FILE) + cp /tmp/master.key ${FILE} + chmod o-rwx ${FILE} + fi + echo "Encryption at rest configured" + fi echo 'Done' {{- with .Values.extraInitContainers }} {{- tpl (toYaml .) $ | nindent 8 }} @@ -439,8 +465,18 @@ spec: {{- with .Values.extraEnvFrom }} {{- tpl (toYaml .) $ | nindent 12 }} {{- end }} - {{- with .Values.extraEnv }} - env: {{- tpl (toYaml .) $ | nindent 12 }} + {{- if or (eq .Values.configuration.encryption.type "pkcs12") (.Values.extraEnv) }} + env: + {{- if eq .Values.configuration.encryption.type "pkcs12" }} + - name: GRAPHDB_DATA_ENCRYPTION_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ required "configuration.encryption.keystorePasswordExistingSecret is required" .Values.configuration.encryption.keystorePasswordExistingSecret }} + key: {{ required "configuration.encryption.keystorePasswordSecretKey is required" .Values.configuration.encryption.keystorePasswordSecretKey }} + {{- end }} + {{- with .Values.extraEnv }} + {{- tpl (toYaml .) $ | nindent 12 }} + {{- end }} {{- end }} volumeMounts: - name: {{ .Values.persistence.volumeClaimTemplate.name }} diff --git a/values.yaml b/values.yaml index e822dde..cd2cbb0 100644 --- a/values.yaml +++ b/values.yaml @@ -282,6 +282,32 @@ configuration: # The path where the keystore/truststore will be mounted inside the container. mountPath: /etc/graphdb/tls/tomcat/ + + # Encryption at rest configuration + # + # GraphDB implements encryption at rest by using a master key, either written to file on disk, or stored in a custom provided keystore. + # There are 3 scenarios for using this configuration + # - By leaving the `type` empty, thus disabling encryption at rest + # - By setting the `type` to `file` and providing the encryption file location + # - By setting the `type` to `pkcs12` and providing the keystore file location, the keystore password and the master key alias. + # + # - GraphDB docs: https://docs.google.com/document/d/1auDa-yHF0hh9SDe5Bvv71mRMw2a8ykd1K3Oxc2CT9b0/edit?pli=1&tab=t.0 + encryption: + # Encryption type. Cna be one of `pkcs12`, `file` or empty string. Default = "" (disabled) + type: "" + # The file that contains the master key. Can be either a simple file, or keystore + file: "" + # The secret name for the master key value + masterKeyExistingSecret: "graphdb-masterkey" + # The key corresponding to the master key secret value + masterKeySecretKey: "masterKey" + # The secret name for the keystore password, if `pkcs12` encryption key is configured + keystorePasswordExistingSecret: "" + # The key corresponding to the keystore password secret value. Default keystorePassword + keystorePasswordSecretKey: "keystorePassword" + # Master key alias, as stored in the keystore (for `type` = `pkcs12`) + alias: "graphdb-master-key" + # Configurations for GraphDB's Logback # Ref: https://graphdb.ontotext.com/documentation/11.4/diagnosing-and-reporting-critical-errors.html#logs #