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

Expose /env and /config for Configuration reporting #6652

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ type CertificatesConfig struct {

type SecurityConfig struct {
// Set the AES256 secret which is used to encode certificate private keys when they uploaded via certificate storage
PrivateCertificateEncodingSecret string `json:"private_certificate_encoding_secret"`
PrivateCertificateEncodingSecret string `json:"private_certificate_encoding_secret" structviewer:"obfuscate"`

// Enable Gateway Control API to use Mutual TLS. Certificates can be set via `security.certificates.control_api` section
ControlAPIUseMutualTLS bool `json:"control_api_use_mutual_tls"`
Expand All @@ -587,6 +587,28 @@ type SecurityConfig struct {
Certificates CertificatesConfig `json:"certificates"`
}

type ConfigurationReflectionCfg struct {

// Enable controls the availability of HTTP endpoints for monitoring and debugging Tyk Gateway.
// These endpoints provide critical system information and are disabled by default for security reasons.
// Access to these endpoints requires a secret, defined in the `security.secret` configuration field.
// Available endpoints include:
// * /config - a read-only HTTP endpoint that returns the current config keys and values in JSON notation.
// * /env - a read-only HTTP endpoint that returns the current config keys and values in an environment variable
// format
Enable bool `json:"enable"`

// Ensure the Gateway configuration port is set
// The Configuration API runs on a separate port, so you can secure this port behind a firewall.
APIPort int `json:"api_port"`

// This should be changed as soon as Tyk is installed on your system.
// This value is used in when using Tyk Gateway Config APIs. It should be passed along as the X-Tyk-Authorization
// header in any requests made. Tyk assumes that you are sensible enough not to expose the management endpoints
// publicly and to keep this configuration value to yourself.
APIKey string `json:"api_key" structviewer:"obfuscate"`
}

type NewRelicConfig struct {
// New Relic Application name
AppName string `json:"app_name"`
Expand Down Expand Up @@ -680,13 +702,15 @@ type Config struct {
// Set to run your Gateway Control API on a separate port, and protect it behind a firewall if needed. Please make sure you follow this guide when setting the control port https://tyk.io/docs/planning-for-production/#change-your-control-port.
ControlAPIPort int `json:"control_api_port"`

ConfigurationReflection ConfigurationReflectionCfg `json:"configuration_reflection"`

// This should be changed as soon as Tyk is installed on your system.
// This value is used in every interaction with the Tyk Gateway API. It should be passed along as the X-Tyk-Authorization header in any requests made.
// Tyk assumes that you are sensible enough not to expose the management endpoints publicly and to keep this configuration value to yourself.
Secret string `json:"secret"`
Secret string `json:"secret" structviewer:"obfuscate"`

// The shared secret between the Gateway and the Dashboard to ensure that API Definition downloads, heartbeat and Policy loads are from a valid source.
NodeSecret string `json:"node_secret"`
NodeSecret string `json:"node_secret" structviewer:"obfuscate"`

// Linux PID file location. Do not change unless you know what you are doing. Default: /var/run/tyk/tyk-gateway.pid
PIDFileLocation string `json:"pid_file_location"`
Expand Down Expand Up @@ -1084,7 +1108,7 @@ type Config struct {
} `json:"kv"`

// Secrets are key-value pairs that can be accessed in the dashboard via "secrets://"
Secrets map[string]string `json:"secrets"`
Secrets map[string]string `json:"secrets" structviewer:"obfuscate"`

// Override the default error code and or message returned by middleware.
// The following message IDs can be used to override the message and error codes:
Expand Down
71 changes: 71 additions & 0 deletions gateway/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/TykTechnologies/structviewer"
htmltemplate "html/template"
"io/ioutil"
stdlog "log"
Expand Down Expand Up @@ -639,6 +640,7 @@ func (gw *Gateway) loadControlAPIEndpoints(muxer *mux.Router) {
muxer.HandleFunc("/debug/pprof/profile", pprofhttp.Profile)
muxer.HandleFunc("/debug/pprof/{_:.*}", pprofhttp.Index)
}
gw.loadConfigurationAPI(muxer)

r.MethodNotAllowedHandler = MethodNotAllowedHandler{}

Expand Down Expand Up @@ -1940,6 +1942,7 @@ func (gw *Gateway) startServer() {
muxer := &proxyMux{}

router := mux.NewRouter()

gw.loadControlAPIEndpoints(router)

muxer.setRouter(gw.GetConfig().ControlAPIPort, "", router, gw.GetConfig())
Expand Down Expand Up @@ -1977,3 +1980,71 @@ func (gw *Gateway) SetConfig(conf config.Config, skipReload ...bool) {
gw.config.Store(conf)
gw.configMu.Unlock()
}

func (gw *Gateway) loadConfigurationAPI(muxer *mux.Router) error {

config := gw.GetConfig()

// Check if enabled
if config.ConfigurationReflection.Enable != true {
mainLog.Info("configuration reflection API is disabled in the configuration. Please enable it if you need to use it")
return nil
}
mainLog.Debug("configuration reflection API is enabled")

if config.ControlAPIPort == 0 {
return fmt.Errorf("configuration reflection API requires a dedicated control port. Please set `control_api_port` in order to use it")
}
/*
port := config.ControlAPIPort
if port == 0 {
port = config.ConfigurationReflection.APIPort
}
// Check the port
if port == 0 {
return fmt.Errorf("configuration reflection API requires a separate port. Please set it in order to use it")
}
mainLog.Info("configuration reflection API Port is set to %d", port)
*/

// Check the API key
if config.ConfigurationReflection.APIKey == "" {
return fmt.Errorf("configuration reflection API port is not set. Please set it in order to use it")
}

var structviewerCfg = &structviewer.Config{
Object: config,
ParseComments: false,
}
const GW_ENV_PREFIX = "TYK_GW_"
v, err := structviewer.New(structviewerCfg, GW_ENV_PREFIX)
if err != nil {
return err
}

// TODO: Update swagger.yaml of the gateway
// Define routes and middleware specific to the Config API
muxer.Handle("/config", authConfigurationAPI(http.HandlerFunc(v.ConfigHandler), config.ConfigurationReflection.APIKey))
muxer.Handle("/env", authConfigurationAPI(http.HandlerFunc(v.EnvsHandler), config.ConfigurationReflection.APIKey))

mainLog.Info("--> Configuration reflection API is available on control port")

return nil
}

// authConfigurationAPI will ensure that the accessor of the HTTP API has the
// correct security credentials - this is a shared secret between the
// client and the owner and is set in the settings. This should
// never be made public!
func authConfigurationAPI(next http.Handler, apiKey string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tykAuthKey := r.Header.Get(header.XTykAuthorization)
if tykAuthKey != apiKey {
errMsg := "Attempted administrative access to cnfiguration reflection with invalid or missing key!"
mainLog.Error(errMsg)
doJSONWrite(w, http.StatusUnauthorized, apiError(errMsg))
return
}
next.ServeHTTP(w, r)
})
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ require (
github.com/TykTechnologies/graphql-go-tools/v2 v2.0.0-20240509085643-e95cdc317e1d
github.com/TykTechnologies/kin-openapi v0.90.0
github.com/TykTechnologies/opentelemetry v0.0.21
github.com/TykTechnologies/structviewer v1.1.1
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/go-redis/redismock/v9 v9.2.0
github.com/goccy/go-json v0.10.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ github.com/TykTechnologies/opentelemetry v0.0.21 h1:/ew4NET0nbLKmsNKmuEavTU+Zp3L
github.com/TykTechnologies/opentelemetry v0.0.21/go.mod h1:5LkNDN08FYVhSTH0gC3hwk6cH6jP3F8cc5mv2asUHyA=
github.com/TykTechnologies/storage v1.2.2 h1:NfBIpnMu9cPMrLxFrKIVzQHtTsvXte7/VdmFC0QrSfw=
github.com/TykTechnologies/storage v1.2.2/go.mod h1:x4/SA+yiTmYkOyhQy18eNLgGJR4G6/kxX6qXBpzFmtw=
github.com/TykTechnologies/structviewer v1.1.1 h1:9/++875RSRc/8rmUgAbrVuQIziVsM1sm2/MsDiG7g8A=
github.com/TykTechnologies/structviewer v1.1.1/go.mod h1:jrG78SYN2mxqbjDwSk6z5KIEwMWaZLiRV0yaxt5p2dg=
github.com/TykTechnologies/tyk-pump v1.10.0 h1:mc2sRUlY6pPN8cdOUzswi8Ukjgtoxo5YMSh1XUTinwQ=
github.com/TykTechnologies/tyk-pump v1.10.0/go.mod h1:dN4jBt2NlveiWalfTBgmyhkdRFL5kbCA02BwBBvAl2g=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
Expand Down