github.com/kjdelisle/consul@v1.4.5/agent/acl.go (about)

     1  package agent
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/consul/acl"
     7  	"github.com/hashicorp/consul/agent/local"
     8  	"github.com/hashicorp/consul/agent/structs"
     9  	"github.com/hashicorp/consul/types"
    10  	"github.com/hashicorp/serf/serf"
    11  )
    12  
    13  // resolveToken is the primary interface used by ACL-checkers in the agent
    14  // endpoints, which is the one place where we do some ACL enforcement on
    15  // clients. Some of the enforcement is normative (e.g. self and monitor)
    16  // and some is informative (e.g. catalog and health).
    17  func (a *Agent) resolveToken(id string) (acl.Authorizer, error) {
    18  	// ACLs are disabled
    19  	if !a.delegate.ACLsEnabled() {
    20  		return nil, nil
    21  	}
    22  
    23  	// Disable ACLs if version 8 enforcement isn't enabled.
    24  	if !a.config.ACLEnforceVersion8 {
    25  		return nil, nil
    26  	}
    27  
    28  	if acl.RootAuthorizer(id) != nil {
    29  		return nil, acl.ErrRootDenied
    30  	}
    31  
    32  	if a.tokens.IsAgentMasterToken(id) {
    33  		return a.aclMasterAuthorizer, nil
    34  	}
    35  	return a.delegate.ResolveToken(id)
    36  }
    37  
    38  func (a *Agent) initializeACLs() error {
    39  	// Build a policy for the agent master token.
    40  	// The builtin agent master policy allows reading any node information
    41  	// and allows writes to the agent with the node name of the running agent
    42  	// only. This used to allow a prefix match on agent names but that seems
    43  	// entirely unnecessary so it is now using an exact match.
    44  	policy := &acl.Policy{
    45  		Agents: []*acl.AgentPolicy{
    46  			&acl.AgentPolicy{
    47  				Node:   a.config.NodeName,
    48  				Policy: acl.PolicyWrite,
    49  			},
    50  		},
    51  		NodePrefixes: []*acl.NodePolicy{
    52  			&acl.NodePolicy{
    53  				Name:   "",
    54  				Policy: acl.PolicyRead,
    55  			},
    56  		},
    57  	}
    58  	master, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	a.aclMasterAuthorizer = master
    63  	return nil
    64  }
    65  
    66  // resolveProxyToken attempts to resolve an ACL ID to a local proxy token.
    67  // If a local proxy isn't found with that token, nil is returned.
    68  func (a *Agent) resolveProxyToken(id string) *local.ManagedProxy {
    69  	for _, p := range a.State.Proxies() {
    70  		if p.ProxyToken == id {
    71  			return p
    72  		}
    73  	}
    74  
    75  	return nil
    76  }
    77  
    78  // vetServiceRegister makes sure the service registration action is allowed by
    79  // the given token.
    80  func (a *Agent) vetServiceRegister(token string, service *structs.NodeService) error {
    81  	// Resolve the token and bail if ACLs aren't enabled.
    82  	rule, err := a.resolveToken(token)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if rule == nil {
    87  		return nil
    88  	}
    89  
    90  	// Vet the service itself.
    91  	if !rule.ServiceWrite(service.Service, nil) {
    92  		return acl.ErrPermissionDenied
    93  	}
    94  
    95  	// Vet any service that might be getting overwritten.
    96  	services := a.State.Services()
    97  	if existing, ok := services[service.ID]; ok {
    98  		if !rule.ServiceWrite(existing.Service, nil) {
    99  			return acl.ErrPermissionDenied
   100  		}
   101  	}
   102  
   103  	// If the service is a proxy, ensure that it has write on the destination too
   104  	// since it can be discovered as an instance of that service.
   105  	if service.Kind == structs.ServiceKindConnectProxy {
   106  		if !rule.ServiceWrite(service.Proxy.DestinationServiceName, nil) {
   107  			return acl.ErrPermissionDenied
   108  		}
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  // vetServiceUpdate makes sure the service update action is allowed by the given
   115  // token.
   116  func (a *Agent) vetServiceUpdate(token string, serviceID string) error {
   117  	// Resolve the token and bail if ACLs aren't enabled.
   118  	rule, err := a.resolveToken(token)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if rule == nil {
   123  		return nil
   124  	}
   125  
   126  	// Vet any changes based on the existing services's info.
   127  	services := a.State.Services()
   128  	if existing, ok := services[serviceID]; ok {
   129  		if !rule.ServiceWrite(existing.Service, nil) {
   130  			return acl.ErrPermissionDenied
   131  		}
   132  	} else {
   133  		return fmt.Errorf("Unknown service %q", serviceID)
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  // vetCheckRegister makes sure the check registration action is allowed by the
   140  // given token.
   141  func (a *Agent) vetCheckRegister(token string, check *structs.HealthCheck) error {
   142  	// Resolve the token and bail if ACLs aren't enabled.
   143  	rule, err := a.resolveToken(token)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	if rule == nil {
   148  		return nil
   149  	}
   150  
   151  	// Vet the check itself.
   152  	if len(check.ServiceName) > 0 {
   153  		if !rule.ServiceWrite(check.ServiceName, nil) {
   154  			return acl.ErrPermissionDenied
   155  		}
   156  	} else {
   157  		if !rule.NodeWrite(a.config.NodeName, nil) {
   158  			return acl.ErrPermissionDenied
   159  		}
   160  	}
   161  
   162  	// Vet any check that might be getting overwritten.
   163  	checks := a.State.Checks()
   164  	if existing, ok := checks[check.CheckID]; ok {
   165  		if len(existing.ServiceName) > 0 {
   166  			if !rule.ServiceWrite(existing.ServiceName, nil) {
   167  				return acl.ErrPermissionDenied
   168  			}
   169  		} else {
   170  			if !rule.NodeWrite(a.config.NodeName, nil) {
   171  				return acl.ErrPermissionDenied
   172  			}
   173  		}
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  // vetCheckUpdate makes sure that a check update is allowed by the given token.
   180  func (a *Agent) vetCheckUpdate(token string, checkID types.CheckID) error {
   181  	// Resolve the token and bail if ACLs aren't enabled.
   182  	rule, err := a.resolveToken(token)
   183  	if err != nil {
   184  		return err
   185  	}
   186  	if rule == nil {
   187  		return nil
   188  	}
   189  
   190  	// Vet any changes based on the existing check's info.
   191  	checks := a.State.Checks()
   192  	if existing, ok := checks[checkID]; ok {
   193  		if len(existing.ServiceName) > 0 {
   194  			if !rule.ServiceWrite(existing.ServiceName, nil) {
   195  				return acl.ErrPermissionDenied
   196  			}
   197  		} else {
   198  			if !rule.NodeWrite(a.config.NodeName, nil) {
   199  				return acl.ErrPermissionDenied
   200  			}
   201  		}
   202  	} else {
   203  		return fmt.Errorf("Unknown check %q", checkID)
   204  	}
   205  
   206  	return nil
   207  }
   208  
   209  // filterMembers redacts members that the token doesn't have access to.
   210  func (a *Agent) filterMembers(token string, members *[]serf.Member) error {
   211  	// Resolve the token and bail if ACLs aren't enabled.
   212  	rule, err := a.resolveToken(token)
   213  	if err != nil {
   214  		return err
   215  	}
   216  	if rule == nil {
   217  		return nil
   218  	}
   219  
   220  	// Filter out members based on the node policy.
   221  	m := *members
   222  	for i := 0; i < len(m); i++ {
   223  		node := m[i].Name
   224  		if rule.NodeRead(node) {
   225  			continue
   226  		}
   227  		a.logger.Printf("[DEBUG] agent: dropping node %q from result due to ACLs", node)
   228  		m = append(m[:i], m[i+1:]...)
   229  		i--
   230  	}
   231  	*members = m
   232  	return nil
   233  }
   234  
   235  // filterServices redacts services that the token doesn't have access to.
   236  func (a *Agent) filterServices(token string, services *map[string]*structs.NodeService) error {
   237  	// Resolve the token and bail if ACLs aren't enabled.
   238  	rule, err := a.resolveToken(token)
   239  	if err != nil {
   240  		return err
   241  	}
   242  	if rule == nil {
   243  		return nil
   244  	}
   245  
   246  	// Filter out services based on the service policy.
   247  	for id, service := range *services {
   248  		if rule.ServiceRead(service.Service) {
   249  			continue
   250  		}
   251  		a.logger.Printf("[DEBUG] agent: dropping service %q from result due to ACLs", id)
   252  		delete(*services, id)
   253  	}
   254  	return nil
   255  }
   256  
   257  // filterChecks redacts checks that the token doesn't have access to.
   258  func (a *Agent) filterChecks(token string, checks *map[types.CheckID]*structs.HealthCheck) error {
   259  	// Resolve the token and bail if ACLs aren't enabled.
   260  	rule, err := a.resolveToken(token)
   261  	if err != nil {
   262  		return err
   263  	}
   264  	if rule == nil {
   265  		return nil
   266  	}
   267  
   268  	// Filter out checks based on the node or service policy.
   269  	for id, check := range *checks {
   270  		if len(check.ServiceName) > 0 {
   271  			if rule.ServiceRead(check.ServiceName) {
   272  				continue
   273  			}
   274  		} else {
   275  			if rule.NodeRead(a.config.NodeName) {
   276  				continue
   277  			}
   278  		}
   279  		a.logger.Printf("[DEBUG] agent: dropping check %q from result due to ACLs", id)
   280  		delete(*checks, id)
   281  	}
   282  	return nil
   283  }