[Security] Add finer control over script checks (#4715)

* Add -enable-local-script-checks options

These options allow for a finer control over when script checks are enabled by
giving the option to only allow them when they are declared from the local
file system.

* Add documentation for the new option

* Nitpick doc wording
This commit is contained in:
Aestek 2018-10-11 14:22:11 +02:00 committed by Paul Banks
parent 298af6dca7
commit 25f04fbd21
16 changed files with 415 additions and 149 deletions

View File

@ -69,6 +69,13 @@ const (
"service, but no reason was provided. This is a default message."
)
type configSource int
const (
ConfigSourceLocal configSource = iota
ConfigSourceRemote
)
// delegate defines the interface shared by both
// consul.Client and consul.Server.
type delegate interface {
@ -1858,7 +1865,7 @@ func (a *Agent) purgeCheck(checkID types.CheckID) error {
// AddService is used to add a service entry.
// This entry is persistent and the agent will make a best effort to
// ensure it is registered
func (a *Agent) AddService(service *structs.NodeService, chkTypes []*structs.CheckType, persist bool, token string) error {
func (a *Agent) AddService(service *structs.NodeService, chkTypes []*structs.CheckType, persist bool, token string, source configSource) error {
if service.Service == "" {
return fmt.Errorf("Service name missing")
}
@ -1940,7 +1947,7 @@ func (a *Agent) AddService(service *structs.NodeService, chkTypes []*structs.Che
if chkType.Status != "" {
check.Status = chkType.Status
}
if err := a.AddCheck(check, chkType, persist, token); err != nil {
if err := a.AddCheck(check, chkType, persist, token, source); err != nil {
return err
}
}
@ -2010,7 +2017,7 @@ func (a *Agent) RemoveService(serviceID string, persist bool) error {
// This entry is persistent and the agent will make a best effort to
// ensure it is registered. The Check may include a CheckType which
// is used to automatically update the check status
func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *structs.CheckType, persist bool, token string) error {
func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *structs.CheckType, persist bool, token string, source configSource) error {
if check.CheckID == "" {
return fmt.Errorf("CheckID missing")
}
@ -2020,8 +2027,14 @@ func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *structs.CheckType,
return fmt.Errorf("Check is not valid: %v", err)
}
if chkType.IsScript() && !a.config.EnableScriptChecks {
return fmt.Errorf("Scripts are disabled on this agent; to enable, configure 'enable_script_checks' to true")
if chkType.IsScript() {
if source == ConfigSourceLocal && !a.config.EnableLocalScriptChecks {
return fmt.Errorf("Scripts are disabled on this agent; to enable, configure 'enable_script_checks' or 'enable_local_script_checks' to true")
}
if source == ConfigSourceRemote && !a.config.EnableRemoteScriptChecks {
return fmt.Errorf("Scripts are disabled on this agent from remote calls; to enable, configure 'enable_script_checks' to true")
}
}
}
@ -2330,7 +2343,7 @@ func (a *Agent) RemoveCheck(checkID types.CheckID, persist bool) error {
// assigned. We need to restore from disk to enable to continue authenticating
// running proxies that already had that credential injected.
func (a *Agent) addProxyLocked(proxy *structs.ConnectManagedProxy, persist, FromFile bool,
restoredProxyToken string) error {
restoredProxyToken string, source configSource) error {
// Lookup the target service token in state if there is one.
token := a.State.ServiceToken(proxy.TargetServiceID)
@ -2372,7 +2385,7 @@ func (a *Agent) addProxyLocked(proxy *structs.ConnectManagedProxy, persist, From
}
}
err = a.AddService(proxyService, chkTypes, persist, token)
err = a.AddService(proxyService, chkTypes, persist, token, source)
if err != nil {
// Remove the state too
a.State.RemoveProxy(proxyService.ID)
@ -2402,10 +2415,10 @@ func (a *Agent) addProxyLocked(proxy *structs.ConnectManagedProxy, persist, From
// assigned. We need to restore from disk to enable to continue authenticating
// running proxies that already had that credential injected.
func (a *Agent) AddProxy(proxy *structs.ConnectManagedProxy, persist, FromFile bool,
restoredProxyToken string) error {
restoredProxyToken string, source configSource) error {
a.proxyLock.Lock()
defer a.proxyLock.Unlock()
return a.addProxyLocked(proxy, persist, FromFile, restoredProxyToken)
return a.addProxyLocked(proxy, persist, FromFile, restoredProxyToken, source)
}
// resolveProxyCheckAddress returns the best address to use for a TCP check of
@ -2893,13 +2906,13 @@ func (a *Agent) loadServices(conf *config.RuntimeConfig) error {
// syntax sugar and shouldn't be persisted in local or server state.
ns.Connect.SidecarService = nil
if err := a.AddService(ns, chkTypes, false, service.Token); err != nil {
if err := a.AddService(ns, chkTypes, false, service.Token, ConfigSourceLocal); err != nil {
return fmt.Errorf("Failed to register service %q: %v", service.Name, err)
}
// If there is a sidecar service, register that too.
if sidecar != nil {
if err := a.AddService(sidecar, sidecarChecks, false, sidecarToken); err != nil {
if err := a.AddService(sidecar, sidecarChecks, false, sidecarToken, ConfigSourceLocal); err != nil {
return fmt.Errorf("Failed to register sidecar for service %q: %v", service.Name, err)
}
}
@ -2962,7 +2975,7 @@ func (a *Agent) loadServices(conf *config.RuntimeConfig) error {
} else {
a.logger.Printf("[DEBUG] agent: restored service definition %q from %q",
serviceID, file)
if err := a.AddService(p.Service, nil, false, p.Token); err != nil {
if err := a.AddService(p.Service, nil, false, p.Token, ConfigSourceLocal); err != nil {
return fmt.Errorf("failed adding service %q: %s", serviceID, err)
}
}
@ -2988,7 +3001,7 @@ func (a *Agent) loadChecks(conf *config.RuntimeConfig) error {
for _, check := range conf.Checks {
health := check.HealthCheck(conf.NodeName)
chkType := check.CheckType()
if err := a.AddCheck(health, chkType, false, check.Token); err != nil {
if err := a.AddCheck(health, chkType, false, check.Token, ConfigSourceLocal); err != nil {
return fmt.Errorf("Failed to register check '%s': %v %v", check.Name, err, check)
}
}
@ -3043,7 +3056,7 @@ func (a *Agent) loadChecks(conf *config.RuntimeConfig) error {
// services into the active pool
p.Check.Status = api.HealthCritical
if err := a.AddCheck(p.Check, p.ChkType, false, p.Token); err != nil {
if err := a.AddCheck(p.Check, p.ChkType, false, p.Token, ConfigSourceLocal); err != nil {
// Purge the check if it is unable to be restored.
a.logger.Printf("[WARN] agent: Failed to restore check %q: %s",
checkID, err)
@ -3144,7 +3157,7 @@ func (a *Agent) loadProxies(conf *config.RuntimeConfig) error {
restoredToken = persisted.ProxyToken
}
if err := a.addProxyLocked(proxy, true, true, restoredToken); err != nil {
if err := a.addProxyLocked(proxy, true, true, restoredToken, ConfigSourceLocal); err != nil {
return fmt.Errorf("failed adding proxy: %s", err)
}
}
@ -3161,7 +3174,7 @@ func (a *Agent) loadProxies(conf *config.RuntimeConfig) error {
} else if !persisted.FromFile {
if a.State.Proxy(proxyID) == nil {
a.logger.Printf("[DEBUG] agent: restored proxy definition %q", proxyID)
if err := a.addProxyLocked(persisted.Proxy, false, false, persisted.ProxyToken); err != nil {
if err := a.addProxyLocked(persisted.Proxy, false, false, persisted.ProxyToken, ConfigSourceLocal); err != nil {
return fmt.Errorf("failed adding proxy %q: %v", proxyID, err)
}
} else {
@ -3251,7 +3264,7 @@ func (a *Agent) EnableServiceMaintenance(serviceID, reason, token string) error
ServiceName: service.Service,
Status: api.HealthCritical,
}
a.AddCheck(check, nil, true, token)
a.AddCheck(check, nil, true, token, ConfigSourceLocal)
a.logger.Printf("[INFO] agent: Service %q entered maintenance mode", serviceID)
return nil
@ -3297,7 +3310,7 @@ func (a *Agent) EnableNodeMaintenance(reason, token string) {
Notes: reason,
Status: api.HealthCritical,
}
a.AddCheck(check, nil, true, token)
a.AddCheck(check, nil, true, token, ConfigSourceLocal)
a.logger.Printf("[INFO] agent: Node entered maintenance mode")
}

View File

@ -570,7 +570,7 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
}
// Add the check.
if err := s.agent.AddCheck(health, chkType, true, token); err != nil {
if err := s.agent.AddCheck(health, chkType, true, token, ConfigSourceRemote); err != nil {
return nil, err
}
s.syncChanges()
@ -889,18 +889,18 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
}
// Add the service.
if err := s.agent.AddService(ns, chkTypes, true, token); err != nil {
if err := s.agent.AddService(ns, chkTypes, true, token, ConfigSourceRemote); err != nil {
return nil, err
}
// Add proxy (which will add proxy service so do it before we trigger sync)
if proxy != nil {
if err := s.agent.AddProxy(proxy, true, false, ""); err != nil {
if err := s.agent.AddProxy(proxy, true, false, "", ConfigSourceRemote); err != nil {
return nil, err
}
}
// Add sidecar.
if sidecar != nil {
if err := s.agent.AddService(sidecar, sidecarChecks, true, sidecarToken); err != nil {
if err := s.agent.AddService(sidecar, sidecarChecks, true, sidecarToken, ConfigSourceRemote); err != nil {
return nil, err
}
}

View File

@ -1329,6 +1329,60 @@ func TestAgent_RegisterCheck_Scripts(t *testing.T) {
}
}
func TestAgent_RegisterCheckScriptsExecDisable(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), "")
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
args := &structs.CheckDefinition{
Name: "test",
ScriptArgs: []string{"true"},
Interval: time.Second,
}
req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token=abc123", jsonReader(args))
res := httptest.NewRecorder()
_, err := a.srv.AgentRegisterCheck(res, req)
if err == nil {
t.Fatalf("expected error but got nil")
}
if !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("expected script disabled error, got: %s", err)
}
checkID := types.CheckID("test")
if _, ok := a.State.Checks()[checkID]; ok {
t.Fatalf("check registered with exec disable")
}
}
func TestAgent_RegisterCheckScriptsExecRemoteDisable(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), `
enable_local_script_checks = true
`)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
args := &structs.CheckDefinition{
Name: "test",
ScriptArgs: []string{"true"},
Interval: time.Second,
}
req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token=abc123", jsonReader(args))
res := httptest.NewRecorder()
_, err := a.srv.AgentRegisterCheck(res, req)
if err == nil {
t.Fatalf("expected error but got nil")
}
if !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("expected script disabled error, got: %s", err)
}
checkID := types.CheckID("test")
if _, ok := a.State.Checks()[checkID]; ok {
t.Fatalf("check registered with exec disable")
}
}
func TestAgent_RegisterCheck_Passing(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), "")
@ -1419,7 +1473,7 @@ func TestAgent_DeregisterCheck(t *testing.T) {
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
if err := a.AddCheck(chk, nil, false, ""); err != nil {
if err := a.AddCheck(chk, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1445,7 +1499,7 @@ func TestAgent_DeregisterCheckACLDeny(t *testing.T) {
testrpc.WaitForLeader(t, a.RPC, "dc1")
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
if err := a.AddCheck(chk, nil, false, ""); err != nil {
if err := a.AddCheck(chk, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1472,7 +1526,7 @@ func TestAgent_PassCheck(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1500,7 +1554,7 @@ func TestAgent_PassCheck_ACLDeny(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1527,7 +1581,7 @@ func TestAgent_WarnCheck(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1555,7 +1609,7 @@ func TestAgent_WarnCheck_ACLDeny(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1582,7 +1636,7 @@ func TestAgent_FailCheck(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1610,7 +1664,7 @@ func TestAgent_FailCheck_ACLDeny(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1637,7 +1691,7 @@ func TestAgent_UpdateCheck(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1721,7 +1775,7 @@ func TestAgent_UpdateCheck_ACLDeny(t *testing.T) {
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
chkType := &structs.CheckType{TTL: 15 * time.Second}
if err := a.AddCheck(chk, chkType, false, ""); err != nil {
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2751,10 +2805,10 @@ func TestAgent_RegisterServiceDeregisterService_Sidecar(t *testing.T) {
testrpc.WaitForLeader(t, a.RPC, "dc1")
if tt.preRegister != nil {
require.NoError(a.AddService(tt.preRegister, nil, false, ""))
require.NoError(a.AddService(tt.preRegister, nil, false, "", ConfigSourceLocal))
}
if tt.preRegister2 != nil {
require.NoError(a.AddService(tt.preRegister2, nil, false, ""))
require.NoError(a.AddService(tt.preRegister2, nil, false, "", ConfigSourceLocal))
}
// Create an ACL token with require policy
@ -2910,6 +2964,80 @@ func TestAgent_RegisterService_ConnectNative(t *testing.T) {
assert.True(svc.Connect.Native)
}
func TestAgent_RegisterService_ScriptCheck_ExecDisable(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), "")
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
args := &structs.ServiceDefinition{
Name: "test",
Meta: map[string]string{"hello": "world"},
Tags: []string{"master"},
Port: 8000,
Check: structs.CheckType{
Name: "test-check",
Interval: time.Second,
ScriptArgs: []string{"true"},
},
Weights: &structs.Weights{
Passing: 100,
Warning: 3,
},
}
req, _ := http.NewRequest("PUT", "/v1/agent/service/register?token=abc123", jsonReader(args))
_, err := a.srv.AgentRegisterService(nil, req)
if err == nil {
t.Fatalf("expected error but got nil")
}
if !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("expected script disabled error, got: %s", err)
}
checkID := types.CheckID("test-check")
if _, ok := a.State.Checks()[checkID]; ok {
t.Fatalf("check registered with exec disable")
}
}
func TestAgent_RegisterService_ScriptCheck_ExecRemoteDisable(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), `
enable_local_script_checks = true
`)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
args := &structs.ServiceDefinition{
Name: "test",
Meta: map[string]string{"hello": "world"},
Tags: []string{"master"},
Port: 8000,
Check: structs.CheckType{
Name: "test-check",
Interval: time.Second,
ScriptArgs: []string{"true"},
},
Weights: &structs.Weights{
Passing: 100,
Warning: 3,
},
}
req, _ := http.NewRequest("PUT", "/v1/agent/service/register?token=abc123", jsonReader(args))
_, err := a.srv.AgentRegisterService(nil, req)
if err == nil {
t.Fatalf("expected error but got nil")
}
if !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("expected script disabled error, got: %s", err)
}
checkID := types.CheckID("test-check")
if _, ok := a.State.Checks()[checkID]; ok {
t.Fatalf("check registered with exec disable")
}
}
func TestAgent_DeregisterService(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), "")
@ -2920,7 +3048,7 @@ func TestAgent_DeregisterService(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2953,7 +3081,7 @@ func TestAgent_DeregisterService_ACLDeny(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -3127,7 +3255,7 @@ func TestAgent_ServiceMaintenance_Enable(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -3170,7 +3298,7 @@ func TestAgent_ServiceMaintenance_Disable(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -3207,7 +3335,7 @@ func TestAgent_ServiceMaintenance_ACLDeny(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}

View File

@ -438,7 +438,7 @@ func TestAgent_AddService(t *testing.T) {
t.Run(tt.desc, func(t *testing.T) {
// check the service registration
t.Run(tt.srv.ID, func(t *testing.T) {
err := a.AddService(tt.srv, tt.chkTypes, false, "")
err := a.AddService(tt.srv, tt.chkTypes, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -474,6 +474,62 @@ func TestAgent_AddService(t *testing.T) {
}
}
func TestAgent_AddServiceNoExec(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), `
node_name = "node1"
`)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
srv := &structs.NodeService{
ID: "svcid1",
Service: "svcname1",
Tags: []string{"tag1"},
Port: 8100,
}
chk := &structs.CheckType{
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddService(srv, []*structs.CheckType{chk}, false, "", ConfigSourceLocal)
if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("err: %v", err)
}
err = a.AddService(srv, []*structs.CheckType{chk}, false, "", ConfigSourceRemote)
if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("err: %v", err)
}
}
func TestAgent_AddServiceNoRemoteExec(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), `
node_name = "node1"
enable_local_script_checks = true
`)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
srv := &structs.NodeService{
ID: "svcid1",
Service: "svcname1",
Tags: []string{"tag1"},
Port: 8100,
}
chk := &structs.CheckType{
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddService(srv, []*structs.CheckType{chk}, false, "", ConfigSourceRemote)
if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("err: %v", err)
}
}
func TestAgent_RemoveService(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), "")
@ -498,7 +554,7 @@ func TestAgent_RemoveService(t *testing.T) {
}
chkTypes := []*structs.CheckType{&structs.CheckType{TTL: time.Minute}}
if err := a.AddService(srv, chkTypes, false, ""); err != nil {
if err := a.AddService(srv, chkTypes, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -510,7 +566,7 @@ func TestAgent_RemoveService(t *testing.T) {
TTL: time.Minute,
}
hc := check.HealthCheck("node1")
if err := a.AddCheck(hc, check.CheckType(), false, ""); err != nil {
if err := a.AddCheck(hc, check.CheckType(), false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %s", err)
}
@ -536,7 +592,7 @@ func TestAgent_RemoveService(t *testing.T) {
&structs.CheckType{TTL: time.Minute},
&structs.CheckType{TTL: 30 * time.Second},
}
if err := a.AddService(srv, chkTypes, false, ""); err != nil {
if err := a.AddService(srv, chkTypes, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -582,7 +638,7 @@ func TestAgent_RemoveServiceRemovesAllChecks(t *testing.T) {
hchk2 := &structs.HealthCheck{Node: "node1", CheckID: "chk2", Name: "chk2", Status: "critical", ServiceID: "redis", ServiceName: "redis"}
// register service with chk1
if err := a.AddService(svc, []*structs.CheckType{chk1}, false, ""); err != nil {
if err := a.AddService(svc, []*structs.CheckType{chk1}, false, "", ConfigSourceLocal); err != nil {
t.Fatal("Failed to register service", err)
}
@ -592,7 +648,7 @@ func TestAgent_RemoveServiceRemovesAllChecks(t *testing.T) {
}
// update the service with chk2
if err := a.AddService(svc, []*structs.CheckType{chk2}, false, ""); err != nil {
if err := a.AddService(svc, []*structs.CheckType{chk2}, false, "", ConfigSourceLocal); err != nil {
t.Fatal("Failed to update service", err)
}
@ -655,7 +711,7 @@ func verifyIndexChurn(t *testing.T, tags []string) {
Tags: tags,
Weights: weights,
}
if err := a.AddService(svc, nil, true, ""); err != nil {
if err := a.AddService(svc, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -668,7 +724,7 @@ func verifyIndexChurn(t *testing.T, tags []string) {
chkt := &structs.CheckType{
TTL: time.Hour,
}
if err := a.AddCheck(chk, chkt, true, ""); err != nil {
if err := a.AddCheck(chk, chkt, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -680,7 +736,7 @@ func verifyIndexChurn(t *testing.T, tags []string) {
chkt = &structs.CheckType{
TTL: time.Hour,
}
if err := a.AddCheck(chk, chkt, true, ""); err != nil {
if err := a.AddCheck(chk, chkt, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -745,7 +801,7 @@ func TestAgent_AddCheck(t *testing.T) {
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -784,7 +840,7 @@ func TestAgent_AddCheck_StartPassing(t *testing.T) {
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -823,7 +879,7 @@ func TestAgent_AddCheck_MinInterval(t *testing.T) {
ScriptArgs: []string{"exit", "0"},
Interval: time.Microsecond,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -858,7 +914,7 @@ func TestAgent_AddCheck_MissingService(t *testing.T) {
ScriptArgs: []string{"exit", "0"},
Interval: time.Microsecond,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err == nil || err.Error() != `ServiceID "baz" does not exist` {
t.Fatalf("expected service id error, got: %v", err)
}
@ -888,7 +944,7 @@ func TestAgent_AddCheck_RestoreState(t *testing.T) {
chk := &structs.CheckType{
TTL: time.Minute,
}
err = a.AddCheck(health, chk, false, "")
err = a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %s", err)
}
@ -923,7 +979,7 @@ func TestAgent_AddCheck_ExecDisable(t *testing.T) {
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("err: %v", err)
}
@ -932,6 +988,46 @@ func TestAgent_AddCheck_ExecDisable(t *testing.T) {
if memChk := a.State.Checks()["mem"]; memChk != nil {
t.Fatalf("should be missing mem check")
}
err = a.AddCheck(health, chk, false, "", ConfigSourceRemote)
if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent") {
t.Fatalf("err: %v", err)
}
// Ensure we don't have a check mapping
if memChk := a.State.Checks()["mem"]; memChk != nil {
t.Fatalf("should be missing mem check")
}
}
func TestAgent_AddCheck_ExecRemoteDisable(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), `
enable_local_script_checks = true
`)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
health := &structs.HealthCheck{
Node: "foo",
CheckID: "mem",
Name: "memory util",
Status: api.HealthCritical,
}
chk := &structs.CheckType{
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddCheck(health, chk, false, "", ConfigSourceRemote)
if err == nil || !strings.Contains(err.Error(), "Scripts are disabled on this agent from remote calls") {
t.Fatalf("err: %v", err)
}
// Ensure we don't have a check mapping
if memChk := a.State.Checks()["mem"]; memChk != nil {
t.Fatalf("should be missing mem check")
}
}
func TestAgent_AddCheck_GRPC(t *testing.T) {
@ -949,7 +1045,7 @@ func TestAgent_AddCheck_GRPC(t *testing.T) {
GRPC: "localhost:12345/package.Service",
Interval: 15 * time.Second,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -987,7 +1083,7 @@ func TestAgent_AddCheck_Alias(t *testing.T) {
chk := &structs.CheckType{
AliasService: "foo",
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
require.NoError(err)
// Ensure we have a check mapping
@ -1021,7 +1117,7 @@ func TestAgent_AddCheck_Alias_setToken(t *testing.T) {
chk := &structs.CheckType{
AliasService: "foo",
}
err := a.AddCheck(health, chk, false, "foo")
err := a.AddCheck(health, chk, false, "foo", ConfigSourceLocal)
require.NoError(err)
cs := a.State.CheckState("aliashealth")
@ -1051,7 +1147,7 @@ acl_token = "hello"
chk := &structs.CheckType{
AliasService: "foo",
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
require.NoError(err)
cs := a.State.CheckState("aliashealth")
@ -1081,7 +1177,7 @@ acl_token = "hello"
chk := &structs.CheckType{
AliasService: "foo",
}
err := a.AddCheck(health, chk, false, "goodbye")
err := a.AddCheck(health, chk, false, "goodbye", ConfigSourceLocal)
require.NoError(err)
cs := a.State.CheckState("aliashealth")
@ -1120,7 +1216,7 @@ func TestAgent_RemoveCheck(t *testing.T) {
ScriptArgs: []string{"exit", "0"},
Interval: 15 * time.Second,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -1165,7 +1261,7 @@ func TestAgent_HTTPCheck_TLSSkipVerify(t *testing.T) {
TLSSkipVerify: true,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -1214,7 +1310,7 @@ func TestAgent_HTTPCheck_EnableAgentTLSForChecks(t *testing.T) {
Interval: 20 * time.Millisecond,
}
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -1263,7 +1359,7 @@ func TestAgent_updateTTLCheck(t *testing.T) {
}
// Add check and update it.
err := a.AddCheck(health, chk, false, "")
err := a.AddCheck(health, chk, false, "", ConfigSourceLocal)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -1304,7 +1400,7 @@ func TestAgent_PersistService(t *testing.T) {
file := filepath.Join(a.Config.DataDir, servicesDir, stringHash(svc.ID))
// Check is not persisted unless requested
if err := a.AddService(svc, nil, false, ""); err != nil {
if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
if _, err := os.Stat(file); err == nil {
@ -1312,7 +1408,7 @@ func TestAgent_PersistService(t *testing.T) {
}
// Persists to file if requested
if err := a.AddService(svc, nil, true, "mytoken"); err != nil {
if err := a.AddService(svc, nil, true, "mytoken", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
if _, err := os.Stat(file); err != nil {
@ -1335,7 +1431,7 @@ func TestAgent_PersistService(t *testing.T) {
// Updates service definition on disk
svc.Port = 8001
if err := a.AddService(svc, nil, true, "mytoken"); err != nil {
if err := a.AddService(svc, nil, true, "mytoken", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
expected, err = json.Marshal(persistedService{
@ -1429,7 +1525,7 @@ func TestAgent_PurgeService(t *testing.T) {
}
file := filepath.Join(a.Config.DataDir, servicesDir, stringHash(svc.ID))
if err := a.AddService(svc, nil, true, ""); err != nil {
if err := a.AddService(svc, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1442,7 +1538,7 @@ func TestAgent_PurgeService(t *testing.T) {
}
// Re-add the service
if err := a.AddService(svc, nil, true, ""); err != nil {
if err := a.AddService(svc, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1476,7 +1572,7 @@ func TestAgent_PurgeServiceOnDuplicate(t *testing.T) {
}
// First persist the service
if err := a.AddService(svc1, nil, true, ""); err != nil {
if err := a.AddService(svc1, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
a.Shutdown()
@ -1530,7 +1626,7 @@ func TestAgent_PersistProxy(t *testing.T) {
Tags: []string{"foo"},
Port: 8000,
}
require.NoError(a.AddService(svc1, nil, true, ""))
require.NoError(a.AddService(svc1, nil, true, "", ConfigSourceLocal))
// Add a proxy for it
proxy := &structs.ConnectManagedProxy{
@ -1541,12 +1637,12 @@ func TestAgent_PersistProxy(t *testing.T) {
file := filepath.Join(a.Config.DataDir, proxyDir, stringHash("redis-proxy"))
// Proxy is not persisted unless requested
require.NoError(a.AddProxy(proxy, false, false, ""))
require.NoError(a.AddProxy(proxy, false, false, "", ConfigSourceLocal))
_, err := os.Stat(file)
require.Error(err, "proxy should not be persisted")
// Proxy is persisted if requested
require.NoError(a.AddProxy(proxy, true, false, ""))
require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal))
_, err = os.Stat(file)
require.NoError(err, "proxy should be persisted")
@ -1562,7 +1658,7 @@ func TestAgent_PersistProxy(t *testing.T) {
proxy.Config = map[string]interface{}{
"foo": "bar",
}
require.NoError(a.AddProxy(proxy, true, false, ""))
require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal))
content, err = ioutil.ReadFile(file)
require.NoError(err)
@ -1601,7 +1697,7 @@ func TestAgent_PurgeProxy(t *testing.T) {
Tags: []string{"foo"},
Port: 8000,
}
require.NoError(a.AddService(svc1, nil, true, ""))
require.NoError(a.AddService(svc1, nil, true, "", ConfigSourceLocal))
// Add a proxy for it
proxy := &structs.ConnectManagedProxy{
@ -1609,7 +1705,7 @@ func TestAgent_PurgeProxy(t *testing.T) {
Command: []string{"/bin/sleep", "3600"},
}
proxyID := "redis-proxy"
require.NoError(a.AddProxy(proxy, true, false, ""))
require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal))
file := filepath.Join(a.Config.DataDir, proxyDir, stringHash("redis-proxy"))
@ -1619,7 +1715,7 @@ func TestAgent_PurgeProxy(t *testing.T) {
require.NoError(err, "should not be removed")
// Re-add the proxy
require.NoError(a.AddProxy(proxy, true, false, ""))
require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal))
// Removed
require.NoError(a.RemoveProxy(proxyID, true))
@ -1649,7 +1745,7 @@ func TestAgent_PurgeProxyOnDuplicate(t *testing.T) {
Tags: []string{"foo"},
Port: 8000,
}
require.NoError(a.AddService(svc1, nil, true, ""))
require.NoError(a.AddService(svc1, nil, true, "", ConfigSourceLocal))
// Add a proxy for it
proxy := &structs.ConnectManagedProxy{
@ -1657,7 +1753,7 @@ func TestAgent_PurgeProxyOnDuplicate(t *testing.T) {
Command: []string{"/bin/sleep", "3600"},
}
proxyID := "redis-proxy"
require.NoError(a.AddProxy(proxy, true, false, ""))
require.NoError(a.AddProxy(proxy, true, false, "", ConfigSourceLocal))
a.Shutdown()
@ -1716,7 +1812,7 @@ func TestAgent_PersistCheck(t *testing.T) {
file := filepath.Join(a.Config.DataDir, checksDir, checkIDHash(check.CheckID))
// Not persisted if not requested
if err := a.AddCheck(check, chkType, false, ""); err != nil {
if err := a.AddCheck(check, chkType, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
if _, err := os.Stat(file); err == nil {
@ -1724,7 +1820,7 @@ func TestAgent_PersistCheck(t *testing.T) {
}
// Should persist if requested
if err := a.AddCheck(check, chkType, true, "mytoken"); err != nil {
if err := a.AddCheck(check, chkType, true, "mytoken", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
if _, err := os.Stat(file); err != nil {
@ -1748,7 +1844,7 @@ func TestAgent_PersistCheck(t *testing.T) {
// Updates the check definition on disk
check.Name = "mem1"
if err := a.AddCheck(check, chkType, true, "mytoken"); err != nil {
if err := a.AddCheck(check, chkType, true, "mytoken", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
expected, err = json.Marshal(persistedCheck{
@ -1806,7 +1902,7 @@ func TestAgent_PurgeCheck(t *testing.T) {
}
file := filepath.Join(a.Config.DataDir, checksDir, checkIDHash(check.CheckID))
if err := a.AddCheck(check, nil, true, ""); err != nil {
if err := a.AddCheck(check, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1850,7 +1946,7 @@ func TestAgent_PurgeCheckOnDuplicate(t *testing.T) {
}
// First persist the check
if err := a.AddCheck(check1, nil, true, ""); err != nil {
if err := a.AddCheck(check1, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
a.Shutdown()
@ -1926,7 +2022,7 @@ func TestAgent_unloadChecks(t *testing.T) {
Tags: []string{"foo"},
Port: 8000,
}
if err := a.AddService(svc, nil, false, ""); err != nil {
if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -1939,7 +2035,7 @@ func TestAgent_unloadChecks(t *testing.T) {
ServiceID: "redis",
ServiceName: "redis",
}
if err := a.AddCheck(check1, nil, false, ""); err != nil {
if err := a.AddCheck(check1, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %s", err)
}
found := false
@ -2066,7 +2162,7 @@ func TestAgent_unloadServices(t *testing.T) {
}
// Register the service
if err := a.AddService(svc, nil, false, ""); err != nil {
if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
found := false
@ -2192,7 +2288,7 @@ func TestAgent_Service_MaintenanceMode(t *testing.T) {
}
// Register the service
if err := a.AddService(svc, nil, false, ""); err != nil {
if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2267,7 +2363,7 @@ func TestAgent_Service_Reap(t *testing.T) {
}
// Register the service.
if err := a.AddService(svc, chkTypes, false, ""); err != nil {
if err := a.AddService(svc, chkTypes, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2340,7 +2436,7 @@ func TestAgent_Service_NoReap(t *testing.T) {
}
// Register the service.
if err := a.AddService(svc, chkTypes, false, ""); err != nil {
if err := a.AddService(svc, chkTypes, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2383,7 +2479,7 @@ func TestAgent_addCheck_restoresSnapshot(t *testing.T) {
Tags: []string{"foo"},
Port: 8000,
}
if err := a.AddService(svc, nil, false, ""); err != nil {
if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2396,13 +2492,13 @@ func TestAgent_addCheck_restoresSnapshot(t *testing.T) {
ServiceID: "redis",
ServiceName: "redis",
}
if err := a.AddCheck(check1, nil, false, ""); err != nil {
if err := a.AddCheck(check1, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %s", err)
}
// Re-registering the service preserves the state of the check
chkTypes := []*structs.CheckType{&structs.CheckType{TTL: 30 * time.Second}}
if err := a.AddService(svc, chkTypes, false, ""); err != nil {
if err := a.AddService(svc, chkTypes, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %s", err)
}
check, ok := a.State.Checks()["service:redis"]
@ -2471,7 +2567,7 @@ func TestAgent_checkStateSnapshot(t *testing.T) {
Tags: []string{"foo"},
Port: 8000,
}
if err := a.AddService(svc, nil, false, ""); err != nil {
if err := a.AddService(svc, nil, false, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -2484,7 +2580,7 @@ func TestAgent_checkStateSnapshot(t *testing.T) {
ServiceID: "redis",
ServiceName: "redis",
}
if err := a.AddCheck(check1, nil, true, ""); err != nil {
if err := a.AddCheck(check1, nil, true, "", ConfigSourceLocal); err != nil {
t.Fatalf("err: %s", err)
}
@ -2976,9 +3072,9 @@ func TestAgent_AddProxy(t *testing.T) {
Service: "web",
Port: 8080,
}
require.NoError(a.AddService(reg, nil, false, ""))
require.NoError(a.AddService(reg, nil, false, "", ConfigSourceLocal))
err := a.AddProxy(tt.proxy, false, false, "")
err := a.AddProxy(tt.proxy, false, false, "", ConfigSourceLocal)
if tt.wantErr {
require.Error(err)
return
@ -3030,7 +3126,7 @@ func TestAgent_RemoveProxy(t *testing.T) {
Service: "web",
Port: 8080,
}
require.NoError(a.AddService(reg, nil, false, ""))
require.NoError(a.AddService(reg, nil, false, "", ConfigSourceLocal))
// Add a proxy for web
pReg := &structs.ConnectManagedProxy{
@ -3038,7 +3134,7 @@ func TestAgent_RemoveProxy(t *testing.T) {
ExecMode: structs.ProxyExecModeDaemon,
Command: []string{"foo"},
}
require.NoError(a.AddProxy(pReg, false, false, ""))
require.NoError(a.AddProxy(pReg, false, false, "", ConfigSourceLocal))
// Test the ID was created as we expect.
gotProxy := a.State.Proxy("web-proxy")
@ -3069,7 +3165,7 @@ func TestAgent_ReLoadProxiesFromConfig(t *testing.T) {
Service: "web",
Port: 8080,
}
require.NoError(a.AddService(reg, nil, false, ""))
require.NoError(a.AddService(reg, nil, false, "", ConfigSourceLocal))
proxies := a.State.Proxies()
require.Len(proxies, 0)

View File

@ -588,6 +588,9 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
proxyDefaultScriptCommand := c.Connect.ProxyDefaults.ScriptCommand
proxyDefaultConfig := c.Connect.ProxyDefaults.Config
enableRemoteScriptChecks := b.boolVal(c.EnableScriptChecks)
enableLocalScriptChecks := b.boolValWithDefault(c.EnableLocalScriptChecks, enableRemoteScriptChecks)
// ----------------------------------------------------------------
// build runtime config
//
@ -743,7 +746,8 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
DiscoveryMaxStale: b.durationVal("discovery_max_stale", c.DiscoveryMaxStale),
EnableAgentTLSForChecks: b.boolVal(c.EnableAgentTLSForChecks),
EnableDebug: b.boolVal(c.EnableDebug),
EnableScriptChecks: b.boolVal(c.EnableScriptChecks),
EnableRemoteScriptChecks: enableRemoteScriptChecks,
EnableLocalScriptChecks: enableLocalScriptChecks,
EnableSyslog: b.boolVal(c.EnableSyslog),
EnableUI: b.boolVal(c.UI),
EncryptKey: b.stringVal(c.EncryptKey),

View File

@ -191,6 +191,7 @@ type Config struct {
EnableAgentTLSForChecks *bool `json:"enable_agent_tls_for_checks,omitempty" hcl:"enable_agent_tls_for_checks" mapstructure:"enable_agent_tls_for_checks"`
EnableDebug *bool `json:"enable_debug,omitempty" hcl:"enable_debug" mapstructure:"enable_debug"`
EnableScriptChecks *bool `json:"enable_script_checks,omitempty" hcl:"enable_script_checks" mapstructure:"enable_script_checks"`
EnableLocalScriptChecks *bool `json:"enable_local_script_checks,omitempty" hcl:"enable_local_script_checks" mapstructure:"enable_local_script_checks"`
EnableSyslog *bool `json:"enable_syslog,omitempty" hcl:"enable_syslog" mapstructure:"enable_syslog"`
EncryptKey *string `json:"encrypt,omitempty" hcl:"encrypt" mapstructure:"encrypt"`
EncryptVerifyIncoming *bool `json:"encrypt_verify_incoming,omitempty" hcl:"encrypt_verify_incoming" mapstructure:"encrypt_verify_incoming"`

View File

@ -71,6 +71,7 @@ func AddFlags(fs *flag.FlagSet, f *Flags) {
add(&f.Config.Ports.DNS, "dns-port", "DNS port to use.")
add(&f.Config.DNSDomain, "domain", "Domain to use for DNS interface.")
add(&f.Config.EnableScriptChecks, "enable-script-checks", "Enables health check scripts.")
add(&f.Config.EnableLocalScriptChecks, "enable-local-script-checks", "Enables health check scripts from configuration file.")
add(&f.Config.EncryptKey, "encrypt", "Provides the gossip encryption key.")
add(&f.Config.Ports.GRPC, "grpc-port", "Sets the gRPC API port to listen on (currently needed for Envoy xDS only).")
add(&f.Config.Ports.HTTP, "http-port", "Sets the HTTP API port to listen on.")

View File

@ -638,13 +638,21 @@ type RuntimeConfig struct {
// hcl: enable_debug = (true|false)
EnableDebug bool
// EnableScriptChecks controls whether health checks which execute
// scripts are enabled. This includes regular script checks and Docker
// EnableLocalScriptChecks controls whether health checks declared from the local
// config file which execute scripts are enabled. This includes regular script
// checks and Docker checks.
//
// hcl: (enable_script_checks|enable_local_script_checks) = (true|false)
// flag: -enable-script-checks, -enable-local-script-checks
EnableLocalScriptChecks bool
// EnableRemoeScriptChecks controls whether health checks declared from the http API
// which execute scripts are enabled. This includes regular script checks and Docker
// checks.
//
// hcl: enable_script_checks = (true|false)
// flag: -enable-script-checks
EnableScriptChecks bool
EnableRemoteScriptChecks bool
// EnableSyslog is used to also tee all the logs over to syslog. Only supported
// on linux and OSX. Other platforms will generate an error.

View File

@ -351,7 +351,8 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
`-data-dir=` + dataDir,
},
patch: func(rt *RuntimeConfig) {
rt.EnableScriptChecks = true
rt.EnableLocalScriptChecks = true
rt.EnableRemoteScriptChecks = true
rt.DataDir = dataDir
},
},
@ -2973,6 +2974,7 @@ func TestFullConfig(t *testing.T) {
"enable_agent_tls_for_checks": true,
"enable_debug": true,
"enable_script_checks": true,
"enable_local_script_checks": true,
"enable_syslog": true,
"encrypt": "A4wELWqH",
"encrypt_verify_incoming": true,
@ -3504,6 +3506,7 @@ func TestFullConfig(t *testing.T) {
enable_agent_tls_for_checks = true
enable_debug = true
enable_script_checks = true
enable_local_script_checks = true
enable_syslog = true
encrypt = "A4wELWqH"
encrypt_verify_incoming = true
@ -4129,7 +4132,8 @@ func TestFullConfig(t *testing.T) {
EnableACLReplication: true,
EnableAgentTLSForChecks: true,
EnableDebug: true,
EnableScriptChecks: true,
EnableRemoteScriptChecks: true,
EnableLocalScriptChecks: true,
EnableSyslog: true,
EnableUI: true,
EncryptKey: "A4wELWqH",
@ -4918,7 +4922,8 @@ func TestSanitize(t *testing.T) {
"EnableACLReplication": false,
"EnableAgentTLSForChecks": false,
"EnableDebug": false,
"EnableScriptChecks": false,
"EnableLocalScriptChecks": false,
"EnableRemoteScriptChecks": false,
"EnableSyslog": false,
"EnableUI": false,
"EncryptKey": "hidden",

View File

@ -623,9 +623,9 @@ func (c *ConsulProvider) generateCA(privateKey string, sn uint64) (string, error
serialNum := &big.Int{}
serialNum.SetUint64(sn)
template := x509.Certificate{
SerialNumber: serialNum,
Subject: pkix.Name{CommonName: name},
URIs: []*url.URL{id.URI()},
SerialNumber: serialNum,
Subject: pkix.Name{CommonName: name},
URIs: []*url.URL{id.URI()},
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageCertSign |
x509.KeyUsageCRLSign |

View File

@ -79,7 +79,7 @@ func (s *snapshot) persistNodes(sink raft.SnapshotSink,
Node: n.Node,
Address: n.Address,
TaggedAddresses: n.TaggedAddresses,
NodeMeta: n.Meta,
NodeMeta: n.Meta,
}
// Register the node itself

View File

@ -283,7 +283,7 @@ func TestAgent_sidecarServiceFromNodeService(t *testing.T) {
a := NewTestAgent("jones", hcl)
if tt.preRegister != nil {
err := a.AddService(tt.preRegister.NodeService(), nil, false, "")
err := a.AddService(tt.preRegister.NodeService(), nil, false, "", ConfigSourceLocal)
require.NoError(err)
}

View File

@ -49,7 +49,7 @@ func TestMaintCommand_NoArgs(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", agent.ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
if err := a.EnableServiceMaintenance("test", "broken 1", ""); err != nil {
@ -145,7 +145,7 @@ func TestMaintCommand_EnableServiceMaintenance(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", agent.ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}
@ -179,7 +179,7 @@ func TestMaintCommand_DisableServiceMaintenance(t *testing.T) {
ID: "test",
Service: "test",
}
if err := a.AddService(service, nil, false, ""); err != nil {
if err := a.AddService(service, nil, false, "", agent.ConfigSourceLocal); err != nil {
t.Fatalf("err: %v", err)
}

View File

@ -28,8 +28,13 @@ There are several different kinds of checks:
Consul will wait for any child processes spawned by the script to finish. For any
other system, Consul will attempt to force-kill the script and any child processes
it has spawned once the timeout has passed.
In Consul 0.9.0 and later, the agent must be configured with [`enable_script_checks`]
(/docs/agent/options.html#_enable_script_checks) set to `true` in order to enable script checks.
In Consul 0.9.0 and later, script checks are not enabled by default. To use them you
can either use :
* [`enable_local_script_checks`](/docs/agent/options.html#_enable_local_script_checks):
enable script checks defile in local config files. Script checks defined via the HTTP
API will not be allowed.
* [`enable_script_checks`](/docs/agent/options.html#_enable_script_checks): enable
script checks regardless of how they are defined.
* HTTP + Interval - These checks make an HTTP `GET` request every Interval (e.g.
every 30 seconds) to the specified URL. The status of the service depends on

View File

@ -200,9 +200,13 @@ will exit with an error at startup.
* <a name="_enable_script_checks"></a><a href="#_enable_script_checks">`-enable-script-checks`</a> This
controls whether [health checks that execute scripts](/docs/agent/checks.html) are enabled on
this agent, and defaults to `false` so operators must opt-in to allowing these. If enabled,
it is recommended to [enable ACLs](/docs/guides/acl.html) as well to control which users are
allowed to register new checks to execute scripts. This was added in Consul 0.9.0.
this agent, and defaults to `false` so operators must opt-in to allowing these. If enabled, it is recommended
to [enable ACLs](/docs/guides/acl.html) as well to control which users are allowed to register new checks to
execute scripts. This was added in Consul 0.9.0.
* <a name="_enable_local_script_checks"></a><a href="#_enable_local_script_checks">`-enable-local-script-checks`</a>
Like [`enable_script_checks`](#_enable_script_checks), but only enable them when they are defined in the local
config files. Script checks defined in HTTP API registratrions will still not be allowed.
* <a name="_encrypt"></a><a href="#_encrypt">`-encrypt`</a> - Specifies the secret key to
use for encryption of Consul
@ -747,7 +751,7 @@ default will automatically work with some tooling.
#### Common CA Config Options
<p>There are also a number of common configuration options supported by all providers:</p>
* <a name="ca_leaf_cert_ttl"></a><a href="#ca_leaf_cert_ttl">`leaf_cert_ttl`</a> The upper bound on the
lease duration of a leaf certificate issued for a service. In most cases a new leaf certificate will be
requested by a proxy before this limit is reached. This is also the effective limit on how long a server
@ -959,72 +963,72 @@ default will automatically work with some tooling.
[`-disable-keyring-file` command-line flag](#_disable_keyring_file).
* <a name="gossip_lan"></a><a href="#gossip_lan">`gossip_lan`</a> - **(Advanced)** This object contains a number of sub-keys
which can be set to tune the LAN gossip communications. These are only provided for users running especially large
which can be set to tune the LAN gossip communications. These are only provided for users running especially large
clusters that need fine tuning and are prepared to spend significant effort correctly tuning them for their
environment and workload. **Tuning these improperly can cause Consul to fail in unexpected ways**.
The default values are appropriate in almost all deployments.
* <a name="gossip_nodes"></a><a href="#gossip_nodes">`gossip_nodes`</a> - The number of random nodes to send
gossip messages to per gossip_interval. Increasing this number causes the gossip messages to propagate
gossip messages to per gossip_interval. Increasing this number causes the gossip messages to propagate
across the cluster more quickly at the expense of increased bandwidth. The default is 3.
* <a name="gossip_interval"></a><a href="#gossip_interval">`gossip_interval`</a> - The interval between sending
messages that need to be gossiped that haven't been able to piggyback on probing messages. If this is set to
messages that need to be gossiped that haven't been able to piggyback on probing messages. If this is set to
zero, non-piggyback gossip is disabled. By lowering this value (more frequent) gossip messages are propagated
across the cluster more quickly at the expense of increased bandwidth. The default is 200ms.
* <a name="probe_interval"></a><a href="#probe_interval">`probe_interval`</a> - The interval between random node
probes. Setting this lower (more frequent) will cause the cluster to detect failed nodes more quickly
probes. Setting this lower (more frequent) will cause the cluster to detect failed nodes more quickly
at the expense of increased bandwidth usage. The default is 1s.
* <a name="probe_timeout"></a><a href="#probe_timeout">`probe_timeout`</a> - The timeout to wait for an ack from
a probed node before assuming it is unhealthy. This should be at least the 99-percentile of RTT (round-trip time) on
your network. The default is 500ms and is a conservative value suitable for almost all realistic deployments.
* <a name="retransmit_mult"></a><a href="#retransmit_mult">`retransmit_mult`</a> - The multiplier for the number
* <a name="retransmit_mult"></a><a href="#retransmit_mult">`retransmit_mult`</a> - The multiplier for the number
of retransmissions that are attempted for messages broadcasted over gossip. The number of retransmits is scaled
using this multiplier and the cluster size. The higher the multiplier, the more likely a failed broadcast is to
converge at the expense of increased bandwidth. The default is 4.
* <a name="suspicion_mult"></a><a href="#suspicion_mult">`suspicion_mult`</a> - The multiplier for determining the
time an inaccessible node is considered suspect before declaring it dead. The timeout is scaled with the cluster
size and the probe_interval. This allows the timeout to scale properly with expected propagation delay with a
larger cluster size. The higher the multiplier, the longer an inaccessible node is considered part of the
size and the probe_interval. This allows the timeout to scale properly with expected propagation delay with a
larger cluster size. The higher the multiplier, the longer an inaccessible node is considered part of the
cluster before declaring it dead, giving that suspect node more time to refute if it is indeed still alive. The
default is 4.
* <a name="gossip_wan"></a><a href="#gossip_wan">`gossip_wan`</a> - **(Advanced)** This object contains a number of sub-keys
which can be set to tune the WAN gossip communications. These are only provided for users running especially large
which can be set to tune the WAN gossip communications. These are only provided for users running especially large
clusters that need fine tuning and are prepared to spend significant effort correctly tuning them for their
environment and workload. **Tuning these improperly can cause Consul to fail in unexpected ways**.
The default values are appropriate in almost all deployments.
* <a name="gossip_nodes"></a><a href="#gossip_nodes">`gossip_nodes`</a> - The number of random nodes to send
gossip messages to per gossip_interval. Increasing this number causes the gossip messages to propagate
gossip messages to per gossip_interval. Increasing this number causes the gossip messages to propagate
across the cluster more quickly at the expense of increased bandwidth. The default is 3.
* <a name="gossip_interval"></a><a href="#gossip_interval">`gossip_interval`</a> - The interval between sending
messages that need to be gossiped that haven't been able to piggyback on probing messages. If this is set to
messages that need to be gossiped that haven't been able to piggyback on probing messages. If this is set to
zero, non-piggyback gossip is disabled. By lowering this value (more frequent) gossip messages are propagated
across the cluster more quickly at the expense of increased bandwidth. The default is 200ms.
* <a name="probe_interval"></a><a href="#probe_interval">`probe_interval`</a> - The interval between random node
probes. Setting this lower (more frequent) will cause the cluster to detect failed nodes more quickly
probes. Setting this lower (more frequent) will cause the cluster to detect failed nodes more quickly
at the expense of increased bandwidth usage. The default is 1s.
* <a name="probe_timeout"></a><a href="#probe_timeout">`probe_timeout`</a> - The timeout to wait for an ack from
a probed node before assuming it is unhealthy. This should be at least the 99-percentile of RTT (round-trip time) on
your network. The default is 500ms and is a conservative value suitable for almost all realistic deployments.
* <a name="retransmit_mult"></a><a href="#retransmit_mult">`retransmit_mult`</a> - The multiplier for the number
* <a name="retransmit_mult"></a><a href="#retransmit_mult">`retransmit_mult`</a> - The multiplier for the number
of retransmissions that are attempted for messages broadcasted over gossip. The number of retransmits is scaled
using this multiplier and the cluster size. The higher the multiplier, the more likely a failed broadcast is to
converge at the expense of increased bandwidth. The default is 4.
* <a name="suspicion_mult"></a><a href="#suspicion_mult">`suspicion_mult`</a> - The multiplier for determining the
time an inaccessible node is considered suspect before declaring it dead. The timeout is scaled with the cluster
size and the probe_interval. This allows the timeout to scale properly with expected propagation delay with a
larger cluster size. The higher the multiplier, the longer an inaccessible node is considered part of the
size and the probe_interval. This allows the timeout to scale properly with expected propagation delay with a
larger cluster size. The higher the multiplier, the longer an inaccessible node is considered part of the
cluster before declaring it dead, giving that suspect node more time to refute if it is indeed still alive. The
default is 4.

View File

@ -996,8 +996,9 @@ to use for registration events:
access.
In addition to ACLs, in Consul 0.9.0 and later, the agent must be configured with
[`enable_script_checks`](/docs/agent/options.html#_enable_script_checks) set to `true` in order to enable
script checks.
[`enable_script_checks`](/docs/agent/options.html#_enable_script_checks) or
[`enable_local_script_checks`](/docs/agent/options.html#_enable_local_script_checks)
set to `true` in order to enable script checks.
#### Session Rules