diff --git a/agent/config.go b/agent/config.go
index 504a860293..3bbc4b632f 100644
--- a/agent/config.go
+++ b/agent/config.go
@@ -129,6 +129,12 @@ type DNSConfig struct {
RecursorTimeoutRaw string `mapstructure:"recursor_timeout" json:"-"`
}
+// HTTPConfig is used to fine tune the Http sub-system.
+type HTTPConfig struct {
+ // ResponseHeaders are used to add HTTP header response fields to the HTTP API responses.
+ ResponseHeaders map[string]string `mapstructure:"response_headers"`
+}
+
// RetryJoinEC2 is used to configure discovery of instances via Amazon's EC2 api
type RetryJoinEC2 struct {
// The AWS region to look for instances in
@@ -365,6 +371,9 @@ type Config struct {
// Domain is the DNS domain for the records. Defaults to "consul."
Domain string `mapstructure:"domain"`
+ // HTTP configuration
+ HTTPConfig HTTPConfig `mapstructure:"http_config"`
+
// Encryption key to use for the Serf communication
EncryptKey string `mapstructure:"encrypt" json:"-"`
@@ -706,9 +715,6 @@ type Config struct {
// send with the update check. This is used to deduplicate messages.
DisableAnonymousSignature bool `mapstructure:"disable_anonymous_signature"`
- // HTTPAPIResponseHeaders are used to add HTTP header response fields to the HTTP API responses.
- HTTPAPIResponseHeaders map[string]string `mapstructure:"http_api_response_headers"`
-
// AEInterval controls the anti-entropy interval. This is how often
// the agent attempts to reconcile its local state with the server's
// representation of our state. Defaults to every 60s.
@@ -759,11 +765,12 @@ type Config struct {
// deprecated fields
// keep them exported since otherwise the error messages don't show up
- DeprecatedAtlasInfrastructure string `mapstructure:"atlas_infrastructure" json:"-"`
- DeprecatedAtlasToken string `mapstructure:"atlas_token" json:"-"`
- DeprecatedAtlasACLToken string `mapstructure:"atlas_acl_token" json:"-"`
- DeprecatedAtlasJoin bool `mapstructure:"atlas_join" json:"-"`
- DeprecatedAtlasEndpoint string `mapstructure:"atlas_endpoint" json:"-"`
+ DeprecatedAtlasInfrastructure string `mapstructure:"atlas_infrastructure" json:"-"`
+ DeprecatedAtlasToken string `mapstructure:"atlas_token" json:"-"`
+ DeprecatedAtlasACLToken string `mapstructure:"atlas_acl_token" json:"-"`
+ DeprecatedAtlasJoin bool `mapstructure:"atlas_join" json:"-"`
+ DeprecatedAtlasEndpoint string `mapstructure:"atlas_endpoint" json:"-"`
+ DeprecatedHTTPAPIResponseHeaders map[string]string `mapstructure:"http_api_response_headers"`
}
// IncomingHTTPSConfig returns the TLS configuration for HTTPS
@@ -1368,6 +1375,19 @@ func DecodeConfig(r io.Reader) (*Config, error) {
result.TLSCipherSuites = ciphers
}
+ // This is for backwards compatibility.
+ // HTTPAPIResponseHeaders has been replaced with HTTPConfig.ResponseHeaders
+ if len(result.DeprecatedHTTPAPIResponseHeaders) > 0 {
+ fmt.Fprintln(os.Stderr, "==> DEPRECATION: http_api_response_headers is deprecated and "+
+ "is no longer used. Please use http_config.response_headers instead.")
+ if result.HTTPConfig.ResponseHeaders == nil {
+ result.HTTPConfig.ResponseHeaders = make(map[string]string)
+ }
+ for field, value := range result.DeprecatedHTTPAPIResponseHeaders {
+ result.HTTPConfig.ResponseHeaders[field] = value
+ }
+ result.DeprecatedHTTPAPIResponseHeaders = nil
+ }
return &result, nil
}
@@ -1974,12 +1994,12 @@ func MergeConfig(a, b *Config) *Config {
result.SessionTTLMin = b.SessionTTLMin
result.SessionTTLMinRaw = b.SessionTTLMinRaw
}
- if len(b.HTTPAPIResponseHeaders) != 0 {
- if result.HTTPAPIResponseHeaders == nil {
- result.HTTPAPIResponseHeaders = make(map[string]string)
+ if len(b.HTTPConfig.ResponseHeaders) > 0 {
+ if result.HTTPConfig.ResponseHeaders == nil {
+ result.HTTPConfig.ResponseHeaders = make(map[string]string)
}
- for field, value := range b.HTTPAPIResponseHeaders {
- result.HTTPAPIResponseHeaders[field] = value
+ for field, value := range b.HTTPConfig.ResponseHeaders {
+ result.HTTPConfig.ResponseHeaders[field] = value
}
}
if len(b.Meta) != 0 {
diff --git a/agent/config_test.go b/agent/config_test.go
index 67f2d0387b..a573d63987 100644
--- a/agent/config_test.go
+++ b/agent/config_test.go
@@ -332,7 +332,11 @@ func TestDecodeConfig(t *testing.T) {
},
{
in: `{"http_api_response_headers":{"a":"b","c":"d"}}`,
- c: &Config{HTTPAPIResponseHeaders: map[string]string{"a": "b", "c": "d"}},
+ c: &Config{HTTPConfig: HTTPConfig{ResponseHeaders: map[string]string{"a": "b", "c": "d"}}},
+ },
+ {
+ in: `{"http_config":{"response_headers":{"a":"b","c":"d"}}}`,
+ c: &Config{HTTPConfig: HTTPConfig{ResponseHeaders: map[string]string{"a": "b", "c": "d"}}},
},
{
in: `{"key_file":"a"}`,
@@ -1389,8 +1393,10 @@ func TestMergeConfig(t *testing.T) {
},
DisableUpdateCheck: true,
DisableAnonymousSignature: true,
- HTTPAPIResponseHeaders: map[string]string{
- "Access-Control-Allow-Origin": "*",
+ HTTPConfig: HTTPConfig{
+ ResponseHeaders: map[string]string{
+ "Access-Control-Allow-Origin": "*",
+ },
},
UnixSockets: UnixSocketConfig{
UnixSocketPermissions{
diff --git a/agent/http.go b/agent/http.go
index d622958c9c..5a041dafcd 100644
--- a/agent/http.go
+++ b/agent/http.go
@@ -162,7 +162,7 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler {
// wrap is used to wrap functions to make them more convenient
func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Request) (interface{}, error)) http.HandlerFunc {
return func(resp http.ResponseWriter, req *http.Request) {
- setHeaders(resp, s.agent.config.HTTPAPIResponseHeaders)
+ setHeaders(resp, s.agent.config.HTTPConfig.ResponseHeaders)
setTranslateAddr(resp, s.agent.config.TranslateWanAddrs)
// Obfuscate any tokens from appearing in the logs
diff --git a/agent/http_test.go b/agent/http_test.go
index 3c02d75a58..01970a348a 100644
--- a/agent/http_test.go
+++ b/agent/http_test.go
@@ -241,7 +241,7 @@ func TestHTTPAPI_TranslateAddrHeader(t *testing.T) {
func TestHTTPAPIResponseHeaders(t *testing.T) {
t.Parallel()
cfg := TestConfig()
- cfg.HTTPAPIResponseHeaders = map[string]string{
+ cfg.HTTPConfig.ResponseHeaders = map[string]string{
"Access-Control-Allow-Origin": "*",
"X-XSS-Protection": "1; mode=block",
}
diff --git a/website/source/docs/agent/options.html.md b/website/source/docs/agent/options.html.md
index 4bb839304a..2122b31fda 100644
--- a/website/source/docs/agent/options.html.md
+++ b/website/source/docs/agent/options.html.md
@@ -199,7 +199,7 @@ will exit with an error at startup.
- Shared credentials file (`~/.aws/credentials` or the path specified by `AWS_SHARED_CREDENTIALS_FILE`)
- ECS task role metadata (container-specific).
- EC2 instance role metadata.
-
+
The only required IAM permission is `ec2:DescribeInstances`, and it is recommended you make a dedicated
key used only for auto-joining.
@@ -437,7 +437,7 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
"allow" or "deny"; defaults to "allow". The default policy controls the behavior of a token when
there is no matching rule. In "allow" mode, ACLs are a blacklist: any operation not specifically
prohibited is allowed. In "deny" mode, ACLs are a whitelist: any operation not
- specifically allowed is blocked. *Note*: this will not take effect until you've set `acl_datacenter`
+ specifically allowed is blocked. *Note*: this will not take effect until you've set `acl_datacenter`
to enable ACL support.
* `acl_down_policy` - Either
@@ -745,6 +745,30 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
}
```
+ This has been deprecated in Consul 0.9.0. Setting this value will set `http_config.response_headers`
+ instead for backwards compatibility.
+
+* `http_config`
+ This object allows setting options for the HTTP API.
+
+ The following sub-keys are available:
+
+ * `response_headers`
+ This object allows adding headers to the HTTP API responses.
+ For example, the following config can be used to enable
+ [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) on
+ the HTTP API endpoints:
+
+ ```javascript
+ {
+ "http_config": {
+ "response_headers": {
+ "Access-Control-Allow-Origin": "*"
+ }
+ }
+ }
+ ```
+
* `leave_on_terminate` If
enabled, when the agent receives a TERM signal, it will send a `Leave` message to the rest
of the cluster and gracefully leave. The default behavior for this feature varies based on