Skip to content
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

Use libbeat LoadCertificate function on server side #235

Closed
wants to merge 9 commits into from
Closed

Use libbeat LoadCertificate function on server side #235

wants to merge 9 commits into from

Conversation

sterchelen
Copy link

@sterchelen sterchelen commented Oct 13, 2017

To add the encrypted private key loading feature, I've :

  • update the vendor/github.com/elastic/beats/libbeat/outputs package which put in public mode the LoadCertificate function.
  • use the LoadCertificate function and inject the certificate in the http.Server.
  • Modify tests in consequence.
  • Modify reference yaml files.
  • Add more log on certificate / private key loading.

@elasticmachine
Copy link
Contributor

Can one of the admins verify this patch?

@sterchelen
Copy link
Author

@ruflin @jalvz Here is the change to use the libbeat LoadCertificate function.

There is no test for a private key with a pass_phrase. To allow that we should think to reuse the following function with little modification to decrypt the pem block: https://github.com/elastic/beats/blob/d15cab2b3ec265a7f8bf3514c0e4fbc01c498a40/libbeat/outputs/transport/transptest/testing.go#L180

Do I make the modification on beats repository or I copy the function inside our repository and apply the modification ?

@ruflin
Copy link
Member

ruflin commented Oct 16, 2017

As the functionality is inherited from beats now, it should be up to beats to make sure it works as expected. Or is the usage / implementation different here?

@sterchelen
Copy link
Author

@ruflin ,
The implementation is exactly the same as beats ! I will made a pull request on beats to implement this test :).

@sterchelen
Copy link
Author

PR open on beats repository --> elastic/beats#5431
It modify the function that generate a certificate for testing purpose by adding a password parameter.

When the PR will be merged, I'll can add more tests on the beater/server_test.go file with a focus on private key with password handling.

@sterchelen
Copy link
Author

Gentlemen,

I've use the beats modification that I've made to create testing certificate. I've also added a new unit test to test the server in https mode with a encrypted certificate key.

@jalvz
Copy link
Contributor

jalvz commented Nov 13, 2017

Great @sterchelen ! Ill have a look soon. In the meanwhile, can you rebase master and fix conflicts?

@sterchelen
Copy link
Author

sterchelen commented Nov 18, 2017

@jalvz I've already merged master on it :)

@@ -20,7 +20,8 @@ apm-server:
#ssl.enabled: false
#ssl.certificate : "path/to/cert"
#ssl.key : "path/to/private_key"

#ssl.pass_phrase: "foobar"
Copy link
Contributor

Choose a reason for hiding this comment

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

correct attribute here is ssl.key_passphrase

@@ -13,7 +13,10 @@ import (
"testing"
"time"

"github.com/kabukky/httpscerts"
Copy link
Contributor

Choose a reason for hiding this comment

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

this dependency is not used anymore, should be removed then (also remember to run make notice after removing it to remove its entry from the NOTICE file as well)

Copy link
Author

@sterchelen sterchelen Nov 24, 2017

Choose a reason for hiding this comment

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

@jalvz This dependency is already removed. You are looking in the wrong side of the diff :)

Copy link
Contributor

@jalvz jalvz Nov 27, 2017

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Doesn't look like this has been addressed yet.

Copy link
Author

Choose a reason for hiding this comment

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

Resolved !

@@ -160,16 +163,29 @@ func TestServerNoContentType(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, rr.Code, rr.Body.String())
}

func TestServerSecureOkWithPasswordKey(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is good!
I miss 1 more test that "breaks" if the passphrase generated and the one passed in the server config do not match.
Note: in that scenario the server won't be able to start, so you need to assert that a timeout happens instead, the one in waitForServer. That is hardcoded to 10 seconds, so you will also need to modify that function to accept a timeout param and pass a lower value for that test because 10 secs every time it runs would be very slow.
Does this makes sense to you?

logp.Info("Loading private key: %s", config.SSL.Certificate.Key)
cert, err := outputs.LoadCertificate(&config.SSL.Certificate)
if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

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

This code path should also be tested, I think

Copy link
Author

Choose a reason for hiding this comment

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

@jalvz While I'm writing a test for this path, I saw that we are completely hiding error from the setupServer function (server_test file). Particularly on the go run statement.

If we check the error while running the server, we could remove all the checkErrMsgtests.

For instance, the TestServerSecureBadDomain test, would only have to check if an error has occured with the following msg : http: TLS handshake error from 127.0.0.1:60368: remote error: tls: bad certificate.
Again, for the TestServerBadProtocol test, we would only have to check for an error like http: TLS handshake error from 127.0.0.1:60386: tls: oversized record received with length 21536 which tells us that we are trying to reach the https server with the http protocol.

Do you agree ?

Copy link
Contributor

Choose a reason for hiding this comment

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

@sterchelen that sounds good to me, but how do check the error while running the server?

@jalvz
Copy link
Contributor

jalvz commented Nov 22, 2017

Great work @sterchelen ! I think this is very very close :)

Sterchele Nicolas added 7 commits December 23, 2017 16:06
Rev: 5c51448f5fc0c9f458273c452e0ce855fc749a1f
- Inject certificate in the http.Server
- Change tests to use the output.CertificateConfig
- Vendoring transptest package from beats repository
- Use GenCertForTestingPurpose function to generate testing certificates
@sterchelen
Copy link
Author

@jalvz sorry for the delay ... So much professional work :)

@@ -20,7 +20,7 @@ apm-server:
#ssl.enabled: false
#ssl.certificate : "path/to/cert"
#ssl.key : "path/to/private_key"

#ssl.key_passphrase: "foobar"
Copy link
Member

Choose a reason for hiding this comment

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

let's make this an empty string to match other elastic pkgs

@@ -20,7 +20,7 @@ apm-server:
#ssl.enabled: false
#ssl.certificate : "path/to/cert"
#ssl.key : "path/to/private_key"

#ssl.key_passphrase: "foobar"
Copy link
Member

Choose a reason for hiding this comment

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

let's make this an empty string to match other elastic pkgs

beater/client.go Outdated
secureInfo := ""
if secure {
secureInfo = " (secure mode activated)"
}
Copy link
Member

Choose a reason for hiding this comment

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

building secureInfo can be done outside the for loop. Also good with removing it altogether.

Copy link
Author

Choose a reason for hiding this comment

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

Agree with building it outside the for loop. Not agree with removing it. IMO, logged that the server is in secure mode is relatively important to know ?

beater/server.go Outdated
"net/http"
"time"

"github.com/elastic/apm-server/version"
"github.com/elastic/beats/libbeat/outputs"

Copy link
Member

Choose a reason for hiding this comment

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

extra newline here

@@ -274,7 +301,7 @@ func randomAddr() string {
return l.Addr().String()
}

func waitForServer(secure bool, host string) {
func waitForServer(secure bool, host string, timeout int) {
Copy link
Member

Choose a reason for hiding this comment

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

would prefer a context to timeout here but we can add that later

Copy link
Author

Choose a reason for hiding this comment

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

Do you mean the name of the variable is not intelligible ?

if check() == http.StatusOK {
return
}
time.Sleep(time.Second * 1)
Copy link
Member

Choose a reason for hiding this comment

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

How long does this normally take? I expect we can bring this way down.

// if check() == http.StatusOK {
// return
// }
// }
Copy link
Member

Choose a reason for hiding this comment

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

remove commented out code


return &SSLConfig{Cert: cert, PrivateKey: key}
return &SSLConfig{Enabled: newTrue(), Certificate: outputs.CertificateConfig{Certificate: name + ".pem", Key: name + ".key", Passphrase: passwordKey}}
Copy link
Member

Choose a reason for hiding this comment

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

since this is the only usage of newTrue(), a local truthy var like elsewhere would be preferred.

@@ -13,7 +13,10 @@ import (
"testing"
"time"

"github.com/kabukky/httpscerts"
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't look like this has been addressed yet.

@sterchelen
Copy link
Author

 @graphaelli Does the PR seems good to you ?

@sterchelen
Copy link
Author

@graphaelli @ruflin Any news ?

@elasticmachine
Copy link
Contributor

Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually?

@jalvz
Copy link
Contributor

jalvz commented May 8, 2018

Hi @sterchelen we would like to have this changes in, but this got a bit old now and needs to rebase master.
Do you think you will have time to have a look or should I cherry-pick your work and take it from there?

@sterchelen
Copy link
Author

sterchelen commented May 8, 2018 via email

@jalvz
Copy link
Contributor

jalvz commented May 9, 2018

Sounds fantastic! 👍

@sterchelen
Copy link
Author

@jalvz I will start fresh from master ! It tried to rebase master on the branch but it's too old... I don't want to add wrong code.
I will get back to you soon !

@jalvz
Copy link
Contributor

jalvz commented Jun 7, 2018

Hi @sterchelen, I want to make sure you still have time for this. If not it is ok, I appreciate a lot the work you have done so far!

@sterchelen
Copy link
Author

sterchelen commented Jun 8, 2018 via email

@jalvz
Copy link
Contributor

jalvz commented Jun 15, 2018

Took this over to #1010
Thanks @sterchelen !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants