mirror of https://github.com/hashicorp/consul
Matt Keeler
4 years ago
committed by
GitHub
17 changed files with 5337 additions and 10 deletions
@ -0,0 +1,21 @@
|
||||
package agentpb |
||||
|
||||
func (req *AutoConfigRequest) RequestDatacenter() string { |
||||
return req.Datacenter |
||||
} |
||||
|
||||
func (req *AutoConfigRequest) IsRead() bool { |
||||
return false |
||||
} |
||||
|
||||
func (req *AutoConfigRequest) AllowStaleRead() bool { |
||||
return false |
||||
} |
||||
|
||||
func (req *AutoConfigRequest) TokenSecret() string { |
||||
return req.ConsulToken |
||||
} |
||||
|
||||
func (req *AutoConfigRequest) SetTokenSecret(token string) { |
||||
req.ConsulToken = token |
||||
} |
@ -0,0 +1,28 @@
|
||||
// Code generated by protoc-gen-go-binary. DO NOT EDIT.
|
||||
// source: agent/agentpb/auto_config.proto
|
||||
|
||||
package agentpb |
||||
|
||||
import ( |
||||
"github.com/golang/protobuf/proto" |
||||
) |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *AutoConfigRequest) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *AutoConfigRequest) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *AutoConfigResponse) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *AutoConfigResponse) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
@ -0,0 +1,757 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: agent/agentpb/auto_config.proto
|
||||
|
||||
package agentpb |
||||
|
||||
import ( |
||||
fmt "fmt" |
||||
proto "github.com/golang/protobuf/proto" |
||||
config "github.com/hashicorp/consul/agent/agentpb/config" |
||||
io "io" |
||||
math "math" |
||||
) |
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal |
||||
var _ = fmt.Errorf |
||||
var _ = math.Inf |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// AutoConfigRequest is the data structure to be sent along with the
|
||||
// Cluster.AutoConfig RPC
|
||||
type AutoConfigRequest struct { |
||||
// Datacenter is the local datacenter name. This wont actually be set by clients
|
||||
// but rather will be set by the servers to allow for forwarding to
|
||||
// the leader. If it ever happens to be set and differs from the local datacenters
|
||||
// name then an error should be returned.
|
||||
Datacenter string `protobuf:"bytes,1,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"` |
||||
// Node is the node name that the requester would like to assume
|
||||
// the identity of.
|
||||
Node string `protobuf:"bytes,2,opt,name=Node,proto3" json:"Node,omitempty"` |
||||
// Segment is the network segment that the requester would like to join
|
||||
Segment string `protobuf:"bytes,4,opt,name=Segment,proto3" json:"Segment,omitempty"` |
||||
// JWT is a signed JSON Web Token used to authorize the request
|
||||
JWT string `protobuf:"bytes,5,opt,name=JWT,proto3" json:"JWT,omitempty"` |
||||
// ConsulToken is a Consul ACL token that the agent requesting the
|
||||
// configuration already has.
|
||||
ConsulToken string `protobuf:"bytes,6,opt,name=ConsulToken,proto3" json:"ConsulToken,omitempty"` |
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
||||
XXX_unrecognized []byte `json:"-"` |
||||
XXX_sizecache int32 `json:"-"` |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) Reset() { *m = AutoConfigRequest{} } |
||||
func (m *AutoConfigRequest) String() string { return proto.CompactTextString(m) } |
||||
func (*AutoConfigRequest) ProtoMessage() {} |
||||
func (*AutoConfigRequest) Descriptor() ([]byte, []int) { |
||||
return fileDescriptor_c842365210d144b0, []int{0} |
||||
} |
||||
func (m *AutoConfigRequest) XXX_Unmarshal(b []byte) error { |
||||
return m.Unmarshal(b) |
||||
} |
||||
func (m *AutoConfigRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
||||
if deterministic { |
||||
return xxx_messageInfo_AutoConfigRequest.Marshal(b, m, deterministic) |
||||
} else { |
||||
b = b[:cap(b)] |
||||
n, err := m.MarshalTo(b) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return b[:n], nil |
||||
} |
||||
} |
||||
func (m *AutoConfigRequest) XXX_Merge(src proto.Message) { |
||||
xxx_messageInfo_AutoConfigRequest.Merge(m, src) |
||||
} |
||||
func (m *AutoConfigRequest) XXX_Size() int { |
||||
return m.Size() |
||||
} |
||||
func (m *AutoConfigRequest) XXX_DiscardUnknown() { |
||||
xxx_messageInfo_AutoConfigRequest.DiscardUnknown(m) |
||||
} |
||||
|
||||
var xxx_messageInfo_AutoConfigRequest proto.InternalMessageInfo |
||||
|
||||
func (m *AutoConfigRequest) GetDatacenter() string { |
||||
if m != nil { |
||||
return m.Datacenter |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) GetNode() string { |
||||
if m != nil { |
||||
return m.Node |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) GetSegment() string { |
||||
if m != nil { |
||||
return m.Segment |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) GetJWT() string { |
||||
if m != nil { |
||||
return m.JWT |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) GetConsulToken() string { |
||||
if m != nil { |
||||
return m.ConsulToken |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// AutoConfigResponse is the data structure sent in response to a Cluster.AutoConfig request
|
||||
type AutoConfigResponse struct { |
||||
Config *config.Config `protobuf:"bytes,1,opt,name=Config,proto3" json:"Config,omitempty"` |
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
||||
XXX_unrecognized []byte `json:"-"` |
||||
XXX_sizecache int32 `json:"-"` |
||||
} |
||||
|
||||
func (m *AutoConfigResponse) Reset() { *m = AutoConfigResponse{} } |
||||
func (m *AutoConfigResponse) String() string { return proto.CompactTextString(m) } |
||||
func (*AutoConfigResponse) ProtoMessage() {} |
||||
func (*AutoConfigResponse) Descriptor() ([]byte, []int) { |
||||
return fileDescriptor_c842365210d144b0, []int{1} |
||||
} |
||||
func (m *AutoConfigResponse) XXX_Unmarshal(b []byte) error { |
||||
return m.Unmarshal(b) |
||||
} |
||||
func (m *AutoConfigResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
||||
if deterministic { |
||||
return xxx_messageInfo_AutoConfigResponse.Marshal(b, m, deterministic) |
||||
} else { |
||||
b = b[:cap(b)] |
||||
n, err := m.MarshalTo(b) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return b[:n], nil |
||||
} |
||||
} |
||||
func (m *AutoConfigResponse) XXX_Merge(src proto.Message) { |
||||
xxx_messageInfo_AutoConfigResponse.Merge(m, src) |
||||
} |
||||
func (m *AutoConfigResponse) XXX_Size() int { |
||||
return m.Size() |
||||
} |
||||
func (m *AutoConfigResponse) XXX_DiscardUnknown() { |
||||
xxx_messageInfo_AutoConfigResponse.DiscardUnknown(m) |
||||
} |
||||
|
||||
var xxx_messageInfo_AutoConfigResponse proto.InternalMessageInfo |
||||
|
||||
func (m *AutoConfigResponse) GetConfig() *config.Config { |
||||
if m != nil { |
||||
return m.Config |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func init() { |
||||
proto.RegisterType((*AutoConfigRequest)(nil), "agentpb.AutoConfigRequest") |
||||
proto.RegisterType((*AutoConfigResponse)(nil), "agentpb.AutoConfigResponse") |
||||
} |
||||
|
||||
func init() { proto.RegisterFile("agent/agentpb/auto_config.proto", fileDescriptor_c842365210d144b0) } |
||||
|
||||
var fileDescriptor_c842365210d144b0 = []byte{ |
||||
// 258 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0x4c, 0x4f, 0xcd, |
||||
0x2b, 0xd1, 0x07, 0x93, 0x05, 0x49, 0xfa, 0x89, 0xa5, 0x25, 0xf9, 0xf1, 0xc9, 0xf9, 0x79, 0x69, |
||||
0x99, 0xe9, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xec, 0x50, 0x29, 0x29, 0x45, 0x54, 0x95, |
||||
0x10, 0x45, 0xfa, 0xc8, 0x6a, 0x95, 0xa6, 0x32, 0x72, 0x09, 0x3a, 0x96, 0x96, 0xe4, 0x3b, 0x83, |
||||
0x05, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0xe4, 0xb8, 0xb8, 0x5c, 0x12, 0x4b, 0x12, |
||||
0x93, 0x53, 0xf3, 0x4a, 0x52, 0x8b, 0x24, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x90, 0x44, 0x84, |
||||
0x84, 0xb8, 0x58, 0xfc, 0xf2, 0x53, 0x52, 0x25, 0x98, 0xc0, 0x32, 0x60, 0xb6, 0x90, 0x04, 0x17, |
||||
0x7b, 0x70, 0x6a, 0x7a, 0x6e, 0x6a, 0x5e, 0x89, 0x04, 0x0b, 0x58, 0x18, 0xc6, 0x15, 0x12, 0xe0, |
||||
0x62, 0xf6, 0x0a, 0x0f, 0x91, 0x60, 0x05, 0x8b, 0x82, 0x98, 0x42, 0x0a, 0x5c, 0xdc, 0xce, 0xf9, |
||||
0x79, 0xc5, 0xa5, 0x39, 0x21, 0xf9, 0xd9, 0xa9, 0x79, 0x12, 0x6c, 0x60, 0x19, 0x64, 0x21, 0x25, |
||||
0x1b, 0x2e, 0x21, 0x64, 0x67, 0x15, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x0a, 0xa9, 0x71, 0xb1, 0x41, |
||||
0x44, 0xc0, 0x6e, 0xe2, 0x36, 0xe2, 0xd3, 0x83, 0x7a, 0x06, 0xaa, 0x0e, 0x2a, 0xeb, 0x64, 0x7d, |
||||
0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0xce, 0x78, 0x2c, 0xc7, |
||||
0x10, 0xa5, 0x99, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x91, 0x58, |
||||
0x9c, 0x91, 0x99, 0x9c, 0x5f, 0x54, 0x00, 0x0a, 0x8a, 0xe2, 0xd2, 0x1c, 0x7d, 0x94, 0x60, 0x4a, |
||||
0x62, 0x03, 0x87, 0x8c, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x3b, 0x8c, 0xf1, 0x75, 0x68, 0x01, |
||||
0x00, 0x00, |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) Marshal() (dAtA []byte, err error) { |
||||
size := m.Size() |
||||
dAtA = make([]byte, size) |
||||
n, err := m.MarshalTo(dAtA) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return dAtA[:n], nil |
||||
} |
||||
|
||||
func (m *AutoConfigRequest) MarshalTo(dAtA []byte) (int, error) { |
||||
var i int |
||||
_ = i |
||||
var l int |
||||
_ = l |
||||
if len(m.Datacenter) > 0 { |
||||
dAtA[i] = 0xa |
||||
i++ |
||||
i = encodeVarintAutoConfig(dAtA, i, uint64(len(m.Datacenter))) |
||||
i += copy(dAtA[i:], m.Datacenter) |
||||
} |
||||
if len(m.Node) > 0 { |
||||
dAtA[i] = 0x12 |
||||
i++ |
||||
i = encodeVarintAutoConfig(dAtA, i, uint64(len(m.Node))) |
||||
i += copy(dAtA[i:], m.Node) |
||||
} |
||||
if len(m.Segment) > 0 { |
||||
dAtA[i] = 0x22 |
||||
i++ |
||||
i = encodeVarintAutoConfig(dAtA, i, uint64(len(m.Segment))) |
||||
i += copy(dAtA[i:], m.Segment) |
||||
} |
||||
if len(m.JWT) > 0 { |
||||
dAtA[i] = 0x2a |
||||
i++ |
||||
i = encodeVarintAutoConfig(dAtA, i, uint64(len(m.JWT))) |
||||
i += copy(dAtA[i:], m.JWT) |
||||
} |
||||
if len(m.ConsulToken) > 0 { |
||||
dAtA[i] = 0x32 |
||||
i++ |
||||
i = encodeVarintAutoConfig(dAtA, i, uint64(len(m.ConsulToken))) |
||||
i += copy(dAtA[i:], m.ConsulToken) |
||||
} |
||||
if m.XXX_unrecognized != nil { |
||||
i += copy(dAtA[i:], m.XXX_unrecognized) |
||||
} |
||||
return i, nil |
||||
} |
||||
|
||||
func (m *AutoConfigResponse) Marshal() (dAtA []byte, err error) { |
||||
size := m.Size() |
||||
dAtA = make([]byte, size) |
||||
n, err := m.MarshalTo(dAtA) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return dAtA[:n], nil |
||||
} |
||||
|
||||
func (m *AutoConfigResponse) MarshalTo(dAtA []byte) (int, error) { |
||||
var i int |
||||
_ = i |
||||
var l int |
||||
_ = l |
||||
if m.Config != nil { |
||||
dAtA[i] = 0xa |
||||
i++ |
||||
i = encodeVarintAutoConfig(dAtA, i, uint64(m.Config.Size())) |
||||
n1, err := m.Config.MarshalTo(dAtA[i:]) |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
i += n1 |
||||
} |
||||
if m.XXX_unrecognized != nil { |
||||
i += copy(dAtA[i:], m.XXX_unrecognized) |
||||
} |
||||
return i, nil |
||||
} |
||||
|
||||
func encodeVarintAutoConfig(dAtA []byte, offset int, v uint64) int { |
||||
for v >= 1<<7 { |
||||
dAtA[offset] = uint8(v&0x7f | 0x80) |
||||
v >>= 7 |
||||
offset++ |
||||
} |
||||
dAtA[offset] = uint8(v) |
||||
return offset + 1 |
||||
} |
||||
func (m *AutoConfigRequest) Size() (n int) { |
||||
if m == nil { |
||||
return 0 |
||||
} |
||||
var l int |
||||
_ = l |
||||
l = len(m.Datacenter) |
||||
if l > 0 { |
||||
n += 1 + l + sovAutoConfig(uint64(l)) |
||||
} |
||||
l = len(m.Node) |
||||
if l > 0 { |
||||
n += 1 + l + sovAutoConfig(uint64(l)) |
||||
} |
||||
l = len(m.Segment) |
||||
if l > 0 { |
||||
n += 1 + l + sovAutoConfig(uint64(l)) |
||||
} |
||||
l = len(m.JWT) |
||||
if l > 0 { |
||||
n += 1 + l + sovAutoConfig(uint64(l)) |
||||
} |
||||
l = len(m.ConsulToken) |
||||
if l > 0 { |
||||
n += 1 + l + sovAutoConfig(uint64(l)) |
||||
} |
||||
if m.XXX_unrecognized != nil { |
||||
n += len(m.XXX_unrecognized) |
||||
} |
||||
return n |
||||
} |
||||
|
||||
func (m *AutoConfigResponse) Size() (n int) { |
||||
if m == nil { |
||||
return 0 |
||||
} |
||||
var l int |
||||
_ = l |
||||
if m.Config != nil { |
||||
l = m.Config.Size() |
||||
n += 1 + l + sovAutoConfig(uint64(l)) |
||||
} |
||||
if m.XXX_unrecognized != nil { |
||||
n += len(m.XXX_unrecognized) |
||||
} |
||||
return n |
||||
} |
||||
|
||||
func sovAutoConfig(x uint64) (n int) { |
||||
for { |
||||
n++ |
||||
x >>= 7 |
||||
if x == 0 { |
||||
break |
||||
} |
||||
} |
||||
return n |
||||
} |
||||
func sozAutoConfig(x uint64) (n int) { |
||||
return sovAutoConfig(uint64((x << 1) ^ uint64((int64(x) >> 63)))) |
||||
} |
||||
func (m *AutoConfigRequest) Unmarshal(dAtA []byte) error { |
||||
l := len(dAtA) |
||||
iNdEx := 0 |
||||
for iNdEx < l { |
||||
preIndex := iNdEx |
||||
var wire uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
wire |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
fieldNum := int32(wire >> 3) |
||||
wireType := int(wire & 0x7) |
||||
if wireType == 4 { |
||||
return fmt.Errorf("proto: AutoConfigRequest: wiretype end group for non-group") |
||||
} |
||||
if fieldNum <= 0 { |
||||
return fmt.Errorf("proto: AutoConfigRequest: illegal tag %d (wire type %d)", fieldNum, wire) |
||||
} |
||||
switch fieldNum { |
||||
case 1: |
||||
if wireType != 2 { |
||||
return fmt.Errorf("proto: wrong wireType = %d for field Datacenter", wireType) |
||||
} |
||||
var stringLen uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
stringLen |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
intStringLen := int(stringLen) |
||||
if intStringLen < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
postIndex := iNdEx + intStringLen |
||||
if postIndex < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if postIndex > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.Datacenter = string(dAtA[iNdEx:postIndex]) |
||||
iNdEx = postIndex |
||||
case 2: |
||||
if wireType != 2 { |
||||
return fmt.Errorf("proto: wrong wireType = %d for field Node", wireType) |
||||
} |
||||
var stringLen uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
stringLen |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
intStringLen := int(stringLen) |
||||
if intStringLen < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
postIndex := iNdEx + intStringLen |
||||
if postIndex < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if postIndex > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.Node = string(dAtA[iNdEx:postIndex]) |
||||
iNdEx = postIndex |
||||
case 4: |
||||
if wireType != 2 { |
||||
return fmt.Errorf("proto: wrong wireType = %d for field Segment", wireType) |
||||
} |
||||
var stringLen uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
stringLen |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
intStringLen := int(stringLen) |
||||
if intStringLen < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
postIndex := iNdEx + intStringLen |
||||
if postIndex < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if postIndex > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.Segment = string(dAtA[iNdEx:postIndex]) |
||||
iNdEx = postIndex |
||||
case 5: |
||||
if wireType != 2 { |
||||
return fmt.Errorf("proto: wrong wireType = %d for field JWT", wireType) |
||||
} |
||||
var stringLen uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
stringLen |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
intStringLen := int(stringLen) |
||||
if intStringLen < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
postIndex := iNdEx + intStringLen |
||||
if postIndex < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if postIndex > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.JWT = string(dAtA[iNdEx:postIndex]) |
||||
iNdEx = postIndex |
||||
case 6: |
||||
if wireType != 2 { |
||||
return fmt.Errorf("proto: wrong wireType = %d for field ConsulToken", wireType) |
||||
} |
||||
var stringLen uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
stringLen |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
intStringLen := int(stringLen) |
||||
if intStringLen < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
postIndex := iNdEx + intStringLen |
||||
if postIndex < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if postIndex > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.ConsulToken = string(dAtA[iNdEx:postIndex]) |
||||
iNdEx = postIndex |
||||
default: |
||||
iNdEx = preIndex |
||||
skippy, err := skipAutoConfig(dAtA[iNdEx:]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if skippy < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if (iNdEx + skippy) < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if (iNdEx + skippy) > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) |
||||
iNdEx += skippy |
||||
} |
||||
} |
||||
|
||||
if iNdEx > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
return nil |
||||
} |
||||
func (m *AutoConfigResponse) Unmarshal(dAtA []byte) error { |
||||
l := len(dAtA) |
||||
iNdEx := 0 |
||||
for iNdEx < l { |
||||
preIndex := iNdEx |
||||
var wire uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
wire |= uint64(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
fieldNum := int32(wire >> 3) |
||||
wireType := int(wire & 0x7) |
||||
if wireType == 4 { |
||||
return fmt.Errorf("proto: AutoConfigResponse: wiretype end group for non-group") |
||||
} |
||||
if fieldNum <= 0 { |
||||
return fmt.Errorf("proto: AutoConfigResponse: illegal tag %d (wire type %d)", fieldNum, wire) |
||||
} |
||||
switch fieldNum { |
||||
case 1: |
||||
if wireType != 2 { |
||||
return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType) |
||||
} |
||||
var msglen int |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
msglen |= int(b&0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
if msglen < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
postIndex := iNdEx + msglen |
||||
if postIndex < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if postIndex > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
if m.Config == nil { |
||||
m.Config = &config.Config{} |
||||
} |
||||
if err := m.Config.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { |
||||
return err |
||||
} |
||||
iNdEx = postIndex |
||||
default: |
||||
iNdEx = preIndex |
||||
skippy, err := skipAutoConfig(dAtA[iNdEx:]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if skippy < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if (iNdEx + skippy) < 0 { |
||||
return ErrInvalidLengthAutoConfig |
||||
} |
||||
if (iNdEx + skippy) > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) |
||||
iNdEx += skippy |
||||
} |
||||
} |
||||
|
||||
if iNdEx > l { |
||||
return io.ErrUnexpectedEOF |
||||
} |
||||
return nil |
||||
} |
||||
func skipAutoConfig(dAtA []byte) (n int, err error) { |
||||
l := len(dAtA) |
||||
iNdEx := 0 |
||||
for iNdEx < l { |
||||
var wire uint64 |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return 0, ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return 0, io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
wire |= (uint64(b) & 0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
wireType := int(wire & 0x7) |
||||
switch wireType { |
||||
case 0: |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return 0, ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return 0, io.ErrUnexpectedEOF |
||||
} |
||||
iNdEx++ |
||||
if dAtA[iNdEx-1] < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
return iNdEx, nil |
||||
case 1: |
||||
iNdEx += 8 |
||||
return iNdEx, nil |
||||
case 2: |
||||
var length int |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return 0, ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return 0, io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
length |= (int(b) & 0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
if length < 0 { |
||||
return 0, ErrInvalidLengthAutoConfig |
||||
} |
||||
iNdEx += length |
||||
if iNdEx < 0 { |
||||
return 0, ErrInvalidLengthAutoConfig |
||||
} |
||||
return iNdEx, nil |
||||
case 3: |
||||
for { |
||||
var innerWire uint64 |
||||
var start int = iNdEx |
||||
for shift := uint(0); ; shift += 7 { |
||||
if shift >= 64 { |
||||
return 0, ErrIntOverflowAutoConfig |
||||
} |
||||
if iNdEx >= l { |
||||
return 0, io.ErrUnexpectedEOF |
||||
} |
||||
b := dAtA[iNdEx] |
||||
iNdEx++ |
||||
innerWire |= (uint64(b) & 0x7F) << shift |
||||
if b < 0x80 { |
||||
break |
||||
} |
||||
} |
||||
innerWireType := int(innerWire & 0x7) |
||||
if innerWireType == 4 { |
||||
break |
||||
} |
||||
next, err := skipAutoConfig(dAtA[start:]) |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
iNdEx = start + next |
||||
if iNdEx < 0 { |
||||
return 0, ErrInvalidLengthAutoConfig |
||||
} |
||||
} |
||||
return iNdEx, nil |
||||
case 4: |
||||
return iNdEx, nil |
||||
case 5: |
||||
iNdEx += 4 |
||||
return iNdEx, nil |
||||
default: |
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType) |
||||
} |
||||
} |
||||
panic("unreachable") |
||||
} |
||||
|
||||
var ( |
||||
ErrInvalidLengthAutoConfig = fmt.Errorf("proto: negative length found during unmarshaling") |
||||
ErrIntOverflowAutoConfig = fmt.Errorf("proto: integer overflow") |
||||
) |
@ -0,0 +1,36 @@
|
||||
syntax = "proto3"; |
||||
|
||||
package agentpb; |
||||
|
||||
option go_package = "github.com/hashicorp/consul/agent/agentpb"; |
||||
|
||||
import "agent/agentpb/config/config.proto"; |
||||
|
||||
// AutoConfigRequest is the data structure to be sent along with the |
||||
// Cluster.AutoConfig RPC |
||||
message AutoConfigRequest { |
||||
// Datacenter is the local datacenter name. This wont actually be set by clients |
||||
// but rather will be set by the servers to allow for forwarding to |
||||
// the leader. If it ever happens to be set and differs from the local datacenters |
||||
// name then an error should be returned. |
||||
string Datacenter = 1; |
||||
|
||||
// Node is the node name that the requester would like to assume |
||||
// the identity of. |
||||
string Node = 2; |
||||
|
||||
// Segment is the network segment that the requester would like to join |
||||
string Segment = 4; |
||||
|
||||
// JWT is a signed JSON Web Token used to authorize the request |
||||
string JWT = 5; |
||||
|
||||
// ConsulToken is a Consul ACL token that the agent requesting the |
||||
// configuration already has. |
||||
string ConsulToken = 6; |
||||
} |
||||
|
||||
// AutoConfigResponse is the data structure sent in response to a Cluster.AutoConfig request |
||||
message AutoConfigResponse { |
||||
config.Config Config = 1; |
||||
} |
@ -0,0 +1,88 @@
|
||||
// Code generated by protoc-gen-go-binary. DO NOT EDIT.
|
||||
// source: agent/agentpb/config/config.proto
|
||||
|
||||
package config |
||||
|
||||
import ( |
||||
"github.com/golang/protobuf/proto" |
||||
) |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *Config) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *Config) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *Gossip) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *Gossip) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *GossipEncryption) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *GossipEncryption) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *TLS) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *TLS) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *ACL) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *ACL) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *ACLTokens) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *ACLTokens) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *ACLServiceProviderToken) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *ACLServiceProviderToken) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *AutoEncrypt) MarshalBinary() ([]byte, error) { |
||||
return proto.Marshal(msg) |
||||
} |
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *AutoEncrypt) UnmarshalBinary(b []byte) error { |
||||
return proto.Unmarshal(b, msg) |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@
|
||||
syntax = "proto3"; |
||||
|
||||
package config; |
||||
|
||||
option go_package = "github.com/hashicorp/consul/agent/agentpb/config"; |
||||
|
||||
message Config { |
||||
string Datacenter = 1; |
||||
string PrimaryDatacenter = 2; |
||||
string NodeName = 3; |
||||
string SegmentName = 4; |
||||
ACL ACL = 5; |
||||
AutoEncrypt AutoEncrypt = 6; |
||||
Gossip Gossip = 7; |
||||
TLS TLS = 8; |
||||
} |
||||
|
||||
message Gossip { |
||||
GossipEncryption Encryption = 1; |
||||
repeated string RetryJoinLAN = 2; |
||||
} |
||||
|
||||
message GossipEncryption { |
||||
string Key = 1; |
||||
bool VerifyIncoming = 2; |
||||
bool VerifyOutgoing = 3; |
||||
} |
||||
|
||||
message TLS { |
||||
bool VerifyOutgoing = 1; |
||||
bool VerifyServerHostname = 2; |
||||
string CipherSuites = 3; |
||||
string MinVersion = 4; |
||||
bool PreferServerCipherSuites = 5; |
||||
} |
||||
|
||||
message ACL { |
||||
bool Enabled = 1; |
||||
string PolicyTTL = 2; |
||||
string RoleTTL = 3; |
||||
string TokenTTL = 4; |
||||
string DownPolicy = 5; |
||||
string DefaultPolicy = 6; |
||||
bool EnableKeyListPolicy = 7; |
||||
ACLTokens Tokens = 8; |
||||
string DisabledTTL = 9; |
||||
bool EnableTokenPersistence = 10; |
||||
bool MSPDisableBootstrap = 11; |
||||
} |
||||
|
||||
message ACLTokens { |
||||
string Master = 1; |
||||
string Replication = 2; |
||||
string AgentMaster = 3; |
||||
string Default = 4; |
||||
string Agent = 5; |
||||
repeated ACLServiceProviderToken ManagedServiceProvider = 6; |
||||
} |
||||
|
||||
message ACLServiceProviderToken { |
||||
string AccessorID = 1; |
||||
string SecretID = 2; |
||||
} |
||||
|
||||
message AutoEncrypt { |
||||
bool TLS = 1; |
||||
repeated string DNSSAN = 2; |
||||
repeated string IPSAN = 3; |
||||
bool AllowTLS = 4; |
||||
} |
@ -0,0 +1,312 @@
|
||||
package consul |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/base64" |
||||
"fmt" |
||||
"net" |
||||
"time" |
||||
|
||||
"github.com/hashicorp/consul/acl" |
||||
"github.com/hashicorp/consul/agent/agentpb" |
||||
"github.com/hashicorp/consul/agent/agentpb/config" |
||||
"github.com/hashicorp/consul/agent/consul/authmethod/ssoauth" |
||||
"github.com/hashicorp/consul/agent/metadata" |
||||
"github.com/hashicorp/consul/agent/structs" |
||||
"github.com/hashicorp/consul/lib" |
||||
"github.com/hashicorp/consul/lib/template" |
||||
"github.com/hashicorp/consul/tlsutil" |
||||
bexpr "github.com/hashicorp/go-bexpr" |
||||
) |
||||
|
||||
type AutoConfigOptions struct { |
||||
NodeName string |
||||
SegmentName string |
||||
} |
||||
|
||||
type AutoConfigAuthorizer interface { |
||||
// Authorizes the request and returns a struct containing the various
|
||||
// options for how to generate the configuration.
|
||||
Authorize(*agentpb.AutoConfigRequest) (AutoConfigOptions, error) |
||||
} |
||||
|
||||
type disabledAuthorizer struct{} |
||||
|
||||
func (_ *disabledAuthorizer) Authorize(_ *agentpb.AutoConfigRequest) (AutoConfigOptions, error) { |
||||
return AutoConfigOptions{}, fmt.Errorf("Auto Config is disabled") |
||||
} |
||||
|
||||
type jwtAuthorizer struct { |
||||
validator *ssoauth.Validator |
||||
allowReuse bool |
||||
claimAssertions []string |
||||
} |
||||
|
||||
func (a *jwtAuthorizer) Authorize(req *agentpb.AutoConfigRequest) (AutoConfigOptions, error) { |
||||
// perform basic JWT Authorization
|
||||
identity, err := a.validator.ValidateLogin(context.Background(), req.JWT) |
||||
if err != nil { |
||||
// TODO (autoconf) maybe we should add a more generic permission denied error not tied to the ACL package?
|
||||
return AutoConfigOptions{}, acl.PermissionDenied("Failed JWT authorization: %v", err) |
||||
} |
||||
|
||||
varMap := map[string]string{ |
||||
"node": req.Node, |
||||
"segment": req.Segment, |
||||
} |
||||
|
||||
// TODO (autoconf) check for JWT reuse if configured to do so.
|
||||
for _, raw := range a.claimAssertions { |
||||
// validate and fill any HIL
|
||||
filled, err := template.InterpolateHIL(raw, varMap, true) |
||||
if err != nil { |
||||
return AutoConfigOptions{}, fmt.Errorf("Failed to render claim assertion template %q: %w", raw, err) |
||||
} |
||||
|
||||
evaluator, err := bexpr.CreateEvaluatorForType(filled, nil, identity.SelectableFields) |
||||
if err != nil { |
||||
return AutoConfigOptions{}, fmt.Errorf("Failed to create evaluator for claim assertion %q: %w", filled, err) |
||||
} |
||||
|
||||
ok, err := evaluator.Evaluate(identity.SelectableFields) |
||||
if err != nil { |
||||
return AutoConfigOptions{}, fmt.Errorf("Failed to execute claim assertion %q: %w", filled, err) |
||||
} |
||||
|
||||
if !ok { |
||||
return AutoConfigOptions{}, acl.PermissionDenied("Failed JWT claim assertion") |
||||
} |
||||
} |
||||
|
||||
return AutoConfigOptions{ |
||||
NodeName: req.Node, |
||||
SegmentName: req.Segment, |
||||
}, nil |
||||
} |
||||
|
||||
// Cluster endpoint is used for cluster configuration operations
|
||||
type Cluster struct { |
||||
srv *Server |
||||
|
||||
authorizer AutoConfigAuthorizer |
||||
} |
||||
|
||||
// updateTLSCertificatesInConfig will ensure that the TLS settings regarding how an agent is
|
||||
// made aware of its certificates are populated. This will only work if connect is enabled and
|
||||
// in some cases only if auto_encrypt is enabled on the servers. This endpoint has the option
|
||||
// to configure auto_encrypt or potentially in the future to generate the certificates inline.
|
||||
func (c *Cluster) updateTLSCertificatesInConfig(opts AutoConfigOptions, conf *config.Config) error { |
||||
if c.srv.config.AutoEncryptAllowTLS { |
||||
conf.AutoEncrypt = &config.AutoEncrypt{TLS: true} |
||||
} else { |
||||
conf.AutoEncrypt = &config.AutoEncrypt{TLS: false} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// updateACLtokensInConfig will configure all of the agents ACL settings and will populate
|
||||
// the configuration with an agent token usable for all default agent operations.
|
||||
func (c *Cluster) updateACLsInConfig(opts AutoConfigOptions, conf *config.Config) error { |
||||
acl := &config.ACL{ |
||||
Enabled: c.srv.config.ACLsEnabled, |
||||
PolicyTTL: c.srv.config.ACLPolicyTTL.String(), |
||||
RoleTTL: c.srv.config.ACLRoleTTL.String(), |
||||
TokenTTL: c.srv.config.ACLTokenTTL.String(), |
||||
DisabledTTL: c.srv.config.ACLDisabledTTL.String(), |
||||
DownPolicy: c.srv.config.ACLDownPolicy, |
||||
DefaultPolicy: c.srv.config.ACLDefaultPolicy, |
||||
EnableKeyListPolicy: c.srv.config.ACLEnableKeyListPolicy, |
||||
} |
||||
|
||||
// when ACLs are enabled we want to create a local token with a node identity
|
||||
if c.srv.config.ACLsEnabled { |
||||
// we have to require local tokens or else it would require having these servers use a token with acl:write to make a
|
||||
// token create RPC to the servers in the primary DC.
|
||||
if !c.srv.LocalTokensEnabled() { |
||||
return fmt.Errorf("Agent Auto Configuration requires local token usage to be enabled in this datacenter: %s", c.srv.config.Datacenter) |
||||
} |
||||
|
||||
// generate the accessor id
|
||||
accessor, err := lib.GenerateUUID(c.srv.checkTokenUUID) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
// generate the secret id
|
||||
secret, err := lib.GenerateUUID(c.srv.checkTokenUUID) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// set up the token
|
||||
token := structs.ACLToken{ |
||||
AccessorID: accessor, |
||||
SecretID: secret, |
||||
Description: fmt.Sprintf("Auto Config Token for Node %q", opts.NodeName), |
||||
CreateTime: time.Now(), |
||||
Local: true, |
||||
NodeIdentities: []*structs.ACLNodeIdentity{ |
||||
{ |
||||
NodeName: opts.NodeName, |
||||
Datacenter: c.srv.config.Datacenter, |
||||
}, |
||||
}, |
||||
EnterpriseMeta: *structs.DefaultEnterpriseMeta(), |
||||
} |
||||
|
||||
req := structs.ACLTokenBatchSetRequest{ |
||||
Tokens: structs.ACLTokens{&token}, |
||||
CAS: false, |
||||
} |
||||
|
||||
// perform the request to mint the new token
|
||||
if _, err := c.srv.raftApplyMsgpack(structs.ACLTokenSetRequestType, &req); err != nil { |
||||
return err |
||||
} |
||||
|
||||
acl.Tokens = &config.ACLTokens{Agent: secret} |
||||
} |
||||
|
||||
conf.ACL = acl |
||||
return nil |
||||
} |
||||
|
||||
// updateJoinAddressesInConfig determines the correct gossip endpoints that clients should
|
||||
// be connecting to for joining the cluster based on the segment given in the opts parameter.
|
||||
func (c *Cluster) updateJoinAddressesInConfig(opts AutoConfigOptions, conf *config.Config) error { |
||||
members, err := c.srv.LANSegmentMembers(opts.SegmentName) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var joinAddrs []string |
||||
for _, m := range members { |
||||
if ok, _ := metadata.IsConsulServer(m); ok { |
||||
serfAddr := net.TCPAddr{IP: m.Addr, Port: int(m.Port)} |
||||
joinAddrs = append(joinAddrs, serfAddr.String()) |
||||
} |
||||
} |
||||
|
||||
if conf.Gossip == nil { |
||||
conf.Gossip = &config.Gossip{} |
||||
} |
||||
|
||||
conf.Gossip.RetryJoinLAN = joinAddrs |
||||
return nil |
||||
} |
||||
|
||||
// updateGossipEncryptionInConfig will populate the gossip encryption configuration settings
|
||||
func (c *Cluster) updateGossipEncryptionInConfig(_ AutoConfigOptions, conf *config.Config) error { |
||||
// Add gossip encryption settings if there is any key loaded
|
||||
memberlistConfig := c.srv.config.SerfLANConfig.MemberlistConfig |
||||
if lanKeyring := memberlistConfig.Keyring; lanKeyring != nil { |
||||
if conf.Gossip == nil { |
||||
conf.Gossip = &config.Gossip{} |
||||
} |
||||
if conf.Gossip.Encryption == nil { |
||||
conf.Gossip.Encryption = &config.GossipEncryption{} |
||||
} |
||||
|
||||
pk := lanKeyring.GetPrimaryKey() |
||||
if len(pk) > 0 { |
||||
conf.Gossip.Encryption.Key = base64.StdEncoding.EncodeToString(pk) |
||||
} |
||||
|
||||
conf.Gossip.Encryption.VerifyIncoming = memberlistConfig.GossipVerifyIncoming |
||||
conf.Gossip.Encryption.VerifyOutgoing = memberlistConfig.GossipVerifyOutgoing |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// updateTLSSettingsInConfig will populate the TLS configuration settings but will not
|
||||
// populate leaf or ca certficiates.
|
||||
func (c *Cluster) updateTLSSettingsInConfig(_ AutoConfigOptions, conf *config.Config) error { |
||||
// add in TLS configuration
|
||||
if conf.TLS == nil { |
||||
conf.TLS = &config.TLS{} |
||||
} |
||||
conf.TLS.VerifyServerHostname = c.srv.tlsConfigurator.VerifyServerHostname() |
||||
base := c.srv.tlsConfigurator.Base() |
||||
conf.TLS.VerifyOutgoing = base.VerifyOutgoing |
||||
conf.TLS.MinVersion = base.TLSMinVersion |
||||
conf.TLS.PreferServerCipherSuites = base.PreferServerCipherSuites |
||||
|
||||
var err error |
||||
conf.TLS.CipherSuites, err = tlsutil.CipherString(base.CipherSuites) |
||||
return err |
||||
} |
||||
|
||||
// baseConfig will populate the configuration with some base settings such as the
|
||||
// datacenter names, node name etc.
|
||||
func (c *Cluster) baseConfig(opts AutoConfigOptions, conf *config.Config) error { |
||||
if opts.NodeName == "" { |
||||
return fmt.Errorf("Cannot generate auto config response without a node name") |
||||
} |
||||
|
||||
conf.Datacenter = c.srv.config.Datacenter |
||||
conf.PrimaryDatacenter = c.srv.config.PrimaryDatacenter |
||||
conf.NodeName = opts.NodeName |
||||
conf.SegmentName = opts.SegmentName |
||||
|
||||
return nil |
||||
} |
||||
|
||||
type autoConfigUpdater func(c *Cluster, opts AutoConfigOptions, conf *config.Config) error |
||||
|
||||
var ( |
||||
// variable holding the list of config updating functions to execute when generating
|
||||
// the auto config response. This will allow for more easily adding extra self-contained
|
||||
// configurators here in the future.
|
||||
autoConfigUpdaters []autoConfigUpdater = []autoConfigUpdater{ |
||||
(*Cluster).baseConfig, |
||||
(*Cluster).updateJoinAddressesInConfig, |
||||
(*Cluster).updateGossipEncryptionInConfig, |
||||
(*Cluster).updateTLSSettingsInConfig, |
||||
(*Cluster).updateACLsInConfig, |
||||
(*Cluster).updateTLSCertificatesInConfig, |
||||
} |
||||
) |
||||
|
||||
// AgentAutoConfig will authorize the incoming request and then generate the configuration
|
||||
// to push down to the client
|
||||
func (c *Cluster) AutoConfig(req *agentpb.AutoConfigRequest, resp *agentpb.AutoConfigResponse) error { |
||||
// default the datacenter to our datacenter - agents do not have to specify this as they may not
|
||||
// yet know the datacenter name they are going to be in.
|
||||
if req.Datacenter == "" { |
||||
req.Datacenter = c.srv.config.Datacenter |
||||
} |
||||
|
||||
// TODO (autoconf) Is performing auto configuration over the WAN really a bad idea?
|
||||
if req.Datacenter != c.srv.config.Datacenter { |
||||
return fmt.Errorf("invalid datacenter %q - agent auto configuration cannot target a remote datacenter", req.Datacenter) |
||||
} |
||||
|
||||
// forward to the leader
|
||||
if done, err := c.srv.forward("Cluster.AutoConfig", req, req, resp); done { |
||||
return err |
||||
} |
||||
|
||||
// TODO (autoconf) maybe panic instead?
|
||||
if c.authorizer == nil { |
||||
return fmt.Errorf("No Auto Config authorizer is configured") |
||||
} |
||||
|
||||
// authorize the request with the configured authorizer
|
||||
opts, err := c.authorizer.Authorize(req) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
conf := &config.Config{} |
||||
|
||||
// update all the configurations
|
||||
for _, configFn := range autoConfigUpdaters { |
||||
if err := configFn(c, opts, conf); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
resp.Config = conf |
||||
return nil |
||||
} |
@ -0,0 +1,617 @@
|
||||
package consul |
||||
|
||||
import ( |
||||
"encoding/base64" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"math/rand" |
||||
"net" |
||||
"os" |
||||
"path" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/hashicorp/consul/agent/agentpb" |
||||
"github.com/hashicorp/consul/agent/agentpb/config" |
||||
"github.com/hashicorp/consul/agent/structs" |
||||
"github.com/hashicorp/consul/internal/go-sso/oidcauth/oidcauthtest" |
||||
"github.com/hashicorp/consul/sdk/testutil" |
||||
"github.com/hashicorp/consul/tlsutil" |
||||
"github.com/hashicorp/memberlist" |
||||
msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc" |
||||
"github.com/stretchr/testify/require" |
||||
|
||||
"gopkg.in/square/go-jose.v2/jwt" |
||||
) |
||||
|
||||
func testJWTStandardClaims() jwt.Claims { |
||||
now := time.Now() |
||||
|
||||
return jwt.Claims{ |
||||
Subject: "consul", |
||||
Issuer: "consul", |
||||
Audience: jwt.Audience{"consul"}, |
||||
NotBefore: jwt.NewNumericDate(now.Add(-1 * time.Second)), |
||||
Expiry: jwt.NewNumericDate(now.Add(10 * time.Minute)), |
||||
} |
||||
} |
||||
|
||||
func signJWT(t *testing.T, privKey string, claims jwt.Claims, privateClaims interface{}) string { |
||||
t.Helper() |
||||
token, err := oidcauthtest.SignJWT(privKey, claims, privateClaims) |
||||
require.NoError(t, err) |
||||
return token |
||||
} |
||||
|
||||
func signJWTWithStandardClaims(t *testing.T, privKey string, claims interface{}) string { |
||||
t.Helper() |
||||
return signJWT(t, privKey, testJWTStandardClaims(), claims) |
||||
} |
||||
|
||||
// TestClusterAutoConfig is really an integration test of all the moving parts of the Cluster.AutoConfig RPC.
|
||||
// Full testing of the individual parts will not be done in this test:
|
||||
//
|
||||
// * Any implementations of the AutoConfigAuthorizer interface (although these test do use the jwtAuthorizer)
|
||||
// * Each of the individual config generation functions. These can be unit tested separately and many wont
|
||||
// require a running test server.
|
||||
func TestClusterAutoConfig(t *testing.T) { |
||||
type testCase struct { |
||||
request agentpb.AutoConfigRequest |
||||
expected agentpb.AutoConfigResponse |
||||
patchResponse func(t *testing.T, srv *Server, resp *agentpb.AutoConfigResponse) |
||||
err string |
||||
} |
||||
|
||||
gossipKey := make([]byte, 32) |
||||
// this is not cryptographic randomness and is not secure but for the sake of this test its all we need.
|
||||
n, err := rand.Read(gossipKey) |
||||
require.NoError(t, err) |
||||
require.Equal(t, 32, n) |
||||
|
||||
gossipKeyEncoded := base64.StdEncoding.EncodeToString(gossipKey) |
||||
|
||||
// generate a test certificate for the server serving out the insecure RPC
|
||||
cert, key, cacert, err := testTLSCertificates("server.dc1.consul") |
||||
require.NoError(t, err) |
||||
|
||||
// generate a JWT signer
|
||||
pub, priv, err := oidcauthtest.GenerateKey() |
||||
require.NoError(t, err) |
||||
|
||||
_, altpriv, err := oidcauthtest.GenerateKey() |
||||
require.NoError(t, err) |
||||
|
||||
cases := map[string]testCase{ |
||||
"wrong-datacenter": { |
||||
request: agentpb.AutoConfigRequest{ |
||||
Datacenter: "no-such-dc", |
||||
}, |
||||
err: `invalid datacenter "no-such-dc" - agent auto configuration cannot target a remote datacenter`, |
||||
}, |
||||
"unverifiable": { |
||||
request: agentpb.AutoConfigRequest{ |
||||
Node: "test-node", |
||||
// this is signed using an incorrect private key
|
||||
JWT: signJWTWithStandardClaims(t, altpriv, map[string]interface{}{"consul_node_name": "test-node"}), |
||||
}, |
||||
err: "Permission denied: Failed JWT authorization: no known key successfully validated the token signature", |
||||
}, |
||||
"claim-assertion-failed": { |
||||
request: agentpb.AutoConfigRequest{ |
||||
Node: "test-node", |
||||
JWT: signJWTWithStandardClaims(t, priv, map[string]interface{}{"wrong_claim": "test-node"}), |
||||
}, |
||||
err: "Permission denied: Failed JWT claim assertion", |
||||
}, |
||||
"good": { |
||||
request: agentpb.AutoConfigRequest{ |
||||
Node: "test-node", |
||||
JWT: signJWTWithStandardClaims(t, priv, map[string]interface{}{"consul_node_name": "test-node"}), |
||||
}, |
||||
expected: agentpb.AutoConfigResponse{ |
||||
Config: &config.Config{ |
||||
Datacenter: "dc1", |
||||
PrimaryDatacenter: "dc1", |
||||
NodeName: "test-node", |
||||
AutoEncrypt: &config.AutoEncrypt{ |
||||
TLS: true, |
||||
}, |
||||
ACL: &config.ACL{ |
||||
Enabled: true, |
||||
PolicyTTL: "30s", |
||||
TokenTTL: "30s", |
||||
RoleTTL: "30s", |
||||
DisabledTTL: "0s", |
||||
DownPolicy: "extend-cache", |
||||
DefaultPolicy: "deny", |
||||
Tokens: &config.ACLTokens{ |
||||
Agent: "patched-secret", |
||||
}, |
||||
}, |
||||
Gossip: &config.Gossip{ |
||||
Encryption: &config.GossipEncryption{ |
||||
Key: gossipKeyEncoded, |
||||
VerifyIncoming: true, |
||||
VerifyOutgoing: true, |
||||
}, |
||||
}, |
||||
TLS: &config.TLS{ |
||||
VerifyOutgoing: true, |
||||
VerifyServerHostname: true, |
||||
MinVersion: "tls12", |
||||
PreferServerCipherSuites: true, |
||||
}, |
||||
}, |
||||
}, |
||||
patchResponse: func(t *testing.T, srv *Server, resp *agentpb.AutoConfigResponse) { |
||||
// we are expecting an ACL token but cannot check anything for equality
|
||||
// so here we check that it was set and overwrite it
|
||||
require.NotNil(t, resp.Config) |
||||
require.NotNil(t, resp.Config.ACL) |
||||
require.NotNil(t, resp.Config.ACL.Tokens) |
||||
require.NotEmpty(t, resp.Config.ACL.Tokens.Agent) |
||||
resp.Config.ACL.Tokens.Agent = "patched-secret" |
||||
|
||||
// we don't know the expected join address until we start up the test server
|
||||
joinAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: srv.config.SerfLANConfig.MemberlistConfig.AdvertisePort} |
||||
require.NotNil(t, resp.Config.Gossip) |
||||
require.Equal(t, []string{joinAddr.String()}, resp.Config.Gossip.RetryJoinLAN) |
||||
resp.Config.Gossip.RetryJoinLAN = nil |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
_, s, _ := testACLServerWithConfig(t, func(c *Config) { |
||||
c.Domain = "consul" |
||||
c.AutoConfigAuthzEnabled = true |
||||
c.AutoConfigAuthzAuthMethod = structs.ACLAuthMethod{ |
||||
Name: "Auth Config Authorizer", |
||||
Type: "jwt", |
||||
EnterpriseMeta: *structs.DefaultEnterpriseMeta(), |
||||
Config: map[string]interface{}{ |
||||
"BoundAudiences": []string{"consul"}, |
||||
"BoundIssuer": "consul", |
||||
"JWTValidationPubKeys": []string{pub}, |
||||
"ClaimMappings": map[string]string{ |
||||
"consul_node_name": "node", |
||||
}, |
||||
}, |
||||
} |
||||
c.AutoConfigAuthzClaimAssertions = []string{ |
||||
`value.node == "${node}"`, |
||||
} |
||||
c.AutoConfigAuthzAllowReuse = true |
||||
|
||||
cafile := path.Join(c.DataDir, "cacert.pem") |
||||
err := ioutil.WriteFile(cafile, []byte(cacert), 0600) |
||||
require.NoError(t, err) |
||||
|
||||
certfile := path.Join(c.DataDir, "cert.pem") |
||||
err = ioutil.WriteFile(certfile, []byte(cert), 0600) |
||||
require.NoError(t, err) |
||||
|
||||
keyfile := path.Join(c.DataDir, "key.pem") |
||||
err = ioutil.WriteFile(keyfile, []byte(key), 0600) |
||||
require.NoError(t, err) |
||||
|
||||
c.CAFile = cafile |
||||
c.CertFile = certfile |
||||
c.KeyFile = keyfile |
||||
c.VerifyOutgoing = true |
||||
c.VerifyIncoming = true |
||||
c.VerifyServerHostname = true |
||||
c.TLSMinVersion = "tls12" |
||||
c.TLSPreferServerCipherSuites = true |
||||
|
||||
c.ConnectEnabled = true |
||||
c.AutoEncryptAllowTLS = true |
||||
c.SerfLANConfig.MemberlistConfig.GossipVerifyIncoming = true |
||||
c.SerfLANConfig.MemberlistConfig.GossipVerifyOutgoing = true |
||||
|
||||
keyring, err := memberlist.NewKeyring(nil, gossipKey) |
||||
require.NoError(t, err) |
||||
c.SerfLANConfig.MemberlistConfig.Keyring = keyring |
||||
}, false) |
||||
|
||||
conf := tlsutil.Config{ |
||||
CAFile: s.config.CAFile, |
||||
VerifyServerHostname: s.config.VerifyServerHostname, |
||||
VerifyOutgoing: s.config.VerifyOutgoing, |
||||
Domain: s.config.Domain, |
||||
} |
||||
codec, err := insecureRPCClient(s, conf) |
||||
require.NoError(t, err) |
||||
|
||||
waitForLeaderEstablishment(t, s) |
||||
|
||||
for testName, tcase := range cases { |
||||
t.Run(testName, func(t *testing.T) { |
||||
var reply agentpb.AutoConfigResponse |
||||
err := msgpackrpc.CallWithCodec(codec, "Cluster.AutoConfig", &tcase.request, &reply) |
||||
if tcase.err != "" { |
||||
testutil.RequireErrorContains(t, err, tcase.err) |
||||
} else { |
||||
require.NoError(t, err) |
||||
if tcase.patchResponse != nil { |
||||
tcase.patchResponse(t, s, &reply) |
||||
} |
||||
require.Equal(t, tcase.expected, reply) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestClusterAutoConfig_baseConfig(t *testing.T) { |
||||
type testCase struct { |
||||
serverConfig Config |
||||
opts AutoConfigOptions |
||||
expected config.Config |
||||
err string |
||||
} |
||||
|
||||
cases := map[string]testCase{ |
||||
"ok": { |
||||
serverConfig: Config{ |
||||
Datacenter: "oSWzfhnU", |
||||
PrimaryDatacenter: "53XO9mx4", |
||||
}, |
||||
opts: AutoConfigOptions{ |
||||
NodeName: "lBdc0lsH", |
||||
SegmentName: "HZiwlWpi", |
||||
}, |
||||
expected: config.Config{ |
||||
Datacenter: "oSWzfhnU", |
||||
PrimaryDatacenter: "53XO9mx4", |
||||
NodeName: "lBdc0lsH", |
||||
SegmentName: "HZiwlWpi", |
||||
}, |
||||
}, |
||||
"no-node-name": { |
||||
serverConfig: Config{ |
||||
Datacenter: "oSWzfhnU", |
||||
PrimaryDatacenter: "53XO9mx4", |
||||
}, |
||||
err: "Cannot generate auto config response without a node name", |
||||
}, |
||||
} |
||||
|
||||
for name, tcase := range cases { |
||||
t.Run(name, func(t *testing.T) { |
||||
cluster := Cluster{ |
||||
srv: &Server{ |
||||
config: &tcase.serverConfig, |
||||
}, |
||||
} |
||||
|
||||
var actual config.Config |
||||
err := cluster.baseConfig(tcase.opts, &actual) |
||||
if tcase.err == "" { |
||||
require.NoError(t, err) |
||||
require.Equal(t, tcase.expected, actual) |
||||
} else { |
||||
testutil.RequireErrorContains(t, err, tcase.err) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestClusterAutoConfig_updateTLSSettingsInConfig(t *testing.T) { |
||||
_, _, cacert, err := testTLSCertificates("server.dc1.consul") |
||||
require.NoError(t, err) |
||||
|
||||
dir := testutil.TempDir(t, "auto-config-tls-settings") |
||||
t.Cleanup(func() { os.RemoveAll(dir) }) |
||||
|
||||
cafile := path.Join(dir, "cacert.pem") |
||||
err = ioutil.WriteFile(cafile, []byte(cacert), 0600) |
||||
require.NoError(t, err) |
||||
|
||||
parseCiphers := func(t *testing.T, cipherStr string) []uint16 { |
||||
t.Helper() |
||||
ciphers, err := tlsutil.ParseCiphers(cipherStr) |
||||
require.NoError(t, err) |
||||
return ciphers |
||||
} |
||||
|
||||
type testCase struct { |
||||
tlsConfig tlsutil.Config |
||||
expected config.Config |
||||
} |
||||
|
||||
cases := map[string]testCase{ |
||||
"secure": { |
||||
tlsConfig: tlsutil.Config{ |
||||
VerifyOutgoing: true, |
||||
VerifyServerHostname: true, |
||||
TLSMinVersion: "tls12", |
||||
PreferServerCipherSuites: true, |
||||
CAFile: cafile, |
||||
CipherSuites: parseCiphers(t, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"), |
||||
}, |
||||
expected: config.Config{ |
||||
TLS: &config.TLS{ |
||||
VerifyOutgoing: true, |
||||
VerifyServerHostname: true, |
||||
MinVersion: "tls12", |
||||
PreferServerCipherSuites: true, |
||||
CipherSuites: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", |
||||
}, |
||||
}, |
||||
}, |
||||
"less-secure": { |
||||
tlsConfig: tlsutil.Config{ |
||||
VerifyOutgoing: true, |
||||
VerifyServerHostname: false, |
||||
TLSMinVersion: "tls10", |
||||
PreferServerCipherSuites: false, |
||||
CAFile: cafile, |
||||
CipherSuites: parseCiphers(t, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"), |
||||
}, |
||||
expected: config.Config{ |
||||
TLS: &config.TLS{ |
||||
VerifyOutgoing: true, |
||||
VerifyServerHostname: false, |
||||
MinVersion: "tls10", |
||||
PreferServerCipherSuites: false, |
||||
CipherSuites: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
for name, tcase := range cases { |
||||
t.Run(name, func(t *testing.T) { |
||||
logger := testutil.Logger(t) |
||||
configurator, err := tlsutil.NewConfigurator(tcase.tlsConfig, logger) |
||||
require.NoError(t, err) |
||||
|
||||
cluster := &Cluster{ |
||||
srv: &Server{ |
||||
tlsConfigurator: configurator, |
||||
}, |
||||
} |
||||
|
||||
var actual config.Config |
||||
err = cluster.updateTLSSettingsInConfig(AutoConfigOptions{}, &actual) |
||||
require.NoError(t, err) |
||||
require.Equal(t, tcase.expected, actual) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestAutoConfig_updateGossipEncryptionInConfig(t *testing.T) { |
||||
type testCase struct { |
||||
conf memberlist.Config |
||||
expected config.Config |
||||
} |
||||
|
||||
gossipKey := make([]byte, 32) |
||||
// this is not cryptographic randomness and is not secure but for the sake of this test its all we need.
|
||||
n, err := rand.Read(gossipKey) |
||||
require.NoError(t, err) |
||||
require.Equal(t, 32, n) |
||||
gossipKeyEncoded := base64.StdEncoding.EncodeToString(gossipKey) |
||||
|
||||
keyring, err := memberlist.NewKeyring(nil, gossipKey) |
||||
require.NoError(t, err) |
||||
|
||||
cases := map[string]testCase{ |
||||
"encryption-required": { |
||||
conf: memberlist.Config{ |
||||
Keyring: keyring, |
||||
GossipVerifyIncoming: true, |
||||
GossipVerifyOutgoing: true, |
||||
}, |
||||
expected: config.Config{ |
||||
Gossip: &config.Gossip{ |
||||
Encryption: &config.GossipEncryption{ |
||||
Key: gossipKeyEncoded, |
||||
VerifyIncoming: true, |
||||
VerifyOutgoing: true, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
"encryption-allowed": { |
||||
conf: memberlist.Config{ |
||||
Keyring: keyring, |
||||
GossipVerifyIncoming: false, |
||||
GossipVerifyOutgoing: false, |
||||
}, |
||||
expected: config.Config{ |
||||
Gossip: &config.Gossip{ |
||||
Encryption: &config.GossipEncryption{ |
||||
Key: gossipKeyEncoded, |
||||
VerifyIncoming: false, |
||||
VerifyOutgoing: false, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
"encryption-disabled": { |
||||
// zero values all around - if no keyring is configured then the gossip
|
||||
// encryption settings should not be set.
|
||||
}, |
||||
} |
||||
|
||||
for name, tcase := range cases { |
||||
t.Run(name, func(t *testing.T) { |
||||
cluster := Cluster{ |
||||
srv: &Server{ |
||||
config: DefaultConfig(), |
||||
}, |
||||
} |
||||
|
||||
cluster.srv.config.SerfLANConfig.MemberlistConfig = &tcase.conf |
||||
|
||||
var actual config.Config |
||||
err := cluster.updateGossipEncryptionInConfig(AutoConfigOptions{}, &actual) |
||||
require.NoError(t, err) |
||||
require.Equal(t, tcase.expected, actual) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestAutoConfig_updateTLSCertificatesInConfig(t *testing.T) { |
||||
type testCase struct { |
||||
serverConfig Config |
||||
expected config.Config |
||||
} |
||||
|
||||
cases := map[string]testCase{ |
||||
"auto_encrypt-enabled": { |
||||
serverConfig: Config{ |
||||
ConnectEnabled: true, |
||||
AutoEncryptAllowTLS: true, |
||||
}, |
||||
expected: config.Config{ |
||||
AutoEncrypt: &config.AutoEncrypt{TLS: true}, |
||||
}, |
||||
}, |
||||
"auto_encrypt-disabled": { |
||||
serverConfig: Config{ |
||||
ConnectEnabled: true, |
||||
AutoEncryptAllowTLS: false, |
||||
}, |
||||
expected: config.Config{ |
||||
AutoEncrypt: &config.AutoEncrypt{TLS: false}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
for name, tcase := range cases { |
||||
t.Run(name, func(t *testing.T) { |
||||
cluster := Cluster{ |
||||
srv: &Server{ |
||||
config: &tcase.serverConfig, |
||||
}, |
||||
} |
||||
|
||||
var actual config.Config |
||||
err := cluster.updateTLSCertificatesInConfig(AutoConfigOptions{}, &actual) |
||||
require.NoError(t, err) |
||||
require.Equal(t, tcase.expected, actual) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestAutoConfig_updateACLsInConfig(t *testing.T) { |
||||
type testCase struct { |
||||
patch func(c *Config) |
||||
expected config.Config |
||||
verify func(t *testing.T, c *config.Config) |
||||
err string |
||||
} |
||||
|
||||
cases := map[string]testCase{ |
||||
"enabled": { |
||||
patch: func(c *Config) { |
||||
c.ACLsEnabled = true |
||||
c.ACLPolicyTTL = 7 * time.Second |
||||
c.ACLRoleTTL = 10 * time.Second |
||||
c.ACLTokenTTL = 12 * time.Second |
||||
c.ACLDisabledTTL = 31 * time.Second |
||||
c.ACLDefaultPolicy = "allow" |
||||
c.ACLDownPolicy = "deny" |
||||
c.ACLEnableKeyListPolicy = true |
||||
}, |
||||
expected: config.Config{ |
||||
ACL: &config.ACL{ |
||||
Enabled: true, |
||||
PolicyTTL: "7s", |
||||
RoleTTL: "10s", |
||||
TokenTTL: "12s", |
||||
DisabledTTL: "31s", |
||||
DownPolicy: "deny", |
||||
DefaultPolicy: "allow", |
||||
EnableKeyListPolicy: true, |
||||
Tokens: &config.ACLTokens{Agent: "verified"}, |
||||
}, |
||||
}, |
||||
verify: func(t *testing.T, c *config.Config) { |
||||
t.Helper() |
||||
// the agent token secret is non-deterministically generated
|
||||
// So we want to validate that one was set and overwrite with
|
||||
// a value that the expected configurate wants.
|
||||
require.NotNil(t, c) |
||||
require.NotNil(t, c.ACL) |
||||
require.NotNil(t, c.ACL.Tokens) |
||||
require.NotEmpty(t, c.ACL.Tokens.Agent) |
||||
c.ACL.Tokens.Agent = "verified" |
||||
}, |
||||
}, |
||||
"disabled": { |
||||
patch: func(c *Config) { |
||||
c.ACLsEnabled = false |
||||
c.ACLPolicyTTL = 7 * time.Second |
||||
c.ACLRoleTTL = 10 * time.Second |
||||
c.ACLTokenTTL = 12 * time.Second |
||||
c.ACLDisabledTTL = 31 * time.Second |
||||
c.ACLDefaultPolicy = "allow" |
||||
c.ACLDownPolicy = "deny" |
||||
c.ACLEnableKeyListPolicy = true |
||||
}, |
||||
expected: config.Config{ |
||||
ACL: &config.ACL{ |
||||
Enabled: false, |
||||
PolicyTTL: "7s", |
||||
RoleTTL: "10s", |
||||
TokenTTL: "12s", |
||||
DisabledTTL: "31s", |
||||
DownPolicy: "deny", |
||||
DefaultPolicy: "allow", |
||||
EnableKeyListPolicy: true, |
||||
}, |
||||
}, |
||||
}, |
||||
"local-tokens-disabled": { |
||||
patch: func(c *Config) { |
||||
c.PrimaryDatacenter = "somewhere else" |
||||
}, |
||||
err: "Agent Auto Configuration requires local token usage to be enabled in this datacenter", |
||||
}, |
||||
} |
||||
for name, tcase := range cases { |
||||
t.Run(name, func(t *testing.T) { |
||||
_, s, _ := testACLServerWithConfig(t, tcase.patch, false) |
||||
|
||||
waitForLeaderEstablishment(t, s) |
||||
|
||||
cluster := Cluster{srv: s} |
||||
|
||||
var actual config.Config |
||||
err := cluster.updateACLsInConfig(AutoConfigOptions{NodeName: "something"}, &actual) |
||||
if tcase.err != "" { |
||||
testutil.RequireErrorContains(t, err, tcase.err) |
||||
} else { |
||||
require.NoError(t, err) |
||||
if tcase.verify != nil { |
||||
tcase.verify(t, &actual) |
||||
} |
||||
require.Equal(t, tcase.expected, actual) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestAutoConfig_updateJoinAddressesInConfig(t *testing.T) { |
||||
conf := testClusterConfig{ |
||||
Datacenter: "primary", |
||||
Servers: 3, |
||||
} |
||||
|
||||
nodes := newTestCluster(t, &conf) |
||||
|
||||
cluster := Cluster{srv: nodes.Servers[0]} |
||||
|
||||
var actual config.Config |
||||
err := cluster.updateJoinAddressesInConfig(AutoConfigOptions{}, &actual) |
||||
require.NoError(t, err) |
||||
|
||||
var expected []string |
||||
for _, srv := range nodes.Servers { |
||||
expected = append(expected, fmt.Sprintf("127.0.0.1:%d", srv.config.SerfLANConfig.MemberlistConfig.BindPort)) |
||||
} |
||||
require.NotNil(t, actual.Gossip) |
||||
require.ElementsMatch(t, expected, actual.Gossip.RetryJoinLAN) |
||||
} |
Loading…
Reference in new issue