Skip to content

Commit

Permalink
Merge branch 'main' into nfi-net5476-nightly-peering-integ
Browse files Browse the repository at this point in the history
  • Loading branch information
nfi-hashicorp authored Sep 6, 2023
2 parents eb66261 + 56917eb commit abbeab0
Show file tree
Hide file tree
Showing 41 changed files with 827 additions and 280 deletions.
6 changes: 6 additions & 0 deletions .changelog/18381.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:improvement
checks: It is now possible to configure agent TCP checks to use TLS with
optional server SNI and mutual authentication. To use TLS with a TCP check, the
check must enable the `tcp_use_tls` boolean. By default the agent will use the
TLS configuration in the `tls.default` stanza.
```
3 changes: 3 additions & 0 deletions .changelog/18667.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
api: Add support for listing ACL tokens by service name.
```
3 changes: 3 additions & 0 deletions .changelog/18668.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:breaking-change
audit-logging: **(Enterprise only)** allowing timestamp based filename only on rotation. initially the filename will be just file.json
```
8 changes: 4 additions & 4 deletions .github/scripts/get_runner_classes_windows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ set -euo pipefail
case "$GITHUB_REPOSITORY" in
*-enterprise)
# shellcheck disable=SC2129
echo "compute-small=['self-hosted', 'windows', 'small']" >>"$GITHUB_OUTPUT"
echo "compute-medium=['self-hosted', 'windows', 'medium']" >>"$GITHUB_OUTPUT"
echo "compute-large=['self-hosted', 'windows', 'large']" >>"$GITHUB_OUTPUT"
echo "compute-small=['self-hosted', 'ondemand', 'os=windows-2019']" >>"$GITHUB_OUTPUT"
echo "compute-medium=['self-hosted', 'ondemand', 'os=windows-2019']" >>"$GITHUB_OUTPUT"
echo "compute-large=['self-hosted', 'ondemand', 'os=windows-2019']" >>"$GITHUB_OUTPUT"
# m5d.8xlarge is equivalent to our xl custom runner in CE
echo "compute-xl=['self-hosted', 'ondemand', 'windows', 'type=m6a.2xlarge']" >>"$GITHUB_OUTPUT"
echo "compute-xl=['self-hosted', 'ondemand', 'os=windows-2019']" >>"$GITHUB_OUTPUT"
;;
*)
# shellcheck disable=SC2129
Expand Down
1 change: 1 addition & 0 deletions agent/acl_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ func (s *HTTPHandlers) ACLTokenList(resp http.ResponseWriter, req *http.Request)
args.Policy = req.URL.Query().Get("policy")
args.Role = req.URL.Query().Get("role")
args.AuthMethod = req.URL.Query().Get("authmethod")
args.ServiceName = req.URL.Query().Get("servicename")
if err := parseACLAuthMethodEnterpriseMeta(req, &args.ACLAuthMethodEnterpriseMeta); err != nil {
return nil, err
}
Expand Down
32 changes: 32 additions & 0 deletions agent/acl_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,38 @@ func TestACL_HTTP(t *testing.T) {
require.Error(t, err)
testutil.RequireErrorContains(t, err, "Only lowercase alphanumeric")
})

t.Run("Create with valid service identity", func(t *testing.T) {
tokenInput := &structs.ACLToken{
Description: "token for service identity sn1",
ServiceIdentities: []*structs.ACLServiceIdentity{
{
ServiceName: "sn1",
},
},
}

req, _ := http.NewRequest("PUT", "/v1/acl/token", jsonBody(tokenInput))
req.Header.Add("X-Consul-Token", "root")
resp := httptest.NewRecorder()
_, err := a.srv.ACLTokenCreate(resp, req)
require.NoError(t, err)
})

t.Run("List by ServiceName", func(t *testing.T) {
req, _ := http.NewRequest("GET", "/v1/acl/tokens?servicename=sn1", nil)
req.Header.Add("X-Consul-Token", "root")
resp := httptest.NewRecorder()
raw, err := a.srv.ACLTokenList(resp, req)
require.NoError(t, err)
tokens, ok := raw.(structs.ACLTokenListStubs)
require.True(t, ok)
require.Len(t, tokens, 1)
token := tokens[0]
require.Equal(t, "token for service identity sn1", token.Description)
require.Len(t, token.ServiceIdentities, 1)
require.Equal(t, "sn1", token.ServiceIdentities[0].ServiceName)
})
})
}

Expand Down
20 changes: 13 additions & 7 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -3066,14 +3066,20 @@ func (a *Agent) addCheck(check *structs.HealthCheck, chkType *structs.CheckType,
chkType.Interval = checks.MinInterval
}

var tlsClientConfig *tls.Config
if chkType.TCPUseTLS {
tlsClientConfig = a.tlsConfigurator.OutgoingTLSConfigForCheck(chkType.TLSSkipVerify, chkType.TLSServerName)
}

tcp := &checks.CheckTCP{
CheckID: cid,
ServiceID: sid,
TCP: chkType.TCP,
Interval: chkType.Interval,
Timeout: chkType.Timeout,
Logger: a.logger,
StatusHandler: statusHandler,
CheckID: cid,
ServiceID: sid,
TCP: chkType.TCP,
Interval: chkType.Interval,
Timeout: chkType.Timeout,
Logger: a.logger,
TLSClientConfig: tlsClientConfig,
StatusHandler: statusHandler,
}
tcp.Start()
a.checkTCPs[cid] = tcp
Expand Down
90 changes: 83 additions & 7 deletions agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/hashicorp/consul/agent/grpc-external/limiter"
"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/proxycfg-sources/local"
"github.com/hashicorp/consul/agent/xds"
proxytracker "github.com/hashicorp/consul/internal/mesh/proxy-tracker"
"io"
mathrand "math/rand"
"net"
"net/http"
Expand All @@ -34,6 +30,12 @@ import (
"testing"
"time"

"github.com/hashicorp/consul/agent/grpc-external/limiter"
"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/proxycfg-sources/local"
"github.com/hashicorp/consul/agent/xds"
proxytracker "github.com/hashicorp/consul/internal/mesh/proxy-tracker"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/google/tcpproxy"
Expand Down Expand Up @@ -973,6 +975,80 @@ func TestAgent_AddServiceWithH2CPINGCheck(t *testing.T) {
requireCheckExists(t, a, "test-h2cping-check")
}

func startMockTLSServer(t *testing.T) (addr string, closeFunc func() error) {
// Load certificates
cert, err := tls.LoadX509KeyPair("../test/key/ourdomain_server.cer", "../test/key/ourdomain_server.key")
require.NoError(t, err)
// Create a certificate pool
rootCertPool := x509.NewCertPool()
caCert, err := os.ReadFile("../test/ca/root.cer")
require.NoError(t, err)
rootCertPool.AppendCertsFromPEM(caCert)
// Configure TLS
config := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: rootCertPool,
}
// Start TLS server
ln, err := tls.Listen("tcp", "127.0.0.1:0", config)
require.NoError(t, err)
go func() {
for {
conn, err := ln.Accept()
if err != nil {
return
}
io.Copy(io.Discard, conn)
conn.Close()
}
}()
return ln.Addr().String(), ln.Close
}

func TestAgent_AddServiceWithTCPTLSCheck(t *testing.T) {
t.Parallel()
dataDir := testutil.TempDir(t, "agent")
a := NewTestAgent(t, `
data_dir = "`+dataDir+`"
enable_agent_tls_for_checks = true
datacenter = "dc1"
tls {
defaults {
ca_file = "../test/ca/root.cer"
cert_file = "../test/key/ourdomain_server.cer"
key_file = "../test/key/ourdomain_server.key"
}
}
`)
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
// Start mock TCP+TLS server
addr, closeServer := startMockTLSServer(t)
defer closeServer()
check := &structs.HealthCheck{
Node: "foo",
CheckID: "arbitraryTCPServerTLSCheck",
Name: "arbitraryTCPServerTLSCheck",
Status: api.HealthCritical,
}
chkType := &structs.CheckType{
TCP: addr,
TCPUseTLS: true,
TLSServerName: "server.dc1.consul",
Interval: 5 * time.Second,
}
err := a.AddCheck(check, chkType, false, "", ConfigSourceLocal)
require.NoError(t, err)
// Retry until the healthcheck is passing.
retry.Run(t, func(r *retry.R) {
status := getCheck(a, "arbitraryTCPServerTLSCheck")
if status.Status != api.HealthPassing {
r.Fatalf("bad: %v", status.Status)
}
})
}

func TestAgent_AddServiceNoExec(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
Expand Down Expand Up @@ -4308,7 +4384,7 @@ func TestAgent_consulConfig_RequestLimits(t *testing.T) {

t.Parallel()
hcl := `
limits {
limits {
request_limits {
mode = "enforcing"
read_rate = 8888
Expand Down Expand Up @@ -6278,7 +6354,7 @@ func TestAgent_scadaProvider(t *testing.T) {
},
Overrides: `
cloud {
resource_id = "organization/0b9de9a3-8403-4ca6-aba8-fca752f42100/project/0b9de9a3-8403-4ca6-aba8-fca752f42100/consul.cluster/0b9de9a3-8403-4ca6-aba8-fca752f42100"
resource_id = "organization/0b9de9a3-8403-4ca6-aba8-fca752f42100/project/0b9de9a3-8403-4ca6-aba8-fca752f42100/consul.cluster/0b9de9a3-8403-4ca6-aba8-fca752f42100"
client_id = "test"
client_secret = "test"
}`,
Expand Down
38 changes: 26 additions & 12 deletions agent/checks/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,19 +625,20 @@ func (c *CheckH2PING) Start() {
go c.run()
}

// CheckTCP is used to periodically make an TCP/UDP connection to
// determine the health of a given check.
// CheckTCP is used to periodically make a TCP connection to determine the
// health of a given check.
// The check is passing if the connection succeeds
// The check is critical if the connection returns an error
// Supports failures_before_critical and success_before_passing.
type CheckTCP struct {
CheckID structs.CheckID
ServiceID structs.ServiceID
TCP string
Interval time.Duration
Timeout time.Duration
Logger hclog.Logger
StatusHandler *StatusHandler
CheckID structs.CheckID
ServiceID structs.ServiceID
TCP string
Interval time.Duration
Timeout time.Duration
Logger hclog.Logger
TLSClientConfig *tls.Config
StatusHandler *StatusHandler

dialer *net.Dialer
stop bool
Expand Down Expand Up @@ -694,17 +695,30 @@ func (c *CheckTCP) run() {

// check is invoked periodically to perform the TCP check
func (c *CheckTCP) check() {
conn, err := c.dialer.Dial(`tcp`, c.TCP)
var conn io.Closer
var err error
var checkType string

if c.TLSClientConfig == nil {
conn, err = c.dialer.Dial(`tcp`, c.TCP)
checkType = "TCP"
} else {
conn, err = tls.DialWithDialer(c.dialer, `tcp`, c.TCP, c.TLSClientConfig)
checkType = "TCP+TLS"
}

if err != nil {
c.Logger.Warn("Check socket connection failed",
c.Logger.Warn(fmt.Sprintf("Check %s connection failed", checkType),
"check", c.CheckID.String(),
"error", err,
)
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
return
}

conn.Close()
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("TCP connect %s: Success", c.TCP))
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("%s connect %s: Success", checkType, c.TCP))

}

// CheckUDP is used to periodically send a UDP datagram to determine the health of a given check.
Expand Down
1 change: 1 addition & 0 deletions agent/config/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,7 @@ func (b *builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
Body: stringVal(v.Body),
DisableRedirects: boolVal(v.DisableRedirects),
TCP: stringVal(v.TCP),
TCPUseTLS: boolVal(v.TCPUseTLS),
UDP: stringVal(v.UDP),
Interval: b.durationVal(fmt.Sprintf("check[%s].interval", id), v.Interval),
DockerContainerID: stringVal(v.DockerContainerID),
Expand Down
1 change: 1 addition & 0 deletions agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ type CheckDefinition struct {
DisableRedirects *bool `mapstructure:"disable_redirects"`
OutputMaxSize *int `mapstructure:"output_max_size"`
TCP *string `mapstructure:"tcp"`
TCPUseTLS *bool `mapstructure:"tcp_use_tls"`
UDP *string `mapstructure:"udp"`
Interval *string `mapstructure:"interval"`
DockerContainerID *string `mapstructure:"docker_container_id" alias:"dockercontainerid"`
Expand Down
Loading

0 comments on commit abbeab0

Please sign in to comment.