diff --git a/Makefile b/Makefile index 4b988deb..1fffc667 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,7 @@ e2e-offline-in-mem: ## brings up offline proxy in in-memory mode and runs e2e sd e2e-online-in-mem: ## brings up proxy in online in memory mode and runs e2e sdk tests against it docker-compose --env-file .env.online_in_mem -f ./docker-compose.yml up -d --remove-orphans proxy sleep 5 ## TODO replace with a check for the proxy and all envs being healthy - go test -p 1 -v ./tests/... -env=".env.online" | tee /dev/stderr | go-junit-report -set-exit-code > online-in-memory.xml + STREAM_URL=https://localhost:7000 go test -p 1 -v ./tests/... -env=".env.online" | tee /dev/stderr | go-junit-report -set-exit-code > online-in-memory.xml e2e-online-redis: ## brings up proxy in online in redis mode and runs e2e sdk tests against it docker-compose --env-file .env.online_redis -f ./docker-compose.yml up -d --remove-orphans proxy redis diff --git a/docker-compose.yml b/docker-compose.yml index f2ec0175..f102de44 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,7 @@ services: dockerfile: ./Dockerfile volumes: - ${CONFIG_VOLUME:-./config:/config} + - ./tests/e2e/certs:/certs ports: - 7000:${PORT:-7000} @@ -45,4 +46,4 @@ services: - "5555:5555" volumes: - ./config/pushpin:/etc/pushpin - command: "pushpin --port 7000 --merge-output" + command: "pushpin --merge-output" diff --git a/docs/configuration.md b/docs/configuration.md index 0ac65b35..319eba69 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -80,7 +80,7 @@ Adjust how often certain actions are performed. | METRIC_POST_DURATION | metric-post-duration | How often in seconds the proxy posts metrics to Harness. Set to 0 to disable. | int | 60 | | HEARTBEAT_INTERVAL | heartbeat-interval | How often in seconds the proxy polls pings it's health function | int | 60 | -### TLS (beta) +### TLS | Environment Variable | Flag | Description | Type | Default | |----------------------|-------------|-----------------------------------------------------------------------------|--------|---------| | TLS_ENABLED | tls-enabled | If true the proxy will use the tlsCert and tlsKey to run with https enabled | bool | false | diff --git a/docs/tls.md b/docs/tls.md index 88506473..c5aad7d5 100644 --- a/docs/tls.md +++ b/docs/tls.md @@ -1,7 +1,7 @@ # Enabling TLS There are two ways to configure the Relay Proxy to accept HTTPS requests. -### Native TLS (Beta) +### Native TLS You can configure the Relay Proxy to start with HTTPS enabled. This can be configured using the TLS config options. See [configuration](./configuration.md) for details. This does not provide every fine-grained configuration option available to secure servers. If you require more control the best option is to use a program made for this purpose, and follow the "External TLS" option below. diff --git a/tests/e2e/certs/cert.crt b/tests/e2e/certs/cert.crt new file mode 100644 index 00000000..2788eb88 --- /dev/null +++ b/tests/e2e/certs/cert.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID4DCCAsigAwIBAgIUSA2IRPfH2IVDnUjZtpl19g/XbAswDQYJKoZIhvcNAQEL +BQAwYDESMBAGA1UEAwwJbG9jYWxob3N0MQswCQYDVQQGEwJHQjEZMBcGA1UECAwQ +Tm9ydGhlcm4gSXJlbGFuZDEQMA4GA1UEBwwHQmVsZmFzdDEQMA4GA1UECgwHSGFy +bmVzczAeFw0yMjEyMDYxNjE3NTJaFw0yMzEyMDYxNjE3NTJaMGAxEjAQBgNVBAMM +CWxvY2FsaG9zdDELMAkGA1UEBhMCR0IxGTAXBgNVBAgMEE5vcnRoZXJuIElyZWxh +bmQxEDAOBgNVBAcMB0JlbGZhc3QxEDAOBgNVBAoMB0hhcm5lc3MwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGzGzF+M2h5CluKUiFXochnjjZQS4pmTis +b1zfk4D1Ej2RRub/Roj1zNaasz2y9jU3fnXo88mK1BoDxUGYtE3UV1k+AUfNCmFp +t7hS0yrdR5B9N9UzuRa37Bm1DchtLLvqkfksxBxLVyrrureuDWrpCbEtoYETpvea +Iw7dkRGhA6pJbu8ZMJOauzs0cGXY5sEYgslgk6NK53/uFf3EAwZnxXMPXfHl2RLp +Xbc/YkpGmMm9hNhbal3PokqnvXvLrCJOfaKFG2SEow5cr3sXEqgmIQ0mRv4Q0Ihg +YmkObJy3IEniIFV2xRpX13u1Tsc/TZwKV/JX9NKHlcoU2JFsHvzNAgMBAAGjgZEw +gY4wHQYDVR0OBBYEFOh/rIvgQfy+Ld7TY2rt0frqwZjTMB8GA1UdIwQYMBaAFOh/ +rIvgQfy+Ld7TY2rt0frqwZjTMA4GA1UdDwEB/wQEAwIFoDAgBgNVHSUBAf8EFjAU +BggrBgEFBQcDAQYIKwYBBQUHAwIwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAAB +MA0GCSqGSIb3DQEBCwUAA4IBAQA/qYHUGZorGMvqXXxiaeIKGaOrGG3ZaQTUbl3I +Djs8wNA0Ql1MNXgSYx6jrPnW06PbvquNEj6W6CPObtfrcTdeiUL9Yl93tF5NERjN +fNCNyuVGhDV2dDc/ykZJojmfcRwvQWbpeQPSVjv/mkU6fRKHf0kJJku6HYjRvCza +hE6I9loYZTSx095EvWkJ8UbMCCZUp6QlWpk2hPQlkzwwWQxYsI005tuxITOXcj0Q +69wdMdvl9MFu00uytsVwXSrJ4dyWP/f8b8U2s9TbDGPGTWbeiqa5MWOr9/y4sVAH +UJ2SvHL1Xiq5gBSAa0mUmf+aUSQoFZHfC5WbROJ9yEhbxnve +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tests/e2e/certs/cert.key b/tests/e2e/certs/cert.key new file mode 100644 index 00000000..26dcb286 --- /dev/null +++ b/tests/e2e/certs/cert.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGzGzF+M2h5Clu +KUiFXochnjjZQS4pmTisb1zfk4D1Ej2RRub/Roj1zNaasz2y9jU3fnXo88mK1BoD +xUGYtE3UV1k+AUfNCmFpt7hS0yrdR5B9N9UzuRa37Bm1DchtLLvqkfksxBxLVyrr +ureuDWrpCbEtoYETpveaIw7dkRGhA6pJbu8ZMJOauzs0cGXY5sEYgslgk6NK53/u +Ff3EAwZnxXMPXfHl2RLpXbc/YkpGmMm9hNhbal3PokqnvXvLrCJOfaKFG2SEow5c +r3sXEqgmIQ0mRv4Q0IhgYmkObJy3IEniIFV2xRpX13u1Tsc/TZwKV/JX9NKHlcoU +2JFsHvzNAgMBAAECggEALlvvpb8enPkrHDBuZAOmOZW/JhLIJBVCHRwfKVgpg30M +dHt3VOJq//8TsKHJ6pj10gogjwGC52gM5QI0CNtLJxBzlD0SNGOOUevxBQePgGi2 +7ix+AIDSJnPdjtY2/hanf80osWLOQleCf9RcDy+71bpX4g8+nYmbRguU5OB2nvhk +847hX3wenb/mXIfRH0McQWjo44K+FGubIAGKXbSVssTF7gtXcimAxo7Tk/2XWpmI +Tprh/5BTglI12UTV4F377lD1hw9j7mgmr6LSozOoMEABUbfzVQvLDx4FfzRCPKQv +0ZfK8nEQ+GyMy5TjwOXpWXg1HZE+1wr/GFSew+ob9QKBgQD8h6qJ5Np2TeGylUAB +8ximt5gvUbHKRl2P+9oUpbkRmlHNBaG87WNQeHwwNyYI1dpFiCaYYCbi1Q4bPMMu +LD7L4Jn/qLr7zcLF+cO/NH1S7VGrhnktIQBzMr03uExHYSLa+kAgPNGlTXiUxzU7 +zxKprRiIpfUzEd72BGbg79KqxwKBgQDJh77rRTrCS9G+JlA9L4VQFtNYzq7mLlZA +n7FGruorWnv2Qog0aMpmzBP+r17Su3Q2UNG8R87+x1wvXA7ncMMc1eVQWM088sZm +xo/V2SGLw3f3jAzqOvQ+30SIAB2poHTKYnrw9q4i2on225Qv7ud5Yn+B/M0DK+nh +y1Xy4EjnywKBgBER4pc7nwDMNutpZ1A6bHooguL/9LKlmwF2lsE6io4EDm97Z/lr +WoFAA7UGpU2Hlx+IGoPGTBqdKDzzGIZwezYw0ngTocAPopDbVz3/gFEwtYqQpnRE +fNFMprmzfYR9rmt66wbC1bEE0ZfM9245ixtpFfV2smJnXNjoZ0PhMi5VAoGBAMen +i1aMNIVPFhEa5f1n+dv5cRKXWKDEIUFOtBNBsM6YixzSlxvNAVBMODbmSLvfaGdz +NAYi4gh5O3PT8RQLG9GSeudZwqLyJeqmJtOGlHxhf5WokxbupxEuojdWXgyx4WKr +o/7bdHMlLO96ZFoEhiA0m/wMlpLgy4mdp53B45h3AoGBAM/G73sDvflOuJXy9rng +YyBp5PFPbnNB5GlC8vhbbyW2Xqvq7vfaOiZC/56IyahqjiRxiiukPoeV+CRx6NCo +vZ92HL7zoWx2KXMKxC+iZrxRN8Q9gG9H9MvvHAhPTIkEFcC0Q8Urw//rJW8tWraj +8vP7Zcmb/yoXj0CO2SD8hpA6 +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/tests/e2e/server_test.go b/tests/e2e/server_test.go index fdd91af2..1a05ff75 100644 --- a/tests/e2e/server_test.go +++ b/tests/e2e/server_test.go @@ -3,6 +3,8 @@ package e2e import ( "testing" + "github.com/harness/ff-proxy/tests/e2e/testhelpers" + harness "github.com/harness/ff-golang-server-sdk/client" "github.com/harness/ff-golang-server-sdk/evaluation" "github.com/stretchr/testify/assert" @@ -46,6 +48,7 @@ func TestServerSDK(t *testing.T) { harness.WithEventsURL(GetStreamURL()), harness.WithStreamEnabled(false), harness.WithTarget(tt.args.Target), + harness.WithHTTPClient(testhelpers.GetCertClient()), ) if err != nil { t.Fatalf("Couldn't create sdk err %s", err) diff --git a/tests/e2e/stream_test.go b/tests/e2e/stream_test.go index 1b57ce41..f60ec890 100644 --- a/tests/e2e/stream_test.go +++ b/tests/e2e/stream_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/harness/ff-proxy/tests/e2e/testhelpers" + "github.com/harness/ff-proxy/gen/admin" harness "github.com/harness/ff-golang-server-sdk/client" @@ -80,9 +82,13 @@ func TestEvent(t *testing.T) { eventChan := make(chan stream.Message, 10) eventListener := EventListener{eventChan} + // if running locally with https enabled using the self-signed certs in /certs folder you need to add the cert + // to your trusted list like we do in the e2e test pipeline - this is because + // the go sdk sse client creates it's own http client which doesn't use the trusted certs we load in GetCertClient client, err := harness.NewCfClient(tt.args.Key, harness.WithURL(GetStreamURL()), harness.WithEventStreamListener(eventListener), + harness.WithHTTPClient(testhelpers.GetCertClient()), ) if err != nil { t.Error("Couldn't create sdk") @@ -172,6 +178,7 @@ func AddAuthToken(ctx context.Context, req *http.Request) error { // DefaultClient returns the default admin client func DefaultClient() *admin.Client { client, err := admin.NewClient(GetRemoteURL()) + client.Client = testhelpers.GetCertClient() if err != nil { return nil diff --git a/tests/e2e/testhelpers/client.go b/tests/e2e/testhelpers/client.go index debcbe59..d1e69fa1 100644 --- a/tests/e2e/testhelpers/client.go +++ b/tests/e2e/testhelpers/client.go @@ -2,8 +2,13 @@ package testhelpers import ( "context" + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" + "io/ioutil" + "net/http" + "strings" log "github.com/sirupsen/logrus" @@ -12,6 +17,10 @@ import ( "github.com/harness/ff-proxy/gen/client" ) +const ( + localCertFile = "./certs/cert.crt" +) + // AuthenticateSDKClient performs an auth request and returns the token and environment to use func AuthenticateSDKClient(key string, url string, target *client.Target) (token string, claims domain.Claims, err error) { serverToken, err := Authenticate(key, url, target) @@ -40,12 +49,49 @@ func Authenticate(apiKey string, url string, target *client.Target) (*client.Aut func DefaultEvaluationClient(url string) *client.Client { log.Infof("Connecting client to %s", url) c, err := client.NewClient(url) + // if we're connecting in https mode we should trust the self-signed certs used by the tests + if strings.Contains(url, "https") { + c.Client = GetCertClient() + } if err != nil { return nil } return c } +// GetCertClient returns a custom http client which defines a certificate authority and trusts our certs from the /cert folder +// this avoids any errors when run locally and doesn't require the certs to be manually trusted on your machine +func GetCertClient() *http.Client { + // Get the SystemCertPool, continue with an empty pool on error + rootCAs, _ := x509.SystemCertPool() + if rootCAs == nil { + rootCAs = x509.NewCertPool() + } + + // Read in the cert file + certs, err := ioutil.ReadFile(localCertFile) + if err != nil { + log.Fatalf("Failed to append %q to RootCAs: %v", localCertFile, err) + } + + // Append our cert to the system pool + if ok := rootCAs.AppendCertsFromPEM(certs); !ok { + log.Println("No certs appended, using system certs only") + } + + // Trust the augmented cert pool in our client + config := &tls.Config{ + RootCAs: rootCAs, + MinVersion: tls.VersionTLS12, + } + + tr := &http.Transport{TLSClientConfig: config} + + client := &http.Client{Transport: tr} + + return client +} + // DecodeClaims ... func DecodeClaims(tokenString string) (domain.Claims, error) { claims := domain.Claims{} diff --git a/tests/e2e/testhelpers/setup/main.go b/tests/e2e/testhelpers/setup/main.go index 2443a2e0..83a1932e 100644 --- a/tests/e2e/testhelpers/setup/main.go +++ b/tests/e2e/testhelpers/setup/main.go @@ -35,7 +35,10 @@ USER_ACCESS_TOKEN=%s` var onlineProxyInMemTemplate = `ACCOUNT_IDENTIFIER=%s ORG_IDENTIFIER=%s ADMIN_SERVICE_TOKEN=%s -API_KEYS=%s` +API_KEYS=%s +TLS_ENABLED=true +TLS_CERT=certs/cert.crt +TLS_KEY=certs/cert.key` var onlineProxyRedisTemplate = `ACCOUNT_IDENTIFIER=%s ORG_IDENTIFIER=%s