Site chooser using osascript and API

jtrant
Valued Contributor

Hello,

I'm brainstorming ideas around managing multiple sites in Jamf with one ADE instance to keep things as simple as possible.

With new restrictions on MDM actions that can be taken on non-ADE devices, I'm thinking that associating my ADE instance with a 'Staging' site in Jamf where no configuration profiles or policies are scoped, and having the tech select from a list of available JSS sites retrieved from Jamf via the API and displayed as a selectable drop-down with osascript. The Mac would then be moved to the site they choose from the list, e.g. laptops, servers, zoom.

This would allow us to enroll all Macs via ADE and then drop them into the correct site where the relevant configuration profiles and policies are scoped.

Has anyone encountered something similar that might have a script they can share?

Thanks,
Justin.

13 REPLIES 13

jesseshipley
Contributor

I've literally spent the last 2 months working on this exact issue. I've finally designed an onboarding process that has the user select their site at enrollment during DEPNotify. The main challenges were around securely getting the API credentials to the end user system. EOD, there is NO SECURE WAY of doing this. Jamf does not offer any method for sending credentials in a script to a computer that does't end up using them in plain text on disk or is ps output. That said, you can but limitations in place that limit the exposure / risk associated. You should have separate accounts for site read (used to get the list they can choose from) and site write (which requires computer write and user write capabilities). You should also make the policy restricted to a specific LDAP user group in Self Service so that a technician must authenticate before even getting access to the policy. I can't directly share my script with you but i can definitely help you with different parts of yours if you need. You can find me here or on Slack as @tulgeywood.

francksartori
New Contributor III

Hi. I'm developing an onboarding tool called MacOnboardingMate. I don't target Jamf Pro specifically but your post makes me think I should implement for Jamf Pro a "Site selector" in the "Customize your Mac" pane (2:00 on the demo video online). Because I don't target regulated environments, I chose to encrypt the API credentials with RSA protocol, the private key sitting inside the package that contains the tool. The existence of the private key on the client side is short term (everything is deleted when the tool, installed through a PreStage Enrollment package, exits). I'm always listening for comments to improve this projet and make it more useful. Best regards. Franck

jesseshipley
Contributor

Encrypting the keys if the package contains both parts isn't really doing much. I utilize a similar method of leverage the PKG itself for getting the creds on system but I use a unix socket to pass the credentials from the PKG directly to the LaunchDaemon it installs. This mean the creds live on disk only during the ADE installation process (not safe, but very annoying to get). After they are passed via the unix socket they only live in memory while the daemon is running that first time.

jtrant
Valued Contributor

Thanks @jesseshipley and @francksartori.

Only my own team have access to the Scripts section of our Jamf Pro instance, so my working theory is to use encrypted script parameters and keep the private key in the Scripts section of Jamf. The public key would be in the policy which is accessible to the rest of our IT team, but they would be stored separately. Am I on the right path?

I can get the list of available sites from the API, but that would report returned values in text form. How to return the selected value to Jamf Pro in a format it will accept is what I'm stuck on. If it acceps plain text and does not require the ID of the site it's do-able.

chrisyeo
New Contributor II

@jtrant

The "encrypted script parameters" are good (sorta: see below) for that one case of hiding one of the key pair from Jamf Pro users who don't have access to both policies and scripts.

However, this does not provide the same security when the policy runs on the endpoint.

As has already been said; there is currently no secure way of doing this.

jtrant
Valued Contributor

This is too bad, but not unexpected given other reading I've been doing lately. Other than creating multiple ADE instances and moving computers/mobile devices between sites, is there a way to achieve what I'm looking for without the API?

Mauricio
Contributor III

@jtrant A possible way to address the API credentials via scripts is to create specific accounts with very limited controls/access to do just what is needed.
We have API accounts to read specific items of Jamf, others to just write into others. So if the account/password is compromised/exposed the "power" of that account is limited.

jesseshipley
Contributor

@Mauricio this is definitely best practice, but the annoying reality is that the permissions necessary for reassigning site membership are Computer and User update. The good thing is this means you don't have to worry about data exfiltration. The bad news is a bad actor could just overwrite every computer record and user. A better option would be leveraging the newer Jamf API's tokens so you could use a token that is expired at the end of the script (and after a time limit if the script is exited early somehow). The problem there is Jamf doesn't support editing the Site membership in a computer record via the new API (also a slight chicken and egg issue with getting the token to the end user system since Jamf also offers no way of sending tokens to computers but rather requires you request them from that system with the main account creds.)

EOD, the API (in particular the new API) are wildly underdeveloped and Jamf shows no signs of making things better any time soon.

Mauricio
Contributor III

@jesseshipley Agree with the chicken and egg issue with the Jamf Pro API (token-based authentication), without a "middle-entity" to securely generate the token it is has little value to scripting in the Jamf Pro.

One solution we use, to make harder to curious people, is to "encrypt" the shell script, cannot be run via Jamf Pro scripts functionality but deployed via it and called locally.

How to Encrypt Your Bash Shell Script

We have the hashed user name and password as parameters variables and the "encrypted" script will contain the salt and key to decrypt the values and do the rest of the job.
Not ideal but adds a layer of "difficulty" to the solution.

jesseshipley
Contributor

Sadly these "encrypted" options don't actually increase complexity much at all. Parameters form the JPS are passed in plain text to the sh binary. All you need to do is run a ps aux | grep sh and you have what you need.

Mauricio
Contributor III

But what if those plain text parameters variables are strings that are something like this:

U2FsdGVkX19VIPy3QvRIVEw/wq8aBmUi4aOhYWbM1Qgig0WvjgzKmg0NeblqJPwb U2FsdGVkX19VIPy3QvRIVCUa2aXszSZmbjqyVrDE3fbBA2fcGFrloQpJtIbLbEn2

The "obfuscated/encrypted" script will have the salt and key values to decipher that info.

#!/bin/sh
encryptedName='U2FsdGVkX19VIPy3QvRIVEw/wq8aBmUi4aOhYWbM1Qgig0WvjgzKmg0NeblqJPwb'
encryptedPassword='U2FsdGVkX19VIPy3QvRIVCUa2aXszSZmbjqyVrDE3fbBA2fcGFrloQpJtIbLbEn2'

saltEnc='5520fcb742f44854'
keyEnc='fdc64620d7e40dd1dbc4aade7d16e34097137e891a37c824'

function decryptString() {
  echo "${1}" | /usr/bin/openssl enc -aes-256-cbc -d -a -A -S "${2}" -k "${3}"
}

# name
decryptedName=$(decryptString "$encryptedName" "${saltEnc}" "${keyEnc}")
# password
decryptedPassword=$(decryptString "$encryptedPassword" "${saltEnc}" "${keyEnc}")

echo "$decryptedName"
echo "$decryptedPassword"

# do the rest of the job....

Or the salt and key could be hosted elsewhere and the script just curl that info too.
More work for sure

jesseshipley
Contributor

@Mauricio in the end, the only thing protecting your creds is POSIX permissions. Because the script gets downloaded to the JAMF application support folder in plain text and the parameters are published in ps output as plaintext, all the piece are there and can be stolen with a bash oneliner if you have admin creds. You could curl the keys, but you'd be in a similar boat of how you get the password needed for curling the keys to the system. The best solution is sadly the hardest to configure which is to have a service in AWS reading webhooks to trigger API calls if a specific policy is run. You could keep the AWS service locked down from any network access aside from incoming webhooks or API calls to the JPS. But again, that's a lot of effort to do something that Jamf should build a solution into their product for.

jtrant
Valued Contributor

Just to close the loop on this, I ended up creating additional MDM servers in Apple Business Manager and new PreStage configs in Jamf Pro. This allows me to move computers between PreStage configs using the Apple Business Manager UI and have Jamf automatically pick up those changes.

Not ideal, but given the limitations and security implications around the API, I felt this was a better way to achieve what I needed.

Thanks for everyone's advice on this!