Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMTP config: add global and local password file fields #3038

Merged
merged 13 commits into from Sep 16, 2022

Conversation

ericrrath
Copy link
Contributor

Add config fields (for both global email config and route-specific email
config) that specify path to file containing SMTP password. We don't
want the password in the config file itself, and reading the password
from a k8s-secret-backed file keeps the password itself "encrypted at
rest" in etcd, and cleanly separated from the rest of the AM config.

This is intended to partially address issue #2498

I used the same approach as pull request #2534

@joywaves
Copy link

Can't wait to see this PR in place, thank you much @ericrrath

@valvin1
Copy link

valvin1 commented Aug 31, 2022

it looks this PR is what I need to avoid to do weird thing such as :

  • push an smtp password in plain in my config file on a git repository
  • encrypt my whole alertmanager configuration file
  • setup a local smtp to manage authentification

What this PR requires to do some progress?

Copy link
Member

@simonpasquier simonpasquier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for doing this!

Smarthost HostPort `yaml:"smarthost,omitempty" json:"smarthost,omitempty"`
AuthUsername string `yaml:"auth_username,omitempty" json:"auth_username,omitempty"`
AuthPassword Secret `yaml:"auth_password,omitempty" json:"auth_password,omitempty"`
AuthPasswordFile Secret `yaml:"auth_password_file,omitempty" json:"auth_password_file,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need the *File fields to be of type Secret, they can be plain string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, fixed.

config/config.go Outdated
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
SMTPAuthPasswordFile Secret `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here about the field's type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, fixed.

config/config.go Outdated
@@ -365,8 +369,13 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if ec.AuthUsername == "" {
ec.AuthUsername = c.Global.SMTPAuthUsername
}
if ec.AuthPassword == "" {
// require a password only if a username is provided
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how this change relates to the original issue? Can you elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another good catch. I thought username-but-no-password was an invalid config, but now see that it's explicitly supported. Simplified.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, wait, sorry, I was rushing, and misread the code in that last part. no-username is supported, but username-without-password still produces errors. Hold on, let me get this sorted. Sorry for the hassle.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I finally remembered. Local configs inherit fields from the global config, and now that the SMTP password can come from two different kinds of field -- literal or from-file -- I wanted to avoid having a local config with one kind of field inheriting the other kind of field from global. I.e. if the global config has SMTPAuthPasswordFile set, and a local config has AuthPassword set, that local config should not inherit SMTPAuthPasswordFile.

I updated the code again to enforce that; local configs now only inherit the global SMTP password fields if both of the local fields are unset.

}
content, err := os.ReadFile(string(n.conf.AuthPasswordFile))
if err != nil {
return ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should return an error, rather than silently discarding the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed. My first instinct was to have this new func treat both the "raw" and "file" fields being unset as an error, and return that error. But the "upstream" code already has a check for that case, so I just had the new func return "" if both fields are unset.

Add config fields (for both global email config and route-specific email
config) that specify path to file containing SMTP password.  We don't
want the password in the config file itself, and reading the password
from a k8s-secret-backed file keeps the password itself "encrypted at
rest" in etcd, and cleanly separated from the rest of the AM config.

I used the same approach as pull request prometheus#2534 "Add support to set the
Slack URL in the file"
<https://github.com/prometheus/alertmanager/pull/2534/files> in the
upstream repo.

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
docs/configuration.md Outdated Show resolved Hide resolved
docs/configuration.md Show resolved Hide resolved
docs/configuration.md Outdated Show resolved Hide resolved
ericrrath and others added 2 commits September 13, 2022 09:25
Co-authored-by: Simon Pasquier <spasquie@redhat.com>
Signed-off-by: Eric R. Rath <4080262+ericrrath@users.noreply.github.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Copy link
Member

@simonpasquier simonpasquier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add sub-tests here that verify the happy (password file configured with good value) and sad (password file configured with wrong value) paths?

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
@ericrrath
Copy link
Contributor Author

could you add sub-tests here that verify the happy (password file configured with good value) and sad (password file configured with wrong value) paths?

Another good catch; done!

Copy link
Member

@simonpasquier simonpasquier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! I'm being a bit nit-picky but could you also add a test that would configure an invalid file name and trigger an error when getPassword() gets called?

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
… set

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
@ericrrath
Copy link
Contributor Author

Very cool! I'm being a bit nit-picky but could you also add a test that would configure an invalid file name and trigger an error when getPassword() gets called?

Done!

Copy link
Member

@simonpasquier simonpasquier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@@ -365,8 +369,9 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if ec.AuthUsername == "" {
ec.AuthUsername = c.Global.SMTPAuthUsername
}
if ec.AuthPassword == "" {
if ec.AuthPassword == "" && ec.AuthPasswordFile == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@simonpasquier simonpasquier merged commit efc956c into prometheus:main Sep 16, 2022
qinxx108 pushed a commit to qinxx108/alertmanager that referenced this pull request Dec 13, 2022
* SMTP config: add global and local password file fields

Add config fields (for both global email config and route-specific email
config) that specify path to file containing SMTP password.  We don't
want the password in the config file itself, and reading the password
from a k8s-secret-backed file keeps the password itself "encrypted at
rest" in etcd, and cleanly separated from the rest of the AM config.

I used the same approach as pull request prometheus#2534 "Add support to set the
Slack URL in the file"
<https://github.com/prometheus/alertmanager/pull/2534/files> in the
upstream repo.

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* changed *AuthPasswordFile field types to string per review feedback

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* added error to getPassword() retval per review feedback

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* simplified conf.smtp-* files

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* update docs to reflect field type change

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* don't treat username-without-password as invalid

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* test cleanup

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* Apply suggestions from code review

Co-authored-by: Simon Pasquier <spasquie@redhat.com>
Signed-off-by: Eric R. Rath <4080262+ericrrath@users.noreply.github.com>

* Updated per review feedback

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* added sub-test per review feedback

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* added test on Email.getPassword() per feedback

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* only inherit global SMTP passwords if neither local password field is set

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

* removed blank line caught by gofumpt

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>

Signed-off-by: Eric R. Rath <eric.rath@oracle.com>
Signed-off-by: Eric R. Rath <4080262+ericrrath@users.noreply.github.com>
Co-authored-by: Simon Pasquier <spasquie@redhat.com>
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants