Help needed to change the password of the default elastic user with puppet module

Hi!

I'm using the puppet module to manage elasticsearch (https://forge.puppet.com/elastic/elasticsearch) and x-pack. I'm not sure of the best way to change the default x-pack username and password from elastic / changeme.

From the readme I can see that the following should be added to my manifest to change the password:

notify { 'update password': } ~>
elasticsearch::user { 'elastic':
  password => 'mynewpassword',
}

Should I be adding this to my manifest temporarily, triggering the agent, removing it, then updating the api_basic_auth_password and triggering the agent? When I try this the user fails to authenticate. I'm also not sure how this method is feasible when it comes to multiple environments.

@tylerjl are you able to help with this?

Apologies if the answer is obvious - I'm fairly new to puppet and elasticsearch and am finding this part a little hard to follow.

Thanks!

class profile::elasticsearch {
  
  $hostname = $trusted['hostname']
  $datamount = '/mnt/elasticsearch'
  $http_port = 9200
  $transport_port = 9300
  $license = hiera('elasticsearch::license')
  $cluster_name = hiera('elasticsearch::cluster_name')
  $masterlist = hiera('elasticsearch::masterlist')
  $jvm_heap_elastic = hiera('elasticsearch::jvm_heap_elastic')
  $jvm_heap_kibana = hiera('elasticsearch::jvm_heap_kibana')
  $major_version = hiera('elasticsearch::major_version')
  $minor_version = hiera('elasticsearch::minor_version')
  $keystorepass = hiera('elasticsearch::keystorepass')
  $api_username = 'elastic'
  $api_password = 'changeme'
  $store = hiera('common::repository')

  $minimum_masters = (($masterlist.filter |$x| { $x =~ NotUndef }.length) / 2) + 1 # Calculate the quorum to avoid split brain
  
  # The kibana node may not have as much memory assigned to it as the elasticsearch nodes
  # If it is the kibana node, configure the node roles differently
  if $facts['servertype'] == 'kibana' {
    $jvm_heap = $jvm_heap_kibana
    $product1 = 'kibana'
    $instance_config = {
      'node.master'        => false,
      'node.data'          => false,
      'node.ingest'        => false,
      'http.port'          => $http_port,
      'transport.tcp.port' => $transport_port,
    }
  }
  
  else {
    $jvm_heap = $jvm_heap_elastic
    $product1 = hiera('elasticsearch::product1')
    $instance_config = {
      'node.master'        => true,
      'node.data'          => true,
      'http.port'          => $http_port,
      'transport.tcp.port' => $transport_port,
    }
  }

  $cert_location = "/xfer/elasticsearchcerts/${product1}"
  
  # Settings in systemd service file
  $es_defaults = {
    'MAX_LOCKED_MEMORY' => 'unlimited', # LimitMemLock=infinity
  }
  
  # Settings in elasticsearch.yml file
  $es_ymlconfig = {
    'cluster.name'                            => $cluster_name,
    'node.name'                               => $hostname,
    'bootstrap.memory_lock'                   => true, # Ensures memory locking
    'network.host'                            => '_local_,_site_', # Check whether this is site_local or local_site
    'discovery.zen.ping.unicast.hosts'        => $masterlist, # List of master-eligible nodes
    'discovery.zen.minimum_master_nodes'      => $minimum_masters, # Minimum number of master nodes
    'xpack.ml.enabled'                        => false, # Disable machine-learning
  }
  
  file { [ $datamount ]:
    ensure => directory,
    before => Class['elasticsearch'],
  }
  
  # Allow elasticsearch ports on the Linux firewall
  firewall { "200 - ES ports ${http_port}, ${transport_port}":
    action => 'accept',
    proto  => 'tcp',
    dport  => [$http_port, $transport_port],
    before => Class['elasticsearch'],
  }

  # Configure repository from which to download elasticsearch package
  yumrepo { 'elasticsearch':
    ensure   => present,
    baseurl  => "https://artifacts.elastic.co/packages/${major_version}x/yum",
    gpgcheck => 1,
    gpgkey   => 'https://artifacts.elastic.co/GPG-KEY-elasticsearch',
    enabled  => 1,
    before   => Class['elasticsearch'],
  }

  include ::java
  
  class { 'elasticsearch':
    ensure                  => 'present',
    status                  => 'enabled',
    version                 => "${major_version}${minor_version}",
    jvm_options             => [ "-Xms${jvm_heap}g","-Xmx${jvm_heap}g",'-Djdk.io.permissionsUseCanonicalPath=true','-Dlog4j.skipJansi=true','#-XX:+PrintGCApplicationStoppedTime','#-XX:+PrintGCDateStamps','#-XX:+PrintGCDetails','#-XX:+PrintTenuringDistribution','#-XX:+UseGCLogFileRotation','#-XX:-OmitStackTraceInFastThrow','#-XX:GCLogFileSize=128M','#-XX:NumberOfGCLogFiles=32','#-Xloggc:${loggc}'], # Settings in jvm.options file
    restart_on_change       => false, # Ensures the service isn't restarted on config, package or plugin changes
    config                  => $es_ymlconfig,
    datadir                 => "${datamount}/data",
    logdir                  => "${datamount}/logs",
    elasticsearch_user      => 'elasticsearch',
    elasticsearch_group     => 'elasticsearch',
    service_provider        => 'systemd',
    init_defaults           => $es_defaults,
    manage_repo             => false,
    security_plugin         => 'x-pack',
    license                 => $license,
    plugindir               => '/usr/share/elasticsearch/plugins',
    configdir               => '/etc/elasticsearch',
    
    # API settings 
    api_protocol            => 'https',
    api_host                => 'localhost',
    api_port                => $http_port,
    api_timeout             => 10,
    api_basic_auth_username => $api_username,
    api_basic_auth_password => $api_password,
    api_ca_file             => undef,
    api_ca_path             => undef,
    validate_tls            => false,
    require                 => [ File[$datamount], Yumrepo['elasticsearch'] , Firewall["200 - ES ports ${http_port}, ${transport_port}"] ],
  }
  
  # Install x-pack plugin
  elasticsearch::plugin { 'x-pack':
    instances => ["${product1}"],
  }

  # More elasticsearch.yml settings
  elasticsearch::instance { $product1: 
    ssl               => true,
    ca_certificate    => "${cert_location}/ca.crt",
    certificate       => "${cert_location}/${hostname}.crt",
    private_key       => "${cert_location}/${hostname}.key",
    keystore_password => $keystorepass,
    config            => $instance_config,
  }
  
}

Hi @clp01!

There's a few things to bear in mind when working with security/authentication for Elasticsearch in the Puppet module:

  • Currently the module only manages file-based users, and doesn't know how to manage users/roles over the API.
  • The module supports managing secure settings in Elasticsearch keystore files which is documented here.
  • By using the module's secrets parameter to manage the bootstrap password, you can control the password used by the default elastic user when Elasticsearch starts up. The documentation for Elasticsearch security does outline how to use the CLI utilities to set passwords, but if you're relying solely on configuration management, this is probably your best option, since a fresh ES instance will come up with a set of credentials that you control and has been set according to your Puppet resources.

Let me know if that helps or you need additional info.

Thanks so much for the explanation! I am unfamiliar with the keystore file settings so I am looking into this now and will let you know if I have any questions :slight_smile:

Hi @tylerjl,

I tested adding the bootstrap password to the keystore file, but it looks like this was introduced in Elasticsearch 6 and we are using 5.6.6 - sorry I forgot to mention this.

[2018-11-07T07:29:28,578][WARN ][o.e.b.ElasticsearchUncaughtExceptionHandler] [elasticpuppet-es01] uncaught exception in thread [main]
org.elasticsearch.bootstrap.StartupException: java.lang.IllegalArgumentException: unknown secure setting [bootstrap.password] please check that any required plugins are installed, or check the breaking changes documentation for removed settings

Is there a similar method that is compatible with version 5?

Thanks!

If you're relying on users defined in the non-file based realm, then you're pretty limited to what's possible in the module. Because 5.x ships with the default password, you can change credentials and manage them via the API after installing and configuring Elasticsearch, but the module's users and roles providers won't manage those over the REST API.

For managing those resources, just interacting with the user/role API endpoints is probably the best approach.

Thanks for your help @tylerjl! I will revisit this once we have upgraded :slight_smile:

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.