...

Source file src/github.com/google/s2a-go/s2a_options.go

Documentation: github.com/google/s2a-go

     1  /*
     2   *
     3   * Copyright 2021 Google LLC
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     https://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package s2a
    20  
    21  import (
    22  	"context"
    23  	"crypto/tls"
    24  	"errors"
    25  	"sync"
    26  
    27  	"github.com/google/s2a-go/fallback"
    28  	"github.com/google/s2a-go/stream"
    29  	"google.golang.org/grpc/credentials"
    30  
    31  	s2apb "github.com/google/s2a-go/internal/proto/common_go_proto"
    32  )
    33  
    34  // Identity is the interface for S2A identities.
    35  type Identity interface {
    36  	// Name returns the name of the identity.
    37  	Name() string
    38  }
    39  
    40  type spiffeID struct {
    41  	spiffeID string
    42  }
    43  
    44  func (s *spiffeID) Name() string { return s.spiffeID }
    45  
    46  // NewSpiffeID creates a SPIFFE ID from id.
    47  func NewSpiffeID(id string) Identity {
    48  	return &spiffeID{spiffeID: id}
    49  }
    50  
    51  type hostname struct {
    52  	hostname string
    53  }
    54  
    55  func (h *hostname) Name() string { return h.hostname }
    56  
    57  // NewHostname creates a hostname from name.
    58  func NewHostname(name string) Identity {
    59  	return &hostname{hostname: name}
    60  }
    61  
    62  type uid struct {
    63  	uid string
    64  }
    65  
    66  func (h *uid) Name() string { return h.uid }
    67  
    68  // NewUID creates a UID from name.
    69  func NewUID(name string) Identity {
    70  	return &uid{uid: name}
    71  }
    72  
    73  // VerificationModeType specifies the mode that S2A must use to verify the peer
    74  // certificate chain.
    75  type VerificationModeType int
    76  
    77  // Three types of verification modes.
    78  const (
    79  	Unspecified = iota
    80  	ConnectToGoogle
    81  	Spiffe
    82  )
    83  
    84  // ClientOptions contains the client-side options used to establish a secure
    85  // channel using the S2A handshaker service.
    86  type ClientOptions struct {
    87  	// TargetIdentities contains a list of allowed server identities. One of the
    88  	// target identities should match the peer identity in the handshake
    89  	// result; otherwise, the handshake fails.
    90  	TargetIdentities []Identity
    91  	// LocalIdentity is the local identity of the client application. If none is
    92  	// provided, then the S2A will choose the default identity, if one exists.
    93  	LocalIdentity Identity
    94  	// S2AAddress is the address of the S2A.
    95  	S2AAddress string
    96  	// Optional transport credentials.
    97  	// If set, this will be used for the gRPC connection to the S2A server.
    98  	TransportCreds credentials.TransportCredentials
    99  	// EnsureProcessSessionTickets waits for all session tickets to be sent to
   100  	// S2A before a process completes.
   101  	//
   102  	// This functionality is crucial for processes that complete very soon after
   103  	// using S2A to establish a TLS connection, but it can be ignored for longer
   104  	// lived processes.
   105  	//
   106  	// Usage example:
   107  	//   func main() {
   108  	//     var ensureProcessSessionTickets sync.WaitGroup
   109  	//     clientOpts := &s2a.ClientOptions{
   110  	//       EnsureProcessSessionTickets: &ensureProcessSessionTickets,
   111  	//       // Set other members.
   112  	//     }
   113  	//     creds, _ := s2a.NewClientCreds(clientOpts)
   114  	//     conn, _ := grpc.Dial(serverAddr, grpc.WithTransportCredentials(creds))
   115  	//     defer conn.Close()
   116  	//
   117  	//     // Make RPC call.
   118  	//
   119  	//     // The process terminates right after the RPC call ends.
   120  	//     // ensureProcessSessionTickets can be used to ensure resumption
   121  	//     // tickets are fully processed. If the process is long-lived, using
   122  	//     // ensureProcessSessionTickets is not necessary.
   123  	//     ensureProcessSessionTickets.Wait()
   124  	//   }
   125  	EnsureProcessSessionTickets *sync.WaitGroup
   126  	// If true, enables the use of legacy S2Av1.
   127  	EnableLegacyMode bool
   128  	// VerificationMode specifies the mode that S2A must use to verify the
   129  	// peer certificate chain.
   130  	VerificationMode VerificationModeType
   131  
   132  	// Optional fallback after dialing with S2A fails.
   133  	FallbackOpts *FallbackOptions
   134  
   135  	// Generates an S2AStream interface for talking to the S2A server.
   136  	getS2AStream func(ctx context.Context, s2av2Address string) (stream.S2AStream, error)
   137  
   138  	// Serialized user specified policy for server authorization.
   139  	serverAuthorizationPolicy []byte
   140  }
   141  
   142  // FallbackOptions prescribes the fallback logic that should be taken if the application fails to connect with S2A.
   143  type FallbackOptions struct {
   144  	// FallbackClientHandshakeFunc is used to specify fallback behavior when calling s2a.NewClientCreds().
   145  	// It will be called by ClientHandshake function, after handshake with S2A fails.
   146  	// s2a.NewClientCreds() ignores the other FallbackDialer field.
   147  	FallbackClientHandshakeFunc fallback.ClientHandshake
   148  
   149  	// FallbackDialer is used to specify fallback behavior when calling s2a.NewS2aDialTLSContextFunc().
   150  	// It passes in a custom fallback dialer and server address to use after dialing with S2A fails.
   151  	// s2a.NewS2aDialTLSContextFunc() ignores the other FallbackClientHandshakeFunc field.
   152  	FallbackDialer *FallbackDialer
   153  }
   154  
   155  // FallbackDialer contains a fallback tls.Dialer and a server address to connect to.
   156  type FallbackDialer struct {
   157  	// Dialer specifies a fallback tls.Dialer.
   158  	Dialer *tls.Dialer
   159  	// ServerAddr is used by Dialer to establish fallback connection.
   160  	ServerAddr string
   161  }
   162  
   163  // DefaultClientOptions returns the default client options.
   164  func DefaultClientOptions(s2aAddress string) *ClientOptions {
   165  	return &ClientOptions{
   166  		S2AAddress:       s2aAddress,
   167  		VerificationMode: ConnectToGoogle,
   168  	}
   169  }
   170  
   171  // ServerOptions contains the server-side options used to establish a secure
   172  // channel using the S2A handshaker service.
   173  type ServerOptions struct {
   174  	// LocalIdentities is the list of local identities that may be assumed by
   175  	// the server. If no local identity is specified, then the S2A chooses a
   176  	// default local identity, if one exists.
   177  	LocalIdentities []Identity
   178  	// S2AAddress is the address of the S2A.
   179  	S2AAddress string
   180  	// Optional transport credentials.
   181  	// If set, this will be used for the gRPC connection to the S2A server.
   182  	TransportCreds credentials.TransportCredentials
   183  	// If true, enables the use of legacy S2Av1.
   184  	EnableLegacyMode bool
   185  	// VerificationMode specifies the mode that S2A must use to verify the
   186  	// peer certificate chain.
   187  	VerificationMode VerificationModeType
   188  
   189  	// Generates an S2AStream interface for talking to the S2A server.
   190  	getS2AStream func(ctx context.Context, s2av2Address string) (stream.S2AStream, error)
   191  }
   192  
   193  // DefaultServerOptions returns the default server options.
   194  func DefaultServerOptions(s2aAddress string) *ServerOptions {
   195  	return &ServerOptions{
   196  		S2AAddress:       s2aAddress,
   197  		VerificationMode: ConnectToGoogle,
   198  	}
   199  }
   200  
   201  func toProtoIdentity(identity Identity) (*s2apb.Identity, error) {
   202  	if identity == nil {
   203  		return nil, nil
   204  	}
   205  	switch id := identity.(type) {
   206  	case *spiffeID:
   207  		return &s2apb.Identity{IdentityOneof: &s2apb.Identity_SpiffeId{SpiffeId: id.Name()}}, nil
   208  	case *hostname:
   209  		return &s2apb.Identity{IdentityOneof: &s2apb.Identity_Hostname{Hostname: id.Name()}}, nil
   210  	case *uid:
   211  		return &s2apb.Identity{IdentityOneof: &s2apb.Identity_Uid{Uid: id.Name()}}, nil
   212  	default:
   213  		return nil, errors.New("unrecognized identity type")
   214  	}
   215  }
   216  

View as plain text