Documentation ¶
Overview ¶
Protocol provides a listener and dial function that can be used to easily integrate this library into other applications. An application can wrap its incoming listener with an InterceptingListener from this package, which will handle the connection iff the incoming TLS NextProto value is one known by this library, and it can have its dial function use this package for dialing. Either a connection will be returned or a (possibly temporary) error; on the application side, it merely needs to check the negotiated protocol in the returned tls.Conn to see if it matches the defined authentication proto (a fetch connection will _always_ return a (temporary) error). If so, the node is successfully authenticated.
Using this package is optional but encouraged when possible to avoid having to instrument logic directly within an app.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Dial ¶
func Dial( ctx context.Context, storage nodeenrollment.Storage, addr string, opt ...nodeenrollment.Option, ) (net.Conn, error)
Dial returns a function suitable for dialing a connection to an InterceptingListener. It takes in storage, an address, and options.
Supported options: WithRandomReader, WithStorageWrapper (passed through to LoadNodeCredentials and NodeCredentials.Store), WithNotBeforeClockSkew/WithNotAfterClockSkew (these are used as NotBefore/NotAfter lifetimes for the generated cert used for client side TLS), WithExtraAlpnProtos (passed through to the client side TLS configuration), WithActivationToken/WithRegistrationWrapper/WithWrappingRegistrationFlowApplicationSpecificParams (passed through to CreateFetchNodeCredentialsRequest)
Types ¶
type ClientInfo ¶ added in v0.1.5
type ClientInfo struct {
// contains filtered or unexported fields
}
ClientInfo allows us to pass information back from the TLS handshake
type Conn ¶ added in v0.1.5
Conn embeds a *tls.Conn and allows us to add extra bits into it
func NewConn ¶ added in v0.1.7
NewConn constructs a conn from a base TLS connection and possibly client next protos.
Supported options: WithExtraAlpnProtos (used to set clientNextProtos), WithState (storing client state information)
func (*Conn) ClientNextProtos ¶ added in v0.1.5
ClientNextProtos returns the value of NextProtos originally presented by the client at connection time
func (*Conn) ClientState ¶ added in v0.1.19
ClientState returns the value of the state embedded into the original client request, which may be nil
type FetchCredsFn ¶
type FetchCredsFn = func( context.Context, nodeenrollment.Storage, *types.FetchNodeCredentialsRequest, ...nodeenrollment.Option, ) (*types.FetchNodeCredentialsResponse, error)
FetchCredsFn is a function that is used when a node requests fetching its initial credentials. It returns a response or an error. This is called during TLS negotiation for the given ALPN proto.
Note that options do not carry across gRPC; in practice this means they do not carry across multiple nodes. Only options meant for local use (WithRandomReader, WithStorageWrapper, WithLogger) etc. should be used, via the direct functions.
type GenerateServerCertificatesFn ¶
type GenerateServerCertificatesFn = func( context.Context, nodeenrollment.Storage, *types.GenerateServerCertificatesRequest, ...nodeenrollment.Option, ) (*types.GenerateServerCertificatesResponse, error)
GenerateServerCertificatesFn is a function that is used when a node is connecting by the upstream node to fetch a certificate to present to the node. It returns a response or an error. This is called during TLS negotiation for the given ALPN proto.
Note that options do not carry across gRPC; in practice this means they do not carry across multiple nodes. Only options meant for local use (WithRandomReader, WithStorageWrapper, WithLogger) etc. should be used, via the direct functions.
type InterceptingListener ¶
type InterceptingListener struct {
// contains filtered or unexported fields
}
InterceptingListener is a listener that transparently handles fetch and auth flows if the right ALPN protos are found, and passes through otherwise
func NewInterceptingListener ¶
func NewInterceptingListener( config *InterceptingListenerConfiguration, ) (*InterceptingListener, error)
New creates a new listener based on the passed in listener (which should not be a TLS listener) and the given base TLS configuration. This function will substitute its own TLS configuration to handle the protos specific to nodeenrollment. Any connection coming in that is not using those protos will simply be passed through.
The context value is not used here, but simply passed through to other library functions. To stop the listener, close it normally.
func (*InterceptingListener) Accept ¶
func (l *InterceptingListener) Accept() (conn net.Conn, retErr error)
Accept accepts the next connection.
If the TLS protos is one of our known credential fetching/auth protos, we'll handle it. Otherwise we pass through.
You should check the resulting connection before trusting it. You can do that by seeing if the negotiated protocol was the auth protocol handled by this library:
if strings.HasPrefix( returnedConn.(*protocol.Conn).Conn.ConnectionState().NegotiatedProtocol, nodeenrollment.AuthenticateNodeNextProtoV1Prefix ) { // Authenticated by this library } else { // Not authenticated by this library }
There is also some special behavior around the errors that this function returns. For compatibility with listeners passed into gRPC servers, most errors satisfy a Temporary interface so that returning an error does not cause the gRPC server to shut down the listener, which should really only happen for system-level errors rather than connection-specific errors. For gRPC this should likely just work, but if you need to check if this is a true error in your own code, you can do this:
if tempErr, ok := err.(interface { Temporary() bool }); ok && tempErr.Temporary() {
If it's temporary, continue on and accept the next connection.
What's returned is a protocol.Conn; it contains an embedded *tls.Conn as the Conn variable, if needed.
func (*InterceptingListener) Addr ¶
func (l *InterceptingListener) Addr() net.Addr
Addr satisfies the net.Listener interface and simply returns the base listener's address
func (*InterceptingListener) Close ¶
func (l *InterceptingListener) Close() error
Close satisfies the net.Listener interface and closes the base listener
type InterceptingListenerConfiguration ¶
type InterceptingListenerConfiguration struct { // The context that will be used to call any functions once a connection is // accepted. Required. Context context.Context // The storage that will be used for any storage needs for connections. // Required. Storage nodeenrollment.Storage // The base listener to accept connections from and possibly intercept. // Required. BaseListener net.Listener // The TLS configuration to use if the incoming connection is not one // handled by this library. If nil, any connection not handled by this // library will be closed. BaseTlsConfiguration *tls.Config // The function to use for the FetchCredentials operation. If nil, the // default will be used, which is suitable for a server. FetchCredsFunc FetchCredsFn // The function to use for the GenerateServerCertificates operation. If nil, // the default will be used, which is suitable for a server. GenerateServerCertificatesFunc GenerateServerCertificatesFn // If provided, options to pass into various storage functions, e.g. // WithRandomReader, WithStorageWrapper, WithLogger, etc. Options []nodeenrollment.Option }
InterceptingListenerConfiguration contains config information for InterceptingListener