Skip to content

add a new collector that gets information about a server's TLS certificates #1765

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

Open
wants to merge 22 commits into
base: main
Choose a base branch
from

Conversation

laverya
Copy link
Member

@laverya laverya commented Mar 31, 2025

Description, Motivation and Context

In order to determine if there is a MITM proxy, it is useful to know what the certificate is returned by an external endpoint.

This allows doing so, and analyzing the result by comparing the certificate's issuer to an expected value.

Checklist

  • New and existing tests pass locally with introduced changes.
  • Tests for the changes have been added (for bug fixes / features)
  • The commit message(s) are informative and highlight any breaking changes
  • Any documentation required has been added/updated. For changes to https://troubleshoot.sh/ create a PR here

Does this PR introduce a breaking change?

  • Yes
  • No

@laverya laverya added the type::feature New feature or request label Mar 31, 2025
@laverya
Copy link
Member Author

laverya commented Mar 31, 2025

example collected output:

{
  "peer_certificates": [
    {
      "issuer": "localhost",
      "subject": "localhost",
      "serial": "223988171543336272920354702839529366910",
      "not_before": "2025-03-31T22:51:45Z",
      "not_after": "2025-03-31T23:51:45Z",
      "is_ca": false,
      "raw": "MIIC/jCCAeagAwIBAgIRAKiCjXwzGYpbzqguTLBYZX4wDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTI1MDMzMTIyNTE0NVoXDTI1MDMzMTIzNTE0NVowFDESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn2dQnXU+Q/liN7lcG5ik0F5kqkD341IRpohxYsL9yA2w2uxGHxstajYuh9aiuD40RvQ2XmyGXsX8z7pWPjzDiKPO5EkU+0ahPi3kHAGyy4nD/tcevtUR7fOO4mirqvxozZkhLUAYN3zEn374V+WcdjuogAStBpgRFAltfH/9lLGlET0QFP2j+030JxcNpsLgnRSS/RGmiHZ0Ybk+OaMnj4cOQto0Jo2X51hQL6MYuNu1a1SAy2c8OXMuu9gaj7LwdFHVhSiAUFZHZRBW5Eisp2NXVtGmV/C9ybj7sk6MEGsalb3jCSsmPWKSrAcyH0lgR4r6AKwQd+AgNotOZPl6cwIDAQABo0swSTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBABoFF/8mqT9vS2+awapvjTVfmKQ1fcMB0KVyi28UD3rEEzfAxIT2aViIXoS5bb30esdfFzfFAmWss6E0tHBbul2vccAW/kQPx6XqZGpdEKQc0Dr2uB9FRu4Bx13CfSprMgqeoK1/O/VKtcQ8jQIbLSA9/QIFAJ6Oo3vBSMWRo+izi2NZQ/nIrSbk2a4NpDcv6tfJcSOGfS0JIIrKf/EEu2po7HpD8vE1hCzqsWOhC1+yV46tvOsOFRJ6FEusBlH8Kh4WsSld+S/ARsAoaJyc2Ft77D/YrSBYlaFWSO4VGo4rXP6q2nGcGz7/eXR4n1Q7F9P75/xnZrZakcl5K6wlGgc="
    }
  ]
}

And the output for replicated.app:

{
  "peer_certificates": [
    {
      "issuer": "E5",
      "subject": "replicated.app",
      "serial": "366647399446765119739694467366731491294821",
      "not_before": "2025-02-12T20:48:06Z",
      "not_after": "2025-05-13T20:48:05Z",
      "is_ca": false,
      "raw": "MIIDkDCCAxagAwIBAgISBDV62JAIFJ/68CYg4GL6V75lMAoGCCqGSM49BAMDMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJFNTAeFw0yNTAyMTIyMDQ4MDZaFw0yNTA1MTMyMDQ4MDVaMBkxFzAVBgNVBAMTDnJlcGxpY2F0ZWQuYXBwMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtLBSWSjTkS63NvKjChgv0IRLXQ+8qQVZfGa27M8Odvok+0nDivOLwvXToIfcsb87rj2ZolYaMZ51oZMAPTer8KOCAiMwggIfMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUAcqA0Ax0SYkbpaTHUE1/3K+F+8MwHwYDVR0jBBgwFoAUnytfzzwhT50Et+0rLMTGcIvS1w0wVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vZTUuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9lNS5pLmxlbmNyLm9yZy8wKwYDVR0RBCQwIoIQKi5yZXBsaWNhdGVkLmFwcIIOcmVwbGljYXRlZC5hcHAwEwYDVR0gBAwwCjAIBgZngQwBAgEwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdgDM+w9qhXEJZf6Vm1PO6bJ8IumFXA2XjbapflTA/kwNsAAAAZT8INAKAAAEAwBHMEUCIQChEKizx3gdCm8rATD9JULAHFmhCcNCiPjLaKIuyV624AIgDIxiox82edgyw1ENlsCTVgM849qDBOLr41WeSIG04kwAdwATSt8atZhCCXgMb+9MepGkFrcjSc5YV2rfrtqnwqvgIgAAAZT8INHBAAAEAwBIMEYCIQCuxLNpzW2lYKwJ2uLBSu14wH0jc+oxrH4lA/QLXm2CeQIhAM66PhzUGhgrypwyKW0F9AwH73tPHoRZHWgDnWBjX7B+MAoGCCqGSM49BAMDA2gAMGUCMFMMHRfHegdMljQd68qhTv6hL0ySV9nn2u85mWcilDHUMbQSGaqH8liyMfNlR/a7+gIxALSdKsdnyrqAsViMDAMo56gwaq8EeGtSyfWfmPiRlRinn6ANwxf6bs6J3csBgM+hdw=="
    },
    {
      "issuer": "ISRG Root X1",
      "subject": "E5",
      "serial": "174873564306387906651619802726858882526",
      "not_before": "2024-03-13T00:00:00Z",
      "not_after": "2027-03-12T23:59:59Z",
      "is_ca": true,
      "raw": "MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAwWhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqKa2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBOVHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgwgfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZwi9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyVXP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GOkoAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNqcm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOIE1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0eK1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcXGWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyLsVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJdVQD9F6Na/+zmXCc="
    }
  ]
}

@laverya laverya marked this pull request as ready for review April 1, 2025 15:09
@laverya laverya requested a review from a team as a code owner April 1, 2025 15:09
tlsInfo := types.TLSInfo{}

conf := &tls.Config{
InsecureSkipVerify: true,
Copy link
Member

Choose a reason for hiding this comment

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

this should be an option in the collector

Copy link
Member Author

Choose a reason for hiding this comment

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

Are you sure? IMO this should just be the default - you want to know the cert regardless of whether the host trusts it

Copy link
Member

Choose a reason for hiding this comment

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

I'm not 100% on the use case for adding this now, but I can see it being useful later if we let users pass in custom CAs. In that scenario, to make sure we're using the right certs, InsecureSkipVerify should be set to false. Otherwise, if we don't handle it on the collector side, users on the analyzer side would have to figure out if the certificate chain was trusted. Not saying we need to fix this here, but we should probably file a story for it if not done here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I would agree with adding a "this cert chain is trusted by the host" bit later, but I think the "is this trusted with the provided CA/host CAs" is already covered by the HTTP collector.

The goal of this is to figure out what certs are being used, and I think getting back an error if you didn't set "allow untrusted" is unintuitive

Co-authored-by: Ethan Mosbaugh <[email protected]>
@@ -60,6 +60,12 @@ type TimeAnalyze struct {
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
}

type TLSAnalyze struct {
Copy link
Member

Choose a reason for hiding this comment

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

Should we name this HostTLSAnalyze to keep it consistent with the others?

Also, similar to collector_shared, you'll need to add this to the HostAnalyze struct as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

🤦

Copy link
Member Author

Choose a reason for hiding this comment

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

Should we name this HostTLSAnalyze to keep it consistent with the others?

very few of the others have 'host' in the name - just 4 of 25

NotAfter: cert.NotAfter.Format(time.RFC3339),
IsCA: cert.IsCA,
Raw: cert.Raw,
tlsInfo.Error = err.Error()
Copy link
Member

Choose a reason for hiding this comment

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

I guess I had imagined you would piggyback on this

func checkTCPConnection(progressChan chan<- interface{}, listenAddress string, dialAddress string, timeout time.Duration) (NetworkStatus, error) {

@laverya
Copy link
Member Author

laverya commented Apr 1, 2025

@emosbaugh to prevent hardcoding the expected cert issuer in analyzers, I've added a new bit of collector + analyzer logic:

  1. You can supply an additional parameter expectedCertSubpath to the collector. If you do, the collector will make a request to that subpath on the target host and also pass a header tls-request-hostname with the target address - and will include the response in the collected data.
  2. The analyzer has a new mode that compares what was returned in 1 with what certificate the server actually had.

This way we have to update the replicated.app server with a new route (pretty easy), but the issuer isn't hardcoded anymore

@laverya
Copy link
Member Author

laverya commented Apr 3, 2025

Putting this on hold - it's not clear this is a good way to detect non-default CAs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type::feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants