Hi,
I have prepared a wiki page summarizing the discussion that happened previously on this list: https://lists.fedorahosted.org/pipermail/sssd-devel/2014-July/020867.html
Here is the wiki page: https://fedorahosted.org/sssd/wiki/DesignDocs/RestrictDomainsInPAM For your convenience, I copied the design page text below verbatim.
Does that reflect the discussion accurately?
Provided it does...
Daniel, based on the contents of the page, do you which parts of SSSD need to be touched? I was wondering if we could help with some of the three subtasks. For example adding a new option requires touching several places such as the man pages or the python configAPI. Could we maybe create a skeleton that just loads the option for you?
Please note I'm not trying to take over the feature from you, your contribution is really welcome. It's just that some parts of the SSSD development process, such as adding a new option are not documented anywhere and might be difficult to find for a newcomer. And we would like to get this feature merged sooner rather than later..
See the full design page text below:
= Restricting the domains a PAM service can auth against =
Related ticket(s): * https://fedorahosted.org/sssd/ticket/2370
=== Problem statement === Some environments require that different PAM applications can use a different set of SSSD domains. An example might be a system where, depending on which VPN PAM service you log with, you authenticate against a different set of remote servers. The legacy PAM modules were able to use a different configuration file altogether as a parameter for the PAM module. This wiki page describes a similar feature for the SSSD.
=== Overview of the solution === On the PAM client side, the PAM module should receive a new option that specifies the SSSD domains to authenticate against. However, the SSSD daemon can't fully trust all PAM services. We can't rely on the PAM service fields either, as the data the PAM client sends to the PAM application can be faked by the client, especially by users who posses shell access or can start custom applications. Instead, there needs to be a list of users who we trust. Typically, this would be a list of users who run the PAM aware applications we wish to restrict (such as `vsftpd` or `openvpn`). This list would default to `root` only.
These trusted users would be allowed to authenticate against any domain and would also be able to restrict the domains further using a new pam_sss option. For the untrusted users, we need to keep a list of domains allowed to authenticate against, too. Since by default there are no restrictions on the allowed domains, this list would default to "all domains are allowed".
=== Implementation details === This section breaks down the Overview of the solution into consumable pieces.
==== Add a new option `pam_trusted_users` ==== A new option must be added to the PAM responder. This option will be a list of numerical UIDs or user names that are trusted. This list will be parsed during PAM responder initialization (`pam_process_init` call) using the `csv_string_to_uid_array` function and stored in the PAM responder context (`struct pam_ctx`). The PAC responder does pretty much the same in the `pac_process_init` function.
In the responder, we already have the credentials of the client stored in the `cli_ctx` structure. When a new request comes into the `pam_forwarder` function, we will match the client UID against the list of trusted IDs and determine whether the client is trusted or not.
==== Add a option to limit the domains for untrusted users ==== Another option, called `pam_allowed_auth_domains` shall be added. This option will list the SSSD domains an untrusted client can authenticate against. The option will accept either a comma-separated list of SSSD domains or any of two special values "all" and "none". The default value will be "all" in order to keep the current behaviour where any client can authenticate against any domain.
The option will be parsed during `pam_process_init` and stored in the `pam_ctx` structure. An untrusted client will only be allowed to send a request to a domain that matches the list of allowed domains.
In order to keep the implementation simple, the `allow` keyword would copy all domain names into `pam_ctx` and the `none` keyword would set the variable holding the names to NULL. Then the check would be a simple loop for all cases.
Care must be taken to ensure a sensible PAM error code for cases where the domain wouldn't match.
==== Add a new pam module option to limit the domains ==== The PAM module will gain a new option, called `domains` that will allow the administrator to use a list of domains to authenticate this PAM service against. In the PAM responder, this option will only be in effect for trusted clients. If the client is trusted, only domains listed in this PAM option will be considered for authentication.
Please note that a patch implementing most of the functionality of this PAM module option was contributed to the sssd-devel mailing list by Daniel Gollub already.
==== Password Changes ==== Password changes should be allowed against all domains.
=== How To Test === 1. Prepare an SSSD installation with at least two domains A and B. 1. Pick a PAM service that is running by a trusted user. One example might be VPN service ran by the openvpn user or similar. Add this user as a value of `pam_trusted_users` option in the `[pam]` section. 1. Add one of the domains (domain A) as a `domain=` parameter into the `auth` section of your service's PAM config file 1. Edit `sssd.conf` and set `pam_allowed_auth_domains = none`. 1. Authenticate using the selected PAM service as a user from domain A. The authentication should succeed. 1. Authenticate using the same service as a user from domain B. The authentication should fail and there should be a reasonable (ie not System Error) return code returned to the application 1. Authenticate using a different PAM service. Make sure this service is ran by an untrusted user (not root!). Logins against both A and B should fail. 1. Change the value of `pam_allowed_auth_domains` to A. Login against A should succeed from a service running as untrusted user. 1. Change the value of `pam_allowed_auth_domains` to all. Login against both domains should succeed from a service running as untrusted user. 1. Remove the `domains=` option from the PAM config file. The trusted service should now be able to log in against both SSSD domains.
=== Authors === * Daniel Gollub dgollub@brocade.com * Jakub Hrozek jhrozek@redhat.com * Simo Sorce simo@redhat.com
On Fri, Sep 19, 2014 at 08:26:48PM +0200, Jakub Hrozek wrote:
=== Overview of the solution === On the PAM client side, the PAM module should receive a new option that specifies the SSSD domains to authenticate against. However, the SSSD daemon can't fully trust all PAM services. We can't rely on the PAM service fields either, as the data the PAM client sends to the PAM application can be faked by the client, especially by users who posses shell access or can start custom applications. Instead, there needs to be a list of users who we trust. Typically, this would be a list of users who run the PAM aware applications we wish to restrict (such as `vsftpd` or `openvpn`). This list would default to `root` only.
These trusted users would be allowed to authenticate against any domain and would also be able to restrict the domains further using a new pam_sss option. For the untrusted users, we need to keep a list of domains allowed to authenticate against, too. Since by default there are no restrictions on the allowed domains, this list would default to "all domains are allowed".
What would be the recommended workflow for services that create new PAM services on the fly. Think of hosting multitude of web services (Apaches) running each in different uid. When setting up that web service, PAM server might get configured for it, restricting the list of domains this PAM service is allowed/supposed to use. For this to work, sssd.conf would need to be amended each time and sssd restarted, adding new uid of the new Apache setup to the list of pam_trusted_users.
Why eactly does the list of domains need to be protected by the list of uids?
On Mon, Sep 22, 2014 at 02:03:51PM +0200, Jan Pazdziora wrote:
On Fri, Sep 19, 2014 at 08:26:48PM +0200, Jakub Hrozek wrote:
=== Overview of the solution === On the PAM client side, the PAM module should receive a new option that specifies the SSSD domains to authenticate against. However, the SSSD daemon can't fully trust all PAM services. We can't rely on the PAM service fields either, as the data the PAM client sends to the PAM application can be faked by the client, especially by users who posses shell access or can start custom applications. Instead, there needs to be a list of users who we trust. Typically, this would be a list of users who run the PAM aware applications we wish to restrict (such as `vsftpd` or `openvpn`). This list would default to `root` only.
These trusted users would be allowed to authenticate against any domain and would also be able to restrict the domains further using a new pam_sss option. For the untrusted users, we need to keep a list of domains allowed to authenticate against, too. Since by default there are no restrictions on the allowed domains, this list would default to "all domains are allowed".
What would be the recommended workflow for services that create new PAM services on the fly. Think of hosting multitude of web services (Apaches) running each in different uid. When setting up that web service, PAM server might get configured for it, restricting the list of domains this PAM service is allowed/supposed to use. For this to work, sssd.conf would need to be amended each time and sssd restarted, adding new uid of the new Apache setup to the list of pam_trusted_users.
Would adding each of the users to a certain group and amending the configuration so that also a trusted GID can be specified help?
Why eactly does the list of domains need to be protected by the list of uids?
Apparently the rest of the PAM data can be faked by the client.
See: https://lists.fedorahosted.org/pipermail/sssd-devel/2014-July/020895.html and: https://lists.fedorahosted.org/pipermail/sssd-devel/2014-July/020897.html and: https://lists.fedorahosted.org/pipermail/sssd-devel/2014-July/020907.html
On Mon, Sep 22, 2014 at 03:54:09PM +0200, Jakub Hrozek wrote:
Why eactly does the list of domains need to be protected by the list of uids?
Apparently the rest of the PAM data can be faked by the client.
How is that worse than the current situation when the client can pass "user@DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT" to pam_start?
On Mon, Sep 22, 2014 at 03:58:50PM +0200, Jan Pazdziora wrote:
On Mon, Sep 22, 2014 at 03:54:09PM +0200, Jakub Hrozek wrote:
Why eactly does the list of domains need to be protected by the list of uids?
Apparently the rest of the PAM data can be faked by the client.
How is that worse than the current situation when the client can pass "user@DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT" to pam_start?
It's not worse, but the options aim at hardening the situation :)
Currently, all processes are untrusted and all processes can access whatever domain they want. With the proposed scheme, some UIDs can be trusted to send PAM data because we know who that process is. These processes can not only access all domains but also restrict themeselves to a subset of domains.
What is an untrusted process allowed to do is controlled by a new proposed pam_allowed_auth_domains parameter. If you want only trusted processes to access DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT you can set:
[sssd] domains = public, DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT
[pam] pam_trusted_users = apache pam_allowed_auth_domains = public
and in /etc/pam.d/httpd: pam_sss domains=DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT
Now the apache user is able to access DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT and all other users are only able to access the public domain.
Makes sense?
On Mon, Sep 22, 2014 at 05:13:32PM +0200, Jakub Hrozek wrote:
On Mon, Sep 22, 2014 at 03:58:50PM +0200, Jan Pazdziora wrote:
On Mon, Sep 22, 2014 at 03:54:09PM +0200, Jakub Hrozek wrote:
Why eactly does the list of domains need to be protected by the list of uids?
Apparently the rest of the PAM data can be faked by the client.
How is that worse than the current situation when the client can pass "user@DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT" to pam_start?
It's not worse, but the options aim at hardening the situation :)
Currently, all processes are untrusted and all processes can access whatever domain they want. With the proposed scheme, some UIDs can be trusted to send PAM data because we know who that process is. These processes can not only access all domains but also restrict themeselves to a subset of domains.
What is an untrusted process allowed to do is controlled by a new proposed pam_allowed_auth_domains parameter. If you want only trusted processes to access DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT you can set:
[sssd] domains = public, DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT
[pam] pam_trusted_users = apache pam_allowed_auth_domains = public
and in /etc/pam.d/httpd: pam_sss domains=DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT
Now the apache user is able to access DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT and all other users are only able to access the public domain.
Makes sense?
Simo, does the design page reflect the discussion accurately? Can we start on the implementation?
On Tue, 23 Sep 2014 11:22:45 +0200 Jakub Hrozek jhrozek@redhat.com wrote:
On Mon, Sep 22, 2014 at 05:13:32PM +0200, Jakub Hrozek wrote:
On Mon, Sep 22, 2014 at 03:58:50PM +0200, Jan Pazdziora wrote:
On Mon, Sep 22, 2014 at 03:54:09PM +0200, Jakub Hrozek wrote:
Why eactly does the list of domains need to be protected by the list of uids?
Apparently the rest of the PAM data can be faked by the client.
How is that worse than the current situation when the client can pass "user@DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT" to pam_start?
It's not worse, but the options aim at hardening the situation :)
Currently, all processes are untrusted and all processes can access whatever domain they want. With the proposed scheme, some UIDs can be trusted to send PAM data because we know who that process is. These processes can not only access all domains but also restrict themeselves to a subset of domains.
What is an untrusted process allowed to do is controlled by a new proposed pam_allowed_auth_domains parameter. If you want only trusted processes to access DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT you can set:
[sssd] domains = public, DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT
[pam] pam_trusted_users = apache pam_allowed_auth_domains = public
and in /etc/pam.d/httpd: pam_sss domains=DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT
Now the apache user is able to access DOMAIN.THEY.SHOULD.NOT.KNOW.ABOUT and all other users are only able to access the public domain.
Makes sense?
Simo, does the design page reflect the discussion accurately? Can we start on the implementation?
Yes I made a minor edit to the password change clause, should we add a test point about it too ?
Simo.
On Tue, Sep 23, 2014 at 09:07:06AM -0400, Simo Sorce wrote:
Simo, does the design page reflect the discussion accurately? Can we start on the implementation?
Yes I made a minor edit to the password change clause, should we add a test point about it too ?
Simo.
Ah, thank you very much, that much clearer. Yes, I agree we should add a test case -- so far I added one that says pretty much what you said in the implementation phase. I'm not sure if we need more, because normally you're not allowed to chpass as anyone else than self and IIRC we explicitly drop password change requests from root.
In another conversation with Dmitri, I proposed two other changes I'd like to discuss:
Normally, the list of allowed domains for untrusted users should be 'all', which is the current behavirour. However, if the trusted user list is set, we should default to 'none' and require that access to untrusted domains is set explicitly.
The other change is a new [domain] section option, maybe "allow_untrusted" that would make it possible to augment the global list of domains allowed for untrusted users. While the option doesn't have too much use now, it will be very useful when we allow merging configs and defining a new domain just by dropping a file.
On Tue, 23 Sep 2014 15:39:19 +0200 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Sep 23, 2014 at 09:07:06AM -0400, Simo Sorce wrote:
Simo, does the design page reflect the discussion accurately? Can we start on the implementation?
Yes I made a minor edit to the password change clause, should we add a test point about it too ?
Simo.
Ah, thank you very much, that much clearer. Yes, I agree we should add a test case -- so far I added one that says pretty much what you said in the implementation phase. I'm not sure if we need more, because normally you're not allowed to chpass as anyone else than self and IIRC we explicitly drop password change requests from root.
In another conversation with Dmitri, I proposed two other changes I'd like to discuss:
Normally, the list of allowed domains for untrusted users should be 'all', which is the current behavirour. However, if the trusted user list is set, we should default to 'none' and require that access to untrusted domains is set explicitly.
Why ? I do not think we really need to have this, having defaults change based on other parameters may confuse people. I would rather just document that you should change the other value in the man page and documentation.
The other change is a new [domain] section option, maybe "allow_untrusted" that would make it possible to augment the global list of domains allowed for untrusted users. While the option doesn't have too much use now, it will be very useful when we allow merging configs and defining a new domain just by dropping a file.
I would defer this to when we have actual requests for it. I am not necessarily opposed but it will be confusing. You see a list of domains (or even 'none') and then you have to (at least mentally) parse all the code snippets to find out who can do what.
I think domain snippets, in general, should not influence other services behavior, but just define the domain itself.
Simo.
On Tue, Sep 23, 2014 at 10:03:36AM -0400, Simo Sorce wrote:
On Tue, 23 Sep 2014 15:39:19 +0200 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Sep 23, 2014 at 09:07:06AM -0400, Simo Sorce wrote:
Simo, does the design page reflect the discussion accurately? Can we start on the implementation?
Yes I made a minor edit to the password change clause, should we add a test point about it too ?
Simo.
Ah, thank you very much, that much clearer. Yes, I agree we should add a test case -- so far I added one that says pretty much what you said in the implementation phase. I'm not sure if we need more, because normally you're not allowed to chpass as anyone else than self and IIRC we explicitly drop password change requests from root.
In another conversation with Dmitri, I proposed two other changes I'd like to discuss:
Normally, the list of allowed domains for untrusted users should be 'all', which is the current behavirour. However, if the trusted user list is set, we should default to 'none' and require that access to untrusted domains is set explicitly.
Why ? I do not think we really need to have this, having defaults change based on other parameters may confuse people. I would rather just document that you should change the other value in the man page and documentation.
I'm afraid administrators will not read the docs in full. If the default is 'allow all' they might just append the domains=foo parameter to the pam_sss.so line and think that the pam module can only contact a certain domain. In reality, all untrusted processes would still be able to access all domains.
Forcing the admin to change the list of domains accessible to untrusted users would make sure they explicitly spell out the domains..
The other change is a new [domain] section option, maybe "allow_untrusted" that would make it possible to augment the global list of domains allowed for untrusted users. While the option doesn't have too much use now, it will be very useful when we allow merging configs and defining a new domain just by dropping a file.
I would defer this to when we have actual requests for it. I am not necessarily opposed but it will be confusing. You see a list of domains (or even 'none') and then you have to (at least mentally) parse all the code snippets to find out who can do what.
I think domain snippets, in general, should not influence other services behavior, but just define the domain itself.
OK, we can defer. I will make a note to the ticket that describes including configuration so that we don't forget.
On Tue, 23 Sep 2014 16:54:45 +0200 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Sep 23, 2014 at 10:03:36AM -0400, Simo Sorce wrote:
On Tue, 23 Sep 2014 15:39:19 +0200 Jakub Hrozek jhrozek@redhat.com wrote:
On Tue, Sep 23, 2014 at 09:07:06AM -0400, Simo Sorce wrote:
Simo, does the design page reflect the discussion accurately? Can we start on the implementation?
Yes I made a minor edit to the password change clause, should we add a test point about it too ?
Simo.
Ah, thank you very much, that much clearer. Yes, I agree we should add a test case -- so far I added one that says pretty much what you said in the implementation phase. I'm not sure if we need more, because normally you're not allowed to chpass as anyone else than self and IIRC we explicitly drop password change requests from root.
In another conversation with Dmitri, I proposed two other changes I'd like to discuss:
Normally, the list of allowed domains for untrusted users should be 'all', which is the current behavirour. However, if the trusted user list is set, we should default to 'none' and require that access to untrusted domains is set explicitly.
Why ? I do not think we really need to have this, having defaults change based on other parameters may confuse people. I would rather just document that you should change the other value in the man page and documentation.
I'm afraid administrators will not read the docs in full. If the default is 'allow all' they might just append the domains=foo parameter to the pam_sss.so line and think that the pam module can only contact a certain domain. In reality, all untrusted processes would still be able to access all domains.
Forcing the admin to change the list of domains accessible to untrusted users would make sure they explicitly spell out the domains..
Ok what about we change how things work then. We set pam_allowed_auth_domains to always be none by default, but we make the default for pam_trusted_users to be ALL (or * whatever looks better).
This way in current configs all keeps working as users are all trusted.
The other change is a new [domain] section option, maybe "allow_untrusted" that would make it possible to augment the global list of domains allowed for untrusted users. While the option doesn't have too much use now, it will be very useful when we allow merging configs and defining a new domain just by dropping a file.
I would defer this to when we have actual requests for it. I am not necessarily opposed but it will be confusing. You see a list of domains (or even 'none') and then you have to (at least mentally) parse all the code snippets to find out who can do what.
I think domain snippets, in general, should not influence other services behavior, but just define the domain itself.
OK, we can defer. I will make a note to the ticket that describes including configuration so that we don't forget.
Thanks
Simo.
On Tue, Sep 23, 2014 at 11:01:22AM -0400, Simo Sorce wrote:
Normally, the list of allowed domains for untrusted users should be 'all', which is the current behavirour. However, if the trusted user list is set, we should default to 'none' and require that access to untrusted domains is set explicitly.
Why ? I do not think we really need to have this, having defaults change based on other parameters may confuse people. I would rather just document that you should change the other value in the man page and documentation.
I'm afraid administrators will not read the docs in full. If the default is 'allow all' they might just append the domains=foo parameter to the pam_sss.so line and think that the pam module can only contact a certain domain. In reality, all untrusted processes would still be able to access all domains.
Forcing the admin to change the list of domains accessible to untrusted users would make sure they explicitly spell out the domains..
Ok what about we change how things work then. We set pam_allowed_auth_domains to always be none by default, but we make the default for pam_trusted_users to be ALL (or * whatever looks better).
I think we have a similar problem here b/c we need to document that merely adding domains= to the pam_sss.so module doesn't restrict the domains sssd talks to, you still need to edit sssd.conf. But we only have one set of defaults and they don't change, so I'm OK with this proposal.
This way in current configs all keeps working as users are all trusted.
Previous configs would work also in the previous schema, but I agree the configuration is simpler now.
On Tue, Sep 23, 2014 at 10:03:36AM -0400, Simo Sorce wrote:
I would defer this to when we have actual requests for it. I am not necessarily opposed but it will be confusing. You see a list of domains (or even 'none') and then you have to (at least mentally) parse all the code snippets to find out who can do what.
I think domain snippets, in general, should not influence other services behavior, but just define the domain itself.
Actually, I've been hoping we could move towards making [domain/...] and [pam-service/...] and other types not just define what their are, but also the behaviour of the rest of the sssd towards that object. It feels a bit more natural to say "for this domain, these users can consume the identities", than go the other way round.
On Mon, 29 Sep 2014 15:28:28 +0200 Jan Pazdziora jpazdziora@redhat.com wrote:
On Tue, Sep 23, 2014 at 10:03:36AM -0400, Simo Sorce wrote:
I would defer this to when we have actual requests for it. I am not necessarily opposed but it will be confusing. You see a list of domains (or even 'none') and then you have to (at least mentally) parse all the code snippets to find out who can do what.
I think domain snippets, in general, should not influence other services behavior, but just define the domain itself.
Actually, I've been hoping we could move towards making [domain/...] and [pam-service/...] and other types not just define what their are, but also the behaviour of the rest of the sssd towards that object. It feels a bit more natural to say "for this domain, these users can consume the identities", than go the other way round.
The problem of doing this is that then users from "other" domains are kind of out of place, also the admin needs to inspect several snippets to find out what is the overall security policy, I am not comfortable with the latter specifically.
Simo.
sssd-devel@lists.fedorahosted.org