connect

package
v1.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2018 License: MPL-2.0 Imports: 23 Imported by: 0

Documentation

Index

Examples

Constants

View Source
const (
	// ConsulResolverTypeService indicates resolving healthy service nodes.
	ConsulResolverTypeService int = iota

	// ConsulResolverTypePreparedQuery indicates resolving via prepared query.
	ConsulResolverTypePreparedQuery
)

Variables

This section is empty.

Functions

func CertURIFromConn

func CertURIFromConn(conn net.Conn) (connect.CertURI, error)

CertURIFromConn is a helper to extract the service identifier URI from a net.Conn. If the net.Conn is not a *tls.Conn then an error is always returned. If the *tls.Conn didn't present a valid connect certificate, or is not yet past the handshake, an error is returned.

func TestCAPool

func TestCAPool(t testing.T, cas ...*structs.CARoot) *x509.CertPool

TestCAPool returns an *x509.CertPool containing the passed CA's root(s)

func TestPeerCertificates

func TestPeerCertificates(t testing.T, service string, ca *structs.CARoot) []*x509.Certificate

TestPeerCertificates returns a []*x509.Certificate as you'd get from tls.Conn.ConnectionState().PeerCertificates including the named certificate.

func TestSvcKeyPair

func TestSvcKeyPair(t testing.T, service string, ca *structs.CARoot) tls.Certificate

TestSvcKeyPair returns an tls.Certificate containing both cert and private key for a given service under a given CA from the testdata dir.

func TestTLSConfig

func TestTLSConfig(t testing.T, service string, ca *structs.CARoot) *tls.Config

TestTLSConfig returns a *tls.Config suitable for use during tests.

Types

type ConsulResolver

type ConsulResolver struct {
	// Client is the Consul API client to use. Must be non-nil or Resolve will
	// panic.
	Client *api.Client

	// Namespace of the query target.
	Namespace string

	// Name of the query target.
	Name string

	// Type of the query target. Should be one of the defined ConsulResolverType*
	// constants. Currently defaults to ConsulResolverTypeService.
	Type int

	// Datacenter to resolve in, empty indicates agent's local DC.
	Datacenter string
	// contains filtered or unexported fields
}

ConsulResolver queries Consul for a service instance.

func (*ConsulResolver) Resolve

func (cr *ConsulResolver) Resolve(ctx context.Context) (string, connect.CertURI, error)

Resolve performs service discovery against the local Consul agent and returns the address and expected identity of a suitable service instance.

type Resolver

type Resolver interface {
	// Resolve returns a single service instance to connect to. Implementations
	// may attempt to ensure the instance returned is currently available. It is
	// expected that a client will re-dial on a connection failure so making an
	// effort to return a different service instance each time where available
	// increases reliability. The context passed can be used to impose timeouts
	// which may or may not be respected by implementations that make network
	// calls to resolve the service. The addr returned is a string in any valid
	// form for passing directly to `net.Dial("tcp", addr)`. The certURI
	// represents the identity of the service instance. It will be matched against
	// the TLS certificate URI SAN presented by the server and the connection
	// rejected if they don't match.
	Resolve(ctx context.Context) (addr string, certURI connect.CertURI, err error)
}

Resolver is the interface implemented by a service discovery mechanism to get the address and identity of an instance to connect to via Connect as a client.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service represents a Consul service that accepts and/or connects via Connect. This can represent a service that only is a server, only is a client, or both.

TODO(banks): Agent implicit health checks based on knowing which certs are available should prevent clients being routed until the agent knows the service has been delivered valid certificates. Once built, document that here too.

func NewDevServiceFromCertFiles

func NewDevServiceFromCertFiles(serviceID string, logger *log.Logger,
	caFile, certFile, keyFile string) (*Service, error)

NewDevServiceFromCertFiles creates a Service using certificate and key files passed instead of fetching them from the client.

func NewDevServiceWithTLSConfig

