github.com/outbrain/consul@v1.4.5/website/source/docs/connect/native/go.html.md (about)

     1  ---
     2  layout: "docs"
     3  page_title: "Connect - Native Application Integration - Go"
     4  sidebar_current: "docs-connect-native-go"
     5  description: |-
     6    We provide a library that makes it drop-in simple to integrate Connect with most Go applications. For most Go applications, Connect can be natively integrated in just a single line of code excluding imports and struct initialization.
     7  ---
     8  
     9  # Connect-Native Integration with Go
    10  
    11  We provide a library that makes it drop-in simple to integrate Connect
    12  with most [Go](https://golang.org/) applications. This page shows examples
    13  of integrating this library for accepting or establishing Connect-based
    14  connections. For most Go applications, Connect can be natively integrated
    15  in just a single line of code excluding imports and struct initialization.
    16  
    17  In addition to this, please read and understand the
    18  [overview of Connect-Native integrations](/docs/connect/native.html).
    19  In particular, after integrating applications with Connect, they must declare
    20  that they accept Connect-based connections via their service definitions.
    21  
    22  ## Accepting Connections
    23  
    24  Any server that supports TLS (HTTP, gRPC, net/rpc, etc.) can begin
    25  accepting Connect-based connections in just a few lines of code. For most
    26  existing applications, converting the server to accept Connect-based
    27  connections will require only a one-line change excluding imports and
    28  structure initialization.
    29  
    30  The
    31  Go library exposes a `*tls.Config` that _automatically_ communicates with
    32  Consul to load certificates and authorize inbound connections during the
    33  TLS handshake. This also automatically starts goroutines to update any
    34  changing certs.
    35  
    36  Example, followed by more details:
    37  
    38  ```go
    39  import(
    40    "net/http"
    41  
    42    "github.com/hashicorp/consul/api"
    43    "github.com/hashicorp/consul/connect"
    44  )
    45  
    46  func main() {
    47    // Create a Consul API client
    48    client, _ := api.NewClient(api.DefaultConfig())
    49  
    50    // Create an instance representing this service. "my-service" is the
    51    // name of _this_ service. The service should be cleaned up via Close.
    52    svc, _ := connect.NewService("my-service", client)
    53    defer svc.Close()
    54  
    55    // Creating an HTTP server that serves via Connect
    56    server := &http.Server{
    57      Addr:      ":8080",
    58      TLSConfig: svc.ServerTLSConfig(),
    59      // ... other standard fields
    60    }
    61  
    62    // Serve!
    63    server.ListenAndServeTLS("", "")
    64  }
    65  ```
    66  
    67  The first step is to create a Consul API client. This is almost always the
    68  default configuration with an ACL token set, since you want to communicate
    69  to the local agent. The default configuration will also read the ACL token
    70  from environment variables if set. The Go library will use this client to request certificates,
    71  authorize connections, and more.
    72  
    73  Next, `connect.NewService` is called to create a service structure representing
    74  the _currently running service_. This structure maintains all the state
    75  for accepting and establishing connections. An application should generally
    76  create one service and reuse that one service for all servers and clients.
    77  
    78  Finally, a standard `*http.Server` is created. The magic line is the `TLSConfig`
    79  value. This is set to a TLS configuration returned by the service structure.
    80  This TLS configuration is configured to automatically load certificates
    81  in the background, cache them, and authorize inbound connections. The service
    82  structure automatically handles maintaining blocking queries to update certificates
    83  in the background if they change.
    84  
    85  Since the service returns a standard `*tls.Config`, _any_ server that supports
    86  TLS can be configured. This includes gRPC, net/rpc, basic TCP, and more.
    87  Another example is shown below with just a plain TLS listener:
    88  
    89  ```go
    90  import(
    91    "crypto/tls"
    92  
    93    "github.com/hashicorp/consul/api"
    94    "github.com/hashicorp/consul/connect"
    95  )
    96  
    97  func main() {
    98    // Create a Consul API client
    99    client, _ := api.NewClient(api.DefaultConfig())
   100  
   101    // Create an instance representing this service. "my-service" is the
   102    // name of _this_ service. The service should be cleaned up via Close.
   103    svc, _ := connect.NewService("my-service", client)
   104    defer svc.Close()
   105  
   106    // Creating an HTTP server that serves via Connect
   107    listener, _ := tls.Listen("tcp", ":8080", svc.ServerTLSConfig())
   108    defer listener.Close()
   109  
   110    // Accept
   111    go acceptLoop(listener)
   112  }
   113  ```
   114  
   115  ## HTTP Clients
   116  
   117  For Go applications that need to Connect to HTTP-based upstream dependencies,
   118  the Go library can construct an `*http.Client` that automatically establishes
   119  Connect-based connections as long as Consul-based service discovery is used.
   120  
   121  Example, followed by more details:
   122  
   123  ```go
   124  import(
   125    "github.com/hashicorp/consul/api"
   126    "github.com/hashicorp/consul/connect"
   127  )
   128  
   129  func main() {
   130    // Create a Consul API client
   131    client, _ := api.NewClient(api.DefaultConfig())
   132  
   133    // Create an instance representing this service. "my-service" is the
   134    // name of _this_ service. The service should be cleaned up via Close.
   135    svc, _ := connect.NewService("my-service", client)
   136    defer svc.Close()
   137  
   138    // Get an HTTP client
   139    httpClient := svc.HTTPClient()
   140  
   141    // Perform a request, then use the standard response
   142    resp, _ := httpClient.Get("https://userinfo.service.consul/user/mitchellh")
   143  }
   144  ```
   145  
   146  The first step is to create a Consul API client and service. These are the
   147  same steps as accepting connections and are explained in detail in the
   148  section above. If your application is both a client and server, both the
   149  API client and service structure can be shared and reused.
   150  
   151  Next, we call `svc.HTTPClient()` to return a specially configured
   152  `*http.Client`. This client will automatically established Connect-based
   153  connections using Consul service discovery.
   154  
   155  Finally, we perform an HTTP `GET` request to a hypothetical userinfo service.
   156  The HTTP client configuration automatically sends the correct client
   157  certificate, verifies the server certificate, and manages background
   158  goroutines for updating our certificates as necessary.
   159  
   160  If the application already uses a manually constructed `*http.Client`,
   161  the `svc.HTTPDialTLS` function can be used to configure the
   162  `http.Transport.DialTLS` field to achieve equivalent behavior.
   163  
   164  ### Hostname Requirements
   165  
   166  The hostname used in the request URL is used to identify the logical service
   167  discovery mechanism for the target. **It's not actually resolved via DNS** but
   168  used as a logical identifier for a Consul service discovery mechanism. It has
   169  the following specific limitations:
   170  
   171   * The scheme must be `https://`.
   172   * It must be a Consul DNS name in one of the following forms:
   173     * `<name>.service[.<datacenter>].consul` to discover a healthy service
   174       instance for a given service.
   175     * `<name>.query[.<datacenter>].consul` to discover an instance via
   176       [Prepared Query](/api/query.html).
   177   * The top-level domain _must_ be `.consul` even if your cluster has a custom
   178     `domain` configured for it's DNS interface. This might be relaxed in the
   179     future.
   180   * Tag filters for services are not currently supported (i.e.
   181     `tag1.web.service.consul`) however the same behaviour can be achieved using a
   182     prepared query.
   183   * External DNS names, raw IP addresses and so on will cause an error and should
   184     be fetched using a separate `HTTPClient`.
   185  
   186  
   187  ## Raw TLS Connection
   188  
   189  For a raw `net.Conn` TLS connection, the `svc.Dial` function can be used.
   190  This will establish a connection to the desired service via Connect and
   191  return the `net.Conn`. This connection can then be used as desired.
   192  
   193  Example:
   194  
   195  ````go
   196  import(
   197    "context"
   198  
   199    "github.com/hashicorp/consul/api"
   200    "github.com/hashicorp/consul/connect"
   201  )
   202  
   203  func main() {
   204    // Create a Consul API client
   205    client, _ := api.NewClient(api.DefaultConfig())
   206  
   207    // Create an instance representing this service. "my-service" is the
   208    // name of _this_ service. The service should be cleaned up via Close.
   209    svc, _ := connect.NewService("my-service", client)
   210    defer svc.Close()
   211  
   212    // Connect to the "userinfo" Consul service.
   213    conn, _ := svc.Dial(context.Background(), &connect.ConsulResolver{
   214      Client: client,
   215      Name:   "userinfo",
   216    })
   217  }
   218  ```
   219  
   220  This uses a familiar `Dial`-like function to establish raw `net.Conn` values.
   221  The second parameter to dial is an implementation of the `connect.Resolver`
   222  interface. The example above uses the `*connect.ConsulResolver` implementation
   223  to perform Consul-based service discovery. This also automatically determines
   224  the correct certificate metadata we expect the remote service to serve.
   225  
   226  ## Static Addresses, Custom Resolvers
   227  
   228  In the raw TLS connection example, you see the use of a `connect.Resolver`
   229  implementation. This interface can be implemented to perform address
   230  resolution. This must return the address and also the URI SAN expected
   231  in the TLS certificate served by the remote service.
   232  
   233  The Go library provides two built-in resolvers:
   234  
   235    * `*connect.StaticResolver` can be used for static addresses where no
   236      service discovery is required. The expected cert URI SAN must be
   237      manually specified.
   238  
   239    * `*connect.ConsulResolver` which resolves services and prepared queries
   240      via the Consul API. This also automatically determines the expected
   241      cert URI SAN.