Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ the client used to send the request.
| `client.identity-aware-proxy.audience` | The Identity-Aware-Proxy audience. (client-id of the IAP oauth2 credential) | required `""` |
| `client.tls.certificate-file` | Path to a client certificate (in PEM format) for mTLS configurations. | `""` |
| `client.tls.private-key-file` | Path to a client private key (in PEM format) for mTLS configurations. | `""` |
| `client.tls.ca-file` | Path to a root CA (in PEM format) for mTLS configurations. | Optional `""` |
| `client.tls.renegotiation` | Type of renegotiation support to provide. (`never`, `freely`, `once`). | `"never"` |
| `client.network` | The network to use for ICMP endpoint client (`ip`, `ip4` or `ip6`). | `"ip"` |
| `client.tunnel` | Name of the SSH tunnel to use for this endpoint. See [Tunneling](#tunneling). | `""` |
Expand Down Expand Up @@ -713,6 +714,7 @@ endpoints:
tls:
certificate-file: /path/to/user_cert.pem
private-key-file: /path/to/user_key.pem
ca-file: /path/to/root-ca.pem # Not required for non-self-signed certificate authorities
renegotiation: once
conditions:
- "[STATUS] == 200"
Expand Down
19 changes: 19 additions & 0 deletions client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package client
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"net"
"net/http"
"net/url"
"os"
"regexp"
"strconv"
"time"
Expand Down Expand Up @@ -113,6 +115,9 @@ type TLSConfig struct {
// PrivateKeyFile is the private key file for TLS in PEM format.
PrivateKeyFile string `yaml:"private-key-file,omitempty"`

// CAFile is the CA certificate file for TLS in PEM format.
CAFile string `yaml:"ca-file,omitempty"`

RenegotiationSupport string `yaml:"renegotiation,omitempty"`
}

Expand Down Expand Up @@ -205,6 +210,12 @@ func (t *TLSConfig) isValid() error {
if err != nil {
return err
}
if len(t.CAFile) > 0 {
_, err := os.ReadFile(t.CAFile)
if err != nil {
return err
}
}
return nil
}
return ErrInvalidClientTLSConfig
Expand Down Expand Up @@ -345,6 +356,14 @@ func configureTLS(tlsConfig *tls.Config, c TLSConfig) *tls.Config {
return nil
}
tlsConfig.Certificates = []tls.Certificate{clientTLSCert}

if c.CAFile != "" {
caCert, _ := os.ReadFile(c.CAFile)
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig.RootCAs = caCertPool
}

tlsConfig.Renegotiation = tls.RenegotiateNever
renegotiationSupport := map[string]tls.RenegotiationSupport{
"once": tls.RenegotiateOnceAsClient,
Expand Down
10 changes: 10 additions & 0 deletions client/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,21 @@ func TestConfig_TlsIsValid(t *testing.T) {
cfg: &Config{TLS: &TLSConfig{CertificateFile: "../testdata/cert.pem", PrivateKeyFile: "../testdata/cert.key"}},
expectedErr: false,
},
{
name: "good-tls-with-ca-config",
cfg: &Config{TLS: &TLSConfig{CertificateFile: "../testdata/cert.pem", PrivateKeyFile: "../testdata/cert.key", CAFile: "../testdata/cert.pem"}},
expectedErr: false,
},
{
name: "missing-certificate-file",
cfg: &Config{TLS: &TLSConfig{CertificateFile: "doesnotexist", PrivateKeyFile: "../testdata/cert.key"}},
expectedErr: true,
},
{
name: "missing-ca-file",
cfg: &Config{TLS: &TLSConfig{CertificateFile: "../testdata/cert.pem", PrivateKeyFile: "../testdata/cert.key", CAFile: "doesnotexist"}},
expectedErr: true,
},
{
name: "bad-certificate-file",
cfg: &Config{TLS: &TLSConfig{CertificateFile: "../testdata/badcert.pem", PrivateKeyFile: "../testdata/cert.key"}},
Expand Down