Skip to content

Commit

Permalink
Added cloud.id and cloud.auth config settings (elastic#4964)
Browse files Browse the repository at this point in the history
* Added cloud.id and cloud.auth config settings

This adds two new configuration settings: `cloud.id` and `cloud.auth`.
They can be used in the configuration file, or from the CLI like this:

```
./metricbeat -e -E cloud.id=<cloud-id> -E cloud.auth=<cloud-auth>
```

The ES/KB settings are changed via overwritting, but we display an INFO
level message that the settings are changed by the cloud-id.

Closes elastic#4959.

* goimports fix

* aded more tests

* added basic docs

* changelog

* addressed comments

* Check that we're not enabling a second output

* remove unused var

* Addressed comments

(cherry picked from commit bd6981d)
  • Loading branch information
tsg authored and Tudor Golubenco committed Aug 23, 2017
1 parent a9da916 commit c46fc43
Show file tree
Hide file tree
Showing 19 changed files with 569 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta1...master[Check the HEAD di

- Update init scripts to use the `test config` subcommand instead of the deprecated `-configtest` flag. {issue}4600[4600]
- Get by default the credentials for connecting to Kibana from the Elasticsearch output configuration. {pull}4867[4867]
- Added `cloud.id` and `cloud.auth` settings, for simplifying using Beats with the Elastic Cloud. {issue}4959[4959]

*Auditbeat*

Expand Down
13 changes: 13 additions & 0 deletions auditbeat/auditbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,19 @@ auditbeat.modules:
#processors:
#- add_docker_metadata: ~

#============================= Elastic Cloud ==================================

# These settings simplify using auditbeat with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs ======================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
15 changes: 14 additions & 1 deletion auditbeat/auditbeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ auditbeat.modules:

#============================== Kibana =====================================

# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# This requires a Kibana endpoint configuration.
setup.kibana:

Expand All @@ -69,6 +69,19 @@ setup.kibana:
# IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
#host: "localhost:5601"

#============================= Elastic Cloud ==================================

# These settings simplify using auditbeat with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs =====================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
13 changes: 13 additions & 0 deletions filebeat/filebeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,19 @@ filebeat.prospectors:
#processors:
#- add_docker_metadata: ~

#============================= Elastic Cloud ==================================

# These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs ======================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
15 changes: 14 additions & 1 deletion filebeat/filebeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ filebeat.config.modules:

#============================== Kibana =====================================

# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# This requires a Kibana endpoint configuration.
setup.kibana:

Expand All @@ -115,6 +115,19 @@ setup.kibana:
# IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
#host: "localhost:5601"

#============================= Elastic Cloud ==================================

# These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs =====================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
13 changes: 13 additions & 0 deletions heartbeat/heartbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,19 @@ heartbeat.scheduler:
#processors:
#- add_docker_metadata: ~

#============================= Elastic Cloud ==================================

# These settings simplify using heartbeat with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs ======================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
15 changes: 14 additions & 1 deletion heartbeat/heartbeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ heartbeat.monitors:

#============================== Kibana =====================================

# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# This requires a Kibana endpoint configuration.
setup.kibana:

Expand All @@ -62,6 +62,19 @@ setup.kibana:
# IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
#host: "localhost:5601"

#============================= Elastic Cloud ==================================

# These settings simplify using heartbeat with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs =====================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
13 changes: 13 additions & 0 deletions libbeat/_meta/config.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@
#processors:
#- add_docker_metadata: ~

#============================= Elastic Cloud ==================================

# These settings simplify using beatname with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs ======================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
15 changes: 14 additions & 1 deletion libbeat/_meta/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

#============================== Kibana =====================================

# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API.
# This requires a Kibana endpoint configuration.
setup.kibana:

Expand All @@ -39,6 +39,19 @@ setup.kibana:
# IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
#host: "localhost:5601"

#============================= Elastic Cloud ==================================

# These settings simplify using beatname with the Elastic Cloud (https://cloud.elastic.co/).

# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
# `setup.kibana.host` options.
# You can find the `cloud.id` in the Elastic Cloud web UI.
#cloud.id:

# The cloud.auth setting overwrites the `output.elasticsearch.username` and
# `output.elasticsearch.password` settings. The format is `<user>:<pass>`.
#cloud.auth:

#================================ Outputs =====================================

# Configure what outputs to use when sending the data collected by the beat.
Expand Down
6 changes: 6 additions & 0 deletions libbeat/beat/beat.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (

"github.com/elastic/beats/libbeat/api"
"github.com/elastic/beats/libbeat/cfgfile"
"github.com/elastic/beats/libbeat/cloudid"
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/common/cfgwarn"
"github.com/elastic/beats/libbeat/common/file"
Expand Down Expand Up @@ -443,6 +444,11 @@ func (b *Beat) configure() error {
return fmt.Errorf("error loading config file: %v", err)
}

err = cloudid.OverwriteSettings(cfg)
if err != nil {
return err
}

b.RawConfig = cfg
err = cfg.Unpack(&b.Config)
if err != nil {
Expand Down
128 changes: 128 additions & 0 deletions libbeat/cloudid/cloudid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// package cloudid contains functions for parsing the cloud.id and cloud.auth
// settings and modifying the configuration to take them into account.
package cloudid

import (
"encoding/base64"
"fmt"
"net/url"
"strings"

"github.com/pkg/errors"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/logp"
)

// OverwriteSettings modifies the received config object by overwriting the
// output.elasticsearch.hosts, output.elasticsearch.username, output.elasticsearch.password,
// setup.kibana.host settings based on values derived from the cloud.id and cloud.auth
// settings.
func OverwriteSettings(cfg *common.Config) error {

cloudID, _ := cfg.String("cloud.id", -1)
cloudAuth, _ := cfg.String("cloud.auth", -1)

if cloudID == "" && cloudAuth == "" {
// nothing to hack
return nil
}

logp.Debug("cloudid", "cloud.id: %s, cloud.auth: %s", cloudID, cloudAuth)
if cloudID == "" {
return errors.New("cloud.auth specified but cloud.id is empty. Please specify both.")
}

// cloudID overwrites
esURL, kibanaURL, err := decodeCloudID(cloudID)
if err != nil {
return errors.Errorf("Error decoding cloud.id: %v", err)
}

logp.Info("Setting Elasticsearch and Kibana URLs based on the cloud id: output.elasticsearch.hosts=%s and setup.kibana.host=%s", esURL, kibanaURL)

esURLConfig, err := common.NewConfigFrom([]string{esURL})
if err != nil {
return err
}

// Before enabling the ES output, check that no other output is enabled
tmp := struct {
Output common.ConfigNamespace `config:"output"`
}{}
if err := cfg.Unpack(&tmp); err != nil {
return err
}
if out := tmp.Output; out.IsSet() && out.Name() != "elasticsearch" {
return errors.Errorf("The cloud.id setting enables the Elasticsearch output, but you already have the %s output enabled in the config", out.Name())
}

err = cfg.SetChild("output.elasticsearch.hosts", -1, esURLConfig)
if err != nil {
return err
}

err = cfg.SetString("setup.kibana.host", -1, kibanaURL)
if err != nil {
return err
}

if cloudAuth != "" {
// cloudAuth overwrites
username, password, err := decodeCloudAuth(cloudAuth)
if err != nil {
return err
}

err = cfg.SetString("output.elasticsearch.username", -1, username)
if err != nil {
return err
}

err = cfg.SetString("output.elasticsearch.password", -1, password)
if err != nil {
return err
}
}

return nil
}

// decodeCloudID decodes the cloud.id into elasticsearch-URL and kibana-URL
func decodeCloudID(cloudID string) (string, string, error) {

// 1. Ignore anything before `:`.
idx := strings.LastIndex(cloudID, ":")
if idx >= 0 {
cloudID = cloudID[idx+1:]
}

// 2. base64 decode
decoded, err := base64.StdEncoding.DecodeString(cloudID)
if err != nil {
return "", "", errors.Wrapf(err, "base64 decoding failed on %s", cloudID)
}

// 3. separate based on `$`
words := strings.Split(string(decoded), "$")
if len(words) < 3 {
return "", "", errors.Errorf("Expected at least 3 parts in %s", string(decoded))
}

// 4. form the URLs
esURL := url.URL{Scheme: "https", Host: fmt.Sprintf("%s.%s:443", words[1], words[0])}
kibanaURL := url.URL{Scheme: "https", Host: fmt.Sprintf("%s.%s:443", words[2], words[0])}

return esURL.String(), kibanaURL.String(), nil
}

// decodeCloudAuth splits the cloud.auth into username and password.
func decodeCloudAuth(cloudAuth string) (string, string, error) {

idx := strings.Index(cloudAuth, ":")
if idx < 0 {
return "", "", errors.New("cloud.auth setting doesn't contain `:` to split between username and password")
}

return cloudAuth[0:idx], cloudAuth[idx+1:], nil
}
Loading

0 comments on commit c46fc43

Please sign in to comment.