api: IntentionCheck

This commit is contained in:
Mitchell Hashimoto 2018-05-11 17:19:54 -07:00
parent b5b29cd6af
commit bf99a7f54a
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
3 changed files with 89 additions and 1 deletions

View File

@ -1159,7 +1159,7 @@ func TestAPI_AgentConnectProxyConfig(t *testing.T) {
TargetServiceName: "foo",
ContentHash: "93baee1d838888ae",
ExecMode: "daemon",
Command: []string{"consul connect proxy"},
Command: []string{"consul", "connect", "proxy"},
Config: map[string]interface{}{
"bind_address": "127.0.0.1",
"bind_port": float64(20000),

View File

@ -83,6 +83,18 @@ const (
IntentionMatchDestination IntentionMatchType = "destination"
)
// IntentionCheck are the arguments for the intention check API. For
// more documentation see the IntentionCheck function.
type IntentionCheck struct {
// Source and Destination are the source and destination values to
// check. The destination is always a Consul service, but the source
// may be other values as defined by the SourceType.
Source, Destination string
// SourceType is the type of the value for the source.
SourceType IntentionSourceType
}
// Intentions returns the list of intentions.
func (h *Connect) Intentions(q *QueryOptions) ([]*Intention, *QueryMeta, error) {
r := h.c.newRequest("GET", "/v1/connect/intentions")
@ -156,6 +168,33 @@ func (h *Connect) IntentionMatch(args *IntentionMatch, q *QueryOptions) (map[str
return out, qm, nil
}
// IntentionCheck returns whether a given source/destination would be allowed
// or not given the current set of intentions and the configuration of Consul.
func (h *Connect) IntentionCheck(args *IntentionCheck, q *QueryOptions) (bool, *QueryMeta, error) {
r := h.c.newRequest("GET", "/v1/connect/intentions/check")
r.setQueryOptions(q)
r.params.Set("source", args.Source)
r.params.Set("destination", args.Destination)
if args.SourceType != "" {
r.params.Set("source-type", string(args.SourceType))
}
rtt, resp, err := requireOK(h.c.doRequest(r))
if err != nil {
return false, nil, err
}
defer resp.Body.Close()
qm := &QueryMeta{}
parseQueryMeta(resp, qm)
qm.RequestTime = rtt
var out struct{ Allowed bool }
if err := decodeBody(resp, &out); err != nil {
return false, nil, err
}
return out.Allowed, qm, nil
}
// IntentionCreate will create a new intention. The ID in the given
// structure must be empty and a generate ID will be returned on
// success.

View File

@ -87,6 +87,55 @@ func TestAPI_ConnectIntentionMatch(t *testing.T) {
require.Equal(expected, actual)
}
func TestAPI_ConnectIntentionCheck(t *testing.T) {
t.Parallel()
require := require.New(t)
c, s := makeClient(t)
defer s.Stop()
connect := c.Connect()
// Create
{
insert := [][]string{
{"foo", "*", "foo", "bar"},
}
for _, v := range insert {
ixn := testIntention()
ixn.SourceNS = v[0]
ixn.SourceName = v[1]
ixn.DestinationNS = v[2]
ixn.DestinationName = v[3]
ixn.Action = IntentionActionDeny
id, _, err := connect.IntentionCreate(ixn, nil)
require.Nil(err)
require.NotEmpty(id)
}
}
// Match it
{
result, _, err := connect.IntentionCheck(&IntentionCheck{
Source: "foo/qux",
Destination: "foo/bar",
}, nil)
require.Nil(err)
require.False(result)
}
// Match it (non-matching)
{
result, _, err := connect.IntentionCheck(&IntentionCheck{
Source: "bar/qux",
Destination: "foo/bar",
}, nil)
require.Nil(err)
require.True(result)
}
}
func testIntention() *Intention {
return &Intention{
SourceNS: "eng",