2019-12-19 23:40:30 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
|
|
"github.com/hashicorp/nomad/command/agent/consul"
|
|
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestConsulPolicy_ParseConsulPolicy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
try := func(t *testing.T, text string, expPolicy *ConsulPolicy, expErr string) {
|
|
|
|
policy, err := ParseConsulPolicy(text)
|
|
|
|
if expErr != "" {
|
|
|
|
require.EqualError(t, err, expErr)
|
|
|
|
require.True(t, policy.IsEmpty())
|
|
|
|
} else {
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expPolicy, policy)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("service", func(t *testing.T) {
|
|
|
|
text := `service "web" { policy = "read" }`
|
|
|
|
exp := &ConsulPolicy{
|
|
|
|
Services: []*ConsulServiceRule{{Name: "web", Policy: "read"}},
|
|
|
|
ServicePrefixes: []*ConsulServiceRule(nil),
|
|
|
|
}
|
|
|
|
try(t, text, exp, "")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("service_prefix", func(t *testing.T) {
|
|
|
|
text := `service_prefix "data" { policy = "write" }`
|
|
|
|
exp := &ConsulPolicy{
|
|
|
|
Services: []*ConsulServiceRule(nil),
|
|
|
|
ServicePrefixes: []*ConsulServiceRule{{Name: "data", Policy: "write"}},
|
|
|
|
}
|
|
|
|
try(t, text, exp, "")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("empty", func(t *testing.T) {
|
|
|
|
text := ``
|
|
|
|
expErr := "consul policy contains no service rules"
|
|
|
|
try(t, text, nil, expErr)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("malformed", func(t *testing.T) {
|
|
|
|
text := `this is not valid HCL!`
|
|
|
|
expErr := "failed to parse ACL policy: At 1:22: illegal char"
|
|
|
|
try(t, text, nil, expErr)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConsulPolicy_IsEmpty(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
try := func(t *testing.T, cp *ConsulPolicy, exp bool) {
|
|
|
|
result := cp.IsEmpty()
|
|
|
|
require.Equal(t, exp, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("nil", func(t *testing.T) {
|
|
|
|
cp := (*ConsulPolicy)(nil)
|
|
|
|
try(t, cp, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("empty slices", func(t *testing.T) {
|
|
|
|
cp := &ConsulPolicy{
|
|
|
|
Services: []*ConsulServiceRule(nil),
|
|
|
|
ServicePrefixes: []*ConsulServiceRule(nil),
|
|
|
|
}
|
|
|
|
try(t, cp, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("services nonempty", func(t *testing.T) {
|
|
|
|
cp := &ConsulPolicy{
|
|
|
|
Services: []*ConsulServiceRule{{Name: "example", Policy: "write"}},
|
|
|
|
}
|
|
|
|
try(t, cp, false)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("service_prefixes nonempty", func(t *testing.T) {
|
|
|
|
cp := &ConsulPolicy{
|
|
|
|
ServicePrefixes: []*ConsulServiceRule{{Name: "pre", Policy: "read"}},
|
|
|
|
}
|
|
|
|
try(t, cp, false)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConsulACLsAPI_allowsServiceWrite(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
try := func(t *testing.T, task string, cp *ConsulPolicy, exp bool) {
|
2020-01-15 19:08:10 +00:00
|
|
|
result := cp.allowsServiceWrite(task)
|
2019-12-19 23:40:30 +00:00
|
|
|
require.Equal(t, exp, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
makeCP := func(services [][2]string, prefixes [][2]string) *ConsulPolicy {
|
|
|
|
serviceRules := make([]*ConsulServiceRule, 0, len(services))
|
|
|
|
for _, service := range services {
|
|
|
|
serviceRules = append(serviceRules, &ConsulServiceRule{Name: service[0], Policy: service[1]})
|
|
|
|
}
|
|
|
|
prefixRules := make([]*ConsulServiceRule, 0, len(prefixes))
|
|
|
|
for _, prefix := range prefixes {
|
|
|
|
prefixRules = append(prefixRules, &ConsulServiceRule{Name: prefix[0], Policy: prefix[1]})
|
|
|
|
}
|
|
|
|
return &ConsulPolicy{Services: serviceRules, ServicePrefixes: prefixRules}
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("matching service policy write", func(t *testing.T) {
|
|
|
|
try(t, "task1", makeCP(
|
|
|
|
[][2]string{{"task1", "write"}},
|
|
|
|
nil,
|
|
|
|
), true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("matching service policy read", func(t *testing.T) {
|
|
|
|
try(t, "task1", makeCP(
|
|
|
|
[][2]string{{"task1", "read"}},
|
|
|
|
nil,
|
|
|
|
), false)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("wildcard service policy write", func(t *testing.T) {
|
|
|
|
try(t, "task1", makeCP(
|
|
|
|
[][2]string{{"*", "write"}},
|
|
|
|
nil,
|
|
|
|
), true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("wrong service policy write", func(t *testing.T) {
|
|
|
|
try(t, "other1", makeCP(
|
|
|
|
[][2]string{{"task1", "write"}},
|
|
|
|
nil,
|
|
|
|
), false)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("matching prefix policy write", func(t *testing.T) {
|
|
|
|
try(t, "task-one", makeCP(
|
|
|
|
nil,
|
|
|
|
[][2]string{{"task-", "write"}},
|
|
|
|
), true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("matching prefix policy read", func(t *testing.T) {
|
|
|
|
try(t, "task-one", makeCP(
|
|
|
|
nil,
|
|
|
|
[][2]string{{"task-", "read"}},
|
|
|
|
), false)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("empty prefix policy write", func(t *testing.T) {
|
|
|
|
try(t, "task-one", makeCP(
|
|
|
|
nil,
|
|
|
|
[][2]string{{"", "write"}},
|
|
|
|
), true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("late matching service", func(t *testing.T) {
|
|
|
|
try(t, "task1", makeCP(
|
|
|
|
[][2]string{{"task0", "write"}, {"task1", "write"}},
|
|
|
|
nil,
|
|
|
|
), true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("late matching prefix", func(t *testing.T) {
|
|
|
|
try(t, "task-one", makeCP(
|
|
|
|
nil,
|
|
|
|
[][2]string{{"foo-", "write"}, {"task-", "write"}},
|
|
|
|
), true)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConsulACLsAPI_hasSufficientPolicy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
try := func(t *testing.T, task string, token *api.ACLToken, exp bool) {
|
|
|
|
logger := testlog.HCLogger(t)
|
|
|
|
cAPI := &consulACLsAPI{
|
|
|
|
aclClient: consul.NewMockACLsAPI(logger),
|
|
|
|
logger: logger,
|
|
|
|
}
|
|
|
|
result, err := cAPI.hasSufficientPolicy(task, token)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, exp, result)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("no useful policy or role", func(t *testing.T) {
|
|
|
|
try(t, "service1", consul.ExampleOperatorToken0, false)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("working policy only", func(t *testing.T) {
|
|
|
|
try(t, "service1", consul.ExampleOperatorToken1, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("working role only", func(t *testing.T) {
|
|
|
|
try(t, "service1", consul.ExampleOperatorToken4, true)
|
|
|
|
})
|
|
|
|
}
|