forked from TrueCloudLab/restic
Support for TLS client certificate authentication
This adds --tls-client-cert and --tls-client-key parameters and enables use of that certificate/key pair when connecting to https servers.
This commit is contained in:
parent
e706f1a8d1
commit
e805b968b1
9 changed files with 68 additions and 44 deletions
9
changelog/0.8.2/issue-1522
Normal file
9
changelog/0.8.2/issue-1522
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Enhancement: Add support for TLS client certificate authentication.
|
||||||
|
|
||||||
|
Support has been added to the http backend for providing a TLS client
|
||||||
|
certificate/key pair using `--tls-client-cert` and `--tls-client-key` when
|
||||||
|
connecting to https resources that perform TLS client certificate
|
||||||
|
authentication.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/1522
|
||||||
|
https://github.com/restic/restic/pull/1524
|
|
@ -47,6 +47,8 @@ type GlobalOptions struct {
|
||||||
CacheDir string
|
CacheDir string
|
||||||
NoCache bool
|
NoCache bool
|
||||||
CACerts []string
|
CACerts []string
|
||||||
|
TLSClientCert string
|
||||||
|
TLSClientKey string
|
||||||
CleanupCache bool
|
CleanupCache bool
|
||||||
|
|
||||||
LimitUploadKb int
|
LimitUploadKb int
|
||||||
|
@ -84,6 +86,8 @@ func init() {
|
||||||
f.StringVar(&globalOptions.CacheDir, "cache-dir", "", "set the cache directory")
|
f.StringVar(&globalOptions.CacheDir, "cache-dir", "", "set the cache directory")
|
||||||
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
|
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
|
||||||
f.StringSliceVar(&globalOptions.CACerts, "cacert", nil, "path to load root certificates from (default: use system certificates)")
|
f.StringSliceVar(&globalOptions.CACerts, "cacert", nil, "path to load root certificates from (default: use system certificates)")
|
||||||
|
f.StringVar(&globalOptions.TLSClientCert, "tls-client-cert", "", "path to a TLS client certificate")
|
||||||
|
f.StringVar(&globalOptions.TLSClientKey, "tls-client-key", "", "path to a TLS client certificate key")
|
||||||
f.BoolVar(&globalOptions.CleanupCache, "cleanup-cache", false, "auto remove old cache directories")
|
f.BoolVar(&globalOptions.CleanupCache, "cleanup-cache", false, "auto remove old cache directories")
|
||||||
f.IntVar(&globalOptions.LimitUploadKb, "limit-upload", 0, "limits uploads to a maximum rate in KiB/s. (default: unlimited)")
|
f.IntVar(&globalOptions.LimitUploadKb, "limit-upload", 0, "limits uploads to a maximum rate in KiB/s. (default: unlimited)")
|
||||||
f.IntVar(&globalOptions.LimitDownloadKb, "limit-download", 0, "limits downloads to a maximum rate in KiB/s. (default: unlimited)")
|
f.IntVar(&globalOptions.LimitDownloadKb, "limit-download", 0, "limits downloads to a maximum rate in KiB/s. (default: unlimited)")
|
||||||
|
@ -541,7 +545,7 @@ func open(s string, gopts GlobalOptions, opts options.Options) (restic.Backend,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rt, err := backend.Transport(globalOptions.CACerts)
|
rt, err := backend.Transport(globalOptions.CACerts, globalOptions.TLSClientCert, globalOptions.TLSClientKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -605,7 +609,7 @@ func create(s string, opts options.Options) (restic.Backend, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rt, err := backend.Transport(globalOptions.CACerts)
|
rt, err := backend.Transport(globalOptions.CACerts, globalOptions.TLSClientCert, globalOptions.TLSClientKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ Usage help is available:
|
||||||
-p, --password-file string read the repository password from a file (default: $RESTIC_PASSWORD_FILE)
|
-p, --password-file string read the repository password from a file (default: $RESTIC_PASSWORD_FILE)
|
||||||
-q, --quiet do not output comprehensive progress report
|
-q, --quiet do not output comprehensive progress report
|
||||||
-r, --repo string repository to backup to or restore from (default: $RESTIC_REPOSITORY)
|
-r, --repo string repository to backup to or restore from (default: $RESTIC_REPOSITORY)
|
||||||
|
--tls-client-cert string path to a TLS client certificate
|
||||||
|
--tls-client-key string path to a TLS client certificate key
|
||||||
|
|
||||||
Use "restic [command] --help" for more information about a command.
|
Use "restic [command] --help" for more information about a command.
|
||||||
|
|
||||||
|
@ -98,6 +100,8 @@ command:
|
||||||
-p, --password-file string read the repository password from a file (default: $RESTIC_PASSWORD_FILE)
|
-p, --password-file string read the repository password from a file (default: $RESTIC_PASSWORD_FILE)
|
||||||
-q, --quiet do not output comprehensive progress report
|
-q, --quiet do not output comprehensive progress report
|
||||||
-r, --repo string repository to backup to or restore from (default: $RESTIC_REPOSITORY)
|
-r, --repo string repository to backup to or restore from (default: $RESTIC_REPOSITORY)
|
||||||
|
--tls-client-cert string path to a TLS client certificate
|
||||||
|
--tls-client-key string path to a TLS client certificate key
|
||||||
|
|
||||||
Subcommand that support showing progress information such as ``backup``,
|
Subcommand that support showing progress information such as ``backup``,
|
||||||
``check`` and ``prune`` will do so unless the quiet flag ``-q`` or
|
``check`` and ``prune`` will do so unless the quiet flag ``-q`` or
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newAzureTestSuite(t testing.TB) *test.Suite {
|
func newAzureTestSuite(t testing.TB) *test.Suite {
|
||||||
tr, err := backend.Transport(nil)
|
tr, err := backend.Transport(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newB2TestSuite(t testing.TB) *test.Suite {
|
func newB2TestSuite(t testing.TB) *test.Suite {
|
||||||
tr, err := backend.Transport(nil)
|
tr, err := backend.Transport(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
// Transport returns a new http.RoundTripper with default settings applied. If
|
// Transport returns a new http.RoundTripper with default settings applied. If
|
||||||
// a custom rootCertFilename is non-empty, it must point to a valid PEM file,
|
// a custom rootCertFilename is non-empty, it must point to a valid PEM file,
|
||||||
// otherwise the function will return an error.
|
// otherwise the function will return an error.
|
||||||
func Transport(rootCertFilenames []string) (http.RoundTripper, error) {
|
func Transport(rootCertFilenames []string, tlsClientCert string, tlsClientKey string) (http.RoundTripper, error) {
|
||||||
// copied from net/http
|
// copied from net/http
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
@ -29,6 +29,15 @@ func Transport(rootCertFilenames []string) (http.RoundTripper, error) {
|
||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
TLSClientConfig: &tls.Config{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsClientCert != "" && tlsClientKey != "" {
|
||||||
|
c, err := tls.LoadX509KeyPair(tlsClientCert, tlsClientKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read client certificate/key pair: %v", err)
|
||||||
|
}
|
||||||
|
tr.TLSClientConfig.Certificates = []tls.Certificate{c}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rootCertFilenames == nil {
|
if rootCertFilenames == nil {
|
||||||
|
@ -49,9 +58,7 @@ func Transport(rootCertFilenames []string) (http.RoundTripper, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.TLSClientConfig = &tls.Config{
|
tr.TLSClientConfig.RootCAs = p
|
||||||
RootCAs: p,
|
|
||||||
}
|
|
||||||
|
|
||||||
// wrap in the debug round tripper
|
// wrap in the debug round tripper
|
||||||
return debug.RoundTripper(tr), nil
|
return debug.RoundTripper(tr), nil
|
||||||
|
|
|
@ -68,7 +68,7 @@ func runRESTServer(ctx context.Context, t testing.TB, dir string) (*url.URL, fun
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestSuite(ctx context.Context, t testing.TB, url *url.URL, minimalData bool) *test.Suite {
|
func newTestSuite(ctx context.Context, t testing.TB, url *url.URL, minimalData bool) *test.Suite {
|
||||||
tr, err := backend.Transport(nil)
|
tr, err := backend.Transport(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ func createS3(t testing.TB, cfg MinioTestConfig, tr http.RoundTripper) (be resti
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
||||||
tr, err := backend.Transport(nil)
|
tr, err := backend.Transport(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ func BenchmarkBackendMinio(t *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newS3TestSuite(t testing.TB) *test.Suite {
|
func newS3TestSuite(t testing.TB) *test.Suite {
|
||||||
tr, err := backend.Transport(nil)
|
tr, err := backend.Transport(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newSwiftTestSuite(t testing.TB) *test.Suite {
|
func newSwiftTestSuite(t testing.TB) *test.Suite {
|
||||||
tr, err := backend.Transport(nil)
|
tr, err := backend.Transport(nil, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue