feat: Add TLS support (#556)

* feat: Add TLS support

This adds numerous flags with inspiration taken from Vault
for configuring TLS inside Coder.

This enables secure deployments without a proxy, like Cloudflare.

* Update cli/start.go

Co-authored-by: Colin Adler <colin@coder.com>

* Fix flag help in coder.env

Co-authored-by: Colin Adler <colin@coder.com>
This commit is contained in:
Kyle Carberry
2022-03-24 13:21:05 -06:00
committed by GitHub
parent 565b9403e4
commit bf00487174
8 changed files with 341 additions and 34 deletions

View File

@ -337,6 +337,7 @@ jobs:
gcloud config set compute/zone us-central1-a gcloud config set compute/zone us-central1-a
gcloud compute scp ./dist/coder_*_linux_amd64.deb coder:/tmp/coder.deb gcloud compute scp ./dist/coder_*_linux_amd64.deb coder:/tmp/coder.deb
gcloud compute ssh coder -- sudo dpkg -i /tmp/coder.deb gcloud compute ssh coder -- sudo dpkg -i /tmp/coder.deb
gcloud compute ssh coder -- sudo systemctl daemon-reload
- name: Start - name: Start
run: gcloud compute ssh coder -- sudo service coder restart run: gcloud compute ssh coder -- sudo service coder restart

View File

@ -2,7 +2,10 @@ package cli
import ( import (
"context" "context"
"crypto/tls"
"crypto/x509"
"database/sql" "database/sql"
"encoding/pem"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net" "net"
@ -10,6 +13,7 @@ import (
"net/url" "net/url"
"os" "os"
"os/signal" "os/signal"
"strconv"
"time" "time"
"github.com/briandowns/spinner" "github.com/briandowns/spinner"
@ -36,23 +40,23 @@ import (
func start() *cobra.Command { func start() *cobra.Command {
var ( var (
accessURL string
address string address string
dev bool
postgresURL string postgresURL string
provisionerDaemonCount uint8 provisionerDaemonCount uint8
dev bool tlsCertFile string
tlsClientCAFile string
tlsClientAuth string
tlsEnable bool
tlsKeyFile string
tlsMinVersion string
useTunnel bool useTunnel bool
) )
root := &cobra.Command{ root := &cobra.Command{
Use: "start", Use: "start",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), ` ▄█▀ ▀█▄ printLogo(cmd)
▄▄ ▀▀▀ █▌ ██▀▀█▄ ▐█
▄▄██▀▀█▄▄▄ ██ ██ █▀▀█ ▐█▀▀██ ▄█▀▀█ █▀▀
█▌ ▄▌ ▐█ █▌ ▀█▄▄▄█▌ █ █ ▐█ ██ ██▀▀ █
██████▀▄█ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀
`)
if postgresURL == "" { if postgresURL == "" {
// Default to the environment variable! // Default to the environment variable!
postgresURL = os.Getenv("CODER_PG_CONNECTION_URL") postgresURL = os.Getenv("CODER_PG_CONNECTION_URL")
@ -63,6 +67,17 @@ func start() *cobra.Command {
return xerrors.Errorf("listen %q: %w", address, err) return xerrors.Errorf("listen %q: %w", address, err)
} }
defer listener.Close() defer listener.Close()
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
}
if tlsEnable {
listener, err = configureTLS(tlsConfig, listener, tlsMinVersion, tlsClientAuth, tlsCertFile, tlsKeyFile, tlsClientCAFile)
if err != nil {
return xerrors.Errorf("configure tls: %w", err)
}
}
tcpAddr, valid := listener.Addr().(*net.TCPAddr) tcpAddr, valid := listener.Addr().(*net.TCPAddr)
if !valid { if !valid {
return xerrors.New("must be listening on tcp") return xerrors.New("must be listening on tcp")
@ -76,7 +91,12 @@ func start() *cobra.Command {
Scheme: "http", Scheme: "http",
Host: tcpAddr.String(), Host: tcpAddr.String(),
} }
accessURL := localURL if tlsEnable {
localURL.Scheme = "https"
}
if accessURL == "" {
accessURL = localURL.String()
}
var tunnelErr <-chan error var tunnelErr <-chan error
// If we're attempting to tunnel in dev-mode, the access URL // If we're attempting to tunnel in dev-mode, the access URL
// needs to be changed to use the tunnel. // needs to be changed to use the tunnel.
@ -88,17 +108,11 @@ func start() *cobra.Command {
IsConfirm: true, IsConfirm: true,
}) })
if err == nil { if err == nil {
var accessURLRaw string accessURL, tunnelErr, err = tunnel.New(cmd.Context(), localURL.String())
accessURLRaw, tunnelErr, err = tunnel.New(cmd.Context(), localURL.String())
if err != nil { if err != nil {
return xerrors.Errorf("create tunnel: %w", err) return xerrors.Errorf("create tunnel: %w", err)
} }
accessURL, err = url.Parse(accessURLRaw) _, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render(cliui.Styles.Wrap.Render(cliui.Styles.Prompt.String()+`Tunnel started. Your deployment is accessible at:`))+"\n "+cliui.Styles.Field.Render(accessURL))
if err != nil {
return xerrors.Errorf("parse: %w", err)
}
_, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render(cliui.Styles.Wrap.Render(cliui.Styles.Prompt.String()+`Tunnel started. Your deployment is accessible at:`))+"\n "+cliui.Styles.Field.Render(accessURL.String()))
} }
} }
validator, err := idtoken.NewValidator(cmd.Context(), option.WithoutAuthentication()) validator, err := idtoken.NewValidator(cmd.Context(), option.WithoutAuthentication())
@ -106,9 +120,13 @@ func start() *cobra.Command {
return err return err
} }
accessURLParsed, err := url.Parse(accessURL)
if err != nil {
return xerrors.Errorf("parse access url %q: %w", accessURL, err)
}
logger := slog.Make(sloghuman.Sink(os.Stderr)) logger := slog.Make(sloghuman.Sink(os.Stderr))
options := &coderd.Options{ options := &coderd.Options{
AccessURL: accessURL, AccessURL: accessURLParsed,
Logger: logger.Named("coderd"), Logger: logger.Named("coderd"),
Database: databasefake.New(), Database: databasefake.New(),
Pubsub: database.NewPubsubInMemory(), Pubsub: database.NewPubsubInMemory(),
@ -137,6 +155,13 @@ func start() *cobra.Command {
handler, closeCoderd := coderd.New(options) handler, closeCoderd := coderd.New(options)
client := codersdk.New(localURL) client := codersdk.New(localURL)
if tlsEnable {
// Use the TLS config here. This client is used for creating the
// default user, among other things.
client.HTTPClient.Transport = &http.Transport{
TLSClientConfig: tlsConfig,
}
}
provisionerDaemons := make([]*provisionerd.Server, 0) provisionerDaemons := make([]*provisionerd.Server, 0)
for i := uint8(0); i < provisionerDaemonCount; i++ { for i := uint8(0); i < provisionerDaemonCount; i++ {
@ -152,10 +177,18 @@ func start() *cobra.Command {
} }
}() }()
errCh := make(chan error) errCh := make(chan error, 1)
shutdownConnsCtx, shutdownConns := context.WithCancel(cmd.Context())
defer shutdownConns()
go func() { go func() {
defer close(errCh) defer close(errCh)
errCh <- http.Serve(listener, handler) server := http.Server{
Handler: handler,
BaseContext: func(_ net.Listener) context.Context {
return shutdownConnsCtx
},
}
errCh <- server.Serve(listener)
}() }()
config := createConfig(cmd) config := createConfig(cmd)
@ -271,6 +304,7 @@ func start() *cobra.Command {
} }
_, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Prompt.String()+"Waiting for WebSocket connections to close...\n") _, _ = fmt.Fprintf(cmd.OutOrStdout(), cliui.Styles.Prompt.String()+"Waiting for WebSocket connections to close...\n")
shutdownConns()
closeCoderd() closeCoderd()
return nil return nil
}, },
@ -279,11 +313,42 @@ func start() *cobra.Command {
if defaultAddress == "" { if defaultAddress == "" {
defaultAddress = "127.0.0.1:3000" defaultAddress = "127.0.0.1:3000"
} }
root.Flags().StringVarP(&address, "address", "a", defaultAddress, "The address to serve the API and dashboard.") root.Flags().StringVarP(&accessURL, "access-url", "", os.Getenv("CODER_ACCESS_URL"), "Specifies the external URL to access Coder (uses $CODER_ACCESS_URL).")
root.Flags().BoolVarP(&dev, "dev", "", false, "Serve Coder in dev mode for tinkering.") root.Flags().StringVarP(&address, "address", "a", defaultAddress, "The address to serve the API and dashboard (uses $CODER_ADDRESS).")
root.Flags().StringVarP(&postgresURL, "postgres-url", "", "", "URL of a PostgreSQL database to connect to (defaults to $CODER_PG_CONNECTION_URL).") defaultDev, _ := strconv.ParseBool(os.Getenv("CODER_DEV_MODE"))
root.Flags().BoolVarP(&dev, "dev", "", defaultDev, "Serve Coder in dev mode for tinkering (uses $CODER_DEV_MODE).")
root.Flags().StringVarP(&postgresURL, "postgres-url", "", "",
"URL of a PostgreSQL database to connect to (defaults to $CODER_PG_CONNECTION_URL).")
root.Flags().Uint8VarP(&provisionerDaemonCount, "provisioner-daemons", "", 1, "The amount of provisioner daemons to create on start.") root.Flags().Uint8VarP(&provisionerDaemonCount, "provisioner-daemons", "", 1, "The amount of provisioner daemons to create on start.")
root.Flags().BoolVarP(&useTunnel, "tunnel", "", true, "Serve dev mode through a Cloudflare Tunnel for easy setup.") defaultTLSEnable, _ := strconv.ParseBool(os.Getenv("CODER_TLS_ENABLE"))
root.Flags().BoolVarP(&tlsEnable, "tls-enable", "", defaultTLSEnable, "Specifies if TLS will be enabled (uses $CODER_TLS_ENABLE).")
root.Flags().StringVarP(&tlsCertFile, "tls-cert-file", "", os.Getenv("CODER_TLS_CERT_FILE"),
"Specifies the path to the certificate for TLS. It requires a PEM-encoded file. "+
"To configure the listener to use a CA certificate, concatenate the primary certificate "+
"and the CA certificate together. The primary certificate should appear first in the combined file (uses $CODER_TLS_CERT_FILE).")
root.Flags().StringVarP(&tlsClientCAFile, "tls-client-ca-file", "", os.Getenv("CODER_TLS_CLIENT_CA_FILE"),
"PEM-encoded Certificate Authority file used for checking the authenticity of client (uses $CODER_TLS_CLIENT_CA_FILE).")
defaultTLSClientAuth := os.Getenv("CODER_TLS_CLIENT_AUTH")
if defaultTLSClientAuth == "" {
defaultTLSClientAuth = "request"
}
root.Flags().StringVarP(&tlsClientAuth, "tls-client-auth", "", defaultTLSClientAuth,
`Specifies the policy the server will follow for TLS Client Authentication. `+
`Accepted values are "none", "request", "require-any", "verify-if-given", or "require-and-verify" (uses $CODER_TLS_CLIENT_AUTH).`)
root.Flags().StringVarP(&tlsKeyFile, "tls-key-file", "", os.Getenv("CODER_TLS_KEY_FILE"),
"Specifies the path to the private key for the certificate. It requires a PEM-encoded file (uses $CODER_TLS_KEY_FILE).")
defaultTLSMinVersion := os.Getenv("CODER_TLS_MIN_VERSION")
if defaultTLSMinVersion == "" {
defaultTLSMinVersion = "tls12"
}
root.Flags().StringVarP(&tlsMinVersion, "tls-min-version", "", defaultTLSMinVersion,
`Specifies the minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12" or "tls13" (uses $CODER_TLS_MIN_VERSION).`)
defaultTunnelRaw := os.Getenv("CODER_DEV_TUNNEL")
if defaultTunnelRaw == "" {
defaultTunnelRaw = "true"
}
defaultTunnel, _ := strconv.ParseBool(defaultTunnelRaw)
root.Flags().BoolVarP(&useTunnel, "tunnel", "", defaultTunnel, "Serve dev mode through a Cloudflare Tunnel for easy setup (uses $CODER_DEV_TUNNEL).")
_ = root.Flags().MarkHidden("tunnel") _ = root.Flags().MarkHidden("tunnel")
return root return root
@ -346,3 +411,88 @@ func newProvisionerDaemon(ctx context.Context, client *codersdk.Client, logger s
WorkDirectory: tempDir, WorkDirectory: tempDir,
}), nil }), nil
} }
func printLogo(cmd *cobra.Command) {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), ` ▄█▀ ▀█▄
▄▄ ▀▀▀ █▌ ██▀▀█▄ ▐█
▄▄██▀▀█▄▄▄ ██ ██ █▀▀█ ▐█▀▀██ ▄█▀▀█ █▀▀
█▌ ▄▌ ▐█ █▌ ▀█▄▄▄█▌ █ █ ▐█ ██ ██▀▀ █
██████▀▄█ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀
`)
}
func configureTLS(tlsConfig *tls.Config, listener net.Listener, tlsMinVersion, tlsClientAuth, tlsCertFile, tlsKeyFile, tlsClientCAFile string) (net.Listener, error) {
switch tlsMinVersion {
case "tls10":
tlsConfig.MinVersion = tls.VersionTLS10
case "tls11":
tlsConfig.MinVersion = tls.VersionTLS11
case "tls12":
tlsConfig.MinVersion = tls.VersionTLS12
case "tls13":
tlsConfig.MinVersion = tls.VersionTLS13
default:
return nil, xerrors.Errorf("unrecognized tls version: %q", tlsMinVersion)
}
switch tlsClientAuth {
case "none":
tlsConfig.ClientAuth = tls.NoClientCert
case "request":
tlsConfig.ClientAuth = tls.RequestClientCert
case "require-any":
tlsConfig.ClientAuth = tls.RequireAnyClientCert
case "verify-if-given":
tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven
case "require-and-verify":
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
default:
return nil, xerrors.Errorf("unrecognized tls client auth: %q", tlsClientAuth)
}
if tlsCertFile == "" {
return nil, xerrors.New("tls-cert-file is required when tls is enabled")
}
if tlsKeyFile == "" {
return nil, xerrors.New("tls-key-file is required when tls is enabled")
}
certPEMBlock, err := os.ReadFile(tlsCertFile)
if err != nil {
return nil, xerrors.Errorf("read file %q: %w", tlsCertFile, err)
}
keyPEMBlock, err := os.ReadFile(tlsKeyFile)
if err != nil {
return nil, xerrors.Errorf("read file %q: %w", tlsKeyFile, err)
}
keyBlock, _ := pem.Decode(keyPEMBlock)
if keyBlock == nil {
return nil, xerrors.New("decoded pem is blank")
}
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
return nil, xerrors.Errorf("create key pair: %w", err)
}
tlsConfig.GetCertificate = func(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &cert, nil
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(certPEMBlock)
tlsConfig.RootCAs = certPool
if tlsClientCAFile != "" {
caPool := x509.NewCertPool()
data, err := ioutil.ReadFile(tlsClientCAFile)
if err != nil {
return nil, xerrors.Errorf("read %q: %w", tlsClientCAFile, err)
}
if !caPool.AppendCertsFromPEM(data) {
return nil, xerrors.Errorf("failed to parse CA certificate in tls-client-ca-file")
}
tlsConfig.ClientCAs = caPool
}
return tls.NewListener(listener, tlsConfig), nil
}

