Skip to content

Commit 72d7909

Browse files
(FFM-5129) HTTPS support (#117)
* (FFM-5129) Https support * (FFM-5129) docker-compose https mode * (FFM-5129) Update routes file for https
1 parent 8f27587 commit 72d7909

File tree

7 files changed

+102
-19
lines changed

7 files changed

+102
-19
lines changed

cmd/ff-proxy/main.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ var (
111111
generateOfflineConfig bool
112112
configDir string
113113
port int
114+
tlsEnabled bool
115+
tlsCert string
116+
tlsKey string
114117
)
115118

116119
const (
@@ -139,6 +142,9 @@ const (
139142
configDirEnv = "CONFIG_DIR"
140143
pprofEnabledEnv = "PPROF"
141144
portEnv = "PORT"
145+
tlsEnabledEnv = "TLS_ENABLED"
146+
tlsCertEnv = "TLS_CERT"
147+
tlsKeyEnv = "TLS_KEY"
142148

143149
bypassAuthFlag = "bypass-auth"
144150
debugFlag = "debug"
@@ -165,6 +171,9 @@ const (
165171
configDirFlag = "config-dir"
166172
flagPollIntervalFlag = "flag-poll-interval"
167173
portFlag = "port"
174+
tlsEnabledFlag = "tls-enabled"
175+
tlsCertFlag = "tls-cert"
176+
tlsKeyFlag = "tls-key"
168177
)
169178

170179
func init() {
@@ -194,6 +203,10 @@ func init() {
194203
flag.BoolVar(&generateOfflineConfig, generateOfflineConfigFlag, false, "if true the proxy will produce offline config in the /config directory then terminate")
195204
flag.StringVar(&configDir, configDirFlag, "/config", "specify a custom path to search for the offline config directory. Defaults to /config")
196205
flag.IntVar(&port, portFlag, 8000, "port the relay proxy service is exposed on, default's to 8000")
206+
flag.BoolVar(&tlsEnabled, tlsEnabledFlag, false, "if true the proxy will use the tlsCert and tlsKey to run with https enabled")
207+
flag.StringVar(&tlsCert, tlsCertFlag, "", "Path to tls cert file. Required if tls enabled is true.")
208+
flag.StringVar(&tlsKey, tlsKeyFlag, "", "Path to tls key file. Required if tls enabled is true.")
209+
197210
sdkClients = newSDKClientMap()
198211

199212
loadFlagsFromEnv(map[string]string{
@@ -222,6 +235,9 @@ func init() {
222235
configDirEnv: configDirFlag,
223236
flagPollIntervalEnv: flagPollIntervalFlag,
224237
portEnv: portFlag,
238+
tlsEnabledEnv: tlsEnabledFlag,
239+
tlsCertEnv: tlsCertFlag,
240+
tlsKeyEnv: tlsKeyFlag,
225241
})
226242

227243
flag.Parse()
@@ -305,7 +321,7 @@ func main() {
305321
cancel()
306322
}()
307323

308-
logger.Info("service config", "pprof", pprofEnabled, "debug", debug, "bypass-auth", bypassAuth, "offline", offline, "port", port, "admin-service", adminService, "account-identifier", accountIdentifier, "org-identifier", orgIdentifier, "sdk-base-url", sdkBaseURL, "sdk-events-url", sdkEventsURL, "redis-addr", redisAddress, "redis-db", redisDB, "api-keys", fmt.Sprintf("%v", apiKeys), "target-poll-duration", fmt.Sprintf("%ds", targetPollDuration), "heartbeat-interval", fmt.Sprintf("%ds", heartbeatInterval), "flag-stream-enabled", flagStreamEnabled, "flag-poll-interval", fmt.Sprintf("%ds", flagPollInterval), "config-dir", configDir)
324+
logger.Info("service config", "pprof", pprofEnabled, "debug", debug, "bypass-auth", bypassAuth, "offline", offline, "port", port, "admin-service", adminService, "account-identifier", accountIdentifier, "org-identifier", orgIdentifier, "sdk-base-url", sdkBaseURL, "sdk-events-url", sdkEventsURL, "redis-addr", redisAddress, "redis-db", redisDB, "api-keys", fmt.Sprintf("%v", apiKeys), "target-poll-duration", fmt.Sprintf("%ds", targetPollDuration), "heartbeat-interval", fmt.Sprintf("%ds", heartbeatInterval), "flag-stream-enabled", flagStreamEnabled, "flag-poll-interval", fmt.Sprintf("%dm", flagPollInterval), "config-dir", configDir, "tls-enabled", tlsEnabled, "tls-cert", tlsCert, "tls-key", tlsKey)
309325

310326
adminService, err := services.NewAdminService(logger, adminService, adminServiceToken)
311327
if err != nil {
@@ -505,7 +521,7 @@ func main() {
505521

506522
// Configure endpoints and server
507523
endpoints := transport.NewEndpoints(service)
508-
server := transport.NewHTTPServer(port, endpoints, logger)
524+
server := transport.NewHTTPServer(port, endpoints, logger, tlsEnabled, tlsCert, tlsKey)
509525
server.Use(
510526
middleware.NewEchoRequestIDMiddleware(),
511527
middleware.NewEchoLoggingMiddleware(),
@@ -572,7 +588,12 @@ func main() {
572588
go func() {
573589
ticker := time.NewTicker(time.Duration(heartbeatInterval) * time.Second)
574590
logger.Info(fmt.Sprintf("polling heartbeat every %d seconds", heartbeatInterval))
575-
heartbeat(ctx, ticker.C, fmt.Sprintf("http://localhost:%d", port), logger)
591+
protocol := "http"
592+
if tlsEnabled {
593+
protocol = "https"
594+
}
595+
596+
heartbeat(ctx, ticker.C, fmt.Sprintf("%s://localhost:%d", protocol, port), logger)
576597
}()
577598

578599
if err := server.Serve(); err != nil {
@@ -597,7 +618,11 @@ func heartbeat(ctx context.Context, tick <-chan time.Time, listenAddr string, lo
597618
case <-tick:
598619
resp, err := http.Get(fmt.Sprintf("%s/health", listenAddr))
599620
if err != nil {
600-
logger.Error(fmt.Sprintf("heartbeat request failed: %d", resp.StatusCode))
621+
logger.Error(fmt.Sprintf("heartbeat request failed: %s", err))
622+
}
623+
624+
if resp == nil {
625+
continue
601626
}
602627

603628
if resp.StatusCode == http.StatusOK {

docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ services:
2121
- TARGET_POLL_DURATION=${TARGET_POLL_DURATION}
2222
- GENERATE_OFFLINE_CONFIG=${GENERATE_OFFLINE_CONFIG}
2323
- PORT=${PORT}
24+
- TLS_ENABLED=${TLS_ENABLED}
25+
- TLS_CERT=${TLS_CERT}
26+
- TLS_KEY=${TLS_KEY}
2427
build:
2528
context: ./
2629
dockerfile: ./Dockerfile

docker-entrypoint.sh

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,48 @@ fi
3232

3333
# Update pushpin.conf file to use $PORT for http_port
3434
if [ -w /etc/pushpin/pushpin.conf ]; then
35+
PROTOCOL="http_port"
36+
PUSHPIN_PORT=7000
3537
if [ -n "${PORT}" ]; then
36-
echo "Listening for requests on port ${PORT}"
37-
sed -i \
38-
-e "s/http_port=7000/http_port=${PORT}/" \
39-
/etc/pushpin/pushpin.conf
40-
export PORT=
38+
PUSHPIN_PORT=${PORT}
39+
fi
40+
41+
if [ "${TLS_ENABLED}" = true ] ; then
42+
echo "https configured"
43+
PROTOCOL="https_ports"
44+
45+
# write ca cert to pushpin certs directory if exists
46+
if [ -n "${TLS_CERT}" ]; then
47+
echo "copying tls cert from ${TLS_CERT} to etc/pushpin/runner/certs/default_${PUSHPIN_PORT}.crt"
48+
cp ${TLS_CERT} etc/pushpin/runner/certs/default_${PUSHPIN_PORT}.crt
49+
fi
50+
51+
# write ca key to pushpin certs directory if exists
52+
if [ -n "${TLS_KEY}" ]; then
53+
echo "copying tls key from ${TLS_CERT} to etc/pushpin/runner/certs/default_${PUSHPIN_PORT}.key"
54+
cp ${TLS_KEY} etc/pushpin/runner/certs/default_${PUSHPIN_PORT}.key
55+
fi
4156
fi
57+
58+
# set port and protocol for pushpin to listen on e.g. listen for https connections on port 6000
59+
echo "Listening for requests on port ${PUSHPIN_PORT}"
60+
sed -i \
61+
-e "s/http_port=7000/${PROTOCOL}=${PUSHPIN_PORT}/" \
62+
/etc/pushpin/pushpin.conf
63+
export PORT=
4264
else
4365
echo "docker-entrypoint.sh: unable to write to /etc/pushpin/pushpin.conf, readonly"
4466
fi
4567

46-
exec "$@"
68+
# Update routes file to forward traffic using ssl if tls_enabled is true
69+
if [ -w /etc/pushpin/routes ]; then
70+
if [ "${TLS_ENABLED}" = true ] ; then
71+
sed -i \
72+
-e "s/localhost:8000/localhost:8000,ssl,insecure/" \
73+
/etc/pushpin/routes
74+
fi
75+
else
76+
echo "docker-entrypoint.sh: unable to write to /etc/pushpin/routes, readonly"
77+
fi
78+
79+
exec "$@"

docs/configuration.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ Adjust how often certain actions are performed.
8080
| METRIC_POST_DURATION | metric-post-duration | How often in seconds the proxy posts metrics to Harness. Set to 0 to disable. | int | 60 |
8181
| HEARTBEAT_INTERVAL | heartbeat-interval | How often in seconds the proxy polls pings it's health function | int | 60 |
8282

83+
### TLS (beta)
84+
| Environment Variable | Flag | Description | Type | Default |
85+
|----------------------|-------------|-----------------------------------------------------------------------------|--------|---------|
86+
| TLS_ENABLED | tls-enabled | If true the proxy will use the tlsCert and tlsKey to run with https enabled | bool | false |
87+
| TLS_CERT | tls-cert | Path to tls cert file. Required if tls enabled is true. | string | |
88+
| TLS_KEY | tls-key | Path to tls key file. Required if tls enabled is true. | string | |
89+
8390
### Harness URLs
8491
You may need to adjust these if you pass all your traffic through a filter or proxy rather than sending the requests directly.
8592

docs/tls.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# Enabling TLS
2+
There are two ways to configure the Relay Proxy to accept HTTPS requests.
23

3-
The Relay Proxy does not currently natively support running with TLS enabled (coming soon).
4+
### Native TLS (Beta)
5+
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.
46

7+
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.
8+
9+
### External TLS
510
The recommended way to connect to the Relay Proxy using TLS is to place a reverse proxy such as nginx in front of the Relay Proxy. Then all connected sdks should make requests to the reverse proxy url instead of hitting the Relay Proxy directly.
611

712
![TLS Setup](images/TLS.png?raw=true)

transport/http_server.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ import (
1212

1313
// HTTPServer is an http server that handles http requests
1414
type HTTPServer struct {
15-
router *echo.Echo
16-
server *http.Server
17-
log log.Logger
15+
router *echo.Echo
16+
server *http.Server
17+
log log.Logger
18+
tlsEnabled bool
19+
tlsCert string
20+
tlsKey string
1821
}
1922

2023
// NewHTTPServer registers the passed endpoints against routes and returns an
2124
// HTTPServer that's ready to use
22-
func NewHTTPServer(port int, e *Endpoints, l log.Logger) *HTTPServer {
25+
func NewHTTPServer(port int, e *Endpoints, l log.Logger, tlsEnabled bool, tlsCert string, tlsKey string) *HTTPServer {
2326
l = l.With("component", "HTTPServer")
2427

2528
router := echo.New()
@@ -33,9 +36,12 @@ func NewHTTPServer(port int, e *Endpoints, l log.Logger) *HTTPServer {
3336
}
3437

3538
h := &HTTPServer{
36-
router: router,
37-
server: server,
38-
log: l,
39+
router: router,
40+
server: server,
41+
log: l,
42+
tlsEnabled: tlsEnabled,
43+
tlsCert: tlsCert,
44+
tlsKey: tlsKey,
3945
}
4046
h.registerEndpoints(e)
4147
return h
@@ -48,6 +54,10 @@ func (h *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
4854

4955
// Serve listens on the HTTPServers addr and handles requests
5056
func (h *HTTPServer) Serve() error {
57+
if h.tlsEnabled {
58+
h.log.Info("starting https server", "addr", h.server.Addr, "tlsCert", h.tlsCert, "tlsKey", h.tlsKey)
59+
return h.server.ListenAndServeTLS(h.tlsCert, h.tlsKey)
60+
}
5161
h.log.Info("starting http server", "addr", h.server.Addr)
5262
return h.server.ListenAndServe()
5363
}

transport/http_server_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ func setupHTTPServer(t *testing.T, bypassAuth bool, opts ...setupOpts) *HTTPServ
244244
})
245245
endpoints := NewEndpoints(service)
246246

247-
server := NewHTTPServer(8000, endpoints, logger)
247+
server := NewHTTPServer(8000, endpoints, logger, false, "", "")
248248
server.Use(middleware.NewEchoAuthMiddleware([]byte(`secret`), bypassAuth))
249249
return server
250250
}

0 commit comments

Comments
 (0)