func NewDevServiceWithTLSConfig(serviceName string, logger *log.Logger,
	tlsCfg *tls.Config) (*Service, error)

NewDevServiceWithTLSConfig creates a Service using static TLS config passed. It's mostly useful for testing.

func NewService

func NewService(serviceName string, client *api.Client) (*Service, error)

NewService creates and starts a Service. The caller must close the returned service to free resources and allow the program to exit normally. This is typically called in a signal handler.

Caller must provide client which is already configured to speak to the local Consul agent, and with an ACL token that has `service:write` privileges for the service specified.

func NewServiceWithLogger

func NewServiceWithLogger(serviceName string, client *api.Client,
	logger *log.Logger) (*Service, error)

NewServiceWithLogger starts the service with a specified log.Logger.

func TestService

func TestService(t testing.T, service string, ca *structs.CARoot) *Service

TestService returns a Service instance based on a static TLS Config.

func (*Service) Close

func (s *Service) Close() error

Close stops the service and frees resources.

func (*Service) Dial

func (s *Service) Dial(ctx context.Context, resolver Resolver) (net.Conn, error)

Dial connects to a remote Connect-enabled server. The passed Resolver is used to discover a single candidate instance which will be dialled and have it's TLS certificate verified against the expected identity. Failures are returned directly with no retries. Repeated dials may use different instances depending on the Resolver implementation.

Timeout can be managed via the Context.

Calls to Dial made before the Service has loaded certificates from the agent will fail. You can prevent this by using Ready or ReadyWait in app during startup.

func (*Service) HTTPClient

func (s *Service) HTTPClient() *http.Client

HTTPClient returns an *http.Client configured to dial remote Consul Connect HTTP services. The client will return an error if attempting to make requests to a non HTTPS hostname. It resolves the domain of the request with the same syntax as Consul DNS queries although it performs discovery directly via the API rather than just relying on Consul DNS. Hostnames that are not valid Consul DNS queries will fail.

Example

Note: this assumes a suitable Consul ACL token with 'service:write' for service 'web' is set in CONSUL_HTTP_TOKEN ENV var.

client, _ := api.NewClient(api.DefaultConfig())
svc, _ := NewService("web", client)

httpClient := svc.HTTPClient()
resp, _ := httpClient.Get("https://web.service.consul/foo/bar")
handleResponse(resp)
Output:

func (*Service) HTTPDialTLS

func (s *Service) HTTPDialTLS(network,
	addr string) (net.Conn, error)

HTTPDialTLS is compatible with http.Transport.DialTLS. It expects the addr hostname to be specified using Consul DNS query syntax, e.g. "web.service.consul". It converts that into the equivalent ConsulResolver and then call s.Dial with the resolver. This is low level, clients should typically use HTTPClient directly.

func (*Service) Name

func (s *Service) Name() string

Name returns the name of the service this object represents. Note it is the service _name_ as used during discovery, not the ID used to uniquely identify an instance of the service with an agent.

func (*Service) Ready

func (s *Service) Ready() bool

Ready returns whether or not both roots and a leaf certificate are configured. If both are non-nil, they are assumed to be valid and usable.

func (*Service) ReadyWait

func (s *Service) ReadyWait() <-chan struct{}

ReadyWait returns a chan that is closed when the the Service becomes ready for use for the first time. Note that if the Service is ready when it is called it returns a nil chan. Ready means that it has root and leaf certificates configured which we assume are valid. The service may subsequently stop being "ready" if it's certificates expire or are revoked and an error prevents new ones being loaded but this method will not stop returning a nil chan in that case. It is only useful for initial startup. For ongoing health Ready() should be used.

func (*Service) ServerTLSConfig

func (s *Service) ServerTLSConfig() *tls.Config

ServerTLSConfig returns a *tls.Config that allows any TCP listener to accept and authorize incoming Connect clients. It will return a single static config with hooks to dynamically load certificates, and perform Connect authorization during verification. Service implementations do not need to reload this to get new certificates.

