Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

[kibana] create a secret with es token #1720

Merged
merged 15 commits into from
Nov 15, 2022

Conversation

jmlrt
Copy link
Member

@jmlrt jmlrt commented Nov 4, 2022

This PR moves the Elasticsearch token for Kibana creation into Helm pre-install hooks and adds it to a K8S secret so it can be used by every pod of the Kibana Deployment.

The K8S secret and all linked resources are cleaned in post-delete hooks.

The call to Elasticsearch and K8S API to create the ES token and convert it to a secret are done in a Node JS script because the only language runtime available in the Kibana Docker image are Node and Bash, but jq command isn't available which exclude Bash script.

The Node JS script is also available in plain JS format to facilitate the review: https://gist.github.com/jmlrt/482b3d984588c1d3e10a84ce5fcd7b3b

Many thanks @pugnascotia for the help on this script 🙏🏻

Follow-up of #1679
Replace #1715
Fixes #1714

@jmlrt jmlrt force-pushed the kibana-pre-install-token branch 2 times, most recently from 9861c77 to 4a590d9 Compare November 8, 2022 17:48
@jmlrt jmlrt marked this pull request as ready for review November 8, 2022 17:51
@jmlrt jmlrt requested review from framsouza, pugnascotia, jbudz and a team November 8, 2022 18:02
@jmlrt jmlrt added bug Something isn't working kibana labels Nov 8, 2022
@jmlrt
Copy link
Member Author

jmlrt commented Nov 8, 2022

👋🏻 @jbudz @pugnascotia the Node JS script is working fine but could surely be optimized, advises are welcome.

I'm also looking for a better way to handle the case where the Elasticsearch token doesn't exist yet by not having to consider that HTTP 404 is successful (TLDR, when trying to delete an ES token that doesn't exist, it's returning 404) if you have some better idea.

@jmlrt
Copy link
Member Author

jmlrt commented Nov 8, 2022

During the upgrade tests, I think that ES cluster isn't completely ready when kibana is upgraded. Indeed Node JS logs are showing ECONNREFUSED error.

Creating a new Elasticsearch token for Kibana                                                                                     
Cleaning previous token                                                                                                           
DELETE undefined failed:  connect ECONNREFUSED 10.44.11.108:9200                                                                  
Error: connect ECONNREFUSED 10.44.11.108:9200                                                                                     
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {                                                           
  errno: -111,                                                                                                                    
  code: 'ECONNREFUSED',                                                                                                           
  syscall: 'connect',                                                                                                             
  address: '10.44.11.108',                                                                                                        
  port: 9200                                                                                                                      
}                   

However, the K8S job is still in successful state. Need to find a way to fail the JS script in case of this error:

Name:             pre-install-helm-kibana-upgrade-kb-kibana-6dccp                                                                 
Namespace:        default                                                                                                         
Priority:         0                                                                                                               
Service Account:  pre-install-helm-kibana-upgrade-kb-kibana                                                                       
Node:             gke-jmlrt-test-default-pool-5b440e04-0w1m/10.200.0.10                                                           
Start Time:       Tue, 08 Nov 2022 21:51:25 +0100                                                                                 
Labels:           controller-uid=cf0d1165-def4-4377-93b6-fe4164f70475                                                             
                  job-name=pre-install-helm-kibana-upgrade-kb-kibana                                                              
Annotations:      <none>                                                                                                          
Status:           Succeeded                                                                                                       
IP:               10.40.2.20                                       
...

source $HOME/.elasticsearch-serviceaccounttoken
// Elasticsearch API
const esPath = '_security/service/elastic/kibana/credential/token/{{ template "kibana.fullname" . }}';
const esUrl = '{{ .Values.elasticsearchHosts }}' + '/' + esPath
Copy link
Contributor

Choose a reason for hiding this comment

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

