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)([email protected]))"
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