Accessing Elastic Stack services

edit

Accessing Elastic Stack services

edit

To access the Elastic Stack services, you will need to retrieve:

  • the elastic user password for basic authentication
  • the IP of the service, if you want to access the service from outside the Kubernetes cluster

And choose between:

  • using the self-signed certificate with the custom CA (Certificate Authority) generated by ECK
  • configuring your own certificate

Security

edit

All Elastic Stack resources deployed by the ECK Operator are secured by default. The operator sets up basic authentication and TLS to encrypt network traffic to, from, and within your Elasticsearch cluster.

Authentication

edit

To access Elasticsearch, Kibana or APM Server, the operator manages a default user named elastic with the superuser role. Its password is stored in a Secret named <name>-elastic-user.

> kubectl get secret hulk-es-elastic-user -o go-template='{{.data.elastic | base64decode }}'
42xyz42citsale42xyz42

Services

edit

You can access Elasticsearch, Kibana or APM Server by using native Kubernetes services that are not reachable from the public Internet by default.

Managing Kubernetes services

edit

For each resource, Elasticsearch, Kibana or ApmServer, the operator manages a Kubernetes service named <name>-[es|kb|apm]-http, which is of type ClusterIP by default. ClusterIP exposes the service on a cluster-internal IP and makes the service only reachable from the cluster.

> kubectl get svc

NAME                TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
hulk-apm-http       ClusterIP      10.19.212.105   <none>           8200/TCP   1m
hulk-es-http        ClusterIP      10.19.252.160   <none>           9200/TCP   1m
hulk-kb-http        ClusterIP      10.19.247.151   <none>           5601/TCP   1m

Allowing public access

edit

You can expose services in different ways by specifying an http.service.spec.type in the spec of the resource manifest. On cloud providers which support external load balancers, you can set the type field to LoadBalancer to provision a load balancer for the Service, and populate the column EXTERNAL-IP after a short delay. Depending on the cloud provider, it may incur costs.

apiVersion: <kind>.k8s.elastic.co/v1
kind: <Kind>
metadata:
  name: hulk
spec:
  version: 8.16.1
  http:
    service:
      spec:
        type: LoadBalancer
> kubectl get svc

NAME                TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
hulk-apm-http       LoadBalancer   10.19.212.105   35.176.227.106   8200:31000/TCP   1m
hulk-es-http        LoadBalancer   10.19.252.160   35.198.131.115   9200:31320/TCP   1m
hulk-kb-http        LoadBalancer   10.19.247.151   35.242.197.228   5601:31380/TCP   1m

TLS Certificates

edit

This section only covers TLS certificates for the HTTP layer. Those for the transport layer used for Elasticsearch internal communication between Elasticsearch nodes in a cluster are managed by ECK and are not configurable.

Default self-signed certificate

edit

By default, the operator manages a self-signed certificate with a custom CA for Elasticsearch, Kibana and APM Server. The CA, the certificate and the private key are each stored in a separate Secret.

> kubectl get secret | grep es-http
hulk-es-http-ca-internal         Opaque                                2      28m
hulk-es-http-certs-internal      Opaque                                2      28m
hulk-es-http-certs-public        Opaque                                1      28m

The public certificate is stored in a secret named <name>-[es|kb]-http-certs-public.

> kubectl get secret hulk-es-http-certs-public -o go-template='{{index .data "tls.crt" | base64decode }}'
-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIQHC4O/RWX15a3/P3upsm3djANBgkqhkiG9w0BAQsFADA6
...
QLYL4zLEby3vRxq65+xofVBJAaM=
-----END CERTIFICATE-----
Reserving static IP and custom domain
edit

To use a custom domain name with the self-signed certificate, you can reserve a static IP and/or use an Ingress instead of a LoadBalancer Service. Whatever you use, your DNS must be added to the certificate SAN in the spec.http.tls.selfSignedCertificate.subjectAltNames section of your Elastic resource manifest.

spec:
  http:
    service:
      spec:
        type: LoadBalancer
    tls:
      selfSignedCertificate:
        subjectAltNames:
        - ip: 160.46.176.15
        - dns: hulk.example.com

Setting up your own certificate

edit

You can bring your own certificate to configure TLS to ensure that communication between HTTP clients and the cluster is encrypted.

Create a Kubernetes secret with:

  • ca.crt: CA certificate (optional if tls.crt was issued by a well-known CA).
  • tls.crt: the certificate.
  • tls.key: the private key to the first certificate in the certificate chain.
kubectl create secret generic my-cert --from-file=ca.crt=tls.crt --from-file=tls.crt=tls.crt --from-file=tls.key=tls.key

Then you just have to reference the secret name in the http.tls.certificate section of the resource manifest.

spec:
  http:
    tls:
      certificate:
        secretName: my-cert

Disable TLS

edit

You can explicitly disable TLS for Kibana or APM Server and the HTTP layer of Elasticsearch.

spec:
  http:
    tls:
      selfSignedCertificate:
        disabled: true

Requesting the Elasticsearch endpoint

edit

You can request the Elasticsearch endpoint within or outside the Kubernetes cluster.

Within the Kubernetes cluster

  1. Retrieve the CA certificate.
  2. Retrieve the password of the elastic user.
NAME=hulk

kubectl get secret "$NAME-es-http-certs-public" -o go-template='{{index .data "tls.crt" | base64decode }}' > tls.crt
PW=$(kubectl get secret "$NAME-es-elastic-user" -o go-template='{{.data.elastic | base64decode }}')

curl --cacert tls.crt -u elastic:$PW https://$NAME-es-http:9200/

Outside the Kubernetes cluster

  1. Retrieve the CA certificate.
  2. Retrieve the password of the elastic user.
  3. Retrieve the IP of the LoadBalancer Service.
NAME=hulk

kubectl get secret "$NAME-es-http-certs-public" -o go-template='{{index .data "tls.crt" | base64decode }}' > tls.crt
IP=$(kubectl get svc "$NAME-es-http" -o jsonpath='{.status.loadBalancer.ingress[].ip}')
PW=$(kubectl get secret "$NAME-es-elastic-user" -o go-template='{{.data.elastic | base64decode }}')

curl --cacert tls.crt -u elastic:$PW https://$IP:9200/

Now you should get this message:

curl: (51) SSL: no alternative certificate subject name matches target host name '35.198.131.115'

Add the external IP of the service to the SANs of the certificate in the same Elasticsearch resource YAML manifest used to create the cluster and apply it again using kubectl.

spec:
  http:
    service:
      spec:
        type: LoadBalancer
    tls:
      selfSignedCertificate:
        subjectAltNames:
        - ip: 35.198.131.115

You can now reach Elasticsearch:

> curl --cacert tls.crt -u elastic:$PASSWORD https://$IP:9200/
{
  "name" : "hulk-es-4qk62zd928",
  "cluster_name" : "hulk",
  "cluster_uuid" : "q6itjqFqRqW576FXF0uohg",
  "version" : {...},
  "tagline" : "You Know, for Search"
}