NRI OpenStandia Advent Calendar 2021 の24日目は、OSSのIGAプラットフォームである midPoint に最近コントリビュートして対応が可能になった、Active DirectoryのForeign Security Principal を扱う方法について紹介します。
Foreign Security Principal とは
Foreign Security Principal (以下、FSP) とは、 信頼できる外部のフォレストの Security Principal を表すために、Active Directory (以下、AD) によって作成されるオブジェクト のことをいいます。FSPにより、外部のSecurity Principalを自分のドメイン内のセキュリティグループ (ただし、ドメインローカル限定) に追加し、リソースに対するパーミッションを付与することができます。
詳しくは、Microsoftの以下のページを参照してください。
FSPでADドメイン間のグループメンバーシップを表現する
FSPを使うことで、異なるADドメイン間でもフォレスト信頼関係が結ばれていれば、セキュリティグループに他ドメインのユーザを追加し、アクセス制御ができます。もう少し具体的な例で説明します。
以下のADドメインがあるとします。
a.example.com
b.example.com
そして、セキュリティグループとユーザがそれぞれ以下のように存在するとします。
- (ドメインローカルの) セキュリティグループ: cn=g001,OU=Groups,OU=Sample,DC=a,DC=example,DC=com
- ユーザ: cn=u001,OU=Users,OU=Sample,DC=b,DC=example,DC=com
ここで、このADドメインでフォレスト間の信頼関係を結び、ユーザ (cn=u001
) を異なるADドメイン上のセキュリティグループ (cn=g001
) にメンバーとして追加してアクセス制御したい、とします。
これは、ADの管理ツールである「Active Directoryユーザーとコンピューター」で操作を行うことで簡単に実施できます。前提としてフォレスト間の信頼関係が設定されていて、かつセキュリティグループのタイプがドメインローカルであれば1、該当セキュリティグループのメンバー編集画面にて、外部のADドメインのユーザーをメンバーとして設定できるようになります。
ただし、設定しても実際の外部ADドメインのユーザ (cn=u001
) の情報が直接メンバーとして登録されるわけではありません。ここで登場するのがFSPです。メンバーとして登録した瞬間に、この例だと a.example.com
のAD側で、ou=ForeignSecurityPrincipals コンテナ配下にFSPオブジェクトが1つ自動作成されます。そして、セキュリティグループのメンバーにはこの自動的に作成されたFSPオブジェクトが設定されています。
実は、このFSPのcn
値は、外部ADドメインのユーザ (cn=u001
) の objectSid
の値を指しています。つまり、下図のようにFSPオブジェクトを間に挟んで、間接的に外部ドメインのユーザがセキュリティグループに登録される形になります。
また、注意すべきAD上の制限として、このFSPオブジェクトを直接作成することができません。セキュリティグループのメンバーに追加したタイミングで、AD側で自動生成される仕組みとなります。
LDAPプロトコルでFSPを扱う場合の注意点
ADの管理ツールである「Active Directoryユーザーとコンピューター」で操作を行う分には意識しなくてよいですが、LDAPプロトコルでこのFSPを扱う場合には他の注意点があります。
セキュリティグループのメンバーとして登録する際のLDIFは、以下のようにする必要があります。通常、member
にはDNフォーマットで値を設定しますが、<SID=
+ objectSid
+ >
という特殊なフォーマットになります。<>
で挟むことが必要なので注意してください。
dn: cn=g001,OU=Groups,OU=Sample,DC=a,DC=example,DC=com
changetype: modify
add: member
member: <SID=外部ADドメインのユーザのobjectSidの値>
この特殊フォーマットが必要なのは、セキュリティグループのメンバーに登録する際だけです。一旦登録した後に、セキュリティグループからメンバーを解除する場合は、実体として登録されたFSPのDNをmember
に指定して解除することができます (特殊フォーマットでobjectSid
を指定してメンバー解除することも可能)。
midPointでどう扱うか
ここまで、AD側の仕組みの話をしました。いよいよ次に、midPointからどのようにしてこのようなグループメンバーシップ関係をプロビジョニングすることができるか、見ていきましょう。
ShadowObjectの構成
midPointでは、プロビジョニング先や源泉のデータをShadowObjectとして表現しています。a.example.com
ドメインに閉じてみると、g001
のセキュリティグループとFSPオブジェクトの間の通常のグループメンバーシップとして見ることができます。よって、下図のようにmidPoint内で各種オブジェクトを構成し、AD側にプロビジョニングできればよさそうです。
midPoint内でu001
のUserTypeに対して、b.example.com
には通常のADのuser
オブジェクトでプロビジョニングを行い、g001
のOrgTypeにアサインされたタイミングで、a.example.com
にはFSPオブジェクトとしてプロビジョニングさせるという考え方です。
midPointでFSPオブジェクトを扱う上での課題
前述の通りのShadowObjectを構成するように後は設定すればOK、といいたいところなのですが、AD側の仕様のところで説明したとおり、以下のAD側の仕様があります。
- FSPオブジェクトを直接作成できない。代わりに、セキュリティグループにメンバーとして登録する必要がある。
- メンバーに登録する際は、LDAPプロトコルでは
<SID=
+objectSid
+>
という特殊なフォーマットで指定する必要がある。
midPointによるADプロビジョニングは、標準でmidPoint本体にバンドルされている Active Directory Connector というコネクタを利用しますが、内部ではLDAPプロトコルを使用しています。コネクタはリソース (つまり、AD) に対するCRUD操作を実装していますので、FSPオブジェクトの作成時には処理を行わない、メンバー登録時には特殊フォーマットを利用するという特別な処理が必要になります。つまり、このコネクタがFSPを意識した処理を実装している必要があります。
残念ながら、Active Directory Connector はこの機能は備えておりませんでした。そこで、以下のプルリクエストを送りFSP対応機能を今回コントリビューションしました。
2021/12/24時点ではmidPoint本体にはまだバンドルされていませんが、JARファイルをActive Directory Connectorのサイトより取得して利用することができます。v3.3.1以降のものを利用してください。
リソース定義 (Active Directory Connector設定) / a.example.com
用
Active Directory Connector v3.3.1 以降を使い、設定します。以下、設定ポイントです。
FSP対応機能の有効化
デフォルトでは、コントリビューションしたFSP対応機能は無効になっています。有効にするには、以下のようにallowFSPProcessing
オプションをtrue
に設定します。
<icfc:configurationProperties xmlns:gen70="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/bundle/com.evolveum.polygon.connector-ldap/com.evolveum.polygon.connector.ldap.ad.AdLdapConnector">
...
<!--
フォレスト間グループメンバーシップをFSPを利用して行うため有効化
-->
<gen70:allowFSPProcessing>true</gen70:allowFSPProcessing>
</icfc:configurationProperties>
</connectorConfiguration>
また、FSPのスキーマ情報を取得するようにも設定しておきます(generationConstraints
でフィルタする場合)。
<schema>
<generationConstraints>
...
<!--
FSPのスキーマを取得
-->
<generateObjectClass>ri:foreignSecurityPrincipal</generateObjectClass>
</generationConstraints>
</schema>
schemaHandling
設定
まず、セキュリティグループそのもののプロビジョニング設定です。注意点として、ドメインローカルタイプのセキュリティグループとして作成する必要があります。これは、groupType
に-2147483644
を設定すればOKです。それ以外は従来のプロビジョニング設定と同じです。
<objectType>
<kind>entitlement</kind>
<intent>group</intent>
<displayName>グループ</displayName>
<default>false</default>
<objectClass>ri:group</objectClass>
...
<attribute>
<c:ref>ri:groupType</c:ref>
<outbound>
<strength>strong</strength>
<expression>
<script>
<code>
// ADの仕様上、フォレスト間グループメンバーシップをFSPで行うにはドメインローカルタイプのグループとする
// Global Security Group
// Global: -2147483646
// Domain Local: -2147483644
// Universal: -2147483640
return -2147483644
</code>
</script>
</expression>
</outbound>
</attribute>
</objectType>
次に、FSPオブジェクトのプロビジョニング設定です。ポイントは以下の3点です。
- 作成するRDNには、
b.example.com
のユーザのobjectSid
を取得してcn=objectSidの値
を設定する。 - 該当のセキュリティグループに対してAssociationの設定を行う。
-
ri:dn
のmatchingRule
にはdefault
を利用してCase-sensitiveモードで処理する。
例では、kind=account, intent=fsp
として定義しています。
<objectType>
<kind>account</kind>
<intent>fsp</intent>
<displayName>foreignSecurityPrincipal</displayName>
<default>false</default>
<objectClass>ri:foreignSecurityPrincipal</objectClass>
<baseContext>
<objectClass>ri:organizationalUnit</objectClass>
<filter>
<q:equal>
<q:path>attributes/dn</q:path>
<expression>
<script>
<code>
"CN=ForeignSecurityPrincipals,DC=a,DC=example,DC=com"
</code>
</script>
</expression>
</q:equal>
</filter>
</baseContext>
<attribute>
<ref>ri:dn</ref>
<!--
DN用のMatchingRuleはここでは使用しない。
DNは本来Case-insensitiveなため内部的に小文字で統一して管理されるが
DNを構成するSIDの値が小文字に変換されるとエラーとなる。
そこで、Case-sensitiveモードで処理する。
<matchingRule>distinguishedName</matchingRule>
-->
<matchingRule>default</matchingRule>
<outbound>
<strength>weak</strength>
<source>
<path>$focus/name</path>
</source>
<expression>
<script>
<code>
import com.evolveum.midpoint.xml.ns._public.common.common_3.*
// b.example.comのユーザのobjectSidを取得
shadow = midpoint.getLinkedShadow(focus, "611a0df5-3809-46af-a5fe-122a14a8a8ec", ShadowKindType.ACCOUNT, "default")
sid = basic.getAttributeValue(shadow, "objectSid")
return basic.composeDnWithSuffix("cn", sid, "CN=ForeignSecurityPrincipals,DC=a,DC=example,DC=com")
</code>
</script>
</expression>
</outbound>
</attribute>
<!--
FSPオブジェクトをセキュリティグループのメンバーとする
-->
<association>
<ref>ri:group</ref>
<displayName>AD Cross-forest Group Membership</displayName>
<tolerant>false</tolerant>
<kind>entitlement</kind>
<intent>group</intent>
<direction>objectToSubject</direction>
<associationAttribute>ri:member</associationAttribute>
<valueAttribute>ri:dn</valueAttribute>
<shortcutAssociationAttribute>ri:memberOf</shortcutAssociationAttribute>
<shortcutValueAttribute>ri:dn</shortcutValueAttribute>
<explicitReferentialIntegrity>false</explicitReferentialIntegrity>
</association>
</objectType>
リソース定義 (Active Directory Connector設定) / b.example.com
用
例の構成だと、b.example.com
側ではFSPオブジェクトを扱う必要がありませんので、こちら側のリソース定義は特に注意点はありません。単に、u001
をb.example.com
側のuser
オブジェクトとしてプロビジョニングするように通常の設定を行うだけでOKです。
プロビジョニング用のメタロールの作成
ADプロビジョニング用のメタロールをArchetypeTypeやRoleTypeで作成します。UserType用とOrgType用の2つを用意します。
UserType用
b.example.com
にu001
をプロビジョニングするだけなので、ここは通常のプロビジョニング用メタロールを設定すればOKです。
OrgType用
a.example.com
にg001
をプロビジョニングするための通常の設定に加えて、ここではFSPオブジェクトをプロビジョニングするための設定が必要になります。以下がその部分です。a.example.com
用のリソース定義で設定した kind=account, intent=fsp
に対してAssociationを設定することになります。
ここでのポイントは、condition
タグを利用して、(このメタロールがアサインされた) OrgTypeにUserTypeがアサインされた場合に、該当のUserTypeがb.example.com
に対するShadowObjectを持っているかどうかを条件とします。b.example.com
に対するShadowObjectを持つということは、b.example.com
にuser
オブジェクトがプロビジョニングされているということであり、FSPオブジェクトを使ってグループメンバーシップを結ぶ対象となります。
<!--
b.example.comのユーザのShadowObjectを持つユーザが
組織に所属した場合に、FSPでグループメンバーシップをプロビジョニングする
-->
<inducement>
<construction>
<strength>strong</strength>
<resourceRef oid="8a40cfef-a6ff-4baa-a88f-01c08789025d" relation="org:default" type="c:ResourceType">
</resourceRef>
<kind>account</kind>
<intent>fsp</intent>
<association>
<c:ref>ri:group</c:ref>
<outbound>
<authoritative>true</authoritative>
<strength>strong</strength>
<expression>
<associationFromLink>
<projectionDiscriminator>
<kind>entitlement</kind>
<intent>group</intent>
</projectionDiscriminator>
</associationFromLink>
</expression>
</outbound>
</association>
</construction>
<condition>
<expression>
<script>
<code>
import com.evolveum.midpoint.xml.ns._public.common.common_3.*
if (focus == null) {
return false
}
// b.example.comのユーザのShadowObjectが存在するかチェック
shadow = midpoint.getLinkedShadow(focus, "611a0df5-3809-46af-a5fe-122a14a8a8ec", ShadowKindType.ACCOUNT, "default")
return shadow != null
</code>
</script>
</expression>
</condition>
<order>2</order>
<focusType>c:UserType</focusType>
</inducement>
動作確認
以下のオペレーションを実施することでFSPオブジェクトが想定通りプロビジョニングされることを確認できます。
- midPointで
g001
のOrgTypeを作成してメタロールを適用 =>a.example.com
にg001
セキュリティグループがプロビジョニングされる。 - midPointで
u001
のUserTypeを作成してメタロールを適用 =>b.example.com
にu001
ユーザがプロビジョニングされる。 - midPointで
u001
のUserTypeに、g001
のOrgTypeをアサインする =>a.example.com
にFSPオブジェクトが作成され、g001
のメンバーにそのFSPオブジェクトが設定される。
確認した環境
このFSPオブジェクトを利用したグループメンバーシップのプロビジョニングは、以下の環境で動作確認済みです。AD互換のSamba 4でもフォレスト間信頼が実装されており、FSPオブジェクトをAD同様に扱うことが可能になっています。なお、Samba 4でフォレスト間信頼を設定するには、こちらのStefan Kania氏のサイトで公開されている Seting up trusts between two Samba-domains を参考にするとよいでしょう。
- Windows Server 2019
- AWS Managed Microsoft AD
- Samba 4.13.14
ただし、AWS Managed Microsoft ADの場合はAWSの仕様により、用意されている管理者アカウントでもAD操作権限が制限されており、以下の操作ができません。
- FSPオブジェクトの
memberOf
が参照できない - FSPオブジェクトを削除できない
そこで、もしa.example.com
がAWS Managed Microsoft ADの場合は、以下の様にリソース定義を設定することでこの問題を回避することができます。
-
<association>
:memberOf
参照を利用したショートカットを使わないようにする -
<existence>
: FSPオブジェクトが削除されないようにする
具体的な設定例は以下のようになります。
<association>
<ref>ri:group</ref>
<displayName>AD cross-forest group membership</displayName>
<tolerant>false</tolerant>
<kind>entitlement</kind>
<intent>group</intent>
<direction>objectToSubject</direction>
<associationAttribute>ri:member</associationAttribute>
<valueAttribute>ri:dn</valueAttribute>
<!--
AWS Managed Microsoft ADの場合はショートカットは使えない
<shortcutAssociationAttribute>ri:memberOf</shortcutAssociationAttribute>
<shortcutValueAttribute>ri:dn</shortcutValueAttribute>
-->
<explicitReferentialIntegrity>false</explicitReferentialIntegrity>
</association>
<activation>
<existence>
<outbound>
<expression>
<script>
<code>
// AWS Managed Microsoft ADではFSPオブジェクトの削除が
// 禁止されているため、削除を抑止する
true
</code>
</script>
</expression>
</outbound>
</existence>
</activation>
まとめ
NRI OpenStandia Advent Calendar 2021 の24日目は、midPointでADのFSPをどう扱えばよいかをご紹介しました。FSPを利用したグループメンバーシップを設定する必要のある大規模・複雑なAD構成を持っており、midPointでうまくエンタイトルメント管理をされたい方は是非試してみてください。
-
ADの仕様で、ドメインローカルタイプのセキュリティグループのみが、外部ドメインのユーザをグループに追加することができます。 ↩