forked from TrueCloudLab/restic
Merge pull request 2094 from juergenhoetzel/password-command
Add support for reading password from external command
This commit is contained in:
commit
4609b5c24d
4 changed files with 55 additions and 20 deletions
8
changelog/unreleased/pull-2094
Normal file
8
changelog/unreleased/pull-2094
Normal file
|
@ -0,0 +1,8 @@
|
|||
Enhancement: Run command to get password
|
||||
|
||||
We've added the `--password-command` option which allows specifying a command
|
||||
that restic runs every time the password for the repository is needed, so it
|
||||
can be integrated with a password manager or keyring. The option can also be
|
||||
set via the environment variable `$RESTIC_PASSWORD_COMMAND`.
|
||||
|
||||
https://github.com/restic/restic/pull/2094
|
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/restic/restic/internal/errors"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
var version = "0.9.3-dev (compiled manually)"
|
||||
|
@ -43,18 +44,19 @@ const TimeFormat = "2006-01-02 15:04:05"
|
|||
|
||||
// GlobalOptions hold all global options for restic.
|
||||
type GlobalOptions struct {
|
||||
Repo string
|
||||
PasswordFile string
|
||||
KeyHint string
|
||||
Quiet bool
|
||||
Verbose int
|
||||
NoLock bool
|
||||
JSON bool
|
||||
CacheDir string
|
||||
NoCache bool
|
||||
CACerts []string
|
||||
TLSClientCert string
|
||||
CleanupCache bool
|
||||
Repo string
|
||||
PasswordFile string
|
||||
PasswordCommand string
|
||||
KeyHint string
|
||||
Quiet bool
|
||||
Verbose int
|
||||
NoLock bool
|
||||
JSON bool
|
||||
CacheDir string
|
||||
NoCache bool
|
||||
CACerts []string
|
||||
TLSClientCert string
|
||||
CleanupCache bool
|
||||
|
||||
LimitUploadKb int
|
||||
LimitDownloadKb int
|
||||
|
@ -93,6 +95,7 @@ func init() {
|
|||
f.StringVarP(&globalOptions.Repo, "repo", "r", os.Getenv("RESTIC_REPOSITORY"), "repository to backup to or restore from (default: $RESTIC_REPOSITORY)")
|
||||
f.StringVarP(&globalOptions.PasswordFile, "password-file", "p", os.Getenv("RESTIC_PASSWORD_FILE"), "read the repository password from a file (default: $RESTIC_PASSWORD_FILE)")
|
||||
f.StringVarP(&globalOptions.KeyHint, "key-hint", "", os.Getenv("RESTIC_KEY_HINT"), "key ID of key to try decrypting first (default: $RESTIC_KEY_HINT)")
|
||||
f.StringVarP(&globalOptions.PasswordCommand, "password-command", "", os.Getenv("RESTIC_PASSWORD_COMMAND"), "specify a shell command to obtain a password (default: $RESTIC_PASSWORD_COMMAND)")
|
||||
f.BoolVarP(&globalOptions.Quiet, "quiet", "q", false, "do not output comprehensive progress report")
|
||||
f.CountVarP(&globalOptions.Verbose, "verbose", "v", "be verbose (specify --verbose multiple times or level `n`)")
|
||||
f.BoolVar(&globalOptions.NoLock, "no-lock", false, "do not lock the repo, this allows some operations on read-only repos")
|
||||
|
@ -236,7 +239,23 @@ func Exitf(exitcode int, format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
// resolvePassword determines the password to be used for opening the repository.
|
||||
func resolvePassword(opts GlobalOptions, env string) (string, error) {
|
||||
func resolvePassword(opts GlobalOptions) (string, error) {
|
||||
if opts.PasswordFile != "" && opts.PasswordCommand != "" {
|
||||
return "", errors.Fatalf("Password file and command are mutually exclusive options")
|
||||
}
|
||||
if opts.PasswordCommand != "" {
|
||||
args, err := backend.SplitShellStrings(opts.PasswordCommand)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
cmd.Stderr = os.Stderr
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return (strings.TrimSpace(string(output))), nil
|
||||
}
|
||||
if opts.PasswordFile != "" {
|
||||
s, err := textfile.Read(opts.PasswordFile)
|
||||
if os.IsNotExist(errors.Cause(err)) {
|
||||
|
@ -245,7 +264,7 @@ func resolvePassword(opts GlobalOptions, env string) (string, error) {
|
|||
return strings.TrimSpace(string(s)), errors.Wrap(err, "Readfile")
|
||||
}
|
||||
|
||||
if pwd := os.Getenv(env); pwd != "" {
|
||||
if pwd := os.Getenv("RESTIC_PASSWORD"); pwd != "" {
|
||||
return pwd, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ directories in an encrypted repository stored on different backends.
|
|||
if c.Name() == "version" {
|
||||
return nil
|
||||
}
|
||||
pwd, err := resolvePassword(globalOptions, "RESTIC_PASSWORD")
|
||||
pwd, err := resolvePassword(globalOptions)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Resolving password failed: %v\n", err)
|
||||
Exit(1)
|
||||
|
|
|
@ -21,6 +21,19 @@ using a local repository; the remaining sections of this chapter cover all the
|
|||
other options. You can skip to the next chapter once you've read the relevant
|
||||
section here.
|
||||
|
||||
For automated backups, restic accepts the repository location in the
|
||||
environment variable ``RESTIC_REPOSITORY``. For the password, several options
|
||||
exist:
|
||||
|
||||
* Setting the environment variable ``RESTIC_PASSWORD``
|
||||
|
||||
* Specifying the path to a file with the password via the option
|
||||
``--password-file`` or the environment variable ``RESTIC_PASSWORD_FILE``
|
||||
|
||||
* Configuring a program to be called when the password is needed via the
|
||||
option ``--password-command`` or the environment variable
|
||||
``RESTIC_PASSWORD_COMMAND``
|
||||
|
||||
Local
|
||||
*****
|
||||
|
||||
|
@ -41,11 +54,6 @@ command and enter the same password twice:
|
|||
Remembering your password is important! If you lose it, you won't be
|
||||
able to access data stored in the repository.
|
||||
|
||||
For automated backups, restic accepts the repository location in the
|
||||
environment variable ``RESTIC_REPOSITORY``. The password can be read
|
||||
from a file (via the option ``--password-file`` or the environment variable
|
||||
``RESTIC_PASSWORD_FILE``) or the environment variable ``RESTIC_PASSWORD``.
|
||||
|
||||
SFTP
|
||||
****
|
||||
|
||||
|
|
Loading…
Reference in a new issue