On pe, 13 touko 2022, Sam Morris via FreeIPA-users wrote:
I'm looking into using <https://github.com/guilhem/freeipa-issuer> to
request certificates from FreeIPA on behalf of a (FreeIPA) service.

The project authenticates to the FreeIPA API with a specified username
and password:
<https://github.com/guilhem/freeipa-issuer/blob/174d145616a672b09d3fdb56b2dd7c93612e483e/provisionners/freeipa.go#L38>

I presume this means that it's only possible for it to authenticate to
the FreeIPA API as a user, as opposed to a host or service.

Not correct. You can authenticate with any Kerberos principal. Your
rights would be limited to what that object is allowed to do and this
can be adjusted with permissions/privileges/roles:
https://vda.li/en/posts/2016/08/30/Creating-permissions-in-FreeIPA/

We support:
 - adding users and groups to roles (since ... FreeIPA 2?)
 - allow services as group members
   (https://pagure.io/freeipa/issue/7513, since 4.7.0)
 - adding user ID overrides from the Default Trust View as group and
   role members (https://pagure.io/freeipa/issue/7255, since 4.9.0)

Host principal by default has rights to manage own services. We use this
a lot in different scenarios, an example can be seen in my recent update
to FreeIPA workshop where in chapter 12 we set up Keycloak on IPA client
and issue certificates for it, managed by the certmonger with host
principal:
https://freeipa.readthedocs.io/en/latest/workshop/12-external-idp-support.html#set-up-keycloak-idp-on-enrolled-ipa-client


That being the case, I am trying to lock things down as much as
possible, so that the user is only able to request certificates for a
single service.

I've had a read through Fraiser's excellent blog post
<https://frasertweedale.github.io/blog-redhat/posts/2015-09-02-freeipa-cert-issuance-delegation.html>
which points me towards creating a CA ACL, which I've done.

The CA ACL links together the user, the service and for good measure I
specified the CA and the profile too. But it's not sufficient to allow a
certificate request to work, as when the issuer tries to ask for the
certificate:

   Fail to request certificate: ACIError (2100): Insufficient access:
   not allowed to perform operations: request certificate

Returning to the blog post, I gather I additionally need to grant the
following two permissions to the user:

* 'Request Certificate'
* 'System: Modify Services'

What I'd like to understand is the scope of these permissions.

Does 'Request certificate' merely unlock the ability to make requests
that are themselves constrained by CA ACLs? That being the case, this
permission alone doesn't let the user request certificates for any other
hosts or services, right?

As for 'System: Modify Services': I guess granting this permission will
allow the user to add certificates to *any* service? In which case, I
suppose I need to create a new privilege that allows the usercertificate
of a particular entry only to be modified. Are there any examples of
this?

I would start on a different side. What is CA ACL? You can think of the
CA ACL as an HBAC rule:
 - CA id is used as a target host
 - CA profile id is used as a target service name
 - for user, its groups used to populate list of groups in the rule
 - for host, its hostgroups used to populate list of groups in the rule
 - for services, its group membership is also used to populate list of
   groups in the rule

There is an incomplete implementation, though, that does not take actual
service principal into account when evaluating these rules. I need to
file a bug about it and fix it. This is not a problem for certmonger
because it acts as a host principal which is supported.

The sequence of checks when considering whether a bound principal can
request certificates is the following:

 - check whether the bound principal is not a asking for itself and it
   is not a host

 - if that's true, then check that the bound principal can write to
   objectclass attribute of the virtual operation 'Request Certificate':

        # Request Certificate virtual op
        dn: cn=Request Certificate,cn=permissions,cn=pbac,$SUFFIX
        changetype: add
        objectClass: top
        objectClass: groupofnames
        objectClass: ipapermission
        cn: Request Certificate
        member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX

        dn: $SUFFIX
        changetype: modify
        add: aci
        aci: (targetattr = "objectclass")
             (target = "ldap:///cn=request certificate,cn=virtual 
operations,cn=etc,$SUFFIX" )
(version 3.0 ; acl "permission:Request Certificate" ; allow (write)
              groupdn = "ldap:///cn=Request 
Certificate,cn=permissions,cn=pbac,$SUFFIX";)

 - otherwise, check that it can write to the attribute of the virtual
   operation 'Request certificate Ignore CAACL', similar to the above,
   just different pair of permission and ACI, to identify if the bound
   principal can bypass CA ACLs

 - if CA ACLs cannot be bypassed, check CA ACLs

 - do validation of the requested properties depending on whether this
   certificate is asked for user, host, service, krbtgt entry and so on

 - check that the bound principal can write to
   'userCertificate' attribute of the target LDAP object

 - finally, do validation of SAN fields

 - (ask CA to issue certificate)

If the bound principal is host, then its rights would be defined by two
parts:
 - passing CA ACL

 - ability to write to userCertificate attribute in the target
   service/host entry

The latter is controlled by the default ACLs in FreeIPA:

        # Define which hosts can edit services
        # The managedby attribute stores the DN of hosts that are allowed to 
manage
        # a service. Use service-add-host to add hosts to a service.
        dn: cn=services,cn=accounts,$SUFFIX
        changetype: modify
        add: aci
        aci: (targetattr="userCertificate || krbPrincipalKey")
             (version 3.0; acl "Hosts can manage service Certificates and kerberos 
keys";
             allow(write) userattr = "parent[0,1].managedby#USERDN";)

        # Allow hosts to update their own certificate in host/
        # krbLastPwdChange lets a host unenroll itself
        dn: cn=computers,cn=accounts,$SUFFIX
        changetype: modify
        add: aci
        aci: (targetattr="usercertificate || krblastpwdchange || description || l || 
nshostlocation || nshardwareplatform || nsosversion")
(version 3.0; acl "Hosts can modify their own certs and keytabs"; allow(write) userdn = "ldap:///self";;)
        aci: (targetattr="ipasshpubkey")
(version 3.0; acl "Hosts can modify their own SSH public keys"; allow(write) userdn = "ldap:///self";;)

        # Define which hosts can edit other hosts
        # The managedby attribute stores the DN of hosts that are allowed to 
manage
        # another host.
        dn: cn=computers,cn=accounts,$SUFFIX
        changetype: modify
        add: aci
        aci: (targetattr="userCertificate || krbPrincipalKey")
(version 3.0; acl "Hosts can manage other host Certificates and kerberos keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";)
        aci: (targetattr="ipasshpubkey")
             (version 3.0; acl "Hosts can manage other host SSH public keys";
              allow(write) userattr = "parent[0,1].managedby#USERDN";)


So, if you want a host to control which services it can issue
certificates for, just make sure they manage those services, through
'ipa service-add-host' command. Services on the same host can do that
already because they are allowed to create services for themselves and
during that step we add 'managedby' to point to the host-creator.

If you want to limit the host to not issue certificates for some
services on itself, add CA ACLs that allow only use of a specific
CA/profile/host or service rules. The default rule is like HBAC's
allow_all for the default certificate profile for services. Obviously,
you need to design rules globally because lack of a rule means denial.


--
/ Alexander Bokovoy
Sr. Principal Software Engineer
Security / Identity Management Engineering
Red Hat Limited, Finland
_______________________________________________
FreeIPA-users mailing list -- freeipa-users@lists.fedorahosted.org
To unsubscribe send an email to freeipa-users-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-users@lists.fedorahosted.org
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to