Open tagorenathv opened 6 years ago
Sounds like it's related to SELinux. Do you run it, and could you try turning it off to test?
You mean SELinux = disabled? Tried that too. Still no luck.!
What does your pam config file look like?
Who owns /home/testuser1/.google_authenticator
?
What are the ownerships and permissions on /home/testuser1
?
for .google_authenticator: -rw-------. 1 testuser1 testuser1 136 Jul 18 03:37 .google_authenticator
/etc/pam.d conf: auth required pam_sepermit.so
auth required /usr/local/lib/security/pam_google_authenticator.so echo_verification_code auth include postlogin
/etc/ssh/sshd_config conf: ChallengeResponseAuthentication yes AuthenticationMethods publickey,keyboard-interactive
tried almost all module options.
So getenforce
says Disabled
, verifying that SELinux is off?
What are the permissions and ownerships on /home/testuser1
? ls -ld /home/testuser1
(I've improved the error message a bit in https://github.com/google/google-authenticator-libpam/commit/a48e6492d3a8a15c88002c6959e9de8dba5b0bbc, but won't help us here)
these are my complete details:
/var/log/secure : debug log => sshd(pam_google_authenticator)[4498]: debug: no scratch code used from "/home/testuser1/.google_authenticator" sshd(pam_google_authenticator)[4498]: Accepted google_authenticator for testuser1 sshd(pam_google_authenticator)[4498]: Failed to create tempfile "/home/testuser1/.google_authenticator~1lqc2M": Permission denied sshd(pam_google_authenticator)[4498]: Failed to update secret file "/home/testuser1/.google_authenticator": Permission denied sshd(pam_google_authenticator)[4498]: debug: end of google_authenticator for "testuser1". Result: Authentication failure sshd[4493]: error: PAM: Authentication failure for testuser1 from x.x.x.x sshd(pam_google_authenticator)[4499]: debug: start of google_authenticator for "testuser1" sshd(pam_google_authenticator)[4499]: debug: Secret file permissions are 0600. Allowed permissions are 0600 sshd(pam_google_authenticator)[4499]: debug: "/home/testuser1/.google_authenticator" read sshd(pam_google_authenticator)[4499]: debug: shared secret in "/home/testuser1/.google_authenticator" processed sshd[4493]: Postponed keyboard-interactive for testuser1 from x.x.x.x port 54109 ssh2 [preauth]
ls -ld /home/testuser1/ => drwx------. 3 testuser1 testuser1 124 Jul 18 09:54 /home/testuser1/
ls -ld /home/testuser1/.google_authenticator => -rw-------. 1 testuser1 testuser1 136 Jul 18 09:54 /home/testuser1/.google_authenticator
/etc/selinux/config => SELINUX=disabled
/etc/pam.d/sshd =>
auth required pam_sepermit.so
auth required /usr/local/lib/security/pam_google_authenticator.so debug echo_verification_code auth include postlogin
/etc/ssh/sshd_config => ChallengeResponseAuthentication yes AuthenticationMethods publickey,keyboard-interactive
with debug logs it seems perm issues, but with other prems for .google_authenticator or for home folder m getting Server refused our key
Yeah the problem is the Permission denied
. Permissions on home directory and file look good, so it should wotrk.
Again, does running getenforce
say Disabled
, verifying that SELinux is off?
[testuser1@ip-x-x-x-x~]$ getenforce Enforcing
But at /etc/selinux/config: => SELINUX=disabled
Did you reboot after setting that?
I've not done anything with SELinux, nor do I run RHEL, so don't know what else to check.
I havent and i dont think its possible (prod instances) . Do we have any other procedure to make SELINUX disable change got reflected without reboot? With this I think it will work. Please suggest. Thankyou.
I think by design it's not possible to turn it off on a running system. E.g. see this manpage.
You could place the .google_authenticator
somewhere other than the user's home directory using secret=/etc/ga/$USER/.google_authenticator
and create one new directory there per user.
I'm not sure if SELinux would block that, but you could try it.
still same.
sshd(pam_google_authenticator)[18140]: Failed to create tempfile "/etc/ga/testuser1/.google_authenticator~BqkkJ9": Permission denied sshd(pam_google_authenticator)[18140]: Failed to update secret file "/etc/ga/testuser1/.google_authenticator": Permission denied
folder permissions and .google_authenticator are good. I think only way to make this work is to disable SELINUX.
You could make root own all the directories and files under /etc/ga/ and run with user=root
. That at least should work. But users won't be able to manage their own configs then.
Try setting proper SELinux context. SELinux is not something to be avoided. I know it's a confusing (at first) world, but it pays off. Look for tutorials or ask me privately.
You definitely don't want to disable SELinux. The issue here is that later versions of this software create temporary files in the user home directory (by default) before (presumably) copying the contents into the overarching configuration file then removing them. Thus, the SSH process needs to have permission to perform this task.
One solution to allowing the GA software to operate under SELinux is to move the Google Authenticator configuration file to a folder that both SSH and the user can access, e.g.:
sudo semanage fcontext -a -t auth_home_t "/home/[^/]+/\.ga(/.*)?"
mkdir -p ~\.ga
restorecon -Rv ~\.ga
; and/or import SELinux module which transforms the context of any directory called .ga
created in a user home directory using the template:
policy_module(google_authenticator_transfrom, 1.0)
gen_require(`
type unconfined_t, user_home_dir_t, auth_home_t;
')
filetrans_pattern(unconfined_t, user_home_dir_t, auth_home_t, dir, ".ga")
.google_authenticator
file: cat ~/.google_authenticator > ~/.ga/.google_authenticator && chmod 0400 ~/.ga/.google_authenticator
secret=${HOME}/.ga/.google_authenticator
to the end of the auth required pam_google_authenticator.so
line in /etc/pam.d/sshd
This policy, created by audit2allow, fixed the problem, but it seems a bit clunky to allow ssh_t do all it does... the authenticator lib writes a temp file, deletes a temp file, and requires some kind of renaming as well.
--- begin avrule block ---
decl 1:
commons: <empty>
classes: file{ create open read rename setattr unlink write }
roles : <empty>
types : sshd_t user_home_dir_t
users : <empty>
bools : <empty>
levels : <empty>
cats : <empty>
log entries from denials:
Failed to read "/home/$USER/.google_authenticator"
Failed to create tempfile "/home/$USER/.google_authenticator~pNn1dA": Permission denied
Failed to update secret file "/home/$USER/.google_authenticator": Permission denied
Failed to delete tempfile "/home/$USER/.google_authenticator~TuINiX": Permission denied
I ran into another AVC denial for getattr
... so, my conclusion is that it seems like the cleanest solution on Fedora is to use the existing permissions from the ssh selinux module to work around this. From my limited testing yesterday and today, this should solve the problem without having to create a custom selinux policy.
$ sudo semodule -l | grep ^ssh
$ sudo semanage fcontext -l | grep 'unconfined_u:object_r:ssh_home_t'
the line from the selinux module looks like this
/home/[^/]+/\.ssh(/.*)? all files unconfined_u:object_r:ssh_home_t:s0
~]$ mv .google_authenticator .ssh/
~]$ restorecon -Rv .ssh/
Relabeled /home/user1/.ssh/.google_authenticator from unconfined_u:object_r:auth_home_t:s0 to unconfined_u:object_r:ssh_home_t:s0
And in your pam.d/[service] file, set the file location to $HOME/.ssh/.google_authenticator
pam_google_authenticator.so secret=~/.ssh/.google_authenticator
It looks like the rpm creates contexts as auth_home_t, so sshd_t must operate on auth_home_t files for the defaults to work. There is probably a way to better label these or to include a policy in the rpm that makes this work with sshd.
/home/[^/]+/\.google_authenticator all files unconfined_u:object_r:auth_home_t:s0
/home/[^/]+/\.google_authenticator~ all files unconfined_u:object_r:auth_home_t:s0
@jdbarnes-isi Your changed fixed it for CentOS 8.1.1911 as well.
I prefer the fix suggested by @DPStokesNZ over that of @jdbarnes-isi. AFAICS the fix suggested by @jdbarnes-isi will only work for ssh, but not for other servies, whereas the solution proposed by @DPStokesNZ will work for other things besides, such as Cockpit.
There needs to be some coordination to fix that properly and it is not yet fully clear what the best approach is.
Fact: We can't keep the secret file in ~/.google-authenticator
on SELinux enabled systems, since the file trans can't work with regexp and thus files will be wrongly labeled all the time.
Suggestion is to have to secret in something like: ~/.config/google-authentictor/secret
or ~/.config/ga/secret
Once we agreed on a different location (in a directory), we could add the path to the selinux-policy and then integrate it in the package.
Only doing that over a simply default config file for Fedora systems that points to the new location raises likely issues of the secret not be found, as the google-authenticator bin also expects the file in the standard location and you can't define another default it without patching. Also patching would mean, that we would likely need to check for the directory to exist and create otherwise and so the patch gets larger than what I would want to simply carry on in the package.
I would love to have thoughts by the owners of that repo, what they would be happy to go further. BUT we can't fix it for SELinux enabled systems as it behaves at the moment.
@duritong you're saying you want to patch it here, upstream, to not be a file directly in the home directory?
Seems reasonable. Is there a standards doc for how ~/.config/
is laid out?
Also it'd need to be backwards compatible, so it's not as simple as just changing the default. And if ~/.config
doesn't exist then it needs to be mkdir'd. Same with any subdirs.
@ThomasHabets This is the XDG specification: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
Would someone want the authenticator secret to be the same across multiple services? I personally only use the secret for sshd, not sddm (nor have I tried to see if it integrates with sddm or any other auth stack).
Do services that might want to accept g.a. in the pam stack tolerate using their own existing config directories for this kind of file transformation that is done by g.a.-libpam?
Existing functionality works as long as it's documented that generating a single secret once won't be sufficient for all services, and that on SELinux-enabled sysems, you simply have to copy/move the secret somewhere that your service tolerates and restorecon -r
.
@duritong you're saying you want to patch it here, upstream, to not be a file directly in the home directory?
Exactly. I think it make sense, instead of carrying a half-baked patch for Fedora/RHEL distros.
Seems reasonable. Is there a standards doc for how
~/.config/
is laid out?
based on @zpytela link, I would suggest to put the files into ~/.config/google-authenticator
Also it'd need to be backwards compatible, so it's not as simple as just changing the default. And if
~/.config
doesn't exist then it needs to be mkdir'd. Same with any subdirs.
Yes and this is why it won't be a simple patch and I would be glad to have it integrated here. Thank you!
I'll accept a well-written pull request for this, but realistically I won't be implementing it myself.
Note that I will be picky about e.g. how to create the needed directories if they don't already exist.
Hi @DPStokesNZ, I have tried your procedure, however I am still getting the following errors:
Failed to create tempfile "/root/.ga/.google_authenticator~s8p3zH": Permission denied Failed to update secret file "/root/.ga/.google_authenticator": Permission denied
Any hint?
Failed to create tempfile "/root/.ga/.google_authenticator~s8p3zH": Permission denied Failed to update secret file "/root/.ga/.google_authenticator": Permission denied
Did you add the filecontexts to your policy and apply the right context?
I'll accept a well-written pull request for this, but realistically I won't be implementing it myself.
Note that I will be picky about e.g. how to create the needed directories if they don't already exist.
I can not really commit to write such a patch and glad to have anybody picking that task up, with better C knowledge than me.
@duritong, I guess so ... I created the .te file used "make -f" to get a .pp and finally used semodule -i to load the policy
Hi @DPStokesNZ, I have tried your procedure, however I am still getting the following errors:
Failed to create tempfile "/root/.ga/.google_authenticator~s8p3zH": Permission denied Failed to update secret file "/root/.ga/.google_authenticator": Permission denied
Any hint?
Given that you are trying to use /root I would imagine that the semanage fcontext command won't match given that it is /home folder centric. You can check this with a simple ls -laZ ~ | grep ga
and note that the context is probably still admin_home_t
rather than auth_home_t
.
I would suggest adding the following context then perform the restorecon
command:
sudo semanage fcontext -a -t auth_home_t "/root/\.ga(/.*)?"
Also it'd need to be backwards compatible, so it's not as simple as just changing the default.
I quickly glanced over the current code on how to implement this. My initial idea was to tackle authentication first. For example google_authenticator()
could try to use ~/.config/google-authenticator/secret
first and then (if that file does not exist) fall back to the previous location (~/.google_authenticator
). The assumption is that we still want hard-coded default filename(s) in the code and not a config file containing a default filename which has to be parsed at runtime.
Ideally we would only fall back if the path does not exist at all (but not in case of insecure file permissions) but looking at open_secret_file()
it seems that it would be easier to fall back whenever the new path is not suitable. However we should not log Failed to read ...
for the first try to avoid misleading (error) log messages.
Is that a reasonable approach? I did not write any pam modules before so I might be blissfully unaware of some security constraints. I'd be glad for any criticism before any code is written so I don't waste time.
Please note I can't really ensure I will come up with some usable code. Real life tends to insert itself at the worst possible moments...
What I'm thinking is that it may be best to create a new function open_first_secret_file()
or something that tries one, then the other. You can extend the return value of open_secret_file()
to be 0 on success, 1 on fail-but-continue, and 2 for final-fail?
The Failed to read
message is deceptive anyway, it actually failed to open.
But if you wrap it in a function, and only that function calles open_secret_file
, then you can do the logging from the caller depending on the return value, thus prevent double error logging. Also if both fail on open()
you probably want to log just one line saying failed to open either of these two.
Maybe something like that?
You can extend the return value of
open_secret_file()
to be 0 on success, 1 on fail-but-continue, and 2 for final-fail?
Currently open_secret_file()
returns fd
on success (so the code comment above that function is wrong/misleading) so I guess you mean -1 for fail-but-continue and -2 for final fail?
Otherwise I agree that this might be a good way to implement the feature.
Doh, I was fooled by my own incorrect comment on top of the function. :-(
No worries, I can add a commit to a potential PR which fixes that (unless you want to fix that first - feel free to do so ofc).
I fixed the comment
Currently get_secret_filename()
is called within the privileged part of google_authenticator()
while open_secret_file()
is only called after unnecessary privileges were dropped.
get_secret_filename()
from open_first_secret_file()
so the first function is also called with user privileges. The resulting code might be more compact but I suspect this might have some security implications.open_first_secret_file()
. Do you have a preference for two char *
vs char **
+int
?(Sorry if all these detail questions are too much noise and I can understand if you don't want to spend so much time on that little feature you are not interested in. Please drop me a note and I'll try to come up with some working code without guidance - might be more hassle in the review though ;-).
I understand not wanting to waste time implementing something only to be asked to do the other way. :-)
Hmm… I don't see why get_secret_filename()
should not be good, better even, to call after dropping privs. If you want to move things from before to after drop, then probably best to keep that a single commit. One commit, one conceptual change.
Up to you on char*
vs char**
+int
. Whatever makes for cleanest code. I don't foresee a list to be needed in the future, so if it's cleaner to hard code two, then that's fine.
Any progress on this? Can't use google-authenticator with Cockpit on Fedora 34.
Has there been any progress on this?
None that I know. Note that what's left here is actually just a feature request to change the default secrets filename location. Nothing is preventing anyone using the option to PAM, and to the CLI when provisioning.
Workaround:
Save .google_authenticator to .yubico/ directory:
google-authenticator -s .yubico/.google_authenticator
Add this line to your PAM configuration file:
auth required pam_google_authenticator.so secret=~/.yubico/.google_authenticator
SELinux added support for the .yubico/ directory in 2013, so most of the current systems support it: https://github.com/fedora-selinux/selinux-policy/commit/0d81967b8884426951150b126f0e63c294f503ec
My personal workaround is semanage permissive -a cockpit_session_t
.
I still get the error messages but I can use Cockpit with Google Authenticator on Fedora 36 Server Edition.
Updating the label to ssh_home_t resolved the issue for me
Workaround:
- Save .google_authenticator to .yubico/ directory:
google-authenticator -s .yubico/.google_authenticator
- Add this line to your PAM configuration file:
auth required pam_google_authenticator.so secret=~/.yubico/.google_authenticator
SELinux added support for the .yubico/ directory in 2013, so most of the current systems support it: fedora-selinux/selinux-policy@0d81967
Sam problem on Fedora 40/ Fedora IOT:
$ sudo semanage fcontext -l | grep yubico
/home/[^/]+/\.yubico(/.*)? all files unconfined_u:object_r:auth_home_t:s0
/root/\.yubico(/.*)? all files system_u:object_r:auth_home_t:s0
$ sudo semanage fcontext -l | grep .google_authenticator
/home/[^/]+/\.google_authenticator all files unconfined_u:object_r:auth_home_t:s0
/home/[^/]+/\.google_authenticator~ all files unconfined_u:object_r:auth_home_t:s0
/root/\.google_authenticator all files system_u:object_r:auth_home_t:s0
/root/\.google_authenticator~ all files system_u:object_r:auth_home_t:s0
Did it missing (/.*)?
with install script ?
Resolved this by create a new dir, put the .google_authenticator here,then set the pam:
CFG_DIR=$HOME/.config/Google-authenticator
HOMEBASE=$(dirname $HOME)
mkdir -p $CFG_DIR
sudo semanage fcontext --add --type auth_home_t "$HOMEBASE/[^/]+/\.config/Google-authenticator(/.*)?"
sudo restorecon -Rv $CFG_DIR
cat ~/.google_authenticator |tee $CFGDIR/.google_authenticator && chmod 0400 $CFGDIR/.google_authenticator
sudo vi /etc/pam.d/sshd
auth required pam_google_authenticator.so secret=${HOME}/.config/Google-authenticator/.google_authenticator
sudo systemctl restart sshd
log in /var/log/secure : sshd(pam_google_authenticator)[6902]: Accepted google_authenticator for testuser1 sshd(pam_google_authenticator)[6902]: Failed to delete tempfile “/home/testuser1/.google_authenticator~Q6SNiK”: No such file or directory sshd(pam_google_authenticator)[6902]: Failed to update secret file “/home/testuser1/.google_authenticator”: Permission denied sshd[6900]: error: PAM: Authentication failure for testuser1 from XXX.XXX.XX.XX
.google_authenticator have 600 permission. Followed all steps as mentioned, still not able to login. Using RHEL 7.5 AMI.