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.