-
Notifications
You must be signed in to change notification settings - Fork 231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ssh exporter #2138
base: main
Are you sure you want to change the base?
ssh exporter #2138
Conversation
| Name | Type | Description | Default | Required | | ||
| ----------------- | -------- | -------------------------------------------------- | ------- | -------- | | ||
| `verbose_logging` | `bool` | Enable verbose logging for debugging purposes. | `false` | no | | ||
| `targets` | `block` | One or more target configurations for SSH metrics. | | yes | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| `targets` | `block` | One or more target configurations for SSH metrics. | | yes | |
We don't list blocks in the table in the Arguments section. They are listed in the table in the Blocks section.
| `port` | `int` | SSH port number. | `22` | no | | ||
| `username` | `string` | SSH username for authentication. | | yes | | ||
| `password` | `secret` | Password for password-based SSH authentication. | | Required if `key_file` is not provided | | ||
| `key_file` | `string` | Path to the private key file for key-based SSH authentication. | | Required if `password` is not provided | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to just have a key
attribute which is a secret string. People can still get that string from a file if they use local.file. The benefit is that it's more flexible, because you can also get the secret from somewhere like remote.vault or remote.kubernetes.secret.
| `address` | `string` | The IP address or hostname of the target server. | | yes | | ||
| `port` | `int` | SSH port number. | `22` | no | | ||
| `username` | `string` | SSH username for authentication. | | yes | | ||
| `password` | `secret` | Password for password-based SSH authentication. | | Required if `key_file` is not provided | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| `password` | `secret` | Password for password-based SSH authentication. | | Required if `key_file` is not provided | | |
| `password` | `secret` | Password for password-based SSH authentication. | | no |
If an argument is not always required, we'll usually just say "no" in the table and then we'll explain under the table that one of those two arguments must be supplied.
#### Metric Types | ||
|
||
- `gauge`: Represents a numerical value that can go up or down. | ||
- `counter`: Represents a cumulative value that only increases. | ||
|
||
#### parse_regex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#### Metric Types | |
- `gauge`: Represents a numerical value that can go up or down. | |
- `counter`: Represents a cumulative value that only increases. | |
#### parse_regex | |
The `type` argument can have either of the following values: | |
- `gauge`: Represents a numerical value that can go up or down. | |
- `counter`: Represents a cumulative value that only increases. |
We usually don't use sub-headings under the tables, unless there's too much text and there's no other way to structure the information.
The `prometheus.exporter.ssh` component uses the `known_hosts` file to validate host keys and protect against man-in-the-middle (MITM) attacks. Here's how it handles this: | ||
|
||
1. **First-Time Setup**: | ||
- If the `known_hosts` file does not exist, the component creates it and fetches the host key using `ssh-keyscan`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- If the `known_hosts` file does not exist, the component creates it and fetches the host key using `ssh-keyscan`. | |
- If the `~/.ssh/known_hosts` file does not exist, the component creates it and fetches the host key using `ssh-keyscan`. |
Would be good to know where the file is located.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need static mode converters, since static mode doesn't support this exporter :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this file? The reason other exporters have it is that they come from Agent Static mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the code copied from an already existing prometheus exporter? If so, we should probably check the license to make sure it's ok to copy it. But it might be better to just import the other exporter if possible?
time.Sleep(time.Second) | ||
} | ||
if len(output) == 0 { | ||
return fmt.Errorf("failed to fetch host key for %s after 3 attempts: last error: %w", targetAddress, scanErr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a user fixes the issue with this, would they have to restart Alloy for things to start working? Ideally the component should just keep trying periodically until it works.
|
||
|
||
|
||
func (c *SSHClient) RunCommand(command string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any SSH commands that should not be allowed? I realise this may be hard to enforce, but I just think some users might want extra security and I wonder if there are any further checks we can do.
Once the component is merged, it would be useful to have modules in the alloy-modules repo which show how to extract various metrics in Linux. |
# prometheus.exporter.ssh | ||
|
||
The `prometheus.exporter.ssh` component embeds an SSH exporter for collecting metrics from remote servers over SSH and exporting them as Prometheus metrics. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the experimental snippet to document the fact that the component is experimental
--- | ||
canonical: https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.exporter.ssh/ | ||
aliases: | ||
- ../prometheus.exporter.ssh/ # /docs/alloy/latest/reference/components/prometheus.exporter.ssh/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aliases are not need for this component because it's brand new (this was used for mapping after the structure of the doc was changed)
continue | ||
} | ||
|
||
level.Debug(c.logger).Log("msg", "executed custom command", "command", cm.Command, "value", value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add debug statements like this to Live Debugging. They can also include the output of the command.
| `username` | `string` | SSH username for authentication. | | yes | | ||
| `password` | `secret` | Password for password-based SSH authentication. | | Required if `key_file` is not provided | | ||
| `key_file` | `string` | Path to the private key file for key-based SSH authentication. | | Required if `password` is not provided | | ||
| `command_timeout` | `int` | Timeout in seconds for each command execution over SSH. | `30` | no | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a duration? We rarely use dedicated seconds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the expected behavior if command timeout > scrape timeout?
@@ -0,0 +1,194 @@ | |||
package ssh_exporter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this windows compatible?
timeout time.Duration | ||
} | ||
var sshKeyscanCommand = func(targetAddress string) ([]byte, error) { | ||
cmd := exec.Command("ssh-keyscan", "-H", targetAddress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can target address be hijacked for any injection? We should ensure it is an valid URI.
} | ||
} | ||
|
||
file, err := os.OpenFile(knownHostsPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this safe? It likely is because its only called from NewSSHClient but maybe a global mutex?
} | ||
|
||
func (c *SSHCollector) executeCustomCommand(cm CustomMetric) (float64, error) { | ||
output, err := c.client.RunCommand(cm.Command) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The underlying component context should likely also be passed here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And checked against.
The following arguments can be used to configure the exporter's behavior. | ||
All arguments are optional unless specified. Omitted fields take their default values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Observation: In reviewing this I've noticed that the wording of some sections in the Prometheus topics are not consistent with the rest of the components. For example, Arguments in other sections simply state: The following arguments are supported:
I'll create an Issue to follow up on this. No action or suggestions for this PR.
|
||
The following blocks are supported inside the definition of `prometheus.exporter.ssh`: | ||
|
||
| Block | Description | Required | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add/include the Hierarchy
column in this table?
PR Description
ssh exporter for remote hosts
define ip along with password or key for the creation of custom metrics from a remote host via bash interpolation
ex alloy config:
Notes to the Reviewer
plz let me know if issue or something missing with my pr - cheers :)
PR Checklist