View File

@ -2,7 +2,18 @@ package cli_test
import ( import (
"context" "context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"net/http"
"net/url" "net/url"
"os"
"runtime" "runtime"
"testing" "testing"
"time" "time"
@ -10,6 +21,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/coder/coder/cli/clitest" "github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/codersdk" "github.com/coder/coder/codersdk"
"github.com/coder/coder/database/postgres" "github.com/coder/coder/database/postgres"
) )
@ -79,4 +91,146 @@ func TestStart(t *testing.T) {
_, err = client.User(ctx, "") _, err = client.User(ctx, "")
require.NoError(t, err) require.NoError(t, err)
}) })
t.Run("TLSBadVersion", func(t *testing.T) {
t.Parallel()
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
root, _ := clitest.New(t, "start", "--dev", "--tunnel=false", "--address", ":0",
"--tls-enable", "--tls-min-version", "tls9")
err := root.ExecuteContext(ctx)
require.Error(t, err)
})
t.Run("TLSBadClientAuth", func(t *testing.T) {
t.Parallel()
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
root, _ := clitest.New(t, "start", "--dev", "--tunnel=false", "--address", ":0",
"--tls-enable", "--tls-client-auth", "something")
err := root.ExecuteContext(ctx)
require.Error(t, err)
})
t.Run("TLSNoCertFile", func(t *testing.T) {
t.Parallel()
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
root, _ := clitest.New(t, "start", "--dev", "--tunnel=false", "--address", ":0",
"--tls-enable")
err := root.ExecuteContext(ctx)
require.Error(t, err)
})
t.Run("TLSValid", func(t *testing.T) {
t.Parallel()
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
certPath, keyPath := generateTLSCertificate(t)
root, cfg := clitest.New(t, "start", "--dev", "--tunnel=false", "--address", ":0",
"--tls-enable", "--tls-cert-file", certPath, "--tls-key-file", keyPath)
go func() {
err := root.ExecuteContext(ctx)
require.ErrorIs(t, err, context.Canceled)
}()
var accessURLRaw string
require.Eventually(t, func() bool {
var err error
accessURLRaw, err = cfg.URL().Read()
return err == nil
}, 15*time.Second, 25*time.Millisecond)
accessURL, err := url.Parse(accessURLRaw)
require.NoError(t, err)
require.Equal(t, "https", accessURL.Scheme)
client := codersdk.New(accessURL)
client.HTTPClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
//nolint:gosec
InsecureSkipVerify: true,
},
},
}
_, err = client.HasFirstUser(ctx)
require.NoError(t, err)
})
// This cannot be ran in parallel because it uses a signal.
//nolint:paralleltest
t.Run("Shutdown", func(t *testing.T) {
if runtime.GOOS == "windows" {
// Sending interrupt signal isn't supported on Windows!
t.SkipNow()
}
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
root, cfg := clitest.New(t, "start", "--dev", "--tunnel=false", "--address", ":0", "--provisioner-daemons", "0")
done := make(chan struct{})
go func() {
defer close(done)
err := root.ExecuteContext(ctx)
require.NoError(t, err)
}()
var token string
require.Eventually(t, func() bool {
var err error
token, err = cfg.Session().Read()
return err == nil
}, 15*time.Second, 25*time.Millisecond)
// Verify that authentication was properly set in dev-mode.
accessURL, err := cfg.URL().Read()
require.NoError(t, err)
parsed, err := url.Parse(accessURL)
require.NoError(t, err)
client := codersdk.New(parsed)
client.SessionToken = token
orgs, err := client.OrganizationsByUser(ctx, "")
require.NoError(t, err)
coderdtest.NewProvisionerDaemon(t, client)
// Create a workspace so the cleanup occurs!
version := coderdtest.CreateProjectVersion(t, client, orgs[0].ID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, orgs[0].ID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, "", project.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
require.NoError(t, err)
currentProcess, err := os.FindProcess(os.Getpid())
require.NoError(t, err)
err = currentProcess.Signal(os.Interrupt)
require.NoError(t, err)
<-done
})
}
func generateTLSCertificate(t testing.TB) (certPath, keyPath string) {
dir := t.TempDir()
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 180),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
require.NoError(t, err)
certFile, err := os.CreateTemp(dir, "")
require.NoError(t, err)
defer certFile.Close()
_, err = certFile.Write(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}))
require.NoError(t, err)
privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
require.NoError(t, err)
keyFile, err := os.CreateTemp(dir, "")
require.NoError(t, err)
defer keyFile.Close()
err = pem.Encode(keyFile, &pem.Block{Type: "PRIVATE KEY", Bytes: privateKeyBytes})
require.NoError(t, err)
return certFile.Name(), keyFile.Name()
} }

