0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

midPoint by OpenStandiaAdvent Calendar 2024

Day 20

midPoint からActive Directoryにプロビジョニングする(マルチアカウント編)

Last updated at Posted at 2024-12-19

midPoint by OpenStandia Advent Calendar 2024 の20日目は、15日目の記事で構築したActive Directory(以下、AD)互換環境であるSamba4に対して、マルチアカウントをプロビジョニングします。

既に、16日目と17日目の記事でそれぞれADへのユーザーとグループプロビジョニングについて解説済みです。

そして18日目と19日目の記事で、midPointのアソシエーションを利用したオブジェクト間のメンバーシップのプロビジョニングについても解説済みです。

今回はADへのプロビジョニング解説シリーズの締めとして、少し高度な機能であるmidPointの 「マルチアカウント」 を活用した、複数ユーザーや複数グループのプロビジョニングについて解説したいと思います。その前に、midPointのリソース設定などでこれまでよく目にしてきた 「種別(kind)」と「用途(intent)」 についてまずは解説します。

種別(kind)と 用途(intent)とは

リソース設定でオブジェクトタイプを追加する際に、基本情報にて 「種別」「用途」 を設定する箇所がありました。

image.png

「種類(kind)」はmidPointが定義している「アカウント(Account)」「エンタイトルメント(Entitlement)」「汎用(Generic)」の3つから、追加したいリソースのオブジェクトタイプに合わせて基本的に選択していました。ユーザーやアカウントといったオブジェクトを扱うのであれば「アカウント」を選択し、グループやロールといった権限制御に使われるオブジェクトを扱うのであれば「エンタイトルメント」を選択していました。

一方、「用途(intent)」については、これまでの記事では特に設定せずデフォルトの挙動に任せていました(未設定の場合、defaultという値が利用されます)。実はこの「用途(intent)」には、自由な値を設定することができます。「用途(intent)」はそのオブジェクトタイプがどのように使用されることを意図しているかを示します。例えば、連携先システムにおいて一般ユーザーだけでなく、システム管理用のアカウントもあり、それもmidPointからプロビジョニングする場合は、「用途(intent)」を system と設定したりして表現します。

種別(kind)と 用途(intent)によるマルチアカウントの表現

これまで構築したADにマルチアカウントを設定してみます。例として、今までのユーザーと異なる種別として、システムユーザーを別OU配下で管理するとします。

  • ou=Users,ou=IDM,dc=ad,dc=example,dc=com:デフォルトユーザーのOU(16日目の記事で作成済み)
  • ou=SysUsers,ou=IDM,dc=ad,dc=example,dc=com:システムユーザーのOU

ADの起動時の初期処理の修正

ou=SysUsersを追加するため、ADの起動時の初期処理(./ad/ad-init.sh)を以下のように少し修正しておきます。

./ad/ad-init.sh
dn: OU=Users,OU=IDM,$BASE_DN
objectClass: organizationalUnit
+
+dn: OU=SysUsers,OU=IDM,$BASE_DN
+objectClass: organizationalUnit
EOF

これで「ad」コンテナをdocker compose up -d --build adで再ビルドして起動すれば、システムユーザー用のOUが作成されます。

なお、「ad」コンテナはデータを保存するようにDocker Composeで設定していないため、再作成するとプロビジョニングしたデータがクリアされます。「HR recon Orgs」リコンシリエーションタスクと「HR import users」インポートタスクを再度実行して、AD側に再プロビジョニングしておきます。

システムユーザー用のオブジェクトタイプ追加

「AD」リソースに新たにシステムユーザー用のオブジェクトタイプを追加します。用途を system、デフォルトを False とします。

  • 表示名System User
  • 種類アカウント
  • 用途system
  • デフォルトFalse

image.png

リソース・データの設定は、「User」オブジェクトタイプと区別して名寄せできるように「フィルター」にてOUを絞り込んでおきます。

AD側に既に存在するデータとの名寄せのシナリオ1で、「User」と「System User」のどちらの用途なのか判断が必要になります。誤って別の用途として判断されてしまうとコンフリクトエラーが発生し、名寄せに失敗します。フィルターでOUを利用して絞り込んでおくと、「User」と「System User」は異なるOU配下なので用途を正しく判定できます。

  • オブジェクトクラスuser
  • フィルターattributes/dn endsWith[distinguishedName] "ou=SysUsers,ou=IDM,dc=ad,dc=example,dc=com"

image.png

MidPointデータの設定は「User」オブジェクトタイプと同じです。

image.png

デフォルトユーザー用のオブジェクトタイプの修正

既存の「User」オブジェクトタイプの基本情報の編集画面を開き、リソース・データの設定にて「System User」オブジェクトタイプと区別して名寄せできるように「フィルター」設定を追加してOUを絞り込んでおきます。

  • フィルターattributes/dn endsWith[distinguishedName] "ou=Users,ou=IDM,dc=ad,dc=example,dc=com"

image.png

マッピングの設定

今回は、16日目の記事で作成した「User」オブジェクトタイプのアウトバウンドマッピングを少し変えて、sysプレフィックスを設定するようにしておきます。dnuserPrincipalNamesAMAccountNameの「式」はスクリプトとし、以下のコードを設定します。

  • name → dnbasic.composeDnWithSuffix("cn", "sys" + name.orig, "ou=SysUsers,ou=IDM,dc=ad,dc=example,dc=com")
  • name → userPrincipalName"sys" + name + "@ad.example.com"
  • name → sAMAccountName"sys" + name

以下のようになります。

image.png

同期の設定

こちらは16日目の記事と同じ設定にしておきます。

image.png

Correlationの設定

16日目の記事と同じように名寄せも設定しておきます。

名寄せ用のインバウンドマッピングの追加

cnを使って名寄せしますが、プレフィックスを付けているので「式」をスクリプトとして調整します。

image.png

image.png

詳細設定で「Use for」を相関にしておきます。

image.png

Correlationの設定

以下のように設定します。

image.png

image.png

システムユーザー用のロール作成

ADリソースにシステムユーザー用のオブジェクトタイプを追加しましたので、それに対するインデュースメントを設定するプロビジョニング用のロールを作成します。作成手順は、12日目の記事「midPoint におけるロールベースプロビジョニング」で解説済みです。詳細手順はそちらを適宜参照いただき、以下のロールを作成します。

  • 名前System User

image.png

ADリソースへのインデュースメントを追加します。

image.png

追加したオブジェクトタイプ 「種類:アカウント、用途:system」 を選択できるようになっていますので、これを選択してインデュースメントを設定します。

image.png

プロビジョニングの確認

では、作成したロールをユーザーにアサインし、マルチアカウントのプロビジョニング動作を確認してみましょう。既にADにユーザーとしてプロビジョニング済みであるユーザーに対して、作成した「System User」ロールをアサインします。

image.png

「変更のプレビュー」ボタンで設定が想定通りされているか確認します。正しく設定されていれば、下記のようにou=SysUsers配下にsysプレフィックス付きでcnを構成してプロビジョニングする予定であることを確認できます。

image.png

保存後、該当ユーザーのプロジェクションを確認すると、システムユーザーのプロジェクションが追加されていることが分かります。

image.png

種別(kind)と 用途(intent)の限界

用途を自由に増やしてマルチアカウントに対応することができましたが、この方式には限界があります。オブジェクトタイプの追加が事前に必要という静的な設定であり、動的には対応できません。例えば、組織に対応してプロビジョニングするADグループを、ユーザーの種別や職階、契約などで分けて複数作りたい場合に、それらの種類が増えるたびにリソース設定の変更が必要となってしまいます。また、種類が違うだけでマッピング内容が基本同じという場合に、似たようなマッピングを持つオブジェクトタイプの設定が複数並び、メンテナンスも大変です。

そのような状況に対応できるように、midPointではもう1つ タグ(tag) という情報を組み合わせることができます。タグを利用したマルチアカウントについては、以下の公式ドキュメントに記載されています。

このタグを利用する場合は、オブジェクトタイプを新たに追加する必要はありません。オブジェクトタイプの設定の中で、動的にタグを決定するための設定を行うことができます。中々イメージしづらいと思うので、具体的な使用例を紹介します。

タグ(tag)によるマルチアカウントの表現

先ほどはユーザーに関してマルチアカウントでADにプロビジョニングしましたが、今度はグループに対して設定します。便宜上「マルチアカウント」と呼んでいますが、プロビジョニングできるものであれば何でもよいので、ADグループに対しても適用できます。

現状、ADグループは組織情報を元に、1:1でプロビジョニングしています。これを、タグを使って1:Nのグループをプロビジョニングするようにします。

仕様

midPointの組織オブジェクトの詳細画面を開くと、基本情報に「メールドメイン」というマルチバリュー属性があります。本来の用途はこの組織のメールアドレスのドメイン情報を保持するための属性ですが、便宜上この属性にプロビジョニングしたい追加のADグループの種別を設定する仕様とします。例えば以下は、「employee」「staff」「intern」の3つの種別を設定しています。

image.png

この値を設定して組織オブジェクトを保存すると、ADには以下の3つのグループを新たにプロビジョニングするという仕様とします。「cn」が名前_種別となるようにサフィックスを付けたグループを作ります。

  • cn=001_employee,ou=Groups,ou=IDM,dc=ad,dc=example,dc=com
  • cn=001_staff,ou=Groups,ou=IDM,dc=ad,dc=example,dc=com
  • cn=001_intern,ou=Groups,ou=IDM,dc=ad,dc=example,dc=com

オブジェクトタイプの追加

既に「Group」オブジェクトタイプが存在しているのでそちらを修正してもよいですが、サフィックスを付けたマッピングルールとなり混ぜると複雑化しますので、今回はもう一つ「Category Group」というオブジェクトタイプを追加し、そこでタグの設定を追加することとします。

ただし、タグの設定はGUIのサポートがありません。よって、ADリソースのRAW編集画面を開き、以下の<objectType>〜</objectType>を挿入して設定します(タグに関わる部分以外は、今までの記事で解説したように画面から作成できますので、タグ部分のみを追加でも構いません)。

        <objectType>
            <kind>entitlement</kind>
            <intent>categoryGroup</intent>
            <displayName>Category Group</displayName>
            <default>false</default>
            <multiplicity>
                <maxOccurs>unbounded</maxOccurs>
                <tag>
                    <outbound>
                        <source>
                            <path>$focus/mailDomain</path>
                        </source>
                    </outbound>
                </tag>
            </multiplicity>
            <delineation>
                <objectClass>ri:group</objectClass>
            </delineation>
            <focus>
                <type>c:OrgType</type>
            </focus>
            <attribute>
                <ref>ri:dn</ref>
                <outbound>
                    <strength>strong</strength>
                    <source>
                        <path>$focus/name</path>
                    </source>
                    <source>
                        <path>$projection/tag</path>
                    </source>
                    <expression>
                        <script>
                            <code>
                               tag == null ? "cn=$name.orig,ou=Groups,ou=IDM,dc=ad,dc=example,dc=com" : "cn=${name.orig}_${tag},ou=Groups,ou=IDM,dc=ad,dc=example,dc=com"
                            </code>
                        </script>
                    </expression>
                </outbound>
            </attribute>
            <attribute>
                <ref>ri:displayName</ref>
                <outbound>
                    <strength>strong</strength>
                    <source>
                        <path>$focus/displayName</path>
                    </source>
                </outbound>
            </attribute>
            <attribute>
                <ref>ri:sAMAccountName</ref>
                <outbound>
                    <strength>strong</strength>
                    <source>
                        <path>$focus/name</path>
                    </source>
                    <source>
                        <path>$projection/tag</path>
                    </source>
                    <expression>
                        <script>
                            <code>
                               tag == null ? name.orig : "${name.orig}_${tag}"
                            </code>
                        </script>
                    </expression>
                </outbound>
            </attribute>
            <attribute>
                <ref>ri:groupType</ref>
                <outbound>
                    <strength>strong</strength>
                    <expression>
                        <value>-2147483646</value>
                    </expression>
                </outbound>
            </attribute>
        </objectType>

