agent: return the default ACL policy to callers as a header (#9101)
Header is: X-Consul-Default-ACL-Policy=<allow|deny> This is of particular utility when fetching matching intentions, as the fallthrough for a request that doesn't match any intentions is to enforce using the default acl policy.
This commit is contained in:
parent
990134371b
commit
a5bd1ba323
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
agent: return the default ACL policy to callers as a header
|
||||
```
|
|
@ -77,8 +77,8 @@ type RuntimeConfig struct {
|
|||
|
||||
// ACLDefaultPolicy is used to control the ACL interaction when
|
||||
// there is no defined policy. This can be "allow" which means
|
||||
// ACLs are used to black-list, or "deny" which means ACLs are
|
||||
// white-lists.
|
||||
// ACLs are used to deny-list, or "deny" which means ACLs are
|
||||
// allow-lists.
|
||||
//
|
||||
// hcl: acl.default_policy = ("allow"|"deny")
|
||||
ACLDefaultPolicy string
|
||||
|
|
|
@ -268,8 +268,8 @@ type Config struct {
|
|||
|
||||
// ACLDefaultPolicy is used to control the ACL interaction when
|
||||
// there is no defined policy. This can be "allow" which means
|
||||
// ACLs are used to black-list, or "deny" which means ACLs are
|
||||
// white-lists.
|
||||
// ACLs are used to deny-list, or "deny" which means ACLs are
|
||||
// allow-lists.
|
||||
ACLDefaultPolicy string
|
||||
|
||||
// ACLDownPolicy controls the behavior of ACLs if the ACLDatacenter
|
||||
|
|
|
@ -357,6 +357,7 @@ func (s *HTTPHandlers) wrap(handler endpoint, methods []string) http.HandlerFunc
|
|||
return func(resp http.ResponseWriter, req *http.Request) {
|
||||
setHeaders(resp, s.agent.config.HTTPResponseHeaders)
|
||||
setTranslateAddr(resp, s.agent.config.TranslateWANAddrs)
|
||||
setACLDefaultPolicy(resp, s.agent.config.ACLDefaultPolicy)
|
||||
|
||||
// Obfuscate any tokens from appearing in the logs
|
||||
formVals, err := url.ParseQuery(req.URL.RawQuery)
|
||||
|
@ -697,6 +698,12 @@ func setConsistency(resp http.ResponseWriter, consistency string) {
|
|||
}
|
||||
}
|
||||
|
||||
func setACLDefaultPolicy(resp http.ResponseWriter, aclDefaultPolicy string) {
|
||||
if aclDefaultPolicy != "" {
|
||||
resp.Header().Set("X-Consul-Default-ACL-Policy", aclDefaultPolicy)
|
||||
}
|
||||
}
|
||||
|
||||
// setLastContact is used to set the last contact header
|
||||
func setLastContact(resp http.ResponseWriter, last time.Duration) {
|
||||
if last < 0 {
|
||||
|
|
|
@ -415,6 +415,54 @@ func TestHTTPAPI_TranslateAddrHeader(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestHTTPAPI_DefaultACLPolicy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type testcase struct {
|
||||
name string
|
||||
hcl string
|
||||
expect string
|
||||
}
|
||||
|
||||
cases := []testcase{
|
||||
{
|
||||
name: "default is allow",
|
||||
hcl: ``,
|
||||
expect: "allow",
|
||||
},
|
||||
{
|
||||
name: "explicit allow",
|
||||
hcl: `acl { default_policy = "allow" }`,
|
||||
expect: "allow",
|
||||
},
|
||||
{
|
||||
name: "explicit deny",
|
||||
hcl: `acl { default_policy = "deny" }`,
|
||||
expect: "deny",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a := NewTestAgent(t, tc.hcl)
|
||||
defer a.Shutdown()
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
|
||||
a.srv.wrap(handler, []string{"GET"})(resp, req)
|
||||
|
||||
require.Equal(t, tc.expect, resp.Header().Get("X-Consul-Default-ACL-Policy"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPAPIResponseHeaders(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := NewTestAgent(t, `
|
||||
|
|
11
api/api.go
11
api/api.go
|
@ -254,6 +254,11 @@ type QueryMeta struct {
|
|||
// CacheAge is set if request was ?cached and indicates how stale the cached
|
||||
// response is.
|
||||
CacheAge time.Duration
|
||||
|
||||
// DefaultACLPolicy is used to control the ACL interaction when there is no
|
||||
// defined policy. This can be "allow" which means ACLs are used to
|
||||
// deny-list, or "deny" which means ACLs are allow-lists.
|
||||
DefaultACLPolicy string
|
||||
}
|
||||
|
||||
// WriteMeta is used to return meta data about a write
|
||||
|
@ -962,6 +967,12 @@ func parseQueryMeta(resp *http.Response, q *QueryMeta) error {
|
|||
q.AddressTranslationEnabled = false
|
||||
}
|
||||
|
||||
// Parse X-Consul-Default-ACL-Policy
|
||||
switch v := header.Get("X-Consul-Default-ACL-Policy"); v {
|
||||
case "allow", "deny":
|
||||
q.DefaultACLPolicy = v
|
||||
}
|
||||
|
||||
// Parse Cache info
|
||||
if cacheStr := header.Get("X-Cache"); cacheStr != "" {
|
||||
q.CacheHit = strings.EqualFold(cacheStr, "HIT")
|
||||
|
|
|
@ -840,6 +840,7 @@ func TestAPI_ParseQueryMeta(t *testing.T) {
|
|||
resp.Header.Set("X-Consul-LastContact", "80")
|
||||
resp.Header.Set("X-Consul-KnownLeader", "true")
|
||||
resp.Header.Set("X-Consul-Translate-Addresses", "true")
|
||||
resp.Header.Set("X-Consul-Default-ACL-Policy", "deny")
|
||||
|
||||
qm := &QueryMeta{}
|
||||
if err := parseQueryMeta(resp, qm); err != nil {
|
||||
|
@ -858,6 +859,9 @@ func TestAPI_ParseQueryMeta(t *testing.T) {
|
|||
if !qm.AddressTranslationEnabled {
|
||||
t.Fatalf("Bad: %v", qm)
|
||||
}
|
||||
if qm.DefaultACLPolicy != "deny" {
|
||||
t.Fatalf("Bad: %v", qm)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPI_UnixSocket(t *testing.T) {
|
||||
|
|
|
@ -86,6 +86,18 @@ to allow clients to know if address translation is in effect, the
|
|||
and will have a value of `true`. If translation is not enabled then this header
|
||||
will not be present.
|
||||
|
||||
## Default ACL Policy
|
||||
|
||||
All API responses for Consul versions after 1.9 will include an HTTP response
|
||||
header `X-Consul-Default-ACL-Policy` set to either "allow" or "deny" which
|
||||
mirrors the current value of the agent's
|
||||
[`acl.default_policy`](/docs/agent/options#acl_default_policy) option.
|
||||
|
||||
This is also the default [intention](/docs/connect/intentions) enforcement
|
||||
action if no intention matches.
|
||||
|
||||
This is returned even if ACLs are disabled.
|
||||
|
||||
## UUID Format
|
||||
|
||||
UUID-format identifiers generated by the Consul API use the
|
||||
|
|
Loading…
Reference in New Issue