At any time it may be possible that the Service instance does not have access to usable certificates due to not being initially setup yet or a prolonged error during renewal. The listener will be able to accept connections again once connectivity is restored provided the client's Token is valid.

To prevent routing traffic to the app instance while it's certificates are invalid or not populated yet you may use Ready in a health check endpoint and/or ReadyWait during startup before starting the TLS listener. The latter only prevents connections during initial bootstrap (including permission issues where certs can never be issued due to bad credentials) but won't handle the case that certificates expire and an error prevents timely renewal.

Example (HTTP)

Note: this assumes a suitable Consul ACL token with 'service:write' for service 'web' is set in CONSUL_HTTP_TOKEN ENV var.

client, _ := api.NewClient(api.DefaultConfig())
svc, _ := NewService("web", client)
server := &http.Server{
	Addr:      ":8080",
	Handler:   apiHandler{},
	TLSConfig: svc.ServerTLSConfig(),
}
// Cert and key files are blank since the tls.Config will handle providing
// those dynamically.
log.Fatal(server.ListenAndServeTLS("", ""))
Output:

Example (TLS)

Note: this assumes a suitable Consul ACL token with 'service:write' for service 'web' is set in CONSUL_HTTP_TOKEN ENV var.

client, _ := api.NewClient(api.DefaultConfig())
svc, _ := NewService("web", client)
l, _ := tls.Listen("tcp", ":8080", svc.ServerTLSConfig())
acceptLoop(l)
Output:

type StaticResolver

type StaticResolver struct {
	// Addr is the network address (including port) of the instance. It must be
	// the connect-enabled mTLS listener and may be a proxy in front of the actual
	// target service process. It is a string in any valid form for passing
	// directly to net.Dial("tcp", addr).
	Addr string

	// CertURL is the identity we expect the server to present in it's TLS
	// certificate. It must be an exact URI string match or the connection will be
	// rejected.
	CertURI connect.CertURI
}

StaticResolver is a statically defined resolver. This can be used to Dial a known Connect endpoint without performing service discovery.

func (*StaticResolver) Resolve

func (sr *StaticResolver) Resolve(ctx context.Context) (string, connect.CertURI, error)

Resolve implements Resolver by returning the static values.

type TestServer

type TestServer struct {
	// The service name to serve.
	Service string
	// The (test) CA to use for generating certs.
	CA *structs.CARoot
	// TimeoutHandshake controls whether the listening server will complete a TLS
	// handshake quickly enough.
	TimeoutHandshake bool
	// TLSCfg is the tls.Config that will be used. By default it's set up from the
	// service and ca set.
	TLSCfg *tls.Config
	// Addr is the listen address. It is set to a random free port on `localhost`
	// by default.
	Addr string
	// Listening is closed when the listener is run.
	Listening chan struct{}
	// contains filtered or unexported fields
}

TestServer runs a service listener that can be used to test clients. It's behaviour can be controlled by the struct members.

func NewTestServer

func NewTestServer(t testing.T, service string, ca *structs.CARoot) *TestServer

NewTestServer returns a TestServer. It should be closed when test is complete.

func (*TestServer) Close

func (s *TestServer) Close() error

Close stops a TestServer

func (*TestServer) Serve

func (s *TestServer) Serve() error

Serve runs a tcp echo server and blocks until it is closed or errors. If TimeoutHandshake is set it won't start TLS handshake on new connections.

func (*TestServer) ServeHTTPS

func (s *TestServer) ServeHTTPS(h http.Handler) error

ServeHTTPS runs an HTTPS server with the given config. It invokes the passed Handler for all requests.

Directories

Path Synopsis
certgen: a tool for generating test certificates on disk for use as test-fixtures and for end-to-end testing and local development.
certgen: a tool for generating test certificates on disk for use as test-fixtures and for end-to-end testing and local development.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL