diff --git a/cmd/backup/config.go b/cmd/backup/config.go index da7eecf..60717d1 100644 --- a/cmd/backup/config.go +++ b/cmd/backup/config.go @@ -25,7 +25,7 @@ type Config struct { AwsStorageClass string AwsAccessKeyID string `env:"AWS_ACCESS_KEY_ID"` AwsAccessKeyIDFile string `env:"AWS_ACCESS_KEY_ID_FILE,file"` - AwsSecretAccessKey string + AwsSecretAccessKey string `env:"AWS_SECRET_ACCESS_KEY"` AwsSecretAccessKeyFile string `env:"AWS_SECRET_ACCESS_KEY_FILE,file"` AwsIamRoleEndpoint string AwsPartSize int64 @@ -42,7 +42,8 @@ type Config struct { BackupFromSnapshot bool BackupExcludeRegexp RegexpDecoder BackupSkipBackendsFromPrune []string - GpgPassphrase string + GpgPassphrase string `env:"GPG_PASSPHRASE"` + GpgPassphraseFile string `env:"GPG_PASSPHRASE_FILE,file"` NotificationURLs []string `env:"NOTIFICATION_URLS"` NotificationLevel string `envDefault:"error"` EmailNotificationRecipient string @@ -51,17 +52,21 @@ type Config struct { EmailSMTPPort int `env:"EMAIL_SMTP_PORT" envDefault:"587"` EmailSMTPUsername string `env:"EMAIL_SMTP_USERNAME"` EmailSMTPPassword string `env:"EMAIL_SMTP_PASSWORD"` + EmailSMTPPasswordFile string `env:"EMAIL_SMTP_PASSWORD_FILE,file"` WebdavUrl string WebdavUrlInsecure bool WebdavPath string `envDefault:"/"` WebdavUsername string - WebdavPassword string + WebdavPassword string `env:"WEBDAV_PASSWORD"` + WebdavPasswordFile string `env:"WEBDAV_PASSWORD_FILE,file"` SSHHostName string `env:"SSH_HOST_NAME"` SSHPort string `env:"SSH_PORT" envDefault:"22"` SSHUser string `env:"SSH_USER"` SSHPassword string `env:"SSH_PASSWORD"` + SSHPasswordFile string `env:"SSH_PASSWORD_FILE,file"` SSHIdentityFile string `env:"SSH_IDENTITY_FILE" envDefault:"/root/.ssh/id_rsa"` SSHIdentityPassphrase string `env:"SSH_IDENTITY_PASSPHRASE"` + SSHIdentityPassphraseFile string `env:"SSH_IDENTITY_PASSPHRASE_FILE,file"` SSHRemotePath string `env:"SSH_REMOTE_PATH"` ExecLabel string ExecForwardOutput bool @@ -73,13 +78,26 @@ type Config struct { AzureStorageEndpoint string `envDefault:"https://{{ .AccountName }}.blob.core.windows.net/"` DropboxEndpoint string `envDefault:"https://api.dropbox.com/"` DropboxOAuth2Endpoint string `env:"DROPBOX_OAUTH2_ENDPOINT" envDefault:"https://api.dropbox.com/"` - DropboxRefreshToken string - DropboxAppKey string - DropboxAppSecret string + DropboxRefreshToken string `env:"DROPBOX_REFRESH_TOKEN"` + DropboxRefreshTokenFile string `env:"DROPBOX_REFRESH_TOKEN_FILE,file"` + DropboxAppKey string `env:"DROPBOX_APP_KEY"` + DropboxAppKeyFile string `env:"DROPBOX_APP_KEY_FILE,file"` + DropboxAppSecret string `env:"DROPBOX_APP_SECRET"` + DropboxAppSecretFile string `env:"DROPBOX_APP_SECRET_FILE,file"` DropboxRemotePath string DropboxConcurrencyLevel NaturalNumber `envDefault:"6"` } +func (c *Config) getSecret(preferred string, fallback string) string { + if preferred != "" { + return preferred + } + if fallback != "" { + return fallback + } + return "" +} + type CompressionType string func (c *CompressionType) UnmarshalText(text []byte) error { diff --git a/cmd/backup/script.go b/cmd/backup/script.go index ef31ce9..3d52857 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -140,20 +140,8 @@ func newScript() (*script, error) { } if s.c.AwsS3BucketName != "" { - var accessKeyID string - var secretAccessKey string - - if s.c.AwsAccessKeyIDFile != "" { - accessKeyID = s.c.AwsAccessKeyIDFile - } else { - accessKeyID = s.c.AwsAccessKeyID - } - - if s.c.AwsSecretAccessKeyFile != "" { - secretAccessKey = s.c.AwsSecretAccessKeyFile - } else { - secretAccessKey = s.c.AwsSecretAccessKey - } + accessKeyID := s.c.getSecret(s.c.AwsAccessKeyIDFile, s.c.AwsAccessKeyID) + secretAccessKey := s.c.getSecret(s.c.AwsSecretAccessKeyFile, s.c.AwsSecretAccessKey) s3Config := s3.Config{ Endpoint: s.c.AwsEndpoint, @@ -176,11 +164,13 @@ func newScript() (*script, error) { } if s.c.WebdavUrl != "" { + webdavPassword := s.c.getSecret(s.c.WebdavPasswordFile, s.c.WebdavPassword) + webDavConfig := webdav.Config{ URL: s.c.WebdavUrl, URLInsecure: s.c.WebdavUrlInsecure, Username: s.c.WebdavUsername, - Password: s.c.WebdavPassword, + Password: webdavPassword, RemotePath: s.c.WebdavPath, } if webdavBackend, err := webdav.NewStorageBackend(webDavConfig, logFunc); err != nil { @@ -191,13 +181,16 @@ func newScript() (*script, error) { } if s.c.SSHHostName != "" { + sshPassword := s.c.getSecret(s.c.SSHPasswordFile, s.c.SSHPassword) + sshIdentityPassphrase := s.c.getSecret(s.c.SSHIdentityPassphraseFile, s.c.SSHIdentityPassphrase) + sshConfig := ssh.Config{ HostName: s.c.SSHHostName, Port: s.c.SSHPort, User: s.c.SSHUser, - Password: s.c.SSHPassword, + Password: sshPassword, IdentityFile: s.c.SSHIdentityFile, - IdentityPassphrase: s.c.SSHIdentityPassphrase, + IdentityPassphrase: sshIdentityPassphrase, RemotePath: s.c.SSHRemotePath, } if sshBackend, err := ssh.NewStorageBackend(sshConfig, logFunc); err != nil { @@ -232,12 +225,16 @@ func newScript() (*script, error) { } if s.c.DropboxRefreshToken != "" && s.c.DropboxAppKey != "" && s.c.DropboxAppSecret != "" { + dropboxRefreshToken := s.c.getSecret(s.c.DropboxRefreshTokenFile, s.c.DropboxRefreshToken) + dropboxAppKey := s.c.getSecret(s.c.DropboxAppKeyFile, s.c.DropboxAppKey) + dropboxAppSecret := s.c.getSecret(s.c.DropboxAppSecretFile, s.c.DropboxAppSecret) + dropboxConfig := dropbox.Config{ Endpoint: s.c.DropboxEndpoint, OAuth2Endpoint: s.c.DropboxOAuth2Endpoint, - RefreshToken: s.c.DropboxRefreshToken, - AppKey: s.c.DropboxAppKey, - AppSecret: s.c.DropboxAppSecret, + RefreshToken: dropboxRefreshToken, + AppKey: dropboxAppKey, + AppSecret: dropboxAppSecret, RemotePath: s.c.DropboxRemotePath, ConcurrencyLevel: s.c.DropboxConcurrencyLevel.Int(), } @@ -249,10 +246,12 @@ func newScript() (*script, error) { } if s.c.EmailNotificationRecipient != "" { + smtpPassword := s.c.getSecret(s.c.EmailSMTPPasswordFile, s.c.EmailSMTPPassword) + emailURL := fmt.Sprintf( "smtp://%s:%s@%s:%d/?from=%s&to=%s", s.c.EmailSMTPUsername, - s.c.EmailSMTPPassword, + smtpPassword, s.c.EmailSMTPHost, s.c.EmailSMTPPort, s.c.EmailNotificationSender, @@ -513,7 +512,8 @@ func (s *script) createArchive() error { // In case no passphrase is given it returns early, leaving the backup file // untouched. func (s *script) encryptArchive() error { - if s.c.GpgPassphrase == "" { + gpgPassphrase := s.c.getSecret(s.c.GpgPassphraseFile, s.c.GpgPassphrase) + if gpgPassphrase == "" { return nil } @@ -535,7 +535,7 @@ func (s *script) encryptArchive() error { defer outFile.Close() _, name := path.Split(s.file) - dst, err := openpgp.SymmetricallyEncrypt(outFile, []byte(s.c.GpgPassphrase), &openpgp.FileHints{ + dst, err := openpgp.SymmetricallyEncrypt(outFile, []byte(gpgPassphrase), &openpgp.FileHints{ IsBinary: true, FileName: name, }, nil)