(ヽ´ω`) < 助けてほしいマン

わからないことを助けてほしいマンが書くブログ

(ヽ´ω`) < OpenLDAP + SSSDでLinuxログインアカウント一元管理がさっぱりわからん - 3. SSSDの設定 -

(ヽ´ω`) < SSSDが特によくわからん

そもそもSSSDってなんなのよ、という話になるが、RedHatがメインで開発しているオープンソースの統合認証基盤FreeIPAに付随して作成されたソフトウェアとのこと。

じゃあそのFreeIPAって何? となるとこれはもう下記の記事でも読んでくれとしか言えないぐらい、色々な機能を持っている。

thinkit.co.jp

ちなみに記事の題名が「Linuxの認証を簡単にする」と書いてあるが、機能てんこ盛りの構成要素てんこ盛りなので、最初の稼働させるまでは簡単かもしれないのだが、軽い気持ちで実際に運用し始めると軽く地獄を見ると思う。見た。見ている。

そんな重厚でイケてるFreeIPAという基盤に、認証要求元のサーバから実際に問い合わせを行う役割を担うのがSSSDとなる。

実際にはその前にPAMとNSSが入っていて、PAM・NSSから投げられた処理要求をSSSDがキャッシュやらなんやらでうまいこと処理しつつ、更に後ろのFreeIPAやらOpenLDAPやらActiveDirectoryに問い合わせを行ってくれる。

下記のサイトの一番上の図を引用する。

www.certdepot.net

f:id:tsugi-hagi:20191125144438p:plain
Quote From https://www.certdepot.net/rhel8-identity/

この図で左側の "Client" はLinux(より厳密に言うとLinux上のNSSとPAM)で、真ん中にSSSD。右側の "Identity Server" と "Authentication Server" はOpenLDAP, FreeIPA, ActiveDirectoryなどになる。

そう、実はFreeIPAだけではなくOpenLDAP(特にOpenLDAPだけでもないが)やActiveDirectoryも認証のバックエンドとして設定が可能で、今回はOpenLDAPを使った設定を行っていく。

(ヽ´ω`) < パッケージインストール

ここからの作業は、前の記事までで作成したOpenLDAPサーバではなく、実際の認証を行うStagingサーバに対して実施する。
(テストとしてOpenLDAPと同じサーバで設定しても問題なし)

必要になるパッケージをインストールする。

# yum install sssd sssd-client sssd-ldap sssd-tools sssd-common oddjob-mkhomedir

(ヽ´ω`) < SSSDの有効化

SSSDサービスの有効化とNSS, PAMの設定ファイルへの組み込みを行う。

上にも書いた通り、SSSDはNSSとPAMから呼び出されてユーザ情報をバックエンドに拾いに行くので、 /etc/nsswitch.conf/etc/pam.d 以下のファイルにエントリを追加する必要がある。

nsswitch.confはまだいいとして、PAM関連の設定ファイルは触りたくないという人も多いと思うがご安心を。
このための authconfig というコマンドが用意されている。(RHEL8からは非推奨パッケージとなっていて authselect で代替するように言われているが…)

# authconfig --enablesssd --enablesssdauth --enablemkhomedir --update

これにより /etc/nsswitch.conf/etc/pam.d 以下のファイルにSSSDを使用するための設定が追記される。

また --enablemkhomedir により、ユーザログイン時にホームディレクトリが存在しない場合は、自動で作成されるようにPAMの system-authsession にエントリが追加される。

(ヽ´ω`) < sssd.confの作成

/etc/sssd/sssd.conf を作成して、SSSDの動作を定義する。
このファイルの中でOpenLDAPのサーバIPアドレスや、バインドユーザ情報、どのグループに対してログイン・sudoを許可するかを指定していく。

不親切なことにSSSDパッケージをインストールしても、サンプルファイルのようなものは作成してくれないので、0から入力していく必要がある。 流石に面倒なので下記の内容をまるっとコピーして必要な箇所だけ修正していく。

[sssd]
config_file_version = 2
services = nss, pam, sudo, ssh
domains = default

[domain/default]
id_provider = ldap
chpass_provider = none

ldap_uri = ldap://172.16.1.177
ldap_search_base = dc=tsugihagi,dc=local
ldap_id_use_start_tls = False
ldap_tls_reqcert = allow

ldap_default_bind_dn = cn=Manager,dc=tsugihagi,dc=local
ldap_default_authtok_type = password
ldap_default_authtok = hogehoge

ldap_user_ssh_public_key = sshPublicKey

access_provider = simple
simple_allow_groups = managers,sre

ldap_sudo_search_base = cn=staging-server,ou=Sudoers,dc=tsugihagi,dc=local

[nss]
memcache_timeout = 300
filter_groups = root
filter_users = root
entry_cache_nowait_percentage = 75

[pam]

[ssh]

[sudo]

下記のmanを参考にしながら、上から確認していく。(下記のリンクを見ての通り、設定可能な項目が非常に多い。最低限必要と思われる箇所だけ設定していく)

sssd.conf(5): config file for SSSD - Linux man page

sssd-ldap(5): config file for SSSD - Linux man page

sssd-sudo(5): config file for SSSD - Linux man page

sssd-simple(5) - Linux man page

(ヽ´ω`) < Special Section

[sssd]
config_file_version = 2
services = nss, pam, sudo, ssh
domains = default

[sssd] から始まるセクションはSpecial Sectionと呼ばれる。

実はSSSDは単一のサービスではなく、複数の、それぞれの処理を担当するサービスから成り立っている。
それら複数のサービスをまとめて管理するためのサービスはmonitorと呼ばれ、そのmonitorサービスの設定を行うのがこのセクション。


config_file_version = 2

設定ファイルの文法を指定する。SSSD 0.6.0以降は2となる。


services = nss, pam, sudo, ssh

先程複数のサービスから成り立っていると書いたが、どのサービスを使用するかを指定する。

ここで指定したサービスが sssd.service の起動と同時に起動される。
systemdのUnitファイルも確認可能。

# ls /usr/lib/systemd/system/sssd*.service
/usr/lib/systemd/system/sssd-autofs.service  /usr/lib/systemd/system/sssd-pac.service      /usr/lib/systemd/system/sssd.service
/usr/lib/systemd/system/sssd-ifp.service     /usr/lib/systemd/system/sssd-pam.service      /usr/lib/systemd/system/sssd-ssh.service
/usr/lib/systemd/system/sssd-nss.service     /usr/lib/systemd/system/sssd-secrets.service  /usr/lib/systemd/system/sssd-sudo.service

domains = default

SSSDではユーザ情報を保持するデータベースのことをdomainと呼ぶ。またdomainは複数定義することができる。
domains ではdomainが複数存在する場合、どの順番でドメインに対して問い合わせを行うかを指定する。

今回はdomainは1つしか使用しない想定なので、どのdomainにdefaultという名前をつけて定義する。

(ヽ´ω`) < Domain Section

[domain/default]
id_provider = ldap
chpass_provider = none

ldap_uri = ldap://172.16.1.177
ldap_search_base = dc=tsugihagi,dc=local
dap_tls_reqcert = allow

ldap_default_bind_dn = cn=Manager,dc=tsugihagi,dc=local
ldap_default_authtok_type = password
ldap_default_authtok = hogehoge

ldap_user_ssh_public_key = sshPublicKey

access_provider = simple
simple_allow_groups = managers,sre

ldap_sudo_search_base = cn=staging-server,ou=Sudoers,dc=tsugihagi,dc=local

上で記載したとおり、SSSDではユーザ情報を格納するデータベースをdomainと呼ぶが、そのdomainの情報を設定するセクションが Domain Section。
基本的にはこのセクションの設定が一番多くなる。


[domain/default]

domainの名前を記載する。

defaultという名前をつけてあるが、これは別に予約されたキーワードでもなんでもないため特にこの名前にしないといけないということはない。(hogeみたいな名前でもOK)


id_provider = ldap

ユーザ情報をどこから取得するのかを設定する。

今回はOpenLDAPなので ldap と設定。他の値としては、FreeIPAの ipa 、ActiveDirectoryを使用する際の ad がある。


chpass_provider = none

パスワード変更要求が来た場合、どのデータベースで処理するのかを指定する。

今回は公開鍵認証を行うので、ユーザのパスワードは取り扱わない。そのため明示的に none を設定しておく。


ldap_uri = ldap://172.16.1.177

LDAPサーバのURI。

LDAPSを使う場合は ldaps:// を指定する。


ldap_search_base = dc=tsugihagi,dc=local

LDAPサーバに対して問い合わせ(クエリ)を発行する際のベースDN。

規模が大きくなる場合は分けたほうが管理がしやすいかもしれないが、今回はサフィックスを使用。


ldap_id_use_start_tls = False

LDAPサーバに接続した後にSTARTTLSで通信の暗号化を開始するか否か。

本番環境で扱うには暗号化は必須なのだが、その場合証明書の管理から考えないといけないので、今回は一旦暗号化は考慮せずに話をすすめる。


ldap_tls_reqcert = allow

LDAPサーバのサーバ証明書チェックの挙動。

デフォルトは hard で証明書が確認できなかった場合は接続を切断する。
allow は証明書が確認できない、不正な証明書であっても、そのまま接続を続行する。


ldap_default_bind_dn = cn=Manager,dc=tsugihagi,dc=local

LDAPサーバに接続する際のバインドユーザのDN。


ldap_default_authtok_type = password

バインドパスワードの形式。 password は平文でのパスワード記載となる。
obfuscated_password を指定することで難読化することが可能。
実際に設定するには、一旦この値を password と指定してsssd.confを作成後に sss_obfuscate コマンドを実行してやる。

# sss_obfuscate --domain=default

これによって /etc/sssd/sssd.conf の中身が書き換えられて

# diff sssd.conf.bak sssd.conf -u
--- sssd.conf.bak   2019-11-21 09:06:03.103978668 +0000
+++ sssd.conf   2019-11-21 09:06:27.139753597 +0000
@@ -5,7 +5,6 @@
<-- snip -->
-ldap_default_authtok_type = password
-ldap_default_authtok = hogehoge
+ldap_default_authtok_type = obfuscated_password

+ldap_default_authtok = AAAQAEHorIy2fGqSEof7f3erz5FNMvY+0xJsat5MEIFwprl9JwzghKumq3VbkJzkVHAM/8PdCM0fXSfB/EtiA8DJbn4AAQID

<-- snip -->

こんな感じになるのだが… なぜか他のエントリを巻き込んで内容を消してしまったりする。(あるいはsssd.confの内容全てが消えてしまう)

実行する際には sssd.conf のバックアップを取っておいて、コマンド実行後に該当箇所だけコピペをして復元してやる必要がある。

理想を言うならパスワード認証ではなく、クライアント証明書認証を使うべきなので、これは通信経路のTLS化も含めて後から変更する。


ldap_default_authtok = hogehoge

LDAP接続に使用するパスワード。

平文で保存したくない場合は上記の方法で難読化をする。

sssd.conf はパーミッションが 600 でないとSSSDサービスの起動に失敗するので、OS内の他のユーザにパスワードを見られるという危険性はないのだが、構成管理ツール等で構築している場合はソースを閲覧可能なユーザには見られてしまう。

またこの設定ではサーバに接続する際に平文でパスワードを流してしまうので、LDAPSで接続するのが好ましい。この設定については一旦動作確認が取れたあとで追加設定として実施する。


ldap_user_ssh_public_key = sshPublicKey

SSH公開鍵の値が格納されている属性名。


access_provider = simple
simple_allow_groups = managers,sre

SSSDによるアクセスコントロールの方法。

SSSDが認証を行う場合、どのユーザ/グループに対してアクセスを許可するかを制御することができる。
ここでは対象のサーバがstagingサーバであると仮定して simple_allow_groupsmanagers,sre グループに対してアクセスを許可している。

この値を設定することで、どのグループに対してサーバへのログインを許可するかを設定している。( ldap_search_baseou=Groups に設定してあるためそのレベルでのフィルタリングは行っていない)


ldap_sudo_search_base = cn=staging-server,ou=Sudoers,dc=tsugihagi,dc=local

sudoRoleエントリを探すベースDN。

cn=dev-server まで指定してやる。
ou=Sudoers で終わると ou=Sudoers 以下にある全てのsudoRoleエントリが対象となってしまい、サーバ別でのsudoグループが管理できなくなってしまう。(全てのsudoRoleオブジェクトクラスを継承したエントリが検索対象となってしまう)

厳密に言うと sudoHost の値がALLではなく、正確に対象となるホスト名を指定してあればそちらでコントロールが可能なのだが、下記の理由から sudoHost での管理ではなく、この ldap_sudo_search_base の設定による管理としている。

  • AutoScalingGroup管理下のEC2インスタンスではデフォルトのホスト名がインスタンスIDとなる。
  • 上記のような動的に作成・削除されるインスタンスに対して、全て同じホスト名を設定してしまうのは、メトリクス収集システムと相性が悪いケースが多い。例えばDatadogではデフォルトのホスト名がhostnameコマンドの戻り値。
  • sudoHost の値は完全一致で、例えば "ServiceA-*" のようなワイルドカード指定ができない。

ちなみにmanの ldap_sudo_hostname についての記載

Space separated list of hostnames or fully qualified domain names that should be used to filter the rules. If this option is empty, SSSD will try to discover the hostname and the fully qualified domain name automatically.

これを見ると sudoHost の評価に使用されるホスト名を hostname コマンドの出力とは別で、このオプションで指定できるように見えるのだが、

bugzilla.redhat.com

The option ldap_sudo_hostname may be used to change what rules are cached but its useless without changing the system hostname at this moment, so it is more for testing purpose. There is currently no sudo RFE to support changing the hostname AFAIK.

とのこと。

(ヽ´ω`) < sudoersの設定

authconfig コマンドの実行で /etc/nsswitch.conf の内容が書き換えられるのだが、sudoersの検索については手動でエントリを追加してやる必要がある。

echo "sudoers: files sss" >> /etc/nsswitch.conf

(ヽ´ω`) < サービスの有効化・起動

sssd.conf の作成が完了したら、オーナーをrootでパーミッションを600に設定してやる。

chown root:root /etc/sssd/sssd.conf
chmod 600 /etc/sssd/sssd.conf

で、サービスの有効化と起動。ついでに自動でホームディレクトリを作成する処理をしてくれるoddjob-mkhomedirを管理するoddjobdも。

systemctl enable sssd
systemctl start sssd
systemctl enable oddjobd
systemctl start oddjobd

(ヽ´ω`) < 動作確認

id コマンドでユーザ情報が引けるかを確認する。

# id dev-member
uid=10004(dev-member) gid=10002(dev) groups=10002(dev)

# id sre-member
uid=10003(sre-member) gid=10001(sre) groups=10001(sre)

# id sre-senior-member
uid=10002(sre-senior-member) gid=10001(sre) groups=10001(sre)

# id sre-manager
uid=10001(sre-manager) gid=10000 groups=10000,10001(sre),10003(managers)

# id hoge
id: hoge: no such user

ここではサーバへのログイン可・不可を問わず( simple_allow_groups の設定を問わず)対象ユーザのid情報を引くことができる。

これが気持ち悪い場合は ldap_group_search_base オプションで、グループを検索するベースDNを設定する。ここでは最低限のsssd.confの設定とするため省略した。

また、同様に sudo -l -U でsudo権限についても確認する。

# sudo -l -U dev-member
User dev-member is not allowed to run sudo on ip-172-16-1-158.

# sudo -l -U sre-member
User sre-member is not allowed to run sudo on ip-172-16-1-158.

# sudo -l -U sre-senior-member
Matching Defaults entries for sre-senior-member on ip-172-16-1-158:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE
    KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION
    LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE
    LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User sre-senior-member may run the following commands on ip-172-16-1-158:
    (root) ALL

# sudo -l -U sre-manager
Matching Defaults entries for sre-manager on ip-172-16-1-158:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE
    KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION
    LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE
    LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User sre-manager may run the following commands on ip-172-16-1-158:
    (root) ALL

意図したとおり、 Stagingサーバについては sre-senior-member , sre-manager にのみsudo権限が付与されていることが確認できる。

(ヽ´ω`) < 次は?

グループとsudo権限の確認が出来たので、最後にsshd側の設定を行ってOSの認証をコントロールする。