agent: Adding ACL block configuration

This commit is contained in:
Armon Dadgar 2017-08-13 13:46:47 -07:00
parent bc697dc50e
commit 9cd8ac832f
5 changed files with 143 additions and 0 deletions

View File

@ -63,6 +63,7 @@ client {
}
server {
enabled = true
authoritative_region = "foobar"
bootstrap_expect = 5
data_dir = "/tmp/data"
protocol_version = 3
@ -82,6 +83,11 @@ server {
rejoin_after_leave = true
encrypt = "abc"
}
acl {
enabled = true
token_ttl = "30s"
policy_ttl = "30s"
}
telemetry {
statsite_address = "127.0.0.1:1234"
statsd_address = "127.0.0.1:2345"

View File

@ -67,6 +67,9 @@ type Config struct {
// Server has our server related settings
Server *ServerConfig `mapstructure:"server"`
// ACL has our acl related settings
ACL *ACLConfig `mapstructure:"acl"`
// Telemetry is used to configure sending telemetry
Telemetry *Telemetry `mapstructure:"telemetry"`
@ -228,11 +231,35 @@ type ClientConfig struct {
NoHostUUID *bool `mapstructure:"no_host_uuid"`
}
// ACLConfig is configuration specific to the ACL system
type ACLConfig struct {
// Enabled controls if we are enforce and manage ACLs
Enabled bool `mapstructure:"enabled"`
// TokenTTL controls how long we cache ACL tokens. This controls
// how stale they can be when we are enforcing policies. Defaults
// to "30s". Reducing this impacts performance by forcing more
// frequent resolution.
TokenTTL string `mapstructure:"token_ttl"`
tokenTTL time.Duration `mapstructure:"-"`
// PolicyTTL controls how long we cache ACL policies. This controls
// how stale they can be when we are enforcing policies. Defaults
// to "30s". Reducing this impacts performance by forcing more
// frequent resolution.
PolicyTTL string `mapstructure:"policy_ttl"`
policyTTL time.Duration `mapstructure:"-"`
}
// ServerConfig is configuration specific to the server mode
type ServerConfig struct {
// Enabled controls if we are a server
Enabled bool `mapstructure:"enabled"`
// AuthoritativeRegion is used to control which region is treated as
// the source of truth for global tokens and ACL policies.
AuthoritativeRegion string `mapstructure:"authoritative_region"`
// BootstrapExpect tries to automatically bootstrap the Consul cluster,
// by withholding peers until enough servers join.
BootstrapExpect int `mapstructure:"bootstrap_expect"`
@ -565,6 +592,11 @@ func DefaultConfig() *Config {
RetryInterval: "30s",
RetryMaxAttempts: 0,
},
ACL: &ACLConfig{
Enabled: false,
TokenTTL: "30s",
PolicyTTL: "30s",
},
SyslogFacility: "LOCAL0",
Telemetry: &Telemetry{
CollectionInterval: "1s",
@ -676,6 +708,14 @@ func (c *Config) Merge(b *Config) *Config {
result.Server = result.Server.Merge(b.Server)
}
// Apply the acl config
if result.ACL == nil && b.ACL != nil {
server := *b.ACL
result.ACL = &server
} else if b.ACL != nil {
result.ACL = result.ACL.Merge(b.ACL)
}
// Apply the ports config
if result.Ports == nil && b.Ports != nil {
ports := *b.Ports
@ -902,6 +942,22 @@ func isTooManyColons(err error) bool {
return err != nil && strings.Contains(err.Error(), tooManyColons)
}
// Merge is used to merge two ACL configs together
func (a *ACLConfig) Merge(b *ACLConfig) *ACLConfig {
result := *a
if b.Enabled {
result.Enabled = true
}
if b.TokenTTL != "" {
result.TokenTTL = b.TokenTTL
}
if b.PolicyTTL != "" {
result.PolicyTTL = b.PolicyTTL
}
return &result
}
// Merge is used to merge two server configs together
func (a *ServerConfig) Merge(b *ServerConfig) *ServerConfig {
result := *a
@ -909,6 +965,9 @@ func (a *ServerConfig) Merge(b *ServerConfig) *ServerConfig {
if b.Enabled {
result.Enabled = true
}
if b.AuthoritativeRegion != "" {
result.AuthoritativeRegion = b.AuthoritativeRegion
}
if b.BootstrapExpect > 0 {
result.BootstrapExpect = b.BootstrapExpect
}

View File

@ -96,6 +96,7 @@ func parseConfig(result *Config, list *ast.ObjectList) error {
"vault",
"tls",
"http_api_response_headers",
"acl",
}
if err := checkHCLKeys(list, valid); err != nil {
return multierror.Prefix(err, "config:")
@ -118,6 +119,7 @@ func parseConfig(result *Config, list *ast.ObjectList) error {
delete(m, "vault")
delete(m, "tls")
delete(m, "http_api_response_headers")
delete(m, "acl")
// Decode the rest
if err := mapstructure.WeakDecode(m, result); err != nil {
@ -159,6 +161,13 @@ func parseConfig(result *Config, list *ast.ObjectList) error {
}
}
// Parse ACL config
if o := list.Filter("acl"); len(o.Items) > 0 {
if err := parseACL(&result.ACL, o); err != nil {
return multierror.Prefix(err, "acl ->")
}
}
// Parse telemetry config
if o := list.Filter("telemetry"); len(o.Items) > 0 {
if err := parseTelemetry(&result.Telemetry, o); err != nil {
@ -514,6 +523,7 @@ func parseServer(result **ServerConfig, list *ast.ObjectList) error {
"retry_interval",
"rejoin_after_leave",
"encrypt",
"authoritative_region",
}
if err := checkHCLKeys(listVal, valid); err != nil {
return err
@ -541,6 +551,55 @@ func parseServer(result **ServerConfig, list *ast.ObjectList) error {
return nil
}
func parseACL(result **ACLConfig, list *ast.ObjectList) error {
list = list.Elem()
if len(list.Items) > 1 {
return fmt.Errorf("only one 'acl' block allowed")
}
// Get our server object
obj := list.Items[0]
// Value should be an object
var listVal *ast.ObjectList
if ot, ok := obj.Val.(*ast.ObjectType); ok {
listVal = ot.List
} else {
return fmt.Errorf("acl value: should be an object")
}
// Check for invalid keys
valid := []string{
"enabled",
"token_ttl",
"policy_ttl",
}
if err := checkHCLKeys(listVal, valid); err != nil {
return err
}
var m map[string]interface{}
if err := hcl.DecodeObject(&m, listVal); err != nil {
return err
}
var config ACLConfig
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
WeaklyTypedInput: true,
Result: &config,
})
if err != nil {
return err
}
if err := dec.Decode(m); err != nil {
return err
}
*result = &config
return nil
}
func parseTelemetry(result **Telemetry, list *ast.ObjectList) error {
list = list.Elem()
if len(list.Items) > 1 {

View File

@ -84,6 +84,7 @@ func TestConfig_Parse(t *testing.T) {
},
Server: &ServerConfig{
Enabled: true,
AuthoritativeRegion: "foobar",
BootstrapExpect: 5,
DataDir: "/tmp/data",
ProtocolVersion: 3,
@ -103,6 +104,11 @@ func TestConfig_Parse(t *testing.T) {
RetryMaxAttempts: 3,
EncryptKey: "abc",
},
ACL: &ACLConfig{
Enabled: true,
TokenTTL: "30s",
PolicyTTL: "30s",
},
Telemetry: &Telemetry{
StatsiteAddr: "127.0.0.1:1234",
StatsdAddr: "127.0.0.1:2345",

View File

@ -27,6 +27,7 @@ func TestConfig_Merge(t *testing.T) {
Telemetry: &Telemetry{},
Client: &ClientConfig{},
Server: &ServerConfig{},
ACL: &ACLConfig{},
Ports: &Ports{},
Addresses: &Addresses{},
AdvertiseAddrs: &AdvertiseAddrs{},
@ -91,6 +92,7 @@ func TestConfig_Merge(t *testing.T) {
},
Server: &ServerConfig{
Enabled: false,
AuthoritativeRegion: "global",
BootstrapExpect: 1,
DataDir: "/tmp/data1",
ProtocolVersion: 1,
@ -100,6 +102,11 @@ func TestConfig_Merge(t *testing.T) {
MinHeartbeatTTL: 30 * time.Second,
MaxHeartbeatsPerSecond: 30.0,
},
ACL: &ACLConfig{
Enabled: true,
TokenTTL: "60s",
PolicyTTL: "60s",
},
Ports: &Ports{
HTTP: 4646,
RPC: 4647,
@ -223,6 +230,7 @@ func TestConfig_Merge(t *testing.T) {
},
Server: &ServerConfig{
Enabled: true,
AuthoritativeRegion: "global2",
BootstrapExpect: 2,
DataDir: "/tmp/data2",
ProtocolVersion: 2,
@ -238,6 +246,11 @@ func TestConfig_Merge(t *testing.T) {
RetryInterval: "10s",
retryInterval: time.Second * 10,
},
ACL: &ACLConfig{
Enabled: true,
TokenTTL: "20s",
PolicyTTL: "20s",
},
Ports: &Ports{
HTTP: 20000,
RPC: 21000,