s2a_options.go 7.0 KB

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