View File

@ -1,3 +1,6 @@
# Runtime variables for "coder start". # Run "coder start --help" for flag information.
CODER_ADDRESS= CODER_ADDRESS=
CODER_PG_CONNECTION_URL= CODER_PG_CONNECTION_URL=
CODER_TLS_CERT_FILE=
CODER_TLS_ENABLE=
CODER_TLS_KEY_FILE=

View File

@ -21,16 +21,15 @@ import (
func New(serverURL *url.URL) *Client { func New(serverURL *url.URL) *Client {
return &Client{ return &Client{
URL: serverURL, URL: serverURL,
httpClient: &http.Client{}, HTTPClient: &http.Client{},
} }
} }
// Client is an HTTP caller for methods to the Coder API. // Client is an HTTP caller for methods to the Coder API.
type Client struct { type Client struct {
URL *url.URL HTTPClient *http.Client
SessionToken string SessionToken string
URL *url.URL
httpClient *http.Client
} }
// request performs an HTTP request with the body provided. // request performs an HTTP request with the body provided.
@ -71,7 +70,7 @@ func (c *Client) request(ctx context.Context, method, path string, body interfac
opt(req) opt(req)
} }
resp, err := c.httpClient.Do(req) resp, err := c.HTTPClient.Do(req)
if err != nil { if err != nil {
return nil, xerrors.Errorf("do: %w", err) return nil, xerrors.Errorf("do: %w", err)
} }

