{"id":24629567,"url":"https://github.com/framsouza/eck-saml-hot-warm-cold","last_synced_at":"2025-10-31T05:51:00.512Z","repository":{"id":168612653,"uuid":"365582254","full_name":"framsouza/eck-saml-hot-warm-cold","owner":"framsouza","description":"Setting up hot-warm-cold architecture with ECK and SAML authentication","archived":false,"fork":false,"pushed_at":"2021-06-08T07:33:25.000Z","size":61,"stargazers_count":9,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-05T20:11:18.580Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/framsouza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-08T18:14:44.000Z","updated_at":"2023-06-19T05:26:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"59dc6afc-e835-4daf-8811-9571b3a57325","html_url":"https://github.com/framsouza/eck-saml-hot-warm-cold","commit_stats":null,"previous_names":["framsouza/eck-saml-hot-warm-cold"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/framsouza/eck-saml-hot-warm-cold","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framsouza%2Feck-saml-hot-warm-cold","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framsouza%2Feck-saml-hot-warm-cold/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framsouza%2Feck-saml-hot-warm-cold/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framsouza%2Feck-saml-hot-warm-cold/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/framsouza","download_url":"https://codeload.github.com/framsouza/eck-saml-hot-warm-cold/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framsouza%2Feck-saml-hot-warm-cold/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278297785,"owners_count":25963793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-25T06:13:16.237Z","updated_at":"2025-10-04T10:14:55.924Z","avatar_url":"https://github.com/framsouza.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"This document explains how to set up SAML with auth0 as idp using a hot/warm/cold artechicture with ECK. The purpose of this project is to use production features such as dedicated nodes, zone awareness, pod and node affinity, podDisruption and dedicated storage class. To know more, check this [ECK](https://github.com/framsouza/eck) article. Also, you should be familiar with [SAML](https://www.elastic.co/guide/en/elasticsearch/reference/7.12/saml-guide-stack.html).\n\n\n### **Scenario**\n\nIn this scenario we deploy ECK to handle application logging along with a centralized way to authenticate into Kibana using auth0. \n\nECK is our Elastic Cloud on Kubernetes that automates the deployment, provisioning, management and setup of Elaticsearch, APM, Kibana, Beats and Enterprise Search. It’s an easy way to get Elastic Stack up and running on top of Kubernetes.\n\nAs logging and metric data (time-series) has a predictable time of life, we can use hot, warm and cold architecture to better deal with your data over time.\n\nWe will deploy the following resources:\n\n\n\n*   ECK Operator\n*   StorageClass\n*   Elasticsearch\n*   Elasticsearch role Job\n*   Kibana\n*   Ingress Controller\n*   ConfigMap SAML metadata\n\n\n### **Architecture**\n\nTo set up this environment, we use [GKE](https://cloud.google.com/kubernetes-engine) (Google Kubernetes Engine) with the following configurations:\n\n_3 Kubernetes Nodes pools_\n\n\n\n*   1 Hot Node Pool with 6 Kubernetes instances running spread across 3 availability zones\n*   1 Warm Node Pool with Kubernetes instances running spread across 3 availability zones\n*   1 Cold Node Pool with Kubernetes instances running spread across 3 availability zones\n\n_Instances configuration_\n\n\n\n*   Hot nodes: c2-standard-4 (4 vCPUs, 16 GB memory)\n*   Warm nodes: e2-standard-2 (2 vCPUs, 8 GB memory)\n*   Cold nodes: e2-standard-2 (2 vCPUs, 8 GB memory)\n\n_9 Elasticsearch instances total (with individual tiers for hot, warm, and cold data, as well as dedicated masters)_ plus 2 Kibana instances running on GKE zones _europe-west1-b_, _europe-west1-c_ and _europe-west1-d._\n\nFor each GKE node pool, we use a specific Kubernetes label to attach the Elasticsearch instance into the right hardware configuration. The label name is called \"type\" and the values are: hot, warm or cold. You can change and add the label later by using the [command line](https://cloud.google.com/kubernetes-engine/docs/how-to/update-existing-nodepools#updating_node_labels).\n\nThis document contains two parts:\n\n\n\n1. Manifest explanation\n2. How to set up\n\n\n# **Manifest explanation**\n\nThe Elasticsearch manifest file [eck-saml-hot-warm-cold.yml](https://github.com/framsouza/eck-saml-hot-warm-cold/blob/main/eck-saml-hot-warm-cold.yml) contains the Elasticsearch settings and we will examine the relevant parts of the manifest one by one.\n\n\n### **nodeSets:**\n\n\n```\n nodeSets:\n  - name: hot-zone-b\n    count: 1\n    config:\n      node.attr.zone: europe-west1-b\n      cluster.routing.allocation.awareness.attributes: k8s_node_name,zone\n      node.roles: [ data_hot, data_content ]\n      node.store.allow_mmap: false\n```\n\n\nWe have _one_ node called _hot-zone-b_ deployed at zone _europe-west1-b_. Then, we define two routing awareness attributes:\n\n\n\n*   _k8s_node_name_: Makes sure that Elasticsearch allocates primary and replica shards to pods running on different Kubernetes nodes and never to pods that are scheduled onto a single Kubernetes node.\n*   _zone:_ Uses the Kubernetes label called _domain.beta.kubernetes.io/zone. _If Elasticsearch knows which nodes are on the same zone it can distribute the primary shard and its replica shards to minimise the risk of losing all shard copies in the event of a failure.\n\nWe explicitly say that this node will have a _data_hot_ and _data_content_ [role](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#modules-node). \n\n_node.store.allow_mmap : false_ will prevent the virtual address space (on Linux distribution) to run into errors or exceptions because this default configuration is too low. You can find more information about it [here](https://www.elastic.co/guide/en/cloud-on-k8s/1.5/k8s-virtual-memory.html#k8s-virtual-memory).\n\n\n### **xpack.security**\n\n\n```\n     xpack:\n        security:\n          authc:\n            realms:\n              saml:\n                saml1:\n                  attributes.principal: nameid\n                  idp.entity_id: urn:framsouza.eu.auth0.com\n                  idp.metadata.path: /usr/share/elasticsearch/config/framsouza_eu_auth0_com-metadata.xml\n                  order: 2\n                  sp.acs: https://framsouza.co/api/security/v1/saml\n                  sp.entity_id: https://framsouza.co\n                  sp.logout: https://framsouza.co/logout\n```\n\n\nThis is the SAML configuration. You should follow this [guide](https://auth0.com/docs/protocols/saml-protocol/configure-auth0-as-saml-identity-provider#configure-auth0-as-idp) to configure auth0 as idp and then get the metadata file and the idp.* settings.\n\n\n\n*   _attributes.principal:_ Defines which SAML attribute is going to be mapped to the principal (username) of the authenticated user in Kibana\n*   _idp.entity_id:_ Is the SAML EntityID of your Identity Provider (you can get it from SAML metadata file)\n*   _idp.metadata.path:_ Is the file path or the HTTPs URL where your Identity Provider metadata is available. In this example,, we use a file to demonstrate how to mount a volume\n*   _sp.acs:_ Is the Assertion Consumer Service URL where Kibana is listening for incoming SAML messages.\n*   _sp.entity_id:_ Is the SAML EntityID of our Service Provider.\n*   _sp.logout:_ Is the SingleLogout endpoint where the Service Provider is listening for incoming SAML LogoutResponse and LogoutRequest messages\n\nKeep in mind the sp.* configurations must point to Kibana endpoint and the idp.* settings you must collect from your Identity Provider. Also, the SAML metadata is stored in a ConfigMap and mounted as a Volume inside Elasticsearch. The idp also may provide the metadata via HTTP, in this case, auth0 provides the metadata file via HTTP but the purpose is to show to you how to mount configMap (or secret) as a volume into Elasticsearch pods.\n\n\n### **volumeClaimTemplates**\n\n\n```\n   volumeClaimTemplates:\n    - metadata:\n        name: elasticsearch-data\n      spec:\n        accessModes:\n        - ReadWriteOnce\n        resources:\n          requests:\n            storage: 50Gi\n        storageClassName: sc-zone-b\n```\n\n\nThe hot node will have a 50Gi available of disk which refers to the storage class called _sc-zone-b (we will define the storageclass later)_, this is the space available to store elasticsearch data.\n\n\n### **Node and Pod affinity**\n\n\n```\n   podTemplate:\n      spec:\n        nodeSelector:\n          type: hot\n        affinity:\n          nodeAffinity:\n            requiredDuringSchedulingIgnoredDuringExecution:\n              nodeSelectorTerms:\n              - matchExpressions:\n                - key: failure-domain.beta.kubernetes.io/zone\n                  operator: In\n                  values:\n                  - \"europe-west1-b\"\n```\n\n\nThe affinity feature restricts scheduling pods in a group of Kubernetes nodes based on labels. Node affinity is conceptually similar to nodeSelector that defines which node the pod will be scheduled based on the label. _nodeAffinity_ greatly extends the types of constraints you can express using enhancements labels. \n\nnodeAffinity is using requiredDuringSchedulingIgnoredDuringExecution affinity type. That means, a hard requirement that rules _must_ be met for a pod to be scheduled on a node. In this example, we're defining the following: \"only run the pod on nodes in the zone europe-west1-b\". The _nodeSelector_ will be matched with a Label on the Kubernetes node, in this case _type: hot_.\n\n\n### **Containers definition**\n\n\n```\n       containers:\n        - name: elasticsearch\n          resources:\n            requests:\n              memory: 8Gi\n              cpu: 2\n            limits:\n              memory: 8Gi\n```\n\n\nIn this example, this node has 8Gi of memory and is requesting at least 2 cpu cores. New Elasticsearch version (from 7.11) automatically sets the heap size based on the node roles and available memory, there are more information about this new approach [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-managing-compute-resources.html#k8s-compute-resources-elasticsearch). Here we will have 4Gi of heap.\n\n\n### **Creating a configMap**\n\n_You must create this file before the ES manifest_\n\nYou get the metadata file from your idp (in this case, [auth0](https://auth0.com/docs/protocols/saml-protocol/configure-auth0-as-saml-identity-provider#configure-auth0-as-idp)). To put the content inside a configMap you can run the following:\n\n\n```\nkubectl create configmap saml-metadata --from-file=../framsouza_eu_auth0_com-metadata.xml\n```\n\n\nRemember to adjust the file location.\n\n\n### **Volume SAML metadata**\n\n\n```\n         volumeMounts:\n          - name: saml-metadata\n            mountPath:  /usr/share/elasticsearch/config/framsouza_eu_auth0_com-metadata.xml\n        volumes:\n        - name: saml-metadata\n          configMap:\n            name: saml-metadata\n```\n\n\nThe _volumeMounts_ session is where the volume should be mounted inside the pod. In this example, you are mounting a volume _saml-metadata_ and the file is located in _ES_CONFIG_ directory _/usr/share/elasticsearch/config/framsouza_eu_auth0_com-metadata.xml_. \n\nThen, _volumes_ means the volume must be mounted according to a configMap called _saml-metadata_.\n\n\n### **readinessProbe**\n\n\n```\n         readinessProbe:\n            exec:\n              command:\n              - bash\n              - -c\n              - /mnt/elastic-internal/scripts/readiness-probe-script.sh\n            failureThreshold: 3\n            initialDelaySeconds: 10\n            periodSeconds: 12\n            successThreshold: 1\n            timeoutSeconds: 12\n          env:\n          - name: READINESS_PROBE_TIMEOUT\n            value: \"10\"\n```\n\n\nReadiness probe is used to know when a container is ready to start accepting traffic. By default the timeout is 3 seconds, this is acceptable in most cases but if it’s under very heavy load you might need to increase the timeout. This example we are increasing the timeout to 10 seconds and adjusting the check time to 12 seconds. \n\n\n### **initContainer**\n\n\n```\n       initContainers:\n        - command:\n          - sh\n          - -c\n          - |\n            bin/elasticsearch-plugin install --batch repository-gcs\n          name: install-plugins\n```\n\n\nTo install or perform any task at the operational system level before Elasticsearch starts, you should use an initContainer. In this example, we are installing the GCS repository where we can send snapshots.\n\nYou can also build your own image and include the GCS plugin, to do so you can follow this [doc](https://www.elastic.co/blog/elasticsearch-docker-plugin-management). This approach is more production ready, so if you decide to go for it, you don’t need to specify the _install-plugins _initContainer.\n\nThese are the sessions from one node. The rest of the node configuration is basically the same, except for the name, zone, and storageClass name. At the end of the file, you see the following setting (which applies to the whole cluster):\n\n\n```\n updateStrategy:\n    changeBudget:\n      maxSurge: 1\n      maxUnavailable: 1\n  podDisruptionBudget:\n    spec:\n      minAvailable: 2\n      selector:\n        matchLabels:\n          elasticsearch.k8s.elastic.co/cluster-name: elastic-prd\n```\n\n\n_updateStrategy_ controls the number of simultaneous changes in the Elasticsearch cluster. maxSurge: 1 means only one new Pod is created at a time. After the first new Pod is Ready, an old Pod is killed and the second new Pod is created. \n\nIf you don’t specify the strategy you want, the default behaviour is maxSurge: -1 which means that all the required pods are created immediately, it may cause issues if you don’t have enough resources to deal with it. You can find more information [here](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-update-strategy.html#k8s-update-strategy).\n\nWhile maxSurge determines how many new Pods to create, maxUnavailable determines how many old Pods to kill. In this case, we can only kill one old Pod at a time. This ensures the capacity is always at least 3 - 1 Pods. If this is not enough for your environment configuration, you can disable the podDisruption and configure your own.\n\n_podDisruptionBudget_ determines how many nodes must continue running in case of disruption, for instance hardware failures, pod eviction due to out of resource, draining node and so on.\n\n\n# **How to set up**\n\n\n### **Install ECK**\n\nFirst let’s give your google account administrator privileges on the cluster by setting up the RBAC by running the following command:\n\n\n```\nkubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud auth list --filter=status:ACTIVE --format=\"value(account)\")\n\n```\n\n\n\n1. Install the ECK operator, keep in mind we are installing ECK operator version 1.5.0 but you may want to check for updated versions at our [website](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-deploy-eck.html#k8s-deploy-eck).\n\n\n```\nkubectl apply -f https://download.elastic.co/downloads/eck/1.5.0/all-in-one.yaml\n```\n\n\nThis creates the ECK Operator pod and cluster permissions in the namespace _elastic-system_, you can monitor it by running:\n\n\n```\nkubectl -n elastic-system logs -f statefulset.apps/elastic-operator\n```\n\n\n\n### **Configuring StorageClass**\n\nWith StorageClass you can describe the \"classes\" of storage you want to use. Different classes might map to quality of service levels, disk types, backup purpose or any arbitrary policy determined by the administrator.\n\nAs we are using hot/warm/cold architecture, we need to specify a StorageClass for the hot and warm/cold nodes (as they must use different disk types) and associate it with the proper PersistentVolume.\n\nThis is an example of StorageClass that is attached to the PersistentVolume in the hot nodes:\n\n\n```\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: sc-hot\nprovisioner: kubernetes.io/gce-pd\nparameters:\n  type: pd-ssd\nreclaimPolicy: Delete\nvolumeBindingMode: WaitForFirstConsumer\nallowVolumeExpansion: true\n```\n\n\nSome key points:\n\n\n\n*   _provisioner: kubernetes.io/gce-pd_ : It means we are using GCE as provider;\n*   _type: pd-ssd_: - It provides ssd disks for the volumes attached to this StorageClass;\n*   _reclaimPolicy: Delete_ - It deletes PersistentVolumeClaim resources if the owning Elasticsearch nodes are scaled down or a deletion;\n*   _volumeBindingMode: WaitForFirstConsumer_ - It prevents the pod from being scheduled, because of affinity settings, on a host where the bound PersistentVolume is not available, it will also create it in the zone with the unfulfilled claim. \n*   _allowedTopologies_: - It binds your StorageClass with the zone labels (you can use any kind of label)\n\nThe warm and cold ones has the following configuration:\n\n\n```\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: sc-hot\nprovisioner: kubernetes.io/gce-pd\nparameters:\n  type: pd-standard\nreclaimPolicy: Delete\nvolumeBindingMode: WaitForFirstConsumer\nallowVolumeExpansion: true\n```\n\n\nBasically the same apart from the disk type, which is pd-standard (a slow disk).\n\n**Create SAML configmap**\n\n\n```\nkubectl create configmap saml-metadata --from-file=../framsouza_eu_auth0_com-metadata.xml\n```\n\n\n\n## **Create Elasticsearch and Kibana resource**\n\nOnce you have the saml configmap, you can apply the Elasticsearch and Kibana manifest:\n\n\n```\nkubectl create -f eck-saml-hot-warm-cold.yml \u0026\u0026 kubectl create -f kibana.yml\n```\n\n\nIt may take a while until all the resources get ready, but after some minutes you should see something like this:\n\n\n```\nkubectl get pods\nNAME                             READY   STATUS     RESTARTS   AGE\nelastic-prd-es-cold-zone-b-0     1/1     Running    0          35m\nelastic-prd-es-cold-zone-c-0     1/1     Running    0          35m\nelastic-prd-es-cold-zone-d-0     1/1     Running    0          35m\nelastic-prd-es-hot-zone-b-0      1/1     Running    0          35m\nelastic-prd-es-hot-zone-c-0      1/1     Running    0          35m\nelastic-prd-es-hot-zone-d-0      1/1     Running    0          35m\nelastic-prd-es-master-zone-b-0   1/1     Running    0          35m\nelastic-prd-es-master-zone-c-0   1/1     Running    0          35m\nelastic-prd-es-master-zone-d-0   1/1     Running    0          35m\nelastic-prd-es-warm-zone-b-0     1/1     Running    0          16m\nelastic-prd-es-warm-zone-c-0     1/1     Running    0          16m\nelastic-prd-es-warm-zone-d-0     1/1     Running    0          15m\nkibana-prd-kb-7467b79f54-btzhq   1/1     Running    0          4m8s\n```\n\n\nOnce you have all the pods running, there's a [Job](https://github.com/framsouza/eck-saml-hot-warm-cold/blob/main/es-config-job.yml) you must run to create the SAML role mapping inside of Elasticsearch and give the right permission to the user who will login using SAML. You can also create the [role \u0026 role mapping](https://www.elastic.co/guide/en/elasticsearch/reference/7.12/saml-guide-stack.html#saml-role-mapping) via Kibana DevTools or curl.\n\nIf you try to access Kibana via SAML without running this Job, you will get a permission error. In summary, the job will spin up a container, execute the API calls and kill the pod.\n\n\n## **Test connection**\n\nAt this point you can test the connection via curl or exposing Kibana service.\n\nGrab the elastic password\n\n\n```\nkubectl get secret elastic-prd-es-elastic-user -o yaml\n```\n\n\nAnd the ES service name and run the following:\n\n\n```\ncurl -k https://elastic:es-password@es-service-name8:9200/_cluster/health?pretty\n```\n\n\nYou can also temporarily expose the Kibana service and access it with your browser:\n\n\n```\nkubectl port-forward svc/kibana-prd-kb-http 5601\n```\n\n\n\n### **Ingress controller**\n\nBy using ingress controller, you can access your Kibana via domain controller, there are some Ingress Controllers available but in this example we are using ingress-nginx, you can read more about it [here](https://kubernetes.github.io/ingress-nginx/).\n\nTo deploy it, you must run the following command:\n\n\n```\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.46.0/deploy/static/provider/cloud/deploy.yaml\n```\n\n\nIn this example, we are using a valid SSL certificate. To add it as part of our ingress controller we must first create a secret which contains the key and certificate.\n\n\n```\nkubectl create secret tls framsouza-cert --key framsouza_co_key.txt --cert framsouza_co.crt\n```\n\n\nOnce you created the secret, you can deploy the ingress controller manifest, but first let’s have a look at the ingress manifest:\n\n\n```\napiVersion: networking.k8s.io/v1beta1\nkind: Ingress\nmetadata:\n  annotations:\n    kubernetes.io/ingress.class: nginx\n    nginx.ingress.kubernetes.io/backend-protocol: \"HTTPS\"\n  name: ingress\nspec:\n  tls:\n      - hosts:\n          - framsouza.co\n        secretName: framsouza-cert\n  rules:\n    - host: framsouza.co\n      http:\n        paths:\n          - path: /\n            backend:\n              serviceName: kibana-prd-kb-http\n              servicePort: 5601\n```\n\n\nAt the annotations level, we are explicitly saying that we are using nginx as a controller and configuring the communication between the ingress controller and the service to be established via HTTP (`nginx.ingress.kubernetes.io/backend-protocol: \"HTTPS\"`). By the default, Elasticsearch uses HTTPS, without this annotation you may receive a 503 error.\n\nAt the tls level, we are defining the hostname (In this case framsouza.co) to check the secretname called framsouza-cert which is the secret that contains the SSL certificate.\n\nAt the rules level, we are creating a redirection. Every request that arrives at the domain [https://framsouza.co](http://framsouza.co) must be redirected to the Kibana service (`kibana-prd-kb-http`) at the port 5601.\n\nIn some cases, you also want to expose Elasticsearch to be access by some application using your own ssl certificate, to do so you can add a new rule like:\n\n\n```\n          - path: /elasticsearch\n            backend:\n              serviceName: elastic-prd-es-http\n              servicePort: 9200\n```\n\n\nHere, every request to [https://framsouza.co/elasticsearch](https://framsouza.co/elasticsearch) will be redirected to Elasticsearch service.\n\nNow, we are ready to apply the ingress manifest:\n\n\n```\nkubectl create -f ingress.yml\n```\n\n\nWith that, we can access Kibana using our own domain and our own TLS certificate. \n\nHope you can enjoyed the most powerfull Kubernetes feature together with the benefits to use ECK integrated with SAML to handle time series with hot-warm-cold architecture.\n\n[eck-saml.zip](https://github.com/framsouza/eck-saml-hot-warm-cold/blob/main/eck-saml.zip)\n\nCheers,\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fframsouza%2Feck-saml-hot-warm-cold","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fframsouza%2Feck-saml-hot-warm-cold","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fframsouza%2Feck-saml-hot-warm-cold/lists"}