👨‍💻

API ロールと API クライアントを使った Jamf Pro API の使い方入門

2023/09/03に公開

はじめに

23年8月にJamf Pro 10.49.0 で API ロール機能が実装されました。
API ロールとクライアント - Jamf Pro ドキュメント 10.49.0 | Jamf

今まで Jamf Pro の API を使うには下記の手順で行っていました。

  1. Jamf Pro 上でユーザーを作成
  2. Basic 認証で Bearer トークンを取得
  3. Bearer トークンで API を実行

ユーザーの生パスワードを送る形になるのがなんとも微妙な感じだったのですが、今回のリリースで権限を絞ったアクセストークンを簡単に作れるようになりました。
今までのやり方もいますぐ使えなくなるというわけではなさそうですが、どこかのタイミングで使えなくなると思うので、可能なタイミングで API ロール x API クライアントの形式に引っ越しましょう。

また、これから新しく作るものは必ず API ロール x API クライアントをつかうようにしましょう。

過去のやりかた(コード)

まず過去のユーザーを使ったやり方のコードを用意してサクッと解説します。どう変わるのかの参考にしてください。

サンプルコードはみんな大好き GAS のコードにしました。内容としてはコンピューターの一覧を取得する。というシンプルかつありがちなものにしておきました。

コード以外の部分だと、環境変数に下記3つを指定すれば動くようにしてあります。

  • JAMF_SUBDOMAIN
  • JAMF_USER
  • JAMF_PASSWORD

今回はわかりやすいように Bearer トークンの取得処理をclass外から呼び出してトークンを API 実行メソッドに渡せる形にしてあります。
GAS であれば実行時間が5分-30分の制約があるのであまり気にしなくていいですが、 Node.js 等で長時間アクセストークンを使い回す場合はトークンの期限をみて再取得処理とトークンのキャッシュ処理を入れたほうがいいかと思います。

function myFunction() {
  const token = JamfService.getTokenByLegacy();
  const computers = JamfService.findComputers({ token });
  console.log({ computersLength: computers.length});
}

class JamfService {
  static get JAMF_SUBDOMAIN() {
    return PropertiesService.getScriptProperties().getProperty('JAMF_SUBDOMAIN');
  }
  static getTokenByLegacy() {
    // https://developer.jamf.com/jamf-pro/docs/jamf-pro-api-overview#authentication-and-authorization
    const JAMF_USER = PropertiesService.getScriptProperties().getProperty('JAMF_USER');
    const JAMF_PASSWORD = PropertiesService.getScriptProperties().getProperty('JAMF_PASSWORD');
    const authData = Utilities.base64Encode(`${JAMF_USER}:${JAMF_PASSWORD}`);

    // const url = `https://${JamfService.JAMF_SUBDOMAIN}.jamfcloud.com/uapi/auth/tokens`; // これは古いエンドポイントだけど23年9月時点ではまだ使える
    const url = `https://${JamfService.JAMF_SUBDOMAIN}.jamfcloud.com/api/v1/auth/token`;
    const options = {
      method: 'post',
      headers: {
        Authorization: `Basic ${authData}`,
      },
    };

    const response = UrlFetchApp.fetch(url, options);
    const content = JSON.parse(response.getContentText('UTF-8'));
    return content.token;
  }

  static findComputers({ token }) {
    // https://developer.jamf.com/jamf-pro/reference/get_preview-computers
    const baseUrl = `https://${JamfService.JAMF_SUBDOMAIN}.jamfcloud.com/api/preview/computers?sort=id:asc&page-size=500`;
    const options = {
      method: 'get',
      headers: {
        Authorization: `Bearer ${token}`,
        accept: 'application/json',
      },
    };

    let allComputers = [];
    let totalCount = 0;
    let page = 0;
    do {
      const url = baseUrl + `&page=${page++}`;
      console.log({ url });
      const response = UrlFetchApp.fetch(url, options);
      const content = JSON.parse(response.getContentText('UTF-8'));
      totalCount = content.totalCount;
      const computers = content.results;
      allComputers = [...allComputers, ...computers];
    } while (allComputers.length < totalCount)

    return allComputers;
  };
}

昔のコードの解説が終わったところで新しいやり方に変えていきましょう。

API ロール x API クライアントを使ったやり方に変える

基本的には下記の公式ドキュメントに沿って行って行えばOKです。ポイント部分だけ補足します。
API ロールとクライアント - Jamf Pro ドキュメント 10.49.0 | Jamf

イメージとしてはロールを作ってクライアントに割り当てる感じで、 ロール:クライアントN:1 の関係になります。

API ロールを作成する の補足

今回はコンピューターの一覧なので Read Computers だけ指定しました。
エンドポイントごとに必要なロールは下記のドキュメントに書いてあるので、それを見ながら設定するとよいかと思います。
Privileges and Deprecations

API クライアントを作成する の補足

アクセストークンの有効時間は無駄に長くせずに必要な秒数を指定しましょう。
API の検証時に5分だと短すぎたりスルので、検証時は長くしといて本番利用時は短くする、など工夫をしたほうがいいかと思います。

作成すると下記のように Client ID, Client Secret が払い出されます。

API ロール x API クライアントを使ったコードに直す

コード以外の部分だと、環境変数に下記3つを指定すれば動きます。

  • JAMF_SUBDOMAIN (修正前と一緒)
  • JAMF_CLIENT_ID
  • JAMF_CLIENT_SECRET

getTokenByLegacy Function を getToken Function で上書きして呼び出しを修正してください。
トークン取得処理のコードがスッキリしたのがわかるかと思います。

function myFunction() {
  const token = JamfService.getToken();
  const computers = JamfService.findComputers({ token });
  console.log({ computersLength: computers.length});
}

class JamfService {
  static get JAMF_SUBDOMAIN() {
    // ...変わらないので省略
  }
  
  static getToken() {
    // https://developer.jamf.com/jamf-pro/docs/client-credentials
    const url = `https://${JamfService.JAMF_SUBDOMAIN}.jamfcloud.com/api/oauth/token`;
    const options = {
      method: 'post',
      payload: {
        grant_type: 'client_credentials',
        client_id: PropertiesService.getScriptProperties().getProperty('JAMF_CLIENT_ID'),
        client_secret: PropertiesService.getScriptProperties().getProperty('JAMF_CLIENT_SECRET')
      }
    };

    const response = UrlFetchApp.fetch(url, options);
    const content = JSON.parse(response.getContentText('UTF-8'));
    return content.access_token;
  }

  static findComputers({ token }) {
     // ...変わらないので省略
  };
}

おわりに

ユーザーアカウント方式ではなく、API ロール x API クライアント方式にすることで下記のようなメリットがあることがわかりました。

  • API実行ユーザーという謎ユーザーをなくせる(=生パスワードを渡さなくてすむ)
  • API実行処理にどの権限を渡すかが明白になる
  • トークンの有効時間が細かく制御できるようになる
  • コードがスッキリする

本記事は Jamf Pro API を使うにあたっての入門記事としてもおすすめです。
今まで Jamf Pro API を敬遠していた方も本記事を参考に各種処理の自動化にチャレンジしてみてはいかがでしょうか。

おまけ

コンピューター情報の詳細を取得する場合は、旧APIである下記のURLのAPIを使うと良いです。
新しいAPIだと欲しい情報が出ませんでした。
https://developer.jamf.com/jamf-pro/reference/findcomputersbyid

Discussion