Cisco ISE API for Certificate Provisioning

When we added a certificate authority (CA) to Cisco’s ISE in version 1.3, there was a tremendous interest level from the field.  Companies were looking for this functionality to make BYOD and secure network access from endpoints more secure and there was a LOT of buzz about this functionality.

As the guy who flew all over the world carrying the “flag” for a built-in CA in ISE – forcing my message onto all the executives I could find why it was so important, I was naturally ecstatic to see the success of something I championed and fostered since inception.

However, as with everything, there is always a need for more!  ISE admins all over the world felt it was great for the devices that are capable of onboarding, but they needed to issue endpoint certificates to devices that couldn’t go through the automated onboarding process such as: Medical Devices, Point of Sale systems, Linux, etc).

“Make it So” – Jean-Luc Picard

In ISE 1.4, we added a RESTful (REpresentational State Transfer) API for the CA to issue private key + public certificate pairs.  This blog post is dedicated to showing you how to leverage that RESTful API and generate your own certificates for devices that cannot use the automatic provisioning capabilities of the BYOD onboarding process.

Major call out to Victor Ashe, one of the key team members on our small group of Rock-Stars who are responsible for this CA.  Victor is the original author of what I am going to show you in this blog.  Thanks, Victor!


You could (of course) build a full-blown web portal that leverages this API to generate certificates for folks in your organization.  However, I’m going to show you how to do this with a simple script on any Linux or MAC device using CURL.  You can probably get this to work with a Windows device with CURL for Windows, but I don’t feel like doing that – so it won’t be part of the blog 🙂

Let’s Get Started

There are many tools available for REST so please bear in mind, there’s a reason we are using curl instead of a browser based REST Client, like Poster, Postman, etc. The browser based clients just spit back the response body as text, and aren’t smart enough to treat this as a file and let you download it.

You will create two files on your Linux / MAC workstation.  One we will call and the other will be called payload. The script contains the CURL command that puts the information into the API to retrieve the certificate pair.  The payload file contains the details for the certificate that you are trying to generate.
curl -X PUT -H “Authorization: Basic YXBpdXNlcjpoaXNwYXNzd29yZA==” -H “Accept: application/; charset=utf-8” -H “Content-Type: application/; charset=utf-8” –data @payload -v –insecure https://<Your_ISE_Node>:9060/ers/config/endpointcert/certRequest >

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<ns3:endpointcert description=”Created in ERS” xmlns:ns2=”” xmlns:ns3=””>

The resulting zip files (or any error messages upon failure) will appear in a file called So, if the response status isn’t a 200 ok (perhaps a 400 bad request) then the file will just be a text file, so open it in a text editor to see the error message.

The Accept and Content-Type headers are needed in the request (shown above) and they have the same value. This is shown on the documentation page (described below). The Authorization header is a Basic Access Authorization header. The value for this header should be:

Basic <base 64 encoding of ‘username:password’>

For the base 64 encoding, you can go to a site like this  (shown in Figure 2) and go to the “Encode” tab at the top. Type in your username and password, separated by a colon (eg. apiuser:hispassword) and then hit the encode button. You’ll get something like YXBpdXNlcjpoaXNwYXNzd29yZA==. Your value for the “Authorization” header would then be “Basic YXBpdXNlcjpoaXNwYXNzd29yZA==” This is seen above in the curl command.


Before you can use the script, you’ll need to enable ERS on your ISE deployment.  Navigate to: Administration > System > Settings > ERS Settings.  Enable ERS on the Primary Administrative Node as seen in Figure 2.  Don’t forget to click Save.


This page will also show a URL to the ERS documentation. The URL should be https://<your_ise_node>:9060/ers/sdk

This documentation page has a lot of information. The most useful pages should be:
Quick Reference > Setting up
Quick Reference > Request Headers
API Documentation > End Point Certificates

In addition to enabling the ERS API, you will also need a ERS Admin level user.  Navigate to: Administration > System > Admin Access > Administrators > Admin Users.  Click Add and setup an ERS Admin user similar to the one in Figure 3.  Don’t forget to click Save.  This is the username and password that needs to be converted to BASE64 and inserted into the script.


You also need a Certificate Template for the CA to use.  There is a built-in certificate template to all ISE 1.3 installs named “EAP_Authentication_Certificate_Template” that you can use, or you may want to create your own brand-new template for your environment.

Figure 4 shows a custom template that I’m using for this blog post.  You must specify the template name in the payload file in the certTemplateName section.


Let’s go through an example

I created a file named  The contents of this file are shown in Figure 5.


I also created a file named payload.  The contents are shown in Figure 6.


I now run the file, as seen in Figure 7.


Figure 8 shows the resulting zip file and the extracted certificate chain (p12 file).

resulting KeyChain

Again, I want to thank Val Kilmer, err… I mean Victor Ashe for the script and the brilliant ISE CA team for all their continued hard work and top-notch delivery.

Give me my Attribute mapping back for Sponsor Groups

In ISE 1.0 Cisco introduced an integrated Guest solution with a next-generation RADIUS-based policy server.  That policy server was game-changing, certainly.  Other companies responded to this market changing model by making some very strategic moves with their chess pieces to be similarly positioned.

Figure 1 shows an example of the ISE 1.2.x (and below) Sponsor Group Policy.

ISE 1.2 Sponsor Policy

While ISE 1.0 was and is an extremely powerful policy server, it was also viewed as being overly complex and not flexible enough in the areas of Guest life-cycle management.  This was especially true when comparing ISE with it’s closest competitors in the guest access management space.

So, let this be said: the gauntlet has been thrown down, but [Cisco] have answered, and answered with vigor.”  -Gerald Lambeau, Good Will Hunting

ISE 1.3 introduced a completely re-written Guest solution that greatly simplifies the deployment and allows for high-levels of customization.  Things have been simplified GREATLY, but unfortunately some of the power got lost at the same time.

This blog will focus on one specific piece of functionality that was lost, and a brilliant work around that one of my colleagues, Craig Hyps, has devised.

The Missing Functionality:

The ISE Guest solution uses Sponsor Groups to dictate the permissions the employee will have.  In other words, the Sponsor Group determines which types of guest users that can be created, how long those accounts can be active, if the sponsor is allowed to create random/bulk accounts, etc…  From ISE 1.0 through ISE 1.2.x, the ISE administrator had the ability to build very complex IF..THEN..  type of policies to determine which Sponsor Group the employee should be mapped to.  To provide some more clarity of my statement, let’s put that into an IF… Then… format:

IF the LDAP/AD attribute named Manager is Yes
THEN assign them to the Manage_All_Accounts Sponsor Group in ISE.

ElseIF the LDAP/AD attribute named Manager is No
THEN assign them to the Manage_Own_Accounts Sponsor Group in ISE.

In ISE 1.3, it was simplified tremendously because (while it was powerful) it was also very complex for admins to figure out.  However, during the simplification process, come of the power was also removed.

After extensive customer interviews and planning, the design decision was made to simplify Sponsor Group membership for external users (i.e.: user accounts that exist in Active Directory (AD) or LDAP) by mapping to groups in that external identity store.  To provide some more clarity on my statement, let’s put that into an IF… Then… format:

IF sponsor is a member of the AD group named “SponsorALL”
THEN assign them to the Manage_All_Accounts Sponsor Group in ISE.

ElseIF sponsor is member of the AD group named “SponsorOwn”
THEN assign them to the Manage_Own_Accounts Sponsor Group in ISE.

Figure 2 shows the new, simplified sponsor model in ISE 1.3 & 1.4.

ISE 1.3 Sponsor Mapping

So you can see the logic behind the mapping of the external identity that exists very commonly in Active Directory & the local Sponsor Group that dictates the employee’s permissions for creating guest accounts.  For 90-95% of environments, this type of mapping is perfect.  However, there are a few instances where that extra power of looking at attributes instead of or in addition to groups is needed.

Simplicity is the Key”  -Ritchie Blackmore

Well if simplicity is the key to be one of the greatest musicians of all time, maybe that makes Craig Hyps the “Ritchie Blackmore of network access” 🙂  In my 10 years of working with him, he never fails to amaze me with some of the creative workarounds that he is able to come up with, and this blog is detailing one of those brilliant-yet-simple workarounds.

 Craig’s Brilliant Yet Simple Work Around

Basically, the answer to the puzzle is to “Lie to ISE”.  Configure a new LDAP Identity Source that points to your LDAP server, but configure the group string to be the LDAP attribute that you want to use, instead of an actual group.  Think about it, it will see the attribute as the group name & the value of the attribute as the “members”.

Using the example from above, it means the IF… Then… Logic would look like:

IF sponsor’s group has a member named “Yes”
THEN assign them to the Manage_All_Accounts Sponsor Group in ISE.

ElseIF sponsor’s group has a member named “No”
THEN assign them to the Manage_Own_Accounts Sponsor Group in ISE.

This way, ISE thinks there are groups named Yes and No, and that will be the choices in the ISE GUI.

Let’s configure this:

For simplicity sake, I added a value of Yes or No to an existing attribute in my LDAP server (Active Directory).  I used the Job Title field, which translates to the “title” attribute via LDAP.  Figure 3 shows the graphical Job Title field that I am using.


Of course most organizations would have a custom attribute to use, such as “Manager”, or “isManager”, or something like that.  However, for purposes of keeping this example easy, I am just re-using the existing attribute of “title”.

Now, we need to create a new LDAP Identity Store within ISE, just for use with the sponsor portal login.

Navigate to: Administration > Identity Management > External Identity Sources > LDAP.  Click Add.

Provide a name that will help you identify this later as being used just for Sponsor portal login.  You will see in Figure 4 that I used “SecurityDemo_Sponsor”, where the _Sponsor suffix is helping me to document why this Identity Store exists.

Choose the base schema to start with (I used Active Directory), as seen in Figure 4.  Then modify the Group Objectclass and the Group Map Attribute fields to be the LDAP attribute that you are mapping to.  It’s very important to choose Subject Objects Contain References To Groups.  This is the option that will tell the LDAP connector to look for the Group within the subject (the user’s account).


You must fill-in the Connection tab with the correct IP Address(es) and credentials for the LDAP bind.  That is no different in this scenario, so I will skip that tab..  However, the Directory Organization tab is required before you can save the connection.  Figure 5 shows you the example Directory Organization tab.


The Groups Tab is next.  Normally, you can search the directory for the groups & add them.  That will not work in this case.  You have to manually type the values (Yes, No) instead.  Click Add.

Add each value (one at a time) for the attribute that you are mapping to and click Ok.  In our example, the value of title can only be Yes or No, where Yes means they get full sponsorship and No means they will get limited sponsorship capabilities.  Figure 6 shows the Groups tab where the “Yes” group has already been added, and the “No” group is being added.


The LDAP portion is complete.  Don’t forget to click Save when you are done!  Now you need to configure the Sponsor portal to use the new LDAP connection.  By default the Sponsor Portal will use the Identity Source Sequence (ISS) named “Sponsor_Portal_Sequence”.  You need to ensure the new LDAP Identity Source that you just created is used within in this sequence.

Navigate to: Administration > Identity Management > Identity Source Sequences and click on Sponsor_Portal_Sequence to edit it.   Ensure that the new _Sponsor identity source is in the list, and the original LDAP join is not.  Figure 7 shows the ISS.


Don’t forget to click Save when you’re done!  Now you need to assign the correct sponsor users to the Sponsor Groups.  Navigate to Guest Access > Configure and select  Sponsor Groups on the left-hand side.

Select the Sponsor group you are configuring, or create a new one.  Click the Members button.  Choose the new “group” based on the LDAP attribute.  In this example, I have selected SecurityDemo_LDAP:Yes because this is the All_Accounts sponsor group & I want managers to be part of this sponsor group. Figure 8 shows the “Yes” group being added to the Sponsor Group.


Don’t forget to click Save when you’re done!  Repeat this process for each Sponsor group that you need to add members to.

Th-Th-Th-That’s all Folks!   -Porky Pig