View File

@ -59,7 +59,7 @@ func (c *Client) ListenProvisionerDaemon(ctx context.Context) (proto.DRPCProvisi
return nil, xerrors.Errorf("parse url: %w", err) return nil, xerrors.Errorf("parse url: %w", err)
} }
conn, res, err := websocket.Dial(ctx, serverURL.String(), &websocket.DialOptions{ conn, res, err := websocket.Dial(ctx, serverURL.String(), &websocket.DialOptions{
HTTPClient: c.httpClient, HTTPClient: c.HTTPClient,
// Need to disable compression to avoid a data-race. // Need to disable compression to avoid a data-race.
CompressionMode: websocket.CompressionDisabled, CompressionMode: websocket.CompressionDisabled,
}) })

View File

@ -30,7 +30,7 @@ func (c *Client) AuthWorkspaceGoogleInstanceIdentity(ctx context.Context, servic
serviceAccount = "default" serviceAccount = "default"
} }
if gcpClient == nil { if gcpClient == nil {
gcpClient = metadata.NewClient(c.httpClient) gcpClient = metadata.NewClient(c.HTTPClient)
} }
// "format=full" is required, otherwise the responding payload will be missing "instance_id". // "format=full" is required, otherwise the responding payload will be missing "instance_id".
jwt, err := gcpClient.Get(fmt.Sprintf("instance/service-accounts/%s/identity?audience=coder&format=full", serviceAccount)) jwt, err := gcpClient.Get(fmt.Sprintf("instance/service-accounts/%s/identity?audience=coder&format=full", serviceAccount))

2
go.mod
View File

@ -68,7 +68,6 @@ require (
github.com/quasilyte/go-ruleguard/dsl v0.3.19 github.com/quasilyte/go-ruleguard/dsl v0.3.19
github.com/rs/zerolog v1.26.1 github.com/rs/zerolog v1.26.1
github.com/spf13/cobra v1.4.0 github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.1 github.com/stretchr/testify v1.7.1
github.com/tabbed/pqtype v0.1.1 github.com/tabbed/pqtype v0.1.1
github.com/unrolled/secure v1.10.0 github.com/unrolled/secure v1.10.0
@ -207,6 +206,7 @@ require (
github.com/spf13/afero v1.8.1 // indirect github.com/spf13/afero v1.8.1 // indirect
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect