mirror of
https://github.com/containrrr/watchtower.git
synced 2025-09-21 21:30:48 +02:00
Allows flags containing sensitive stuff to be passed as files (#545)
* Allows options containing sensitive stuff (passwords, tokens) to be passed as a file instead * Fixed linter error, added tests, removed notification-url (due to being an array)
This commit is contained in:
parent
6da66fb312
commit
12d323354f
5 changed files with 92 additions and 4 deletions
|
@ -81,6 +81,7 @@ func PreRun(cmd *cobra.Command, args []string) {
|
||||||
scheduleSpec = "@every " + strconv.Itoa(interval) + "s"
|
scheduleSpec = "@every " + strconv.Itoa(interval) + "s"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags.GetSecretsFromFiles(cmd)
|
||||||
cleanup, noRestart, monitorOnly, timeout = flags.ReadFlags(cmd)
|
cleanup, noRestart, monitorOnly, timeout = flags.ReadFlags(cmd)
|
||||||
|
|
||||||
if timeout < 0 {
|
if timeout < 0 {
|
||||||
|
|
|
@ -33,7 +33,7 @@ To receive notifications by email, the following command-line options, or their
|
||||||
- `--notification-email-server-tls-skip-verify` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_TLS_SKIP_VERIFY`): Do not verify the TLS certificate of the mail server. This should be used only for testing.
|
- `--notification-email-server-tls-skip-verify` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_TLS_SKIP_VERIFY`): Do not verify the TLS certificate of the mail server. This should be used only for testing.
|
||||||
- `--notification-email-server-port` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT`): The port used to connect to the SMTP server to send e-mails through. Defaults to `25`.
|
- `--notification-email-server-port` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT`): The port used to connect to the SMTP server to send e-mails through. Defaults to `25`.
|
||||||
- `--notification-email-server-user` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER`): The username to authenticate with the SMTP server with.
|
- `--notification-email-server-user` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER`): The username to authenticate with the SMTP server with.
|
||||||
- `--notification-email-server-password` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD`): The password to authenticate with the SMTP server with.
|
- `--notification-email-server-password` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD`): The password to authenticate with the SMTP server with. Can also reference a file, in which case the contents of the file are used.
|
||||||
- `--notification-email-delay` (env. `WATCHTOWER_NOTIFICATION_EMAIL_DELAY`): Delay before sending notifications expressed in seconds.
|
- `--notification-email-delay` (env. `WATCHTOWER_NOTIFICATION_EMAIL_DELAY`): Delay before sending notifications expressed in seconds.
|
||||||
- `--notification-email-subjecttag` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG`): Prefix to include in the subject tag. Useful when running multiple watchtowers.
|
- `--notification-email-subjecttag` (env. `WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG`): Prefix to include in the subject tag. Useful when running multiple watchtowers.
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ If watchtower is monitoring the same Docker daemon under which the watchtower co
|
||||||
|
|
||||||
To receive notifications in Slack, add `slack` to the `--notifications` option or the `WATCHTOWER_NOTIFICATIONS` environment variable.
|
To receive notifications in Slack, add `slack` to the `--notifications` option or the `WATCHTOWER_NOTIFICATIONS` environment variable.
|
||||||
|
|
||||||
Additionally, you should set the Slack webhook URL using the `--notification-slack-hook-url` option or the `WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL` environment variable.
|
Additionally, you should set the Slack webhook URL using the `--notification-slack-hook-url` option or the `WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL` environment variable. This option can also reference a file, in which case the contents of the file are used.
|
||||||
|
|
||||||
By default, watchtower will send messages under the name `watchtower`, you can customize this string through the `--notification-slack-identifier` option or the `WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER` environment variable.
|
By default, watchtower will send messages under the name `watchtower`, you can customize this string through the `--notification-slack-identifier` option or the `WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER` environment variable.
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ docker run -d \
|
||||||
|
|
||||||
To receive notifications in MSTeams channel, add `msteams` to the `--notifications` option or the `WATCHTOWER_NOTIFICATIONS` environment variable.
|
To receive notifications in MSTeams channel, add `msteams` to the `--notifications` option or the `WATCHTOWER_NOTIFICATIONS` environment variable.
|
||||||
|
|
||||||
Additionally, you should set the MSTeams webhook URL using the `--notification-msteams-hook` option or the `WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL` environment variable.
|
Additionally, you should set the MSTeams webhook URL using the `--notification-msteams-hook` option or the `WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL` environment variable. This option can also reference a file, in which case the contents of the file are used.
|
||||||
|
|
||||||
MSTeams notifier could send keys/values filled by `log.WithField` or `log.WithFields` as MSTeams message facts. To enable this feature add `--notification-msteams-data` flag or set `WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true` environment variable.
|
MSTeams notifier could send keys/values filled by `log.WithField` or `log.WithFields` as MSTeams message facts. To enable this feature add `--notification-msteams-data` flag or set `WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true` environment variable.
|
||||||
|
|
||||||
|
@ -160,7 +160,6 @@ docker run -d \
|
||||||
|
|
||||||
To push a notification to your Gotify instance, register a Gotify app and specify the Gotify URL and app token:
|
To push a notification to your Gotify instance, register a Gotify app and specify the Gotify URL and app token:
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name watchtower \
|
--name watchtower \
|
||||||
|
@ -171,6 +170,8 @@ docker run -d \
|
||||||
containrrr/watchtower
|
containrrr/watchtower
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`-e WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN` or `--notification-gotify-token` can also reference a file, in which case the contents of the file are used.
|
||||||
|
|
||||||
If you want to disable TLS verification for the Gotify instance, you can use either `-e WATCHTOWER_NOTIFICATION_GOTIFY_TLS_SKIP_VERIFY=true` or `--notification-gotify-tls-skip-verify`.
|
If you want to disable TLS verification for the Gotify instance, you can use either `-e WATCHTOWER_NOTIFICATION_GOTIFY_TLS_SKIP_VERIFY=true` or `--notification-gotify-tls-skip-verify`.
|
||||||
|
|
||||||
### [containrrr/shoutrrr](https://github.com/containrrr/shoutrrr)
|
### [containrrr/shoutrrr](https://github.com/containrrr/shoutrrr)
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -48,6 +48,7 @@ require (
|
||||||
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
|
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
|
||||||
github.com/sirupsen/logrus v1.4.1
|
github.com/sirupsen/logrus v1.4.1
|
||||||
github.com/spf13/cobra v0.0.3
|
github.com/spf13/cobra v0.0.3
|
||||||
|
github.com/spf13/pflag v1.0.3
|
||||||
github.com/spf13/viper v1.4.0
|
github.com/spf13/viper v1.4.0
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
github.com/theupdateframework/notary v0.6.1 // indirect
|
github.com/theupdateframework/notary v0.6.1 // indirect
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package flags
|
package flags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -366,3 +369,45 @@ func setEnvOptBool(env string, opt bool) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSecretsFromFiles checks if passwords/tokens/webhooks have been passed as a file instead of plaintext.
|
||||||
|
// If so, the value of the flag will be replaced with the contents of the file.
|
||||||
|
func GetSecretsFromFiles(rootCmd *cobra.Command) {
|
||||||
|
flags := rootCmd.PersistentFlags()
|
||||||
|
|
||||||
|
secrets := []string{
|
||||||
|
"notification-email-server-password",
|
||||||
|
"notification-slack-hook-url",
|
||||||
|
"notification-msteams-hook",
|
||||||
|
"notification-gotify-token",
|
||||||
|
}
|
||||||
|
for _, secret := range secrets {
|
||||||
|
getSecretFromFile(flags, secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSecretFromFile will check if the flag contains a reference to a file; if it does, replaces the value of the flag with the contents of the file.
|
||||||
|
func getSecretFromFile(flags *pflag.FlagSet, secret string) {
|
||||||
|
value, err := flags.GetString(secret)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
if value != "" && isFile(value) {
|
||||||
|
file, err := ioutil.ReadFile(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
err = flags.Set(secret, strings.TrimSpace(string(file)))
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFile(s string) bool {
|
||||||
|
_, err := os.Stat(s)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package flags
|
package flags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -39,3 +40,42 @@ func TestEnvConfig_Custom(t *testing.T) {
|
||||||
// Re-enable this test when we've moved to github actions.
|
// Re-enable this test when we've moved to github actions.
|
||||||
// assert.Equal(t, "1.99", os.Getenv("DOCKER_API_VERSION"))
|
// assert.Equal(t, "1.99", os.Getenv("DOCKER_API_VERSION"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetSecretsFromFilesWithString(t *testing.T) {
|
||||||
|
value := "supersecretstring"
|
||||||
|
|
||||||
|
err := os.Setenv("WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD", value)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testGetSecretsFromFiles(t, "notification-email-server-password", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSecretsFromFilesWithFile(t *testing.T) {
|
||||||
|
value := "megasecretstring"
|
||||||
|
|
||||||
|
// Create the temporary file which will contain a secret.
|
||||||
|
file, err := ioutil.TempFile(os.TempDir(), "watchtower-")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.Remove(file.Name()) // Make sure to remove the temporary file later.
|
||||||
|
|
||||||
|
// Write the secret to the temporary file.
|
||||||
|
secret := []byte(value)
|
||||||
|
_, err = file.Write(secret)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.Setenv("WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD", file.Name())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testGetSecretsFromFiles(t, "notification-email-server-password", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetSecretsFromFiles(t *testing.T, flagName string, expected string) {
|
||||||
|
cmd := new(cobra.Command)
|
||||||
|
SetDefaults()
|
||||||
|
RegisterNotificationFlags(cmd)
|
||||||
|
GetSecretsFromFiles(cmd)
|
||||||
|
value, err := cmd.PersistentFlags().GetString(flagName)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, value)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue