diff --git a/tests/templates/kuttl/ldap/00-patch-ns.yaml b/tests/templates/kuttl/ldap/00-patch-ns.yaml new file mode 100644 index 0000000..d4f91fa --- /dev/null +++ b/tests/templates/kuttl/ldap/00-patch-ns.yaml @@ -0,0 +1,15 @@ +# see https://github.com/stackabletech/issues/issues/566 +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: | + kubectl patch namespace $NAMESPACE --patch=' + { + "metadata": { + "labels": { + "pod-security.kubernetes.io/enforce": "privileged" + } + } + }' + timeout: 120 diff --git a/tests/templates/kuttl/ldap/01-rbac.yaml b/tests/templates/kuttl/ldap/01-rbac.yaml new file mode 100644 index 0000000..64eced8 --- /dev/null +++ b/tests/templates/kuttl/ldap/01-rbac.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-service-account +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: test-role +rules: + - apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - privileged + verbs: + - use +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: test-role-binding +subjects: + - kind: ServiceAccount + name: test-service-account +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: test-role diff --git a/tests/templates/kuttl/ldap/10-assert.yaml b/tests/templates/kuttl/ldap/10-assert.yaml new file mode 100644 index 0000000..9bcbc0e --- /dev/null +++ b/tests/templates/kuttl/ldap/10-assert.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 300 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: openldap +status: + readyReplicas: 1 + replicas: 1 diff --git a/tests/templates/kuttl/ldap/10-install-openldap.yaml b/tests/templates/kuttl/ldap/10-install-openldap.yaml new file mode 100644 index 0000000..8eb3011 --- /dev/null +++ b/tests/templates/kuttl/ldap/10-install-openldap.yaml @@ -0,0 +1,81 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: openldap + labels: + app.kubernetes.io/name: openldap +spec: + selector: + matchLabels: + app.kubernetes.io/name: openldap + serviceName: openldap + replicas: 1 + template: + metadata: + labels: + app.kubernetes.io/name: openldap + spec: + serviceAccountName: test-service-account + containers: + - name: openldap + image: docker.io/bitnami/openldap:2.5 + env: + - name: LDAP_ADMIN_USERNAME + value: admin + - name: LDAP_ADMIN_PASSWORD + value: admin + - name: LDAP_ENABLE_TLS + value: "yes" + - name: LDAP_TLS_CERT_FILE + value: /tls/tls.crt + - name: LDAP_TLS_KEY_FILE + value: /tls/tls.key + - name: LDAP_TLS_CA_FILE + value: /tls/ca.crt + ports: + - name: ldap + containerPort: 1389 + - name: tls-ldap + containerPort: 1636 + volumeMounts: + - name: tls + mountPath: /tls + startupProbe: + tcpSocket: + port: 1389 + readinessProbe: + tcpSocket: + port: 1389 + # See https://github.com/bitnami/containers/issues/40841#issuecomment-1649977191 + securityContext: + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + volumes: + - name: tls + csi: + driver: secrets.stackable.tech + volumeAttributes: + secrets.stackable.tech/class: tls + secrets.stackable.tech/scope: pod +--- +apiVersion: v1 +kind: Service +metadata: + name: openldap + labels: + app.kubernetes.io/name: openldap +spec: + type: ClusterIP + ports: + - name: ldap + port: 1389 + targetPort: ldap + - name: tls-ldap + port: 1636 + targetPort: tls-ldap + selector: + app.kubernetes.io/name: openldap diff --git a/tests/templates/kuttl/ldap/11-assert.yaml b/tests/templates/kuttl/ldap/11-assert.yaml new file mode 100644 index 0000000..87d3577 --- /dev/null +++ b/tests/templates/kuttl/ldap/11-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: + - script: kubectl exec -n $NAMESPACE openldap-0 -- ldapsearch -H ldap://localhost:1389 -D cn=integrationtest,ou=users,dc=example,dc=org -w integrationtest -b ou=users,dc=example,dc=org > /dev/null + - script: kubectl exec -n $NAMESPACE openldap-0 -- bash -c LDAPTLS_CACERT=/tls/ca.crt ldapsearch -Z -H ldaps://localhost:1636 -D cn=integrationtest,ou=users,dc=example,dc=org -w integrationtest -b ou=users,dc=example,dc=org > /dev/null diff --git a/tests/templates/kuttl/ldap/11-create-ldap-user.yaml b/tests/templates/kuttl/ldap/11-create-ldap-user.yaml new file mode 100644 index 0000000..463e57f --- /dev/null +++ b/tests/templates/kuttl/ldap/11-create-ldap-user.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +metadata: + name: create-ldap-user +commands: + - script: kubectl cp -n $NAMESPACE ./create_ldap_user.sh openldap-0:/tmp + - script: kubectl exec -n $NAMESPACE openldap-0 -- sh /tmp/create_ldap_user.sh diff --git a/tests/templates/kuttl/ldap/20-create-opensearch-security-config.yaml b/tests/templates/kuttl/ldap/20-create-opensearch-security-config.yaml new file mode 100644 index 0000000..31930c0 --- /dev/null +++ b/tests/templates/kuttl/ldap/20-create-opensearch-security-config.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: > + envsubst '$NAMESPACE' < 20_opensearch-security-config.yaml | + kubectl apply -n $NAMESPACE -f - diff --git a/tests/templates/kuttl/ldap/20_opensearch-security-config.yaml.j2 b/tests/templates/kuttl/ldap/20_opensearch-security-config.yaml.j2 new file mode 100644 index 0000000..d5130a6 --- /dev/null +++ b/tests/templates/kuttl/ldap/20_opensearch-security-config.yaml.j2 @@ -0,0 +1,106 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: opensearch-security-config +stringData: + action_groups.yml: | + --- + _meta: + type: actiongroups + config_version: 2 + allowlist.yml: | + --- + _meta: + type: allowlist + config_version: 2 + + config: + enabled: false + audit.yml: | + --- + _meta: + type: audit + config_version: 2 + + config: + enabled: false + config.yml: | + --- + _meta: + type: config + config_version: 2 + + config: + dynamic: + authc: + ldap: + http_enabled: true + transport_enabled: true + order: 1 + http_authenticator: + type: basic + challenge: false + authentication_backend: + type: ldap + config: + enable_ssl: true + hosts: + - openldap.$NAMESPACE.svc.cluster.local:1636 + pemtrustedcas_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/ca.crt + userbase: ou=users,dc=example,dc=org + username_attribute: uid + usersearch: (cn={0}) + verify_hostnames: true + authz: {} + internal_users.yml: | + --- + # The hash value is a bcrypt hash and can be generated with plugin/tools/hash.sh + + _meta: + type: internalusers + config_version: 2 + + admin: + hash: $2y$10$xRtHZFJ9QhG9GcYhRpAGpufCZYsk//nxsuel5URh0GWEBgmiI4Q/e + reserved: true + backend_roles: + - admin + description: OpenSearch admin user + + kibanaserver: + hash: $2y$10$vPgQ/6ilKDM5utawBqxoR.7euhVQ0qeGl8mPTeKhmFT475WUDrfQS + reserved: true + description: OpenSearch Dashboards user + nodes_dn.yml: | + --- + _meta: + type: nodesdn + config_version: 2 + roles.yml: | + --- + _meta: + type: roles + config_version: 2 + roles_mapping.yml: | + --- + _meta: + type: rolesmapping + config_version: 2 + + all_access: + reserved: false + backend_roles: + - admin + users: + - integrationtest + + kibana_server: + reserved: true + users: + - kibanaserver + tenants.yml: | + --- + _meta: + type: tenants + config_version: 2 diff --git a/tests/templates/kuttl/ldap/21-assert.yaml.j2 b/tests/templates/kuttl/ldap/21-assert.yaml.j2 new file mode 100644 index 0000000..65425bd --- /dev/null +++ b/tests/templates/kuttl/ldap/21-assert.yaml.j2 @@ -0,0 +1,12 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 600 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: opensearch-nodes-default +status: + readyReplicas: 3 + replicas: 3 diff --git a/tests/templates/kuttl/ldap/21-install-opensearch.yaml.j2 b/tests/templates/kuttl/ldap/21-install-opensearch.yaml.j2 new file mode 100644 index 0000000..7a7ae18 --- /dev/null +++ b/tests/templates/kuttl/ldap/21-install-opensearch.yaml.j2 @@ -0,0 +1,66 @@ +--- +apiVersion: opensearch.stackable.tech/v1alpha1 +kind: OpenSearchCluster +metadata: + name: opensearch +spec: + image: +{% if test_scenario['values']['opensearch'].find(",") > 0 %} + custom: "{{ test_scenario['values']['opensearch'].split(',')[1] }}" + productVersion: "{{ test_scenario['values']['opensearch'].split(',')[0] }}" +{% else %} + productVersion: "{{ test_scenario['values']['opensearch'] }}" +{% endif %} + pullPolicy: IfNotPresent + nodes: + roleGroups: + default: + replicas: 3 + envOverrides: + DISABLE_INSTALL_DEMO_CONFIG: "true" + OPENSEARCH_HOME: {{ test_scenario['values']['opensearch_home'] }} + configOverrides: + opensearch.yml: + # Disable memory mapping in this test; If memory mapping were activated, the kernel setting + # vm.max_map_count would have to be increased to 262144 on the node. + node.store.allow_mmap: "false" + plugins.security.allow_default_init_securityindex: "true" + plugins.security.ssl.transport.enabled: "true" + plugins.security.ssl.transport.pemcert_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/tls.crt + plugins.security.ssl.transport.pemkey_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/tls.key + plugins.security.ssl.transport.pemtrustedcas_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/ca.crt + plugins.security.ssl.http.enabled: "true" + plugins.security.ssl.http.pemcert_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/tls.crt + plugins.security.ssl.http.pemkey_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/tls.key + plugins.security.ssl.http.pemtrustedcas_filepath: {{ test_scenario['values']['opensearch_home'] }}/config/tls/ca.crt + podOverrides: + spec: + containers: + - name: opensearch + volumeMounts: + - name: security-config + mountPath: {{ test_scenario['values']['opensearch_home'] }}/config/opensearch-security + readOnly: true + - name: tls + mountPath: {{ test_scenario['values']['opensearch_home'] }}/config/tls + readOnly: true + securityContext: + fsGroup: 1000 + volumes: + - name: security-config + secret: + secretName: opensearch-security-config + - name: tls + ephemeral: + volumeClaimTemplate: + metadata: + annotations: + secrets.stackable.tech/class: tls + secrets.stackable.tech/scope: node,pod,service=opensearch,service=opensearch-nodes-default-headless + spec: + storageClassName: secrets.stackable.tech + accessModes: + - ReadWriteOnce + resources: + requests: + storage: "1" diff --git a/tests/templates/kuttl/ldap/30-assert.yaml b/tests/templates/kuttl/ldap/30-assert.yaml new file mode 100644 index 0000000..bebbaa9 --- /dev/null +++ b/tests/templates/kuttl/ldap/30-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 600 +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: test-opensearch +status: + succeeded: 1 diff --git a/tests/templates/kuttl/ldap/30-test-opensearch.yaml b/tests/templates/kuttl/ldap/30-test-opensearch.yaml new file mode 100644 index 0000000..ebc8b68 --- /dev/null +++ b/tests/templates/kuttl/ldap/30-test-opensearch.yaml @@ -0,0 +1,166 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: test-opensearch +spec: + template: + spec: + containers: + - name: test-opensearch + image: oci.stackable.tech/sdp/testing-tools:0.2.0-stackable0.0.0-dev + command: + - /bin/bash + - -euxo + - pipefail + - -c + args: + - | + pip install opensearch-py + python scripts/test.py + env: + # required for pip install + - name: HOME + value: /stackable + volumeMounts: + - name: script + mountPath: /stackable/scripts + - name: tls + mountPath: /stackable/tls + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + resources: + requests: + memory: 128Mi + cpu: 100m + limits: + memory: 128Mi + cpu: 400m + volumes: + - name: script + configMap: + name: test-opensearch + - name: tls + ephemeral: + volumeClaimTemplate: + metadata: + annotations: + secrets.stackable.tech/class: tls + spec: + storageClassName: secrets.stackable.tech + accessModes: + - ReadWriteOnce + resources: + requests: + storage: "1" + serviceAccountName: test-service-account + securityContext: + fsGroup: 1000 + restartPolicy: OnFailure +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test-opensearch +data: + test.py: | + # https://docs.opensearch.org/docs/latest/clients/python-low-level/#sample-program + + from opensearchpy import OpenSearch + + host = 'opensearch' + port = 9200 + auth = ('integrationtest', 'integrationtest') # For testing only. Don't store credentials in code. + ca_certs_path = '/stackable/tls/ca.crt' + + # Create the client with SSL/TLS enabled, but hostname verification disabled. + client = OpenSearch( + hosts = [{'host': host, 'port': port}], + http_compress = True, # enables gzip compression for request bodies + http_auth = auth, + # client_cert = client_cert_path, + # client_key = client_key_path, + use_ssl = True, + verify_certs = True, + ssl_assert_hostname = False, + ssl_show_warn = False, + ca_certs = ca_certs_path + ) + + # Create an index with non-default settings. + index_name = 'python-test-index' + index_body = { + 'settings': { + 'index': { + 'number_of_shards': 4 + } + } + } + + response = client.indices.create(index=index_name, body=index_body) + print('\nCreating index:') + print(response) + + # Add a document to the index. + document = { + 'title': 'Moneyball', + 'director': 'Bennett Miller', + 'year': '2011' + } + id = '1' + + response = client.index( + index = index_name, + body = document, + id = id, + refresh = True + ) + + print('\nAdding document:') + print(response) + + # Perform bulk operations + + movies = '{ "index" : { "_index" : "my-dsl-index", "_id" : "2" } } \n { "title" : "Interstellar", "director" : "Christopher Nolan", "year" : "2014"} \n { "create" : { "_index" : "my-dsl-index", "_id" : "3" } } \n { "title" : "Star Trek Beyond", "director" : "Justin Lin", "year" : "2015"} \n { "update" : {"_id" : "3", "_index" : "my-dsl-index" } } \n { "doc" : {"year" : "2016"} }' + + client.bulk(body=movies) + + # Search for the document. + q = 'miller' + query = { + 'size': 5, + 'query': { + 'multi_match': { + 'query': q, + 'fields': ['title^2', 'director'] + } + } + } + + response = client.search( + body = query, + index = index_name + ) + print('\nSearch results:') + print(response) + + # Delete the document. + response = client.delete( + index = index_name, + id = id + ) + + print('\nDeleting document:') + print(response) + + # Delete the index. + response = client.indices.delete( + index = index_name + ) + + print('\nDeleting index:') + print(response) diff --git a/tests/templates/kuttl/ldap/create_ldap_user.sh b/tests/templates/kuttl/ldap/create_ldap_user.sh new file mode 100755 index 0000000..eaf8c51 --- /dev/null +++ b/tests/templates/kuttl/ldap/create_ldap_user.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# To check the existing users +# ldapsearch -H ldap://localhost:1389 -D cn=admin,dc=example,dc=org -w admin -b ou=users,dc=example,dc=org + +# To check the new user +# ldapsearch -H ldap://localhost:1389 -D cn=integrationtest,ou=users,dc=example,dc=org -w integrationtest -b ou=users,dc=example,dc=org + +cat << 'EOF' | ldapadd -H ldap://localhost:1389 -D cn=admin,dc=example,dc=org -w admin +dn: cn=integrationtest,ou=users,dc=example,dc=org +objectClass: inetOrgPerson +objectClass: posixAccount +objectClass: shadowAccount +cn: integrationtest +uid: integrationtest +givenName: Stackable +sn: Integration-Test +mail: integrationtest@stackable.de +uidNumber: 16842 +gidNumber: 100 +homeDirectory: /home/integrationtest +loginShell: /bin/bash +userPassword: {crypt}x +shadowLastChange: 0 +shadowMax: 0 +shadowWarning: 0 +EOF + +ldappasswd -H ldap://localhost:1389 -D cn=admin,dc=example,dc=org -w admin -s integrationtest "cn=integrationtest,ou=users,dc=example,dc=org" diff --git a/tests/test-definition.yaml b/tests/test-definition.yaml index 161a87d..ee2f34a 100644 --- a/tests/test-definition.yaml +++ b/tests/test-definition.yaml @@ -25,6 +25,11 @@ tests: - opensearch - openshift - opensearch_home + - name: ldap + dimensions: + - opensearch + - openshift + - opensearch_home suites: - name: nightly patch: