How to get device certificates on Jamf-managed Macs via ACME with step-ca and use it to join a 802.1X secured network

At work, our Windows computers are bound to AD, they use the AD-integrated PKI to generate device certificates. These certificates are then utilized to get 802.1X authenticated network access, both wired and Wi-Fi.

Our Macs are not bound to AD, but managed with Jamf Pro as our MDM system. In order to also bring the Macs into the network, we had to prepare a few things:

  1. Set up a separate certificate authority (CA), at best on premise and also without additional costs.
  2. Chose a protocol for certificate creation, SCEP or ACME.
  3. Build a configuration profile for Jamf, so the Macs get certificates and also renewals.
  4. Integrate our new CA into our network tool (Cisco ISE)

Our options for free, open source and locally deployable CA’s are quite limited, also the support for Managed-Device-Attestation (MDA) from Apple was desired. This led us to smallstep’s step-ca in conjunction with the Step Posture Connector and ACME as the protocol that supports MDA.

1. The CA

Let’s start with the setup of step-ca on an Ubuntu server. The firewall has to allow Port 443 for all the jamf servers, and for the company network, so the Macs can also reach it. Additional documentation from smallstep is available here:

https://smallstep.com/docs/step-ca/installation/#debianubuntu
https://smallstep.com/docs/step-ca/acme-basics/
https://smallstep.com/docs/step-ca/provisioners/#acme
https://smallstep.com/blog/private-acme-server/

# create the CA
step ca init


✔ Deployment Type: Standalone
What would you like to name your new PKI?
✔ (e.g. Smallstep): OurTestCA
What DNS names or IP addresses will clients use to reach your CA?
✔ (e.g. ca.example.com[,10.1.2.3,etc.]): catest.domain.name
What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)
✔ (e.g. :443 or 127.0.0.1:443): :443
What would you like to name the CA’s first provisioner?
✔ (e.g. you@smallstep.com): your.address@domain.name
✔ [leave empty and we’ll generate one]:
✔ Password: ThisIsATopSecretRootPasswordExample

Generating root certificate… done!
Generating intermediate certificate… done!

Take good care of the newly created root password!

Now, let’s move the CA to /etc/step-ca and create a daemon to start it automatically. See this guide for it. The root password should now be in /etc/step-ca/password.txt

Best practice for additional security is to change the password for the intermediate certificate, as it is used to sign our device certificates, and it then differs from your root certificates‘ password. See also this guide.

step crypto change-pass $(step path)/secrets/intermediate_ca_key

Now, we can configure the step-ca to use ACME and also to use MDA. We have to add a provisioner:

step ca provisioner add acme-da --type ACME --challenge device-attest-01 
--attestation-format apple

✔ CA Configuration: /etc/step-ca/config/ca.json

Success! Your step-ca config has been updated. To pick up the new configuration SIGHUP (kill -1 ) or restart the step-ca process.

Optionally, you can install the new CA certificates on the Ubuntu server via:

step certificate install $(step path)/certs/root_ca.crt

They can be also downloaded from the server:

https://catest.domain.name/roots.pem
https://catest.domain.name/intermediates.pem

The CA on its own is now ready to use, but for signing device certificates, we need a template. You can use this example for it. The file should be here:
/etc/step-ca/templates/certs/x509/leaf.tpl
It must also be added to the ca.json configuration.

We should also switch from file-based configuration to a database by enabling the remote provisioner management feature.

2. The Step Posture Connector

The final step for the CA setup is the creation of a webhook. It is later used by the Step Posture Connector to enable the CA to talk to Jamf and Apple.

step ca provisioner webhook add acme-da step-posture-connector --url https://localhost:9443/webhook/device-attest?mode=computer

✔ CA Configuration: /etc/step-ca/config/ca.json
No admin credentials found. You must login to execute admin commands.
✔ Please enter admin name/subject (e.g., name@example.com): step
✔ Provisioner: your.address@domain.name (JWK)
Please enter the password to decrypt the provisioner key:
Webhook ID: 5022a074-2b05-4n87-someMoreCharacters
Secret: ThisIsATopSecretWebhookSecretExample

As the Connector runs on the same server, we use localhost:9443 as URL. For Jamf Pro, we have to select the device type, as mobiles are handled differently as computers.

Take a note of the Webhook-ID and the Secret, both are needed later.

We should change the expiration period of the certificates, as in default they last only 24 hours. We chose 90 days => 2160 hours.

step ca provisioner update acme-da --x509-min-dur 20m --x509-default-dur 2160h

Our CA uses the binary for Step Posture Connector, not the Docker container. As it is a standard Linux server, we took the amd64 file. It is then copied to /srv/www/htdocs on the server.

Also create a /srv/www/htdocs/ssl directory for the TLS certificates. Now we can use our CA to create the TLS certificates:

step ca certificate localhost server.pem server.key
# copy these to /srv/www/htdocs/ssl
cp server.pem /srv/www/htdocs/ssl/server.pem
cp server.key /srv/www/htdocs/ssl/server.key
# also copy the intermediate cert
cp /etc/step-ca/certs/intermediate_ca.crt /srv/www/htdocs/ssl/ca.pem

Since this certificate expires regularly, it has to be renewed, at best in a cronjob:

step ca renew --force /srv/www/htdocs/ssl/server.pem /srv/www/htdocs/ssl/server.key

We need a Jamf API role for the Connector, see also here. Take a note of the Jamf Client ID and Jamf Client Secret.

All these go into the .env configuration file in /srv/www/htdocs/, see also here.

Let’s start the connector and see, if everything is fine:

/srv/www/htdocs/step-posture-connector_1.0.0_amd64

Everything is fine? Then create a cronjob and start the Connector @reboot and in background. Consider running the Connector as a normal user, not as root.

3. Jamf Configuration Profiles

Now to the fun part. Create a Jamf configuration profile that contains your Root- and Intermediate Certificates (and also the certificate the network infrastructure uses), so the Macs trust your newly created CA.

Screenshot

The real fun starts now. Create a Jamf configuration profile with the ACME Payload, the certificate the network infrastructure uses and network configuration payload, all in one profile.

Screenshot

Let’s take a look at the details. The ACME payload sets the step-ca server, the encryption details, and enables attestation via MDA. The certificate’s Common Name (CN) is set to the serial number of the Mac, so we use the variable $SERIALNUMBER twice.

Screenshot

The Network payload uses the just configured ACME certificate and also the additional certificate for trusting our Cisco ISE. We use EAP-TLS.

Screenshot

The trust settings can be seen here:

Screenshot

When these configuration profiles are deployed, the Macs then get a certificate.


Screenshot

The sequence of the certificate generation with ACME protocol can be seen in this diagram. It shows, how all the components work together.

Sequence diagram of certificate generation with ACME.

The certificates are valid for 90 days, they are automatically renewed, when the Macs are a part of the companies network, e.g. Wi-Fi or LAN on premise or via VPN.

4. Network access

Our Cisco ISE needed the Root- and Intermediate-certificates and imported them.

When a Mac now connects to a network port, it shows the device certificate, the ISE matches the issuer of the certificate with the ones it imported before and if everything checks out, the ISE grants network access to a special, 802.1X protected subnet and the Mac gets an IP address.

That’s it.

5. Caveats

It works fine with ARM Macs, with Intel Macs we’ve had some issues. The MDA has to be deactivated, thus only Intel Macs with T2 chip could possibly work, older would ones definitely not.

Our T2 Macs failed to get a certificate, but they are going to be replaced anyway.

Update 01.08.2025: See part 2 for further configuration of the renewal process.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Ich erkläre mich damit einverstanden, dass meine eingegebenen Daten und meine IP-Adresse nur zum Zweck der Spamvermeidung durch das Programm Akismet in den USA überprüft und gespeichert werden.
Weitere Informationen zu Akismet und Widerrufsmöglichkeiten.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.