On Mon, 03 Jun 2019, Patrick Spinler via FreeIPA-users wrote:
> Hi,
>
> I'm setting up an openvpn server and I'd like to use our
> already existing FreeIPA CA to issue user keys/certs for
> openvpn's use. Since our OpenVPN box is a freeipa client,
> I thought it'd be nice to use certmonger to issue and
> keep up to date these certs.
>
> Ergo, I've created a certificate profile:
>
> pat@apex-freeipa ~$ ipa certprofile-show --all
> OpenVPNUserCert
> dn:
> cn=OpenVPNUserCert,cn=certprofiles,cn=ca,dc=int,dc=apexmw,dc=com
>
> Profile ID: OpenVPNUserCert
> Profile description: OpenVPN User Certificates
> Store issued certificates: FALSE
> objectclass: ipacertprofile, top
>
> And also a CA acl. For experimentation (and working vs
> our test freeipa) I've left this as wide open as I can:
>
> [pat@apex-freeipa ~]$ ipa caacl-show --all
> OpenVPN_User_Certificate_ACL
> dn:
>
ipaUniqueID=6dde33a6-7849-11e9-aa05-525400b52c7b,cn=caacls,cn=ca,dc=int,dc=apexmw,dc=com
> ACL name: OpenVPN_User_Certificate_ACL
> Enabled: TRUE
> CA category: all
> Profile category: all
> User category: all
> Host category: all
> Service category: all
> ipauniqueid: 6dde33a6-7849-11e9-aa05-525400b52c7b
> objectclass: ipaassociation, ipacaacl
>
> Then, on my openvpn server, I ask for a cert for use for
> one of my
> users (myself, in this case):
>
> root@apex-openvpn:~# ipa-getcert request -f
> /etc/openvpn/client/pat.crt -k
> /etc/openvpn/client/pat.key -r -N
> 'CN=pat,O=INT.APEXMW.COM' -K pat -g 4096 --profile
> OpenVPNUserCert
> New signing request "20190603014016" added.
>
>
> But, it fails due to an access err vs the
> 'userCertificate' attribute
> of my account:
>
> root@apex-openvpn:~# ipa-getcert list
> (...snippy snip excess...)
> Request ID '20190603014016':
> status: CA_REJECTED
> ca-error: Server at
>
https://apex-freeipa.int.apexmw.com/ipa/xml denied our
> request, giving up: 2100 (RPC failed at server.
> Insufficient access: Insufficient 'write' privilege to
> the 'userCertificate' attribute of entry
> 'uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com'.).
> stuck: yes
> key pair storage:
> type=FILE,location='/etc/openvpn/client/pat.key'
> certificate:
> type=FILE,location='/etc/openvpn/client/pat.crt'
> CA: IPA
> issuer:
> subject:
> expires: unknown
> pre-save command:
> post-save command:
> track: yes
> auto-renew: yes
>
> If I look at the dirsrv log, here's the accesses I see
> for this request
> (trimmed off the date/time to make the lines a _little_
> shorter):
>
> root@apex-freeipa slapd-INT-APEXMW-COM# grep conn=178
> access | cut -d' ' -f3-
> conn=178 fd=114 slot=114 connection from 10.10.200.1 to
> 10.10.200.1
> conn=178 op=0 BIND dn="" method=sasl version=3
> mech=GSS-SPNEGO
> conn=178 op=0 RESULT err=0 tag=97 nentries=0
> etime=0.0025554208
>
dn="fqdn=apex-openvpn.int.apexmw.com,cn=computers,cn=accounts,dc=int,dc=apexmw,dc=com"
>
> conn=178 op=1 SRCH
> base="cn=ipaconfig,cn=etc,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs=ALL
> conn=178 op=1 RESULT err=0 tag=101 nentries=1
> etime=0.0001319554
> conn=178 op=2 SRCH
> base="cn=masters,cn=ipa,cn=etc,dc=int,dc=apexmw,dc=com"
> scope=2 filter="(&(objectClass=ipaConfigObject)(cn=CA))"
> attrs=ALL
> conn=178 op=2 RESULT err=0 tag=101 nentries=1
> etime=0.0000979573
> conn=178 op=3 SRCH
> base="cn=masters,cn=ipa,cn=etc,dc=int,dc=apexmw,dc=com"
> scope=2 filter="(&(objectClass=ipaConfigObject)(cn=CA))"
> attrs=ALL
> conn=178 op=3 RESULT err=0 tag=101 nentries=1
> etime=0.0000736730
> conn=178 op=4 SRCH
> base="cn=cas,cn=ca,dc=int,dc=apexmw,dc=com" scope=2
> filter="(&(objectClass=ipaca)(cn=ipa))" attrs=""
> conn=178 op=4 RESULT err=0 tag=101 nentries=1
> etime=0.0000499142
> conn=178 op=5 SRCH
> base="cn=ipa,cn=cas,cn=ca,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs="ipaCaId
> ipaCaSubjectDN cn ipaCaIssuerDN description"
> conn=178 op=5 RESULT err=0 tag=101 nentries=1
> etime=0.0000482726
> conn=178 op=6 SRCH
>
base="cn=apex-freeipa.int.apexmw.com,cn=masters,cn=ipa,cn=etc,dc=int,dc=apexmw,dc=com"
> scope=2
>
filter="(&(objectClass=ipaConfigObject)(ipaConfigString=enabledService)(cn=CA))"
> attrs=ALL
> conn=178 op=6 RESULT err=0 tag=101 nentries=1
> etime=0.0000950646 notes=U
> conn=178 op=7 SRCH
> base="cn=accounts,dc=int,dc=apexmw,dc=com" scope=2
>
filter="(&(objectClass=krbprincipalaux)(krbPrincipalName=pat(a)INT.APEXMW.COM))"
> attrs=ALL
> conn=178 op=7 RESULT err=0 tag=101 nentries=1
> etime=0.0002747849
> conn=178 op=8 EXT oid="1.3.6.1.4.1.4203.1.11.3"
> name="whoami-plugin"
> conn=178 op=8 RESULT err=0 tag=120 nentries=0
> etime=0.0000135034
> conn=178 op=9 SRCH base="cn=request certificate ignore
> caacl,cn=virtual
> operations,cn=etc,dc=int,dc=apexmw,dc=com" scope=0
> filter="(objectClass=*)" attrs="objectClass"
> conn=178 op=9 RESULT err=0 tag=101 nentries=1
> etime=0.0000932668 - entryLevelRights: none
> conn=178 op=10 SRCH
> base="uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs="distinguishedName"
> conn=178 op=10 RESULT err=0 tag=101 nentries=1
> etime=0.0000640289
> conn=178 op=11 SRCH
> base="uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs="telephoneNumber
> ipaSshPubKey uid krbCanonicalName ipatokenRadiusUserName
> ipaUserAuthType krbPrincipalExpiration homeDirectory
> nsAccountLock usercertificate;binary title loginShell
> uidNumber mail ipaCertMapData memberOf memberofindirect
> krbPrincipalName givenName gidNumber sn ou userClass
> ipatokenRadiusConfigLink"
> conn=178 op=11 RESULT err=0 tag=101 nentries=1
> etime=0.0001401737
> conn=178 op=12 SRCH base="dc=int,dc=apexmw,dc=com"
> scope=2
>
filter="(|(member=uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com)(memberUser=uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com)(memberHost=uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com))"
> attrs=""
> conn=178 op=12 RESULT err=0 tag=101 nentries=7
> etime=0.0001492344 notes=P pr_idx=0 pr_cookie=-1
> conn=178 op=13 SRCH
> base="uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(userPassword=*)" attrs="userPassword"
> conn=178 op=13 RESULT err=0 tag=101 nentries=1
> etime=0.0000524838
> conn=178 op=14 SRCH
> base="uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(krbPrincipalKey=*)" attrs="krbPrincipalKey"
> conn=178 op=14 RESULT err=0 tag=101 nentries=1
> etime=0.0000597589
> conn=178 op=15 SRCH
>
base="ipaUniqueID=80b23b30-6a0c-11e9-baa3-525400b52c7b,cn=sudorules,cn=sudo,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs="cn"
> conn=178 op=15 RESULT err=0 tag=101 nentries=1
> etime=0.0000379744
> conn=178 op=16 SRCH
>
base="ipaUniqueID=5fb3a640-705a-11e9-aa05-525400b52c7b,cn=hbac,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs="cn"
> conn=178 op=16 RESULT err=0 tag=101 nentries=1
> etime=0.0000337904
> conn=178 op=17 SRCH
> base="cn=caacls,cn=ca,dc=int,dc=apexmw,dc=com" scope=1
> filter="(&(objectClass=ipaassociation)(objectClass=ipacaacl))"
> attrs="serviceCategory cn ipaMemberCertProfile
> ipaMemberCa ipaCertProfileCategory memberUser
> userCategory hostCategory memberHost ipaEnabledFlag
> ipaCaCategory memberService description"
> conn=178 op=17 RESULT err=0 tag=101 nentries=2
> etime=0.0001647058
> conn=178 op=18 EXT oid="1.3.6.1.4.1.4203.1.11.3"
> name="whoami-plugin"
> conn=178 op=18 RESULT err=0 tag=120 nentries=0
> etime=0.0000138321
> conn=178 op=19 SRCH
> base="uid=pat,cn=users,cn=accounts,dc=int,dc=apexmw,dc=com"
> scope=0 filter="(objectClass=*)" attrs="userCertificate"
> conn=178 op=19 RESULT err=0 tag=101 nentries=1
> etime=0.0001475052 - entryLevelRights: none
> conn=178 op=20 UNBIND
> conn=178 op=20 fd=114 closed - U1
>
> To begin with, I note that this session does a BIND with
> 'dn=""', right
> at the beginning, it's essentially an anonymous bind, yah?
No, it is not. BIND operation may be multi-round and
actual result is
not known until all rounds passed through. In your cases,
SASL
GSS-SPNEGO is in use, so on the first round you get the
bound identity:
conn=178 op=0 BIND dn="" method=sasl version=3
mech=GSS-SPNEGO conn=178 op=0 RESULT err=0 tag=97
nentries=0 etime=0.0025554208
dn="fqdn=apex-openvpn.int.apexmw.com,cn=computers,cn=accounts,dc=int,dc=apexmw,dc=com"
E.g. all connection was done using host keytab of that
machine
(apex-openvpn.int....). This is how certmonger works -- it
uses a host
keytab of the machine it runs on.
>
> That operation near the end, here:
>
> op=17 SRCH base="cn=caacls,cn=ca,dc=int,dc=apexmw,dc=com"
> scope=1
> filter="(&(objectClass=ipaassociation)(objectClass=ipacaacl))"
>
>
> seems like it might be kinda key. and indeed, if I
> attempt to run this
> by hand as an anonymous bind, I get no results:
>
> root@apex-freeipa slapd-INT-APEXMW-COM# ldapsearch -x -h
> localhost -b dc=int,dc=apexmw,dc=com -s sub
> "(|(objectClass=ipaassociation)(objectClass=ipacaacl))"
> # extended LDIF
> #
> # LDAPv3
> # base <dc=int,dc=apexmw,dc=com> with scope subtree
> # filter:
> (|(objectClass=ipaassociation)(objectClass=ipacaacl))
> # requesting: ALL
> #
>
> # search result
> search: 2
> result: 0 Success
>
> # numResponses: 1
>
> It's only if I run this as an _authenticated_ bind, that
> I can find my ACL:
>
> root@apex-freeipa slapd-INT-APEXMW-COM# ldapsearch -x -D
> "cn=Directory Manager" -W -h localhost -b
> dc=int,dc=apexmw,dc=com -s sub
> "(&(objectClass=ipaassociation)(objectClass=ipacaacl))" cn
> Enter LDAP Password:
> # extended LDIF
> #
> # LDAPv3
> # base <dc=int,dc=apexmw,dc=com> with scope subtree
> # filter:
> (&(objectClass=ipaassociation)(objectClass=ipacaacl))
> # requesting: cn
> #
>
> # c98b740c-6903-11e9-ad1b-525400b52c7b, caacls, ca,
>
int.apexmw.com
> dn:
> ipaUniqueID=c98b740c-6903-11e9-ad1b-525400b52c7b,cn=caacls,cn=ca,dc=int,dc
> =apexmw,dc=com
> cn: hosts_services_caIPAserviceCert
>
> # 6dde33a6-7849-11e9-aa05-525400b52c7b, caacls, ca,
>
int.apexmw.com
> dn:
> ipaUniqueID=6dde33a6-7849-11e9-aa05-525400b52c7b,cn=caacls,cn=ca,dc=int,dc
> =apexmw,dc=com
> cn: OpenVPN_User_Certificate_ACL
>
> # search result
> search: 2
> result: 0 Success
>
> # numResponses: 3
> # numEntries: 2
>
> Is this (using certmonger to auto-issue signed certs/keys
> for my
> openvpn users) going to be essentially impossible to do,
> here? Do I
> need to go a more traditional route of creating a seperate
> keystore/certdb, issuing a CSR, and feeding that to
> FreeIPA to sign?
You'd need to create an ACL that would allow a host
identity that
certmonger uses to have write rights to the
userCertificate attribute of
the target user. You are already successfully passed CA
ACL check
because the framework tried to see if you have rights to
actually write
the resulting certificate (public cert) to the
userCertficiate attribute
of the target entry, so it was not a question whether you
can issue
(yes, you can) but whether you can store the cert (you
cannot).
A way to create that would be by utilizing
permissions/roles system of FreeIPA.
Something like this:
ipa permission-add write-user-certificate-permission \
--right=write --attrs=userCertificate --type=user
ipa privilege-add write-user-certificate-privilege
ipa privilege-add-permission
write-user-certificate-privilege \
--permissions=write-user-certificate-permission
ipa role-add user-certificate-issuer
ipa role-add-privilege user-certificate-issuer \
--privileges=write-user-certificate-privilege
ipa role-add-member user-certificate-issuer \
--hosts=apex-openvpn
I'm curious - what do you guys do/advise would be best
"logistics" for user certs - would you have separate user
certs per-service or for perhaps, for sake of easing the
burden of it all, just single cert for a user no matter the
services?
many thanks, L.