agent: augment /v1/connect/authorize to cache intentions
This commit is contained in:
parent
56774f24d0
commit
a1f8cb9570
|
@ -2649,4 +2649,13 @@ func (a *Agent) registerCache() {
|
||||||
RefreshTimer: 0,
|
RefreshTimer: 0,
|
||||||
RefreshTimeout: 10 * time.Minute,
|
RefreshTimeout: 10 * time.Minute,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
a.cache.RegisterType(cachetype.IntentionMatchName, &cachetype.IntentionMatch{
|
||||||
|
RPC: a.delegate,
|
||||||
|
}, &cache.RegisterOptions{
|
||||||
|
// Maintain a blocking query, retry dropped connections quickly
|
||||||
|
Refresh: true,
|
||||||
|
RefreshTimer: 0,
|
||||||
|
RefreshTimeout: 10 * time.Minute,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1124,10 +1124,16 @@ func (s *HTTPServer) AgentConnectAuthorize(resp http.ResponseWriter, req *http.R
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
args.Token = token
|
args.Token = token
|
||||||
var reply structs.IndexedIntentionMatches
|
|
||||||
if err := s.agent.RPC("Intention.Match", args, &reply); err != nil {
|
raw, err := s.agent.cache.Get(cachetype.IntentionMatchName, args)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reply, ok := raw.(*structs.IndexedIntentionMatches)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("internal error: response type not correct")
|
||||||
|
}
|
||||||
if len(reply.Matches) != 1 {
|
if len(reply.Matches) != 1 {
|
||||||
return nil, fmt.Errorf("Internal error loading matches")
|
return nil, fmt.Errorf("Internal error loading matches")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2495,13 +2495,14 @@ func TestAgentConnectAuthorize_idNotService(t *testing.T) {
|
||||||
func TestAgentConnectAuthorize_allow(t *testing.T) {
|
func TestAgentConnectAuthorize_allow(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := assert.New(t)
|
require := require.New(t)
|
||||||
a := NewTestAgent(t.Name(), "")
|
a := NewTestAgent(t.Name(), "")
|
||||||
defer a.Shutdown()
|
defer a.Shutdown()
|
||||||
|
|
||||||
target := "db"
|
target := "db"
|
||||||
|
|
||||||
// Create some intentions
|
// Create some intentions
|
||||||
|
var ixnId string
|
||||||
{
|
{
|
||||||
req := structs.IntentionRequest{
|
req := structs.IntentionRequest{
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
|
@ -2514,10 +2515,12 @@ func TestAgentConnectAuthorize_allow(t *testing.T) {
|
||||||
req.Intention.DestinationName = target
|
req.Intention.DestinationName = target
|
||||||
req.Intention.Action = structs.IntentionActionAllow
|
req.Intention.Action = structs.IntentionActionAllow
|
||||||
|
|
||||||
var reply string
|
require.Nil(a.RPC("Intention.Apply", &req, &ixnId))
|
||||||
assert.Nil(a.RPC("Intention.Apply", &req, &reply))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the initial cache hit count
|
||||||
|
cacheHits := a.cache.Hits()
|
||||||
|
|
||||||
args := &structs.ConnectAuthorizeRequest{
|
args := &structs.ConnectAuthorizeRequest{
|
||||||
Target: target,
|
Target: target,
|
||||||
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
||||||
|
@ -2525,12 +2528,70 @@ func TestAgentConnectAuthorize_allow(t *testing.T) {
|
||||||
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
||||||
resp := httptest.NewRecorder()
|
resp := httptest.NewRecorder()
|
||||||
respRaw, err := a.srv.AgentConnectAuthorize(resp, req)
|
respRaw, err := a.srv.AgentConnectAuthorize(resp, req)
|
||||||
assert.Nil(err)
|
require.Nil(err)
|
||||||
assert.Equal(200, resp.Code)
|
require.Equal(200, resp.Code)
|
||||||
|
|
||||||
obj := respRaw.(*connectAuthorizeResp)
|
obj := respRaw.(*connectAuthorizeResp)
|
||||||
assert.True(obj.Authorized)
|
require.True(obj.Authorized)
|
||||||
assert.Contains(obj.Reason, "Matched")
|
require.Contains(obj.Reason, "Matched")
|
||||||
|
|
||||||
|
// That should've been a cache miss, so not hit change
|
||||||
|
require.Equal(cacheHits, a.cache.Hits())
|
||||||
|
|
||||||
|
// Make the request again
|
||||||
|
{
|
||||||
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
respRaw, err := a.srv.AgentConnectAuthorize(resp, req)
|
||||||
|
require.Nil(err)
|
||||||
|
require.Equal(200, resp.Code)
|
||||||
|
|
||||||
|
obj := respRaw.(*connectAuthorizeResp)
|
||||||
|
require.True(obj.Authorized)
|
||||||
|
require.Contains(obj.Reason, "Matched")
|
||||||
|
}
|
||||||
|
|
||||||
|
// That should've been a cache hit
|
||||||
|
require.Equal(cacheHits+1, a.cache.Hits())
|
||||||
|
cacheHits++
|
||||||
|
|
||||||
|
// Change the intention
|
||||||
|
{
|
||||||
|
req := structs.IntentionRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Op: structs.IntentionOpUpdate,
|
||||||
|
Intention: structs.TestIntention(t),
|
||||||
|
}
|
||||||
|
req.Intention.ID = ixnId
|
||||||
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
||||||
|
req.Intention.SourceName = "web"
|
||||||
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
||||||
|
req.Intention.DestinationName = target
|
||||||
|
req.Intention.Action = structs.IntentionActionDeny
|
||||||
|
|
||||||
|
require.Nil(a.RPC("Intention.Apply", &req, &ixnId))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short sleep lets the cache background refresh happen
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
// Make the request again
|
||||||
|
{
|
||||||
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
respRaw, err := a.srv.AgentConnectAuthorize(resp, req)
|
||||||
|
require.Nil(err)
|
||||||
|
require.Equal(200, resp.Code)
|
||||||
|
|
||||||
|
obj := respRaw.(*connectAuthorizeResp)
|
||||||
|
require.False(obj.Authorized)
|
||||||
|
require.Contains(obj.Reason, "Matched")
|
||||||
|
}
|
||||||
|
|
||||||
|
// That should've been a cache hit, too, since it updated in the
|
||||||
|
// background.
|
||||||
|
require.Equal(cacheHits+1, a.cache.Hits())
|
||||||
|
cacheHits++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test when there is an intention denying the connection
|
// Test when there is an intention denying the connection
|
||||||
|
|
Loading…
Reference in New Issue