Will .Values.elasticsearchHosts always only have a single value?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question, it seems it was supposed to support multiple values but a bug that was never fixed prevented it (#603).

As this Kibana chart is supposed to connect to an Elasticsearch cluster deployed via the Elastic Helm charts, all Elasticsearch pods are supposed to be available via a single K8S service that should be used in .Values.elasticsearchHosts.

IMHO, It's not worth fixing #603 and making the script compatible with multiple URLs. I'll update the doc to mention that a single URL (Elasticsearch service URL) is expected for this value, to make it clear.

switch (command) {
case 'create':
console.log('Creating a new Elasticsearch token for Kibana')
createEsToken();
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 it would be cleaner to always return the promises created by requestPromise, so that they are chained together, and put a single top-level .catch(...) here that logs any errors. If that isn't clear, I can put the suggested changes in a rustpad.

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you mean something like that?

function createEsToken() {
  // Chaining requests
  console.log('Cleaning previous token');
  return requestPromise(esUrl, esTokenDeleteOptions).then(() => {
    console.log('Creating new token');
    requestPromise(esUrl, esTokenCreateOptions).then(response => {
      // ...
      requestPromise(k8sPostSecretUrl, secretCreateOptions, secretData)
    });
  });
}

function cleanEsToken() {
  // Chaining requests
  console.log('Cleaning token');
  return requestPromise(esUrl, esTokenDeleteOptions).then(() => {
    // Create the k8s secret
    console.log('Delete K8S secret');
    requestPromise(k8sDeleteSecretUrl, secretDeleteOptions)
  });
}

const command = process.argv[2];
switch (command) {
  case 'create':
    console.log('Creating a new Elasticsearch token for Kibana')
    createEsToken().catch(err => {
      console.error(err);
    });
    break;
  case 'clean':
    console.log('Cleaning the Kibana Elasticsearch token')
    cleanEsToken().catch(err => {
      console.error(err);
    });
    break;
  default:
    console.log('Unknown command');
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, just make sure you're always returning the value of requestPromise, and the chain of promises will finally resolve in the switch.

Copy link
Member Author

Choose a reason for hiding this comment

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

done in e3ef0c1

@jmlrt
Copy link
Member Author

jmlrt commented Nov 9, 2022

I'm also looking for a better way to handle the case where the Elasticsearch token doesn't exist yet by not having to consider that HTTP 404 is successful (TLDR, when trying to delete an ES token that doesn't exist, it's returning 404) if you have some better idea.

improved in 43c08a1

@jmlrt
Copy link
Member Author

jmlrt commented Nov 9, 2022

@pugnascotia PTAL 🙏🏻
I also updated the plain JS version in https://gist.github.com/jmlrt/482b3d984588c1d3e10a84ce5fcd7b3b (and updated the issue description with the good link^^)

@jmlrt
Copy link
Member Author

jmlrt commented Nov 9, 2022

👋🏻 @jbudz @pugnascotia the Node JS script is working fine but could surely be optimized, advises are welcome.

I'm also looking for a better way to handle the case where the Elasticsearch token doesn't exist yet by not having to consider that HTTP 404 is successful (TLDR, when trying to delete an ES token that doesn't exist, it's returning 404) if you have some better idea.

I could reproduce it by setting Elasticsearch replicas to 0 and running the script manually:

kibana@pre-install-kb-kibana-wh4lm:~$ node/bin/node helm-scripts/manage-es-token.js create
Creating a new Elasticsearch token for Kibana
Cleaning previous token
DELETE undefined failed:  connect ECONNREFUSED 10.44.6.135:9200
Error: connect ECONNREFUSED 10.44.6.135:9200
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '10.44.6.135',
  port: 9200
}
kibana@pre-install-kb-kibana-wh4lm:~$ echo $?
0

Despite logging the ECONNREFUSED error, manage-es-token.js still returns success (RC 0).

Need to ensure that the script returns a different RC when it is failing with this error.

@jmlrt
Copy link
Member Author

jmlrt commented Nov 9, 2022

👋🏻 @jbudz @pugnascotia the Node JS script is working fine but could surely be optimized, advises are welcome.
I'm also looking for a better way to handle the case where the Elasticsearch token doesn't exist yet by not having to consider that HTTP 404 is successful (TLDR, when trying to delete an ES token that doesn't exist, it's returning 404) if you have some better idea.

I could reproduce it by setting Elasticsearch replicas to 0 and running the script manually:

kibana@pre-install-kb-kibana-wh4lm:~$ node/bin/node helm-scripts/manage-es-token.js create
Creating a new Elasticsearch token for Kibana
Cleaning previous token
DELETE undefined failed:  connect ECONNREFUSED 10.44.6.135:9200
Error: connect ECONNREFUSED 10.44.6.135:9200
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '10.44.6.135',
  port: 9200
}
kibana@pre-install-kb-kibana-wh4lm:~$ echo $?
0

Despite logging the ECONNREFUSED error, manage-es-token.js still returns success (RC 0).

Need to ensure that the script returns a different RC when it is failing with this error.

should be fixed by 86386f0

jmlrt and others added 2 commits November 10, 2022 13:15
Co-authored-by: Rory Hunter <pugnascotia@users.noreply.github.com>
Co-authored-by: Rory Hunter <pugnascotia@users.noreply.github.com>
@jmlrt
Copy link
Member Author

jmlrt commented Nov 10, 2022

ok to test

@jmlrt
Copy link
Member Author

jmlrt commented Nov 10, 2022

Copy link
Contributor

@framsouza framsouza left a comment

Choose a reason for hiding this comment

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

Great job!! LGTM

Copy link
Member

@mgreau mgreau left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@jmlrt jmlrt merged commit 90f59ef into elastic:main Nov 15, 2022
@jmlrt jmlrt deleted the kibana-pre-install-token branch November 15, 2022 17:07
const base64Token = Buffer.from(token, 'utf8').toString('base64');

// Prepare the k8s secret
secretData = JSON.stringify({
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
secretData = JSON.stringify({
const secretData = JSON.stringify({

Copy link
Member

Choose a reason for hiding this comment

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

whoops I missed the merge, didn't refresh in time. Sorry about the confusion.

Copy link
Member

Choose a reason for hiding this comment

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

(I'll follow up with a PR)

Copy link
Member

Choose a reason for hiding this comment

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

@jmlrt jmlrt added the v8.5.1 label Nov 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working kibana v8.5.1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[kibana] initContainer: configure-kibana-token: Back-off restarting failed container:
5 participants