diff --git a/.circleci/config.yml b/.circleci/config.yml index 68f23b5..ad28fae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 orbs: prometheus: prometheus/prometheus@0.8.0 - codecov: codecov/codecov@1.0.5 + codecov: codecov/codecov@3.1.1 executors: # Whenever the Go version is updated here, .promu.yml should diff --git a/collector/collector_test.go b/collector/collector_test.go index 74cd296..be40789 100644 --- a/collector/collector_test.go +++ b/collector/collector_test.go @@ -38,18 +38,30 @@ const ( var knownHosts *os.File func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { - buffer, err := os.ReadFile("testdata/id_rsa_test1.pub") + pubKeyBuffer, err := os.ReadFile("testdata/id_rsa_test1.pub") if err != nil { fmt.Printf("ERROR reading public key testdata/id_rsa_test1.pub: %s", err) os.Exit(1) } - goodKey, _, _, _, err := ssh.ParseAuthorizedKey(buffer) + pubKey, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyBuffer) if err != nil { fmt.Printf("ERROR parsing public key testdata/id_rsa_test1.pub: %s", err) os.Exit(1) } + pubCertBuffer, err := os.ReadFile("testdata/id_rsa_test1-cert.pub") + if err != nil { + fmt.Printf("ERROR reading public key testdata/id_rsa_test1-cert.pub: %s", err) + os.Exit(1) + } + pubCert, _, _, _, err := ssh.ParseAuthorizedKey(pubCertBuffer) + if err != nil { + fmt.Printf("ERROR parsing public cert key testdata/id_rsa_test1-cert.pub: %s", err) + os.Exit(1) + } - if ssh.KeysEqual(key, goodKey) { + if ssh.KeysEqual(key, pubKey) { + return true + } else if ssh.KeysEqual(key, pubCert) { return true } else { return false @@ -421,6 +433,40 @@ func TestCollectorPrivateKey(t *testing.T) { } } +func TestCollectorCert(t *testing.T) { + expected := ` + # HELP ssh_failure Indicates a failure + # TYPE ssh_failure gauge + ssh_failure{reason="command-error"} 0 + ssh_failure{reason="command-output"} 0 + ssh_failure{reason="error"} 0 + ssh_failure{reason="timeout"} 0 + # HELP ssh_success SSH connection was successful + # TYPE ssh_success gauge + ssh_success 1 + ` + target := &config.Target{ + Host: fmt.Sprintf("localhost:%d", listen), + User: "test", + PrivateKey: "testdata/id_rsa_test1", + Certificate: "testdata/id_rsa_test1-cert.pub", + Timeout: 2, + } + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + collector := NewCollector(target, logger) + gatherers := setupGatherer(collector) + if val, err := testutil.GatherAndCount(gatherers); err != nil { + t.Errorf("Unexpected error: %v", err) + } else if val != 6 { + t.Errorf("Unexpected collection count %d, expected 6", val) + } + if err := testutil.GatherAndCompare(gatherers, strings.NewReader(expected), + "ssh_success", "ssh_failure", "ssh_output"); err != nil { + t.Errorf("unexpected collecting result:\n%s", err) + } +} + func TestCollectorKnownHosts(t *testing.T) { expected := ` # HELP ssh_failure Indicates a failure @@ -539,6 +585,74 @@ func TestCollectDNEKey(t *testing.T) { } } +func TestCollectDNEKeyCert(t *testing.T) { + target := &config.Target{ + Host: fmt.Sprintf("localhost:%d", listen), + User: "test", + PrivateKey: "testdata/dne", + Certificate: "testdata/id_rsa_test1-cert.pub", + Timeout: 2, + } + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + collector := NewCollector(target, logger) + metric := collector.collect() + if metric.FailureReason != "error" { + t.Errorf("Expected failure reason to be error, got %s", metric.FailureReason) + } +} + +func TestCollectDNECert(t *testing.T) { + target := &config.Target{ + Host: fmt.Sprintf("localhost:%d", listen), + User: "test", + PrivateKey: "testdata/id_rsa_test1", + Certificate: "testdata/dne", + Timeout: 2, + } + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + collector := NewCollector(target, logger) + metric := collector.collect() + if metric.FailureReason != "error" { + t.Errorf("Expected failure reason to be error, got %s", metric.FailureReason) + } +} + +func TestCollectBadCert(t *testing.T) { + target := &config.Target{ + Host: fmt.Sprintf("localhost:%d", listen), + User: "test", + PrivateKey: "testdata/id_rsa_test1", + Certificate: "testdata/id_rsa_test1", + Timeout: 2, + } + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + collector := NewCollector(target, logger) + metric := collector.collect() + if metric.FailureReason != "error" { + t.Errorf("Expected failure reason to be error, got %s", metric.FailureReason) + } +} + +func TestCollectBadCertKey(t *testing.T) { + target := &config.Target{ + Host: fmt.Sprintf("localhost:%d", listen), + User: "test", + PrivateKey: "testdata/id_rsa_test1-cert.pub", + Certificate: "testdata/id_rsa_test1-cert.pub", + Timeout: 2, + } + w := log.NewSyncWriter(os.Stderr) + logger := log.NewLogfmtLogger(w) + collector := NewCollector(target, logger) + metric := collector.collect() + if metric.FailureReason != "error" { + t.Errorf("Expected failure reason to be error, got %s", metric.FailureReason) + } +} + func TestCollectBadKey(t *testing.T) { target := &config.Target{ Host: fmt.Sprintf("localhost:%d", listen), diff --git a/collector/testdata/CA b/collector/testdata/CA new file mode 100644 index 0000000..0393894 --- /dev/null +++ b/collector/testdata/CA @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAutjCygC6LBRD+zy0Ux7GcohemZRUS9lYWZm9B0RO/64aB7Gl +ITQbhF4lYBhkxSQ5hl5itM16vUWm+44m/DPCt8tzoWJIfVq6d/L7wTWtEaTh4qq/ +GGxrTFfbKQllIwjqINH6ve7HSI80CxXu21ANfr5S42X5335BymEh4/2QTDM2Jy3/ +sBJlGC7PvPv1ZS6VAJWXnk+K3h0H1eQ3atxbVIL/OaTLMmjuLQYp5OvQDJfv8tMx +Z7SLuEKv4jFY1pO9y2AC60asM8N/r5yzXo/zqCfyVjpY+qPRgmczpimfiYIdiG7r +rje6qQs9oZusjqRa3wxSm5YpU9wvqCH3q0xJIQIDAQABAoIBAQCYqEsV0dxJ8VDN +rv5Bvy4yG3r3DbqFshE+O562ljfZLDz2Nk0NQM6OqoDs72E9tOgPAYSx5gQ3KfZR +JwZxHjUkB2T04SEK0hrxr6PDawB5HvazRAAXi1VrLYjREW0BX+IyaHztu240uVOz +Dvt1UgWEnSmJwyKRWE2WdR/Eb8H6jqLP9RQysUZC2V4LmuiOXqWXbC3fBeStoQHR +bx7XMs0BqzvbAW81bTrH/LM/3xU3/8A00a+U/PLmU6C9NfDnsSR+GP2y9mT4dOTt +s68pL2GtLYFpHxW45cAZIzclm8s0C1pAPIJTxPzZ0pAS720z2xDDyJiurCxLt9aU +zgv84721AoGBAOhuMUReUIUBtnuHxHbhaSchVCRukXtnqUVdgMH3OTSdz7t1TH7j +/EwKafsbOozGmHMqVoYsYP3xqI8NM/q36z8ag7iFJ8ADRQ3S93NtwFX/NYO143Uy +tg2HgQhhzIFBnIuH5wJfc6NkuH8NEGWRuLkndRCXib9WE0P1A9IJQHLTAoGBAM3L +O23pLzooK9GV6wLo2Ix3LboQcTKBT7fYP5SmshJjJVoQhQTNT4e+Lq6LLwgxo/pF +1OaZa1DoQNBINFMyZhhaE+s37kzGwx9S/zIjcvNgU79BXKp+q/C+z0auqlP1TA9L +q69hI1D+b97267qihP/O9quqZnIXRtFpGE0BSlO7AoGAFnI1zc1x5zZgIhPddEGW +fxHn51DKOemr3igGfDTc0GkBG7BbP9HSlqFW1MovYFL5e/21t2VnxH5m8dGrmGXU +kRaFa/dn/FIUhB5AiWQq8+Mejuas3a+VBz9zxZR0RHNKo+ru8zq2lyvt6U8gqz5k +YXUfCAgqZFDysVhjExCTqcMCgYEAvvj3KHL5WZ3HtBHMagHMWuWJ8J2rfjPT14Z8 +0iSzIS8SjXbBCgjA4fYR+fW9anwucGT3QhtjJEyzQNWQgRhG+Bg3XdOkd2kHz3zE +xzFwTfu5G8W7CZjNVHatgSk7dPgwYg1VwEWDcXj8NcusS6DfjUfxTrKtqPiCxngh +jexBnlsCgYArnXDMyHdzTEc6zNyToTjY0TNNSjrYmQPS9p2+EakWzvH0RN0wJmlL +yGLhxi1Yek2numRMrG3Yu9O3UN87JLrjfDxZuf3lsp608HBlxTZyYLlgW3hZuFnd +k0e9d5Q56ZjXrXMdN2VqXkDmNsXP2Ni8kt3H4LSZ32YnkS3jbc4maA== +-----END RSA PRIVATE KEY----- diff --git a/collector/testdata/CA.pub b/collector/testdata/CA.pub new file mode 100644 index 0000000..2f8e0cd --- /dev/null +++ b/collector/testdata/CA.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC62MLKALosFEP7PLRTHsZyiF6ZlFRL2VhZmb0HRE7/rhoHsaUhNBuEXiVgGGTFJDmGXmK0zXq9Rab7jib8M8K3y3OhYkh9Wrp38vvBNa0RpOHiqr8YbGtMV9spCWUjCOog0fq97sdIjzQLFe7bUA1+vlLjZfnffkHKYSHj/ZBMMzYnLf+wEmUYLs+8+/VlLpUAlZeeT4reHQfV5Ddq3FtUgv85pMsyaO4tBink69AMl+/y0zFntIu4Qq/iMVjWk73LYALrRqwzw3+vnLNej/OoJ/JWOlj6o9GCZzOmKZ+Jgh2IbuuuN7qpCz2hm6yOpFrfDFKblilT3C+oIferTEkh tdockendorf@owens-rw02.ten.osc.edu diff --git a/collector/testdata/id_rsa_test1-cert.pub b/collector/testdata/id_rsa_test1-cert.pub new file mode 100644 index 0000000..0bc61cd --- /dev/null +++ b/collector/testdata/id_rsa_test1-cert.pub @@ -0,0 +1 @@ +ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgBlXa+8yYEVnT346kLR44D4lEMTl7Qsx6zVRr2MOqHHcAAAADAQABAAABAQD2vESWN61Xx/sXq+bJZRsSkX1wgRl2SN6lZ7U55Pj23Hvy/F00G0zJh6CNLcGplwcEO26ZwZeB54G6oROC0yL4SBx1whETfPl9+LJxLfdKyb/0/Z6v84H1qlyFujsp9sM13xIfwibNJSEtAh0hgpMFmvWlz0FvWFpX/xWilugsbU1MP7mrlLZ8laehY8vdoUJgI7zgyLfqt+Ok9qO6/5NuMLX1BRRMwI+PwCppsdJjibh6O25mfqqKS/auOptR2AR68wGrQepsA5rI4/WwrnErohZ/MlaAPknZH3eoknTtzJpiouKaBD7vDYjdHrMx6Gz//74nq+i7jSZe2ivnajKhAAAAAAAAAAAAAAABAAAACXRlc3QtY2VydAAAAAgAAAAEdGVzdAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAutjCygC6LBRD+zy0Ux7GcohemZRUS9lYWZm9B0RO/64aB7GlITQbhF4lYBhkxSQ5hl5itM16vUWm+44m/DPCt8tzoWJIfVq6d/L7wTWtEaTh4qq/GGxrTFfbKQllIwjqINH6ve7HSI80CxXu21ANfr5S42X5335BymEh4/2QTDM2Jy3/sBJlGC7PvPv1ZS6VAJWXnk+K3h0H1eQ3atxbVIL/OaTLMmjuLQYp5OvQDJfv8tMxZ7SLuEKv4jFY1pO9y2AC60asM8N/r5yzXo/zqCfyVjpY+qPRgmczpimfiYIdiG7rrje6qQs9oZusjqRa3wxSm5YpU9wvqCH3q0xJIQAAAQ8AAAAHc3NoLXJzYQAAAQCpnycbSvEbvZgRe9YmXxHlJaL8gjrPObE4O0CLhRTkN4CTkfvC+654xuTBJZfksSv00uiRH1INhQ5CyXOGNURn64CwCqif9gvxVGeAvCgUT6WeRr51ZgejJxaXiFu8TUcLC9r3q8Jstbm3M9nIOtveWBO3lW//Kph8TUv2POo931+DTGfZkEMU64GfBjpEmlnLhu/12ALs/K5h4fpDfeLTrdXEF/A49n73Kepsuwj4b0T63Vcrnl6HCrqdL7RCBhQ/wC9Wjaceg3CNkZ/2r/2y4TneTKjw41SkzibcNkmEXRTAm0EcjayuleqTAyGUM4VKC+hDzlEfmIVQYm23VGhN test1