ポイントは以下の箇所です。ここでタグの数を無制限(unbounded)とし、アウトバウンドマッピングで使用するタグの取得元情報としてmailDomain属性を指定しています。これにより、mailDomain属性に設定した値がタグの値として利用されます。

            <multiplicity>
                <maxOccurs>unbounded</maxOccurs>
                <tag>
                    <outbound>
                        <source>
                            <path>$focus/mailDomain</path>
                        </source>
                    </outbound>
                </tag>
            </multiplicity>

そして、そのタグの値を「dn」の値に埋め込んでプロビジョニングするように、アウトバウンドマッピングを書いています。

            <attribute>
                <ref>ri:dn</ref>
                <outbound>
                    <strength>strong</strength>
                    <source>
                        <path>$focus/name</path>
                    </source>
                    <source>
                        <path>$projection/tag</path>
                    </source>
                    <expression>
                        <script>
                            <code>
                               tag == null ? "cn=$name.orig,ou=Groups,ou=IDM,dc=ad,dc=example,dc=com" : "cn=${name.orig}_${tag},ou=Groups,ou=IDM,dc=ad,dc=example,dc=com"
                            </code>
                        </script>
                    </expression>
                </outbound>
            </attribute>

同様に、「sAMAccountName」の値にもタグの値を埋め込んでいます。

            <attribute>
                <ref>ri:sAMAccountName</ref>
                <outbound>
                    <strength>strong</strength>
                    <source>
                        <path>$focus/name</path>
                    </source>
                    <source>
                        <path>$projection/tag</path>
                    </source>
                    <expression>
                        <script>
                            <code>
                               tag == null ? "$name.orig" : "${name.orig}_${tag}"
                            </code>
                        </script>
                    </expression>
                </outbound>
            </attribute>

Company Orgアーキタイプの修正

追加した「Category Group」オブジェクトタイプに対するインデュースメントを設定しておきます。

image.png

プロビジョニングの確認

組織「005」の詳細画面を開き、「メールドメイン」にemployeestaffinternの3つの値を追加して「変更のプレビュー」を見てみます。

image.png

サフィックスが付与された3つのグループが追加されようとしていることが分かります。「保存」ボタンをクリックして保存します。

image.png

この組織のプロジェクションを確認しておきます。以下のように、ADに対して4つのグループがプロビジョニングされた状態となっていることを確認できます。

image.png

試しに、「intern」を削除してまた変更のプレビューを確認すると、連動してデプロビジョニング(グループの削除)が行われることも確認できます。

image.png

このように タグ(tag) を活用することで、オブジェクトタイプを事前に追加することなく動的にマルチアカウントを表現することが可能となります。

タグ(tag)利用時のメンバーシップの連携設定

タグを使ったマルチアカウントでのADグループのプロビジョニングができたので、メンバーシップのプロビジョニングも実施します。種別(kind)と 用途(intent)のみを使用している場合は、静的に決まっているため以下のようなアソシエーションのアウトバウンドマッピングを定義していました。定義済みの種別(kind)と 用途(intent)を設定するだけでした。

    <inducement id="...">
        <construction>
            <strength>weak</strength>
            <resourceRef oid="..." relation="org:default" type="c:ResourceType">
                <!-- AD -->
            </resourceRef>
            <kind>account</kind>
            <intent>default</intent>
            <association id="...">
                <ref>group</ref>
                <outbound>
                    <expression>
                        <associationFromLink>
                            <projectionDiscriminator xsi:type="c:ShadowDiscriminatorType">
                                <kind>entitlement</kind>
                                <intent>default</intent>
                            </projectionDiscriminator>
                        </associationFromLink>
                    </expression>
                </outbound>
            </association>
        </construction>
        <order>2</order>
        <focusType>c:OrgType</focusType>
    </inducement>

一方、タグの場合は所属するプロジェクション(Shadowオブジェクト)が静的に決まらず動的に変わるため、同じ設定は利用できません。そこで、<associationTargetSearch>というタグを使って、ユーザーが所属するグループ(に紐づくShadowオブジェクト)を直接検索する設定を行います。

今回の例の場合、「Company Org」アーキタイプをRAW編集で開き、以下の<inducement>〜</inducement>を追加します。

<resourceRef oid="..."oidには、自身の環境のADリソースのoidを設定してください。

    <inducement>
        <construction>
            <strength>weak</strength>
            <resourceRef oid="..." relation="org:default" type="c:ResourceType">
                <!-- AD -->
            </resourceRef>
            <kind>account</kind>
            <intent>default</intent>
            <association>
                <ref>ri:group</ref>
                <outbound>
                    <expression>
                        <associationTargetSearch>
                            <filter>
                                <q:text>attributes/dn =[distinguishedName] ```
                                            // アーキタイプがアサインされていないユーザーの場合
                                            if (basic.isEmpty(focus.archetypeRef)) {
                                                return null
                                             }
                                            
                                            // ユーザーにアサインされているアーキタイプを取得
                                            archetype = midpoint.resolveReferenceIfExists(focus.archetypeRef)
                                            
                                            // アーキタイプが解決できない場合
                                            if (archetype == null) {
                                                return null
                                            }
                                            
                                            // アーキタイプ名をサフィックスとしてグループを探す
                                            return "cn=${immediateRole.name.orig}_${archetype.name},ou=Groups,ou=IDM,dc=ad,dc=example,dc=com"
                                        ```
                                </q:text>
                            </filter>
                        </associationTargetSearch>
                    </expression>
                </outbound>
            </association>
        </construction>
        <order>2</order>
        <focusType>c:UserType</focusType>
    </inducement>

<associationTargetSearch>の中では<filter>で検索クエリを設定します。<q:text>を使うと、midPoint Query Languageでクエリーを書くことができます。

midPoint Query Languageとは、midPointの至る所(GUI、スクリプト)で使用できる専用のクエリー言語です。詳細は以下の公式ドキュメントを参照してください。

https://docs.evolveum.com/midpoint/reference/support-4.8/concepts/query/midpoint-query-language/

今回の例では、ユーザーにアサインされているアーキタイプの名前(Employee)から所属させるグループ名を自動的に決めています。「Employee」アーキタイプが付与されているユーザーであれば、CN=組織名_employeeのADグループに所属させます。

このようにmidPoint Query Languageでは、中に埋め込む値をGroovyスクリプトでロジックを書いて動的に決めることができます。なお、スクリプト内で使用している以下の変数について補足しておきます。これらはアソシーションのアウトバウンドマッピングでデフォルトでバインドされている変数です。

  • focus:アソシーションのアウトバウンドマッピングを評価する対象のサブジェクト(今回の例だとユーザー)
  • immediateRole:このアウトバウンドマッピングを評価するに当たりサブジェクトにアサインされたオブジェクト(今回の例だと、サブジェクトであるユーザーにアサインされた組織オブジェクト)

タグ(tag)利用時のメンバーシップのプロビジョニング確認

005組織に所属する001ユーザーの詳細画面を開き、1件リコンサイルでプレビューを表示しで動作確認します。以下のように、CN=005_employeeのグループのみにメンバーシップがプロビジョニングされる予定であることが分かります。その他のグループ(CN=005_staffCN=005_intern)には所属となりません。

image.png

保存後、該当ユーザーのプロビジョクションを確認すると、memberOf属性に設定されていることが分かります。

image.png

まとめ

20日目では、midPointのマルチアカウント機能を活用したプロビジョニングについて解説しました。特に、タグ(tag)を使用したマルチアカウント機能は動的に対応できる点が特徴であり、柔軟に対応が可能です。

一人に対して複数アカウントの連携や、会社組織(本部や部など)単位で複数のADグループをプロビジョニングしたいケースはよく見かけると思いますので、本機能を活用していただければと思います。

  1. 11日目の記事「midPoint からCSVにプロビジョニングする」で紹介したプロビジョニング時の名寄